-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement sign-up page with form validation and shared layout structure #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9b9c56c
0aaec6d
99f1d83
b3af5c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| name: Nextblog CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
|
|
||
| # This cancels previous runs if you push again to the same PR | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| quality-check: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout Code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Install pnpm | ||
| uses: pnpm/action-setup@v3 | ||
| with: | ||
| version: 9 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "20" | ||
| cache: "pnpm" | ||
|
|
||
| - name: Install Dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Run Format Check | ||
| run: pnpm run format:check | ||
|
|
||
| - name: Run Lint | ||
| run: pnpm run lint | ||
|
|
||
| - name: Type Check | ||
| run: pnpm exec tsc --noEmit | ||
|
|
||
| - name: Build Project | ||
| run: pnpm run build |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| <!-- BEGIN:nextjs-agent-rules --> | ||
|
|
||
| # This is NOT the Next.js you know | ||
|
|
||
| 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. | ||
|
|
||
| <!-- END:nextjs-agent-rules --> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import Navbar from "@/components/web/navbar"; | ||
|
|
||
| export default function SharedLayout({ | ||
| children, | ||
| }: { | ||
| children: React.ReactNode; | ||
| }) { | ||
| return ( | ||
| <> | ||
| <Navbar /> | ||
| {children} | ||
| </> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| export default function Page() { | ||
| return <h1>Home Page</h1> | ||
| } | ||
| return <h1>Home Page</h1>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| export default function LoginPage() { | ||
| return <h1>Login Page</h1> | ||
| } | ||
| return <h1>Login Page</h1>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import { buttonVariants } from "@/components/ui/button"; | ||
| import { ArrowLeft } from "lucide-react"; | ||
| import Link from "next/link"; | ||
|
|
||
| export default function authLayout({ | ||
| children, | ||
| }: { | ||
| children: React.ReactNode; | ||
| }) { | ||
| return ( | ||
| <div className="min-h-screen flex items-center justify-center"> | ||
| <div className="absolute top-5 left-5"> | ||
| <Link href="/" className={buttonVariants({ variant: "secondary" })}> | ||
| <ArrowLeft className="size-4" /> | ||
| Back to Home | ||
| </Link> | ||
| </div> | ||
| <div className="w-full max-w-md mx-auto">{children}</div> | ||
| </div> | ||
|
Comment on lines
+11
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The wrapper is not - <div className="min-h-screen flex items-center justify-center">
+ <div className="relative min-h-screen flex items-center justify-center">🤖 Prompt for AI Agents |
||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,3 +1,107 @@ | ||||||
| "use client"; | ||||||
|
|
||||||
| import { signUpSchema } from "@/app/schemas/auth"; | ||||||
| import { z } from "zod"; | ||||||
| import { | ||||||
| Card, | ||||||
| CardContent, | ||||||
| CardDescription, | ||||||
| CardHeader, | ||||||
| CardTitle, | ||||||
| } from "@/components/ui/card"; | ||||||
| import { zodResolver } from "@hookform/resolvers/zod"; | ||||||
| import { Controller, useForm } from "react-hook-form"; | ||||||
| import { Input } from "@/components/ui/input"; | ||||||
| import { | ||||||
| Field, | ||||||
| FieldError, | ||||||
| FieldGroup, | ||||||
| FieldLabel, | ||||||
| } from "@/components/ui/field"; | ||||||
| import { Button } from "@/components/ui/button"; | ||||||
|
|
||||||
| export default function SignupPage() { | ||||||
| return <h1>Sign Up Page</h1> | ||||||
| } | ||||||
| const form = useForm<z.infer<typeof signUpSchema>>({ | ||||||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||||
| resolver: zodResolver(signUpSchema as any), | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check installed versions of hookform resolvers, react-hook-form, and zod
fd -t f 'package.json' -d 2 --exec cat {} \; | jq '.dependencies + .devDependencies | with_entries(select(.key | test("react-hook-form|@hookform/resolvers|zod")))'Repository: thyuhtooaung-dev/NextBlog Length of output: 157 🌐 Web query:
💡 Result: No, the latest Citations:
Remove the ESLint flags this ( Proposed fix- resolver: zodResolver(signUpSchema as any),
+ resolver: zodResolver(signUpSchema),📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 25-25: Unexpected any. Specify a different type. ( 🤖 Prompt for AI Agents |
||||||
| defaultValues: { | ||||||
| name: "", | ||||||
| email: "", | ||||||
| password: "", | ||||||
| }, | ||||||
| }); | ||||||
|
|
||||||
| const onSubmit = () => { | ||||||
| console.log("yoo"); | ||||||
| }; | ||||||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Placeholder A few things to address before this is merge-ready:
🛠 Suggested shape- const onSubmit = () => {
- console.log("yoo");
- };
+ const onSubmit = async (data: z.infer<typeof signUpSchema>) => {
+ // TODO: submit to auth endpoint
+ console.log(data);
+ };
@@
- <form onSubmit={form.handleSubmit(onSubmit)}>
+ <form onSubmit={form.handleSubmit(onSubmit)} noValidate>
@@
- <Button type="submit">Sign up</Button>
+ <Button type="submit" disabled={form.formState.isSubmitting}>
+ Sign up
+ </Button>Want me to open a follow-up issue to track the real submit implementation (API call, error surface, redirect)? Also applies to: 44-44, 100-100 🤖 Prompt for AI Agents |
||||||
|
|
||||||
| return ( | ||||||
| <Card> | ||||||
| <CardHeader> | ||||||
| <CardTitle>Sign Up</CardTitle> | ||||||
| <CardDescription>Create a new account to get started</CardDescription> | ||||||
| </CardHeader> | ||||||
| <CardContent> | ||||||
| <form onSubmit={form.handleSubmit(onSubmit)}> | ||||||
| <FieldGroup> | ||||||
| <Controller | ||||||
| control={form.control} | ||||||
| name="name" | ||||||
| render={({ field, fieldState }) => ( | ||||||
| <Field> | ||||||
| <FieldLabel>Full Name</FieldLabel> | ||||||
| <Input | ||||||
| aria-invalid={fieldState.invalid} | ||||||
| placeholder="Jhon Doe" | ||||||
| {...field} | ||||||
| /> | ||||||
| {fieldState.error && ( | ||||||
| <FieldError>{fieldState.error.message}</FieldError> | ||||||
| )} | ||||||
| </Field> | ||||||
|
Comment on lines
+51
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Associate
🛠 Proposed fix (apply to all three fields) render={({ field, fieldState }) => (
<Field>
- <FieldLabel>Full Name</FieldLabel>
+ <FieldLabel htmlFor="name">Full Name</FieldLabel>
<Input
+ id="name"
aria-invalid={fieldState.invalid}
- placeholder="Jhon Doe"
+ placeholder="John Doe"
{...field}
/>Note: the Also applies to: 67-78, 85-96 🤖 Prompt for AI Agents |
||||||
| )} | ||||||
| /> | ||||||
| <Controller | ||||||
| control={form.control} | ||||||
| name="email" | ||||||
| render={({ field, fieldState }) => ( | ||||||
| <Field> | ||||||
| <FieldLabel>Email</FieldLabel> | ||||||
| <Input | ||||||
| aria-invalid={fieldState.invalid} | ||||||
| placeholder="jhon@doe.com" | ||||||
| type="email" | ||||||
| {...field} | ||||||
| /> | ||||||
| {fieldState.error && ( | ||||||
| <FieldError>{fieldState.error.message}</FieldError> | ||||||
| )} | ||||||
| </Field> | ||||||
| )} | ||||||
| /> | ||||||
| <Controller | ||||||
| control={form.control} | ||||||
| name="password" | ||||||
| render={({ field, fieldState }) => ( | ||||||
| <Field> | ||||||
| <FieldLabel>Password</FieldLabel> | ||||||
| <Input | ||||||
| aria-invalid={fieldState.invalid} | ||||||
| placeholder="********" | ||||||
| type="password" | ||||||
| {...field} | ||||||
| /> | ||||||
| {fieldState.error && ( | ||||||
| <FieldError>{fieldState.error.message}</FieldError> | ||||||
| )} | ||||||
| </Field> | ||||||
| )} | ||||||
| /> | ||||||
|
|
||||||
| <Button type="submit">Sign up</Button> | ||||||
| </FieldGroup> | ||||||
| </form> | ||||||
| </CardContent> | ||||||
| </Card> | ||||||
| ); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -127,4 +127,4 @@ | |
| html { | ||
| @apply font-sans; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import z from "zod"; | ||
|
|
||
| export const signUpSchema = z.object({ | ||
| name: z | ||
| .string() | ||
| .min(3, "Name must be at least 3 characters long") | ||
| .max(30, "Name must be at most 30 characters long"), | ||
| email: z.string().email("Invalid email address"), | ||
| password: z.string().min(6, "Password must be at least 6 characters long"), | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename default export to PascalCase.
React component convention (and ESLint
react/*rules commonly used with Next.js) requires component names to start with an uppercase letter.authLayoutshould beAuthLayout.📝 Committable suggestion
🤖 Prompt for AI Agents