-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6a321b4
commit 733ca48
Showing
62 changed files
with
2,911 additions
and
620 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
Oops, something went wrong.