mirror of
https://gitlab.massbug.com/massbug/judge4c.git
synced 2025-07-04 15:52:22 +00:00
feat: implement authentication pages and forms for sign-in and sign-up
This commit is contained in:
parent
67565b1b18
commit
5a0be71f40
@ -1,11 +1,18 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
interface AuthLayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const AuthLayout = ({ children }: AuthLayoutProps) => {
|
||||
const pathname = usePathname();
|
||||
const isSignIn = pathname === "/sign-in";
|
||||
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
<div className="mx-auto max-w-screen-2xl p-4">
|
||||
@ -18,7 +25,11 @@ const AuthLayout = ({ children }: AuthLayoutProps) => {
|
||||
style={{ width: "auto", height: "auto" }}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="secondary">Sign Up</Button>
|
||||
<Button asChild variant="secondary">
|
||||
<Link href={isSignIn ? "/sign-up" : "/sign-in"}>
|
||||
{isSignIn ? "Sign Up" : "Login"}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
<div className="flex flex-col items-center justify-center pt-4 md:pt-14">
|
||||
|
9
src/app/(auth)/sign-in/page.tsx
Normal file
9
src/app/(auth)/sign-in/page.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { SignInCard } from "@/features/auth/components/sign-in-card";
|
||||
|
||||
const SignInPage = () => {
|
||||
return <SignInCard />;
|
||||
};
|
||||
|
||||
export default SignInPage;
|
9
src/app/(auth)/sign-up/page.tsx
Normal file
9
src/app/(auth)/sign-up/page.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { SignUpCard } from "@/features/auth/components/sign-up-card";
|
||||
|
||||
const SignUpPage = () => {
|
||||
return <SignUpCard />;
|
||||
};
|
||||
|
||||
export default SignUpPage;
|
122
src/features/auth/components/sign-in-card.tsx
Normal file
122
src/features/auth/components/sign-in-card.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
import { z } from "zod";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { FcGoogle } from "react-icons/fc";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(1, "Required"),
|
||||
});
|
||||
|
||||
export const SignInCard = () => {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (values: z.infer<typeof formSchema>) => {
|
||||
console.log({ values });
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="w-full h-full md:w-[487px]">
|
||||
<CardHeader className="flex items-center justify-center text-center p-7">
|
||||
<CardTitle className="text-2xl">Welcome back !</CardTitle>
|
||||
</CardHeader>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
name="email"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="email"
|
||||
placeholder="Enter email address"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
name="password"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="password"
|
||||
placeholder="Enter password"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button disabled={false} size="lg" className="w-full">
|
||||
Login
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</CardContent>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7 flex flex-col gap-y-4">
|
||||
<Button
|
||||
disabled={false}
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
>
|
||||
<FcGoogle className="mr-2 size-5" />
|
||||
Login with Google
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
>
|
||||
<FaGithub className="mr-2 size-5" />
|
||||
Login with Github
|
||||
</Button>
|
||||
</CardContent>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7 flex items-center justify-center">
|
||||
<p>
|
||||
Don't have an account?{" "}
|
||||
<Link href="/sign-up">
|
||||
<span className="underline underline-offset-4 hover:text-blue-700">Sign Up</span>
|
||||
</Link>
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
156
src/features/auth/components/sign-up-card.tsx
Normal file
156
src/features/auth/components/sign-up-card.tsx
Normal file
@ -0,0 +1,156 @@
|
||||
import { z } from "zod";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { FcGoogle } from "react-icons/fc";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().trim().min(1, "Required"),
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8, "Minimum of 8 characters required"),
|
||||
});
|
||||
|
||||
export const SignUpCard = () => {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (values: z.infer<typeof formSchema>) => {
|
||||
console.log({ values });
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="w-full h-full md:w-[487px]">
|
||||
<CardHeader className="flex items-center justify-center text-center p-7">
|
||||
<CardTitle className="text-2xl">Sign Up</CardTitle>
|
||||
<CardDescription>
|
||||
By signing up, you're giving a nod to our{" "}
|
||||
<Link href="/privacy">
|
||||
<span className="hover:underline underline-offset-4 text-blue-700">Privacy Policy</span>
|
||||
</Link>{" "}
|
||||
and{" "}
|
||||
<Link href="/terms">
|
||||
<span className="hover:underline underline-offset-4 text-blue-700">Terms of service</span>
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
name="name"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
placeholder="Enter your name"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
name="email"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="email"
|
||||
placeholder="Enter email address"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
name="password"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="password"
|
||||
placeholder="Enter your password"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button disabled={false} size="lg" className="w-full">
|
||||
Login
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</CardContent>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7 flex flex-col gap-y-4">
|
||||
<Button
|
||||
disabled={false}
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
>
|
||||
<FcGoogle className="mr-2 size-5" />
|
||||
Login with Google
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
>
|
||||
<FaGithub className="mr-2 size-5" />
|
||||
Login with Github
|
||||
</Button>
|
||||
</CardContent>
|
||||
<div className="px-7">
|
||||
<Separator />
|
||||
</div>
|
||||
<CardContent className="p-7 flex items-center justify-center">
|
||||
<p>
|
||||
Already have an account?{" "}
|
||||
<Link href="/sign-in">
|
||||
<span className="underline underline-offset-4 hover:text-blue-700">Sign In</span>
|
||||
</Link>
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
@ -6,6 +6,7 @@ export default {
|
||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/features/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
|
Loading…
Reference in New Issue
Block a user