Skip to content

Commit

Permalink
1
Browse files Browse the repository at this point in the history
  • Loading branch information
Zachary-MacArthur committed Dec 17, 2024
1 parent 6a321b4 commit 733ca48
Show file tree
Hide file tree
Showing 62 changed files with 2,911 additions and 620 deletions.
26 changes: 26 additions & 0 deletions actions/getActiveProductsWithPrices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"

import { ProductWithPrice } from "@/types"

const getActiveProductsWithPrices = async (): Promise<ProductWithPrice[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})

const { data, error } = await supabase
.from("products")
.select("*, prices(*)")
.eq("active", true)
.eq("prices.active", true)
.order("metadata->index")
.order("unit_amount", { foreignTable: "prices" })

if (error) {
console.log(20, "getActiveProductsWithPrices - ", error.message)
}

return (data as any) || []
}

export default getActiveProductsWithPrices
27 changes: 27 additions & 0 deletions actions/getLikedSongs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Song } from "@/types"
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"

const getLikedSongs = async (): Promise<Song[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})

const {
data: { session },
} = await supabase.auth.getSession()

const { data } = await supabase
.from("liked_songs")
.select("*, songs(*)")
.eq("user_id", session?.user?.id)
.order("created_at", { ascending: false })

if (!data) return []

return data.map(item => ({
...item.songs,
}))
}

export default getLikedSongs
20 changes: 20 additions & 0 deletions actions/getSongs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"

import { Song } from "@/types"

const getSongs = async (): Promise<Song[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})

const { data, error } = await supabase.from("songs").select("*").order("created_at", { ascending: false })

if (error) {
console.log(17, "getSongs error - ", error.message)
}

return (data as any) || []
}

export default getSongs
29 changes: 29 additions & 0 deletions actions/getSongsById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Song } from "@/types"
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"

const getSongsById = async (): Promise<Song[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})
const { data: sessionData, error: sessionError } = await supabase.auth.getSession()

if (sessionError) {
console.log(12, "session error in getSongsById - ", sessionError.message)
return []
}

const { data, error } = await supabase
.from("songs")
.select("*")
.eq("user_id", sessionData.session?.user.id)
.order("created_at", { ascending: false })

if (error) {
console.log(23, "getSongsById error - ", error.message)
}

return (data as any) || []
}

export default getSongsById
31 changes: 31 additions & 0 deletions actions/getSongsByTitle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies, headers } from "next/headers"

import { Song } from "@/types"

import getSongs from "./getSongs"

const getSongsByTitle = async (title: string): Promise<Song[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})

if (!title) {
const allSongs = await getSongs()
return allSongs
}

const { data, error } = await supabase
.from("songs")
.select("*")
.ilike("title", `%${title}%`)
.order("created_at", { ascending: false })

if (error) {
console.log(25, "error - ", error.message)
}

return (data as any) || []
}

export default getSongsByTitle
35 changes: 35 additions & 0 deletions actions/getSongsByUserId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"

import { Song } from "@/types"

const getSongsByUserId = async (): Promise<Song[]> => {
const supabase = createServerComponentClient({
cookies: cookies,
})

const { data: sessionData, error: sessionError } = await supabase.auth.getSession()

if (sessionError) {
console.log(14, "session error in getSongsByUserId - ", sessionError.message)
return []
}
if (!sessionData.session) {
// it means user not authenticated
return []
}

const { data, error } = await supabase
.from("songs")
.select("*")
.eq("user_id", sessionData.session?.user.id)
.order("created_at", { ascending: false })

if (error) {
console.log(25, "select songs eq user_id error in getSongsByUserId - ", error.message)
}

return (data as any) || []
}

export default getSongsByUserId
38 changes: 38 additions & 0 deletions app/(site)/components/PageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client"

import { Song } from "@/types"
import useOnPlay from "@/hooks/useOnPlay"
import SongItem from "@/components/SongItem"

interface PageContentProps {
songs: Song[]
}

const PageContent: React.FC<PageContentProps> = ({ songs }) => {
const onPlay = useOnPlay(songs)

if (songs.length === 0) {
return <div className="mt-4 text-neutral-400">No songs available.</div>
}

return (
<div
className="
grid
grid-cols-2
sm:grid-cols-3
md:grid-cols-3
lg:grid-cols-4
xl:grid-cols-5
2xl:grid-cols-8
gap-4
mt-4
">
{songs.map(item => (
<SongItem onClick={(id: string) => onPlay(id)} key={item.id} data={item} />
))}
</div>
)
}

