-
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.
Add login and registration page to the frontend
- Loading branch information
Showing
13 changed files
with
322 additions
and
21 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,9 @@ | ||
import { LoginForm } from "@/components/login-form" | ||
|
||
export default function Page() { | ||
return ( | ||
<div className="flex h-screen w-full items-center justify-center px-4"> | ||
<LoginForm /> | ||
</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
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,139 @@ | ||
"use client"; | ||
import { useState } from "react"; | ||
import { useRouter } from "next/navigation"; | ||
import useUser from "@/hooks/use-user"; | ||
|
||
import Link from "next/link"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
|
||
export function LoginForm() { | ||
const router = useRouter(); | ||
const { mutate } = useUser(); | ||
|
||
const [email, setEmail] = useState(""); | ||
const [password, setPassword] = useState(""); | ||
|
||
const handleLogin = async () => { | ||
try { | ||
const body = new URLSearchParams(); | ||
body.append("username", email || ""); | ||
body.append("password", password || ""); | ||
|
||
const response = await fetch("/api/auth/login", { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
Accept: "application/json", | ||
}, | ||
credentials: "include", | ||
body: body.toString(), | ||
}); | ||
|
||
if (!response.ok) { | ||
const errorData = await response.json(); | ||
alert("Login failed: " + errorData.detail); | ||
return; | ||
} | ||
|
||
await mutate(); | ||
|
||
if (typeof window !== "undefined" && window.history.length > 1) { | ||
router.back(); | ||
} else { | ||
router.push("/"); | ||
} | ||
} catch (error) { | ||
console.error("An unexpected error occurred:", error); | ||
alert("An unexpected error occurred"); | ||
} | ||
}; | ||
|
||
const handleRegister = async () => { | ||
try { | ||
const response = await fetch("/api/auth/register", { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
Accept: "application/json", | ||
}, | ||
credentials: "include", | ||
body: JSON.stringify({ | ||
email, | ||
password, | ||
}), | ||
}); | ||
|
||
if (!response.ok) { | ||
const errorData = await response.json(); | ||
alert("Registration failed: " + errorData.detail); | ||
return; | ||
} | ||
|
||
await mutate(); | ||
|
||
handleLogin(); | ||
} catch (error) { | ||
console.error("An unexpected error occurred:", error); | ||
alert("An unexpected error occurred"); | ||
} | ||
}; | ||
|
||
return ( | ||
<Card className="mx-auto w-96"> | ||
<CardHeader> | ||
<CardTitle className="text-2xl">Login or Sign Up</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<div className="grid gap-4"> | ||
<div className="grid gap-2"> | ||
<Label htmlFor="email">Email</Label> | ||
<Input | ||
id="email" | ||
type="email" | ||
placeholder="[email protected]" | ||
required | ||
value={email} | ||
onChange={(e) => setEmail(e.target.value)} | ||
/> | ||
</div> | ||
<div className="grid gap-2"> | ||
<div className="flex items-center"> | ||
<Label htmlFor="password">Password</Label> | ||
{/* <Link href="#" className="ml-auto inline-block text-sm underline"> | ||
Forgot your password? | ||
</Link> */} | ||
</div> | ||
<Input | ||
id="password" | ||
type="password" | ||
required | ||
value={password} | ||
onChange={(e) => setPassword(e.target.value)} | ||
/> | ||
</div> | ||
<Button type="button" className="w-full" onClick={handleLogin}> | ||
Login | ||
</Button> | ||
<Button variant="outline" className="w-full" onClick={handleRegister}> | ||
Sign up | ||
</Button> | ||
</div> | ||
{/* <div className="mt-4 text-center text-sm"> | ||
Don't have an account?{" "} | ||
<Link href="#" className="underline"> | ||
Sign up | ||
</Link> | ||
</div> */} | ||
</CardContent> | ||
</Card> | ||
); | ||
} |
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
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,76 @@ | ||
import * as React from "react" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const Card = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn( | ||
"rounded-xl border bg-card text-card-foreground shadow", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
)) | ||
Card.displayName = "Card" | ||
|
||
const CardHeader = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn("flex flex-col space-y-1.5 p-6", className)} | ||
{...props} | ||
/> | ||
)) | ||
CardHeader.displayName = "CardHeader" | ||
|
||
const CardTitle = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLHeadingElement> | ||
>(({ className, ...props }, ref) => ( | ||
<h3 | ||
ref={ref} | ||
className={cn("font-semibold leading-none tracking-tight", className)} | ||
{...props} | ||
/> | ||
)) | ||
CardTitle.displayName = "CardTitle" | ||
|
||
const CardDescription = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLParagraphElement> | ||
>(({ className, ...props }, ref) => ( | ||
<p | ||
ref={ref} | ||
className={cn("text-sm text-muted-foreground", className)} | ||
{...props} | ||
/> | ||
)) | ||
CardDescription.displayName = "CardDescription" | ||
|
||
const CardContent = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> | ||
)) | ||
CardContent.displayName = "CardContent" | ||
|
||
const CardFooter = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn("flex items-center p-6 pt-0", className)} | ||
{...props} | ||
/> | ||
)) | ||
CardFooter.displayName = "CardFooter" | ||
|
||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } |
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 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as LabelPrimitive from "@radix-ui/react-label" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const labelVariants = cva( | ||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" | ||
) | ||
|
||
const Label = React.forwardRef< | ||
React.ElementRef<typeof LabelPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & | ||
VariantProps<typeof labelVariants> | ||
>(({ className, ...props }, ref) => ( | ||
<LabelPrimitive.Root | ||
ref={ref} | ||
className={cn(labelVariants(), className)} | ||
{...props} | ||
/> | ||
)) | ||
Label.displayName = LabelPrimitive.Root.displayName | ||
|
||
export { Label } |
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,7 +1,9 @@ | ||
export const fetcher = async (url: string) => { | ||
const response = await fetch(url); | ||
if (!response.ok) { | ||
throw new Error(`Error fetching ${url}: ${response.statusText}`); | ||
const error = new Error(`Error fetching ${url}: ${response.statusText}`); | ||
(error as any).status = response.status; | ||
throw error; | ||
} | ||
return response.json(); | ||
}; |
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,17 @@ | ||
import useSWR from "swr"; | ||
import { fetcher } from "@/hooks/fetcher"; | ||
|
||
export default function useUser() { | ||
const { data, mutate, error } = useSWR("/api/auth/me", fetcher); | ||
|
||
const loading = !data && !error; | ||
console.log(error); | ||
const loggedIn = !(error && error.status === 401); | ||
|
||
return { | ||
loading, | ||
loggedIn, | ||
user: data, | ||
mutate, | ||
}; | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
Oops, something went wrong.