Skip to content

Commit dd609b0

Browse files
Merge pull request #1 from thyuhtooaung-dev/feat/auth
feat: implement sign-up page with form validation and shared layout structure
2 parents fac3d8f + b3af5c5 commit dd609b0

21 files changed

Lines changed: 5701 additions & 2932 deletions

File tree

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Nextblog CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
# This cancels previous runs if you push again to the same PR
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
quality-check:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@v4
20+
21+
- name: Install pnpm
22+
uses: pnpm/action-setup@v3
23+
with:
24+
version: 9
25+
26+
- name: Setup Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: "20"
30+
cache: "pnpm"
31+
32+
- name: Install Dependencies
33+
run: pnpm install --frozen-lockfile
34+
35+
- name: Run Format Check
36+
run: pnpm run format:check
37+
38+
- name: Run Lint
39+
run: pnpm run lint
40+
41+
- name: Type Check
42+
run: pnpm exec tsc --noEmit
43+
44+
- name: Build Project
45+
run: pnpm run build

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<!-- BEGIN:nextjs-agent-rules -->
2+
23
# This is NOT the Next.js you know
34

45
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
6+
57
<!-- END:nextjs-agent-rules -->

app/(shared-layout)/layout.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Navbar from "@/components/web/navbar";
2+
3+
export default function SharedLayout({
4+
children,
5+
}: {
6+
children: React.ReactNode;
7+
}) {
8+
return (
9+
<>
10+
<Navbar />
11+
{children}
12+
</>
13+
);
14+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export default function Page() {
2-
return <h1>Home Page</h1>
3-
}
2+
return <h1>Home Page</h1>;
3+
}

app/auth/login/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export default function LoginPage() {
2-
return <h1>Login Page</h1>
3-
}
2+
return <h1>Login Page</h1>;
3+
}

app/auth/sign-up/layout.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { buttonVariants } from "@/components/ui/button";
2+
import { ArrowLeft } from "lucide-react";
3+
import Link from "next/link";
4+
5+
export default function authLayout({
6+
children,
7+
}: {
8+
children: React.ReactNode;
9+
}) {
10+
return (
11+
<div className="min-h-screen flex items-center justify-center">
12+
<div className="absolute top-5 left-5">
13+
<Link href="/" className={buttonVariants({ variant: "secondary" })}>
14+
<ArrowLeft className="size-4" />
15+
Back to Home
16+
</Link>
17+
</div>
18+
<div className="w-full max-w-md mx-auto">{children}</div>
19+
</div>
20+
);
21+
}

app/auth/sign-up/page.tsx

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,107 @@
1+
"use client";
2+
3+
import { signUpSchema } from "@/app/schemas/auth";
4+
import { z } from "zod";
5+
import {
6+
Card,
7+
CardContent,
8+
CardDescription,
9+
CardHeader,
10+
CardTitle,
11+
} from "@/components/ui/card";
12+
import { zodResolver } from "@hookform/resolvers/zod";
13+
import { Controller, useForm } from "react-hook-form";
14+
import { Input } from "@/components/ui/input";
15+
import {
16+
Field,
17+
FieldError,
18+
FieldGroup,
19+
FieldLabel,
20+
} from "@/components/ui/field";
21+
import { Button } from "@/components/ui/button";
22+
123
export default function SignupPage() {
2-
return <h1>Sign Up Page</h1>
3-
}
24+
const form = useForm<z.infer<typeof signUpSchema>>({
25+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
26+
resolver: zodResolver(signUpSchema as any),
27+
defaultValues: {
28+
name: "",
29+
email: "",
30+
password: "",
31+
},
32+
});
33+
34+
const onSubmit = () => {
35+
console.log("yoo");
36+
};
37+
38+
return (
39+
<Card>
40+
<CardHeader>
41+
<CardTitle>Sign Up</CardTitle>
42+
<CardDescription>Create a new account to get started</CardDescription>
43+
</CardHeader>
44+
<CardContent>
45+
<form onSubmit={form.handleSubmit(onSubmit)}>
46+
<FieldGroup>
47+
<Controller
48+
control={form.control}
49+
name="name"
50+
render={({ field, fieldState }) => (
51+
<Field>
52+
<FieldLabel>Full Name</FieldLabel>
53+
<Input
54+
aria-invalid={fieldState.invalid}
55+
placeholder="Jhon Doe"
56+
{...field}
57+
/>
58+
{fieldState.error && (
59+
<FieldError>{fieldState.error.message}</FieldError>
60+
)}
61+
</Field>
62+
)}
63+
/>
64+
<Controller
65+
control={form.control}
66+
name="email"
67+
render={({ field, fieldState }) => (
68+
<Field>
69+
<FieldLabel>Email</FieldLabel>
70+
<Input
71+
aria-invalid={fieldState.invalid}
72+
placeholder="jhon@doe.com"
73+
type="email"
74+
{...field}
75+
/>
76+
{fieldState.error && (
77+
<FieldError>{fieldState.error.message}</FieldError>
78+
)}
79+
</Field>
80+
)}
81+
/>
82+
<Controller
83+
control={form.control}
84+
name="password"
85+
render={({ field, fieldState }) => (
86+
<Field>
87+
<FieldLabel>Password</FieldLabel>
88+
<Input
89+
aria-invalid={fieldState.invalid}
90+
placeholder="********"
91+
type="password"
92+
{...field}
93+
/>
94+
{fieldState.error && (
95+
<FieldError>{fieldState.error.message}</FieldError>
96+
)}
97+
</Field>
98+
)}
99+
/>
100+
101+
<Button type="submit">Sign up</Button>
102+
</FieldGroup>
103+
</form>
104+
</CardContent>
105+
</Card>
106+
);
107+
}

app/globals.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,4 @@
127127
html {
128128
@apply font-sans;
129129
}
130-
}
130+
}

app/layout.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import type { Metadata } from "next";
22
import React from "react";
3-
import { Geist, Geist_Mono } from "next/font/google";
3+
import { Outfit, Geist_Mono } from "next/font/google";
44
import "./globals.css";
5-
import Navbar from "@/components/web/navbar";
65
import { ThemeProvider } from "@/components/ui/theme-provider";
76

8-
const geistSans = Geist({
9-
variable: "--font-geist-sans",
7+
const outfit = Outfit({
8+
variable: "--font-sans",
109
subsets: ["latin"],
1110
});
1211

@@ -27,7 +26,7 @@ export default function RootLayout({
2726
return (
2827
<html lang="en" suppressHydrationWarning>
2928
<body
30-
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
29+
className={`${outfit.variable} ${geistMono.variable} font-sans h-full antialiased`}
3130
>
3231
<ThemeProvider
3332
attribute="class"
@@ -36,7 +35,6 @@ export default function RootLayout({
3635
disableTransitionOnChange
3736
>
3837
<main className={"w-full max-auto px-4 md:px-6 lg:px-8"}>
39-
<Navbar />
4038
{children}
4139
</main>
4240
</ThemeProvider>

app/schemas/auth.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import z from "zod";
2+
3+
export const signUpSchema = z.object({
4+
name: z
5+
.string()
6+
.min(3, "Name must be at least 3 characters long")
7+
.max(30, "Name must be at most 30 characters long"),
8+
email: z.string().email("Invalid email address"),
9+
password: z.string().min(6, "Password must be at least 6 characters long"),
10+
});

0 commit comments

Comments
 (0)