export default PageContent
72 changes: 24 additions & 48 deletions app/(site)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,29 @@
import Header from "@/components/Header"
import ListItem from "@/components/ListItem"
import getSongs from "@/actions/getSongs"
import Header from "../../components/Header"
import ListItem from "../../components/ListItem"
import PageContent from "./components/PageContent"

export const revalidate = 0

export default async function Home() {
const songs = await getSongs()

export default function Home() {
return (
<div className="
bg-neutral-900
rounded-lg
h-full
w-full
overflow-hidden
overflow-y-auto
">
<Header>
<div className="mb-2">
<h1
className="
text-white
text-3xl
font-semibold
">
Welcome back
</h1>
<div
className="
grid
grid-cols-2
sm:grid-cols-3
xl:grid-cols-4
gap-3
mt-4
">
<ListItem
image="/images/liked.png"
name="Liked Songs"
href="liked"
/>
</div>
</div>
</Header>
<div className="mt-2 mb-7 px-6">
<div className="flex justify-between items-center">
<h1 className="text-white text-2xl font-semibold">
New songs
</h1>
</div>
<div>
List of songs
</div>
<div className="text-neutral-400 rounded-lg w-full h-full overflow-hidden overflow-y-auto">
<Header>
<div className="mb-2">
<h1 className="text-white text-3xl font-semibold">Welcome back</h1>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-3 mt-4">
<ListItem image="/images/liked.png" name="Liked Songs" href="liked" />
</div>
</Header>
<div className="mt-2 mb-7 px-6">
<div className="flex justify-between items-center">
<h1 className="text-white text-2xl font-semibold">Newest Songs</h1>
</div>
<PageContent songs={songs} />
</div>
</div>
);
)
}
63 changes: 63 additions & 0 deletions app/account/components/AccountContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client"

import { useEffect, useState } from "react"
import { useRouter } from "next/navigation"

import { useUser } from "@/hooks/useUser"
import Button from "@/components/Button"
import useSubscribeModal from "@/hooks/useSubscribeModal"
import { postData } from "@/libs/helpers"

const AccountContent = () => {
const router = useRouter()
const subscribeModal = useSubscribeModal()
const { isLoading, subscription, user } = useUser()

const [loading, setLoading] = useState(false)

useEffect(() => {
if (!isLoading && !user) {
router.replace("/")
}
}, [isLoading, user, router])

const redirectToCustomerPortal = async () => {
setLoading(true)
try {
const { url, error } = await postData({
url: "/api/create-portal-link",
})
window.location.assign(url)
} catch (error) {
if (error) return alert((error as Error).message)
}
setLoading(false)
}

return (
<div className="mb-7 px-6">
{!subscription && (
<div className="flex flex-col gap-y-4">
<p>No active plan.</p>
<Button onClick={subscribeModal.onOpen} className="w-[300px]">
Subscribe
</Button>
</div>
)}
{subscription && (
<div className="flex flex-col gap-y-4">
<p>
You are currently on the
<b> {subscription?.prices?.products?.name} </b>
plan.
</p>
<Button disabled={loading || isLoading} onClick={redirectToCustomerPortal} className="w-[300px]">
Open customer portal
</Button>
</div>
)}
</div>
)
}

export default AccountContent
10 changes: 10 additions & 0 deletions app/account/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client"
import Box from "@/components/Box"

export default function Error() {
return (
<Box className="h-full justify-center items-center">
<div className="text-neutral-400">Something went wrong</div>
</Box>
)
}
12 changes: 12 additions & 0 deletions app/account/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client"
import { BounceLoader } from "react-spinners"

import Box from "@/components/Box"

export default function Loading() {
return (
<Box className="h-full flex justify-center items-center">
<BounceLoader color="#22c55e" size={40} />
</Box>
)
}
15 changes: 15 additions & 0 deletions app/account/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Header from "@/components/Header"
import AccountContent from "./components/AccountContent"

export default function Page() {
return (
<div className="bg-neutral-900 rounded-lg w-full h-full overflow-hidden overflow-y-auto">
<Header className="from-bg-neutral-900">
<div className="mb-2 flex flex-col gap-y-6">
<h1 className="text-white text-3xl font-semibold">Account Settings</h1>
</div>
</Header>
<AccountContent />
</div>
)
}
Loading

0 comments on commit 733ca48

Please sign in to comment.