Skip to content

Commit

Permalink
Merge pull request #6 from RicardoGEsteves/register-form
Browse files Browse the repository at this point in the history
feat: ✨ Title: feat(auth): Add register form and server actions
  • Loading branch information
RicardoGEsteves authored Jan 6, 2024
2 parents cdaf10f + 6fe39ef commit 18cf727
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 1 deletion.
15 changes: 15 additions & 0 deletions actions/register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use server";

import * as z from "zod";

import { RegisterSchema } from "@/schemas";

export const register = async (values: z.infer<typeof RegisterSchema>) => {
const validatedFields = RegisterSchema.safeParse(values);

if (!validatedFields.success) {
return { error: "Invalid fields." };
}

return { success: "Successfully registered." };
};
8 changes: 8 additions & 0 deletions app/auth/register/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import RegisterForm from "@/components/auth/register-form";

export const metadata = {
title: "Register",
};
export default function RegisterPage() {
return <RegisterForm />;
}
172 changes: 172 additions & 0 deletions components/auth/register-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
"use client";

import { useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import Link from "next/link";

import { useIsClient } from "@/hooks/use-is-client";
import Spinner from "../spinner";
import { RegisterSchema } from "@/schemas";
import CardWrapper from "./card-wrapper";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import FormError from "../form-error";
import FormSuccess from "../form-success";
import { register } from "@/actions/register";

const RegisterForm = () => {
const isClient = useIsClient();

const [error, setError] = useState<string>("");
const [success, setSuccess] = useState<string>("");

const [isPending, startTransition] = useTransition();

const form = useForm<z.infer<typeof RegisterSchema>>({
resolver: zodResolver(RegisterSchema),
defaultValues: {
name: "",
email: "",
password: "",
passwordConfirmation: "",
},
});

const onSubmit = (values: z.infer<typeof RegisterSchema>) => {
startTransition(() => {
register(values).then((data) => {
if (data.success) setSuccess(data.success);
if (data?.error) setError(data.error);
});
});

form.reset();
setSuccess("");
setError("");
};

if (!isClient) return <Spinner />;

return (
<CardWrapper
headerLabel="Register an account to get started!"
backButtonLabel="Have an account already?"
backButtonHref="/auth/login"
showSocial
>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-6"
>
<div className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input
{...field}
disabled={isPending}
type="text"
placeholder="Your Name"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
{...field}
disabled={isPending}
type="email"
placeholder="[email protected]"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input
{...field}
disabled={isPending}
type="password"
placeholder="******"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="passwordConfirmation"
render={({ field }) => (
<FormItem>
<FormLabel>Confirm your password</FormLabel>
<FormControl>
<Input
{...field}
disabled={isPending}
type="password"
placeholder="******"
/>
</FormControl>
<FormMessage />
<Button
size="sm"
variant="link"
asChild
className="px-0 text-muted-foreground"
>
<Link href="/auth/reset">Forgot your password?</Link>
</Button>
</FormItem>
)}
/>
</div>
{error && <FormError message={error} />}
{success && <FormSuccess message={success} />}
<Button
type="submit"
disabled={isPending}
className="w-full hover:bg-sky-400"
>
Register
</Button>
</form>
</Form>
</CardWrapper>
);
};

export default RegisterForm;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbo",
"dev": "rm -rf .next && next dev --turbo",
"build": "next build",
"start": "next start",
"lint": "next lint"
Expand Down
16 changes: 16 additions & 0 deletions schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,19 @@ export const LoginSchema = z.object({
message: "Please enter your password. Password is required.",
}),
});

export const RegisterSchema = z.object({
name: z.string().min(1, {
message: "Please enter your name, required.",
}),
email: z.string().email({
message: "Please enter a valid email address, required.",
}),
password: z.string().min(6, {
message: "Please enter a password with at least 6 characters, required",
}),
//TODO: Add password confirmation and validation
passwordConfirmation: z.string().min(6, {
message: "Please confirm your password, required.",
}),
});

0 comments on commit 18cf727

Please sign in to comment.