Skip to content

Commit 2f59748

Browse files
agmmtooaunghtetnay
authored andcommitted
feat: init login page
1 parent eafd6dc commit 2f59748

File tree

9 files changed

+205
-30
lines changed

9 files changed

+205
-30
lines changed

app/(auth)/login/page.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { LoginForm } from "@/components/login-form"
2+
3+
export default function Page() {
4+
return (
5+
<div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
6+
<div className="w-full max-w-sm">
7+
<LoginForm />
8+
</div>
9+
</div>
10+
)
11+
}

app/(protected)/layout.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { cookies } from 'next/headers'
2+
import { redirect } from 'next/navigation'
3+
4+
export default async function ProtectedLayout({
5+
children,
6+
}: Readonly<{ children: React.ReactNode }>) {
7+
// check if the user is authenticated
8+
// if not, redirect to the login page
9+
// REF: https://nextjs.org/docs/app/api-reference/functions/cookies
10+
const c = await cookies()
11+
const token = c.get('auth')
12+
console.log({ token })
13+
if (!token) {
14+
redirect('/login')
15+
}
16+
return <>{children}</>
17+
}

components/login-form.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { cn } from "@/lib/utils"
2+
import { Button } from "@/components/ui/button"
3+
import {
4+
Card,
5+
CardContent,
6+
CardDescription,
7+
CardHeader,
8+
CardTitle,
9+
} from "@/components/ui/card"
10+
import { Input } from "@/components/ui/input"
11+
import { Label } from "@/components/ui/label"
12+
13+
export function LoginForm({
14+
className,
15+
...props
16+
}: React.ComponentPropsWithoutRef<"div">) {
17+
return (
18+
<div className={cn("flex flex-col gap-6", className)} {...props}>
19+
<Card>
20+
<CardHeader>
21+
<CardTitle className="text-2xl">Login</CardTitle>
22+
<CardDescription>
23+
Enter your email below to login to your account
24+
</CardDescription>
25+
</CardHeader>
26+
<CardContent>
27+
<form>
28+
<div className="flex flex-col gap-6">
29+
<div className="grid gap-2">
30+
<Label htmlFor="email">Email</Label>
31+
<Input
32+
id="email"
33+
type="email"
34+
placeholder="m@example.com"
35+
required
36+
/>
37+
</div>
38+
<div className="grid gap-2">
39+
<div className="flex items-center">
40+
<Label htmlFor="password">Password</Label>
41+
<a
42+
href="#"
43+
className="ml-auto inline-block text-sm underline-offset-4 hover:underline"
44+
>
45+
Forgot your password?
46+
</a>
47+
</div>
48+
<Input id="password" type="password" required />
49+
</div>
50+
<Button type="submit" className="w-full">
51+
Login
52+
</Button>
53+
<Button variant="outline" className="w-full">
54+
Login with Google
55+
</Button>
56+
</div>
57+
<div className="mt-4 text-center text-sm">
58+
Don&apos;t have an account?{" "}
59+
<a href="#" className="underline underline-offset-4">
60+
Sign up
61+
</a>
62+
</div>
63+
</form>
64+
</CardContent>
65+
</Card>
66+
</div>
67+
)
68+
}

components/ui/button.tsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
import * as React from 'react'
2-
import { Slot } from '@radix-ui/react-slot'
3-
import { cva, type VariantProps } from 'class-variance-authority'
1+
import * as React from "react"
2+
import { Slot } from "@radix-ui/react-slot"
3+
import { cva, type VariantProps } from "class-variance-authority"
44

5-
import { cn } from '@/lib/utils'
5+
import { cn } from "@/lib/utils"
66

77
const buttonVariants = cva(
8-
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
8+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
99
{
1010
variants: {
1111
variant: {
12-
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
12+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
1313
destructive:
14-
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
14+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
1515
outline:
16-
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
16+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
1717
secondary:
18-
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19-
ghost: 'hover:bg-accent hover:text-accent-foreground',
20-
link: 'text-primary underline-offset-4 hover:underline',
18+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
19+
ghost: "hover:bg-accent hover:text-accent-foreground",
20+
link: "text-primary underline-offset-4 hover:underline",
2121
},
2222
size: {
23-
default: 'h-10 px-4 py-2',
24-
sm: 'h-9 rounded-md px-3',
25-
lg: 'h-11 rounded-md px-8',
26-
icon: 'h-10 w-10',
23+
default: "h-10 px-4 py-2",
24+
sm: "h-9 rounded-md px-3",
25+
lg: "h-11 rounded-md px-8",
26+
icon: "h-10 w-10",
2727
},
2828
},
2929
defaultVariants: {
30-
variant: 'default',
31-
size: 'default',
30+
variant: "default",
31+
size: "default",
3232
},
3333
}
3434
)
@@ -41,7 +41,7 @@ export interface ButtonProps
4141

