diff options
Diffstat (limited to 'web/app')
| -rw-r--r-- | web/app/api/auth/[...nextauth]/route.tsx | 3 | ||||
| -rw-r--r-- | web/app/api/v1/links/route.ts | 60 | ||||
| -rw-r--r-- | web/app/favicon.ico | bin | 0 -> 25931 bytes | |||
| -rw-r--r-- | web/app/globals.css | 76 | ||||
| -rw-r--r-- | web/app/layout.tsx | 22 | ||||
| -rw-r--r-- | web/app/page.tsx | 15 |
6 files changed, 176 insertions, 0 deletions
diff --git a/web/app/api/auth/[...nextauth]/route.tsx b/web/app/api/auth/[...nextauth]/route.tsx new file mode 100644 index 00000000..bfcda516 --- /dev/null +++ b/web/app/api/auth/[...nextauth]/route.tsx @@ -0,0 +1,3 @@ +import { authHandler } from "@/lib/auth"; + +export { authHandler as GET, authHandler as POST } diff --git a/web/app/api/v1/links/route.ts b/web/app/api/v1/links/route.ts new file mode 100644 index 00000000..5be1018e --- /dev/null +++ b/web/app/api/v1/links/route.ts @@ -0,0 +1,60 @@ +import { authOptions } from "@/lib/auth"; +import prisma from "@/lib/prisma"; +import { ZNewBookmarkedLinkRequest, ZGetLinksResponse, ZBookmarkedLink } from "@/lib/types/api/links"; +import { getServerSession } from "next-auth"; +import { NextRequest, NextResponse } from "next/server"; + +export async function POST(request: NextRequest) { + // TODO: We probably should be using an API key here instead of the session; + const session = await getServerSession(authOptions); + if (!session) { + return new Response(null, { status: 401 }); + } + + const linkRequest = ZNewBookmarkedLinkRequest.safeParse(await request.json()); + + if (!linkRequest.success) { + return NextResponse.json({ + error: linkRequest.error.toString(), + }, { status: 400 }); + } + + const link = await prisma.bookmarkedLink.create({ + data: { + url: linkRequest.data.url, + userId: session.user.id, + } + }); + + let response: ZBookmarkedLink = { ...link }; + + return NextResponse.json(response, { status: 201 }); +} + +export async function GET() { + // TODO: We probably should be using an API key here instead of the session; + const session = await getServerSession(authOptions); + if (!session) { + return new Response(null, { status: 401 }); + } + const links = await prisma.bookmarkedLink.findMany({ + where: { + userId: session.user.id, + }, + select: { + id: true, + url: true, + createdAt: true, + details: { + select: { + title: true, + description: true, + imageUrl: true, + } + }, + } + }); + + let response: ZGetLinksResponse = { links }; + return NextResponse.json(response); +} diff --git a/web/app/favicon.ico b/web/app/favicon.ico Binary files differnew file mode 100644 index 00000000..718d6fea --- /dev/null +++ b/web/app/favicon.ico diff --git a/web/app/globals.css b/web/app/globals.css new file mode 100644 index 00000000..6a757250 --- /dev/null +++ b/web/app/globals.css @@ -0,0 +1,76 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +}
\ No newline at end of file diff --git a/web/app/layout.tsx b/web/app/layout.tsx new file mode 100644 index 00000000..3314e478 --- /dev/null +++ b/web/app/layout.tsx @@ -0,0 +1,22 @@ +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + <html lang="en"> + <body className={inter.className}>{children}</body> + </html> + ); +} diff --git a/web/app/page.tsx b/web/app/page.tsx new file mode 100644 index 00000000..2df40508 --- /dev/null +++ b/web/app/page.tsx @@ -0,0 +1,15 @@ +import { LoginButton } from "../components/auth/login"; +import { LogoutButton } from "../components/auth/logout"; + +export default function Home() { + return ( + <main className="flex min-h-screen flex-col items-center justify-between p-24"> + <div> + <LoginButton /> + <br /> + <br /> + <LogoutButton /> + </div> + </main> + ); +} |