4242
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
4343
({ className, variant, size, asChild = false, ...props }, ref) => {
44-
const Comp = asChild ? Slot : 'button'
44+
const Comp = asChild ? Slot : "button"
4545
return (
4646
<Comp
4747
className={cn(buttonVariants({ variant, size, className }))}
@@ -51,6 +51,6 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
5151
)
5252
}
5353
)
54-
Button.displayName = 'Button'
54+
Button.displayName = "Button"
5555

5656
export { Button, buttonVariants }

components/ui/card.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import * as React from "react"
2+
3+
import { cn } from "@/lib/utils"
4+
5+
const Card = React.forwardRef<
6+
HTMLDivElement,
7+
React.HTMLAttributes<HTMLDivElement>
8+
>(({ className, ...props }, ref) => (
9+
<div
10+
ref={ref}
11+
className={cn(
12+
"rounded-lg border bg-card text-card-foreground shadow-sm",
13+
className
14+
)}
15+
{...props}
16+
/>
17+
))
18+
Card.displayName = "Card"
19+
20+
const CardHeader = React.forwardRef<
21+
HTMLDivElement,
22+
React.HTMLAttributes<HTMLDivElement>
23+
>(({ className, ...props }, ref) => (
24+
<div
25+
ref={ref}
26+
className={cn("flex flex-col space-y-1.5 p-6", className)}
27+
{...props}
28+
/>
29+
))
30+
CardHeader.displayName = "CardHeader"
31+
32+
const CardTitle = React.forwardRef<
33+
HTMLDivElement,
34+
React.HTMLAttributes<HTMLDivElement>
35+
>(({ className, ...props }, ref) => (
36+
<div
37+
ref={ref}
38+
className={cn(
39+
"text-2xl font-semibold leading-none tracking-tight",
40+
className
41+
)}
42+
{...props}
43+
/>
44+
))
45+
CardTitle.displayName = "CardTitle"
46+
47+
const CardDescription = React.forwardRef<
48+
HTMLDivElement,
49+
React.HTMLAttributes<HTMLDivElement>
50+
>(({ className, ...props }, ref) => (
51+
<div
52+
ref={ref}
53+
className={cn("text-sm text-muted-foreground", className)}
54+
{...props}
55+
/>
56+
))
57+
CardDescription.displayName = "CardDescription"
58+
59+
const CardContent = React.forwardRef<
60+
HTMLDivElement,
61+
React.HTMLAttributes<HTMLDivElement>
62+
>(({ className, ...props }, ref) => (
63+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
64+
))
65+
CardContent.displayName = "CardContent"
66+
67+
const CardFooter = React.forwardRef<
68+
HTMLDivElement,
69+
React.HTMLAttributes<HTMLDivElement>
70+
>(({ className, ...props }, ref) => (
71+
<div
72+
ref={ref}
73+
className={cn("flex items-center p-6 pt-0", className)}
74+
{...props}
75+
/>
76+
))
77+
CardFooter.displayName = "CardFooter"
78+
79+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

components/ui/input.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import * as React from 'react'
1+
import * as React from "react"
22

3-
import { cn } from '@/lib/utils'
3+
import { cn } from "@/lib/utils"
44

5-
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
5+
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
66
({ className, type, ...props }, ref) => {
77
return (
88
<input
99
type={type}
1010
className={cn(
11-
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
11+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1212
className
1313
)}
1414
ref={ref}
@@ -17,6 +17,6 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
1717
)
1818
}
1919
)
20-
Input.displayName = 'Input'
20+
Input.displayName = "Input"
2121

2222
export { Input }

components/ui/label.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
'use client'
1+
"use client"
22

3-
import * as React from 'react'
4-
import * as LabelPrimitive from '@radix-ui/react-label'
5-
import { cva, type VariantProps } from 'class-variance-authority'
3+
import * as React from "react"
4+
import * as LabelPrimitive from "@radix-ui/react-label"
5+
import { cva, type VariantProps } from "class-variance-authority"
66

7-
import { cn } from '@/lib/utils'
7+
import { cn } from "@/lib/utils"
88

99
const labelVariants = cva(
10-
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
10+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
1111
)
1212

1313
const Label = React.forwardRef<

0 commit comments

Comments
 (0)