Refactor register flow

This commit is contained in:
Jonathan
2025-06-14 00:17:07 +02:00
committed by Bryan Frimin
parent 94c335e55a
commit f8b93d034a

View File

@@ -1,25 +1,30 @@
import { useState } from "react";
import { Link, useNavigate } from "react-router"; import { Link, useNavigate } from "react-router";
import { Button, Field, useToast } from "@probo/ui"; import { Button, Field, useToast } from "@probo/ui";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { useMutation } from "@tanstack/react-query"; import { z } from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { usePageTitle } from "@probo/hooks";
import { buildEndpoint } from "/providers/RelayProviders"; import { buildEndpoint } from "/providers/RelayProviders";
interface RegisterData { const schema = z.object({
email: string; email: z.string().email(),
password: string; password: z.string().min(8),
fullName: string; fullName: z.string().min(2),
} });
export default function RegisterPage() { export default function RegisterPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [fullName, setFullName] = useState("");
const { __ } = useTranslate(); const { __ } = useTranslate();
const { toast } = useToast();
const navigate = useNavigate(); const navigate = useNavigate();
const { toast } = useToast();
const { register, handleSubmit, formState } = useFormWithSchema(schema, {
defaultValues: {
email: "",
password: "",
fullName: "",
},
});
const registerUser = async (data: RegisterData) => { const onSubmit = handleSubmit(async (data) => {
const response = await fetch( const response = await fetch(
buildEndpoint("/api/console/v1/auth/register"), buildEndpoint("/api/console/v1/auth/register"),
{ {
@@ -32,67 +37,28 @@ export default function RegisterPage() {
} }
); );
// Registration failed
if (!response.ok) { if (!response.ok) {
const errorData = await response.json().catch(() => ({})); const errorData = await response.json().catch(() => ({}));
return { toast({
success: false, title: __("Registration failed"),
error: errorData.message || __("Registration failed"), description: errorData.message || __("Registration failed"),
}; variant: "error",
});
return;
} }
return { success: true, data: await response.json() };
};
const registerMutation = useMutation({
mutationFn: registerUser,
onSuccess: (result) => {
if (result.success) {
toast({ toast({
title: __("Success"), title: __("Success"),
description: __("Account created successfully"), description: __("Account created successfully"),
variant: "success", variant: "success",
}); });
navigate("/", { replace: true }); navigate("/", { replace: true });
} else {
toast({
title: __("Error"),
description: result.error,
variant: "error",
});
}
},
onError: () => {
toast({
title: __("Error"),
description: __("Registration failed"),
variant: "error",
});
},
}); });
const handleSubmit = async (e: React.FormEvent) => { usePageTitle(__("Sign up"));
e.preventDefault();
if (!email || !password || !fullName) {
toast({
title: __("Error"),
description: __("Full name, email, and password are required"),
variant: "error",
});
return;
}
registerMutation.mutate({
email,
password,
fullName,
});
};
return ( return (
<>
<title>{__("Sign up")} - Probo</title>
<div className="space-y-6 w-full max-w-md mx-auto"> <div className="space-y-6 w-full max-w-md mx-auto">
<div className="space-y-2 text-center"> <div className="space-y-2 text-center">
<h1 className="text-3xl font-bold">{__("Sign up")}</h1> <h1 className="text-3xl font-bold">{__("Sign up")}</h1>
@@ -101,46 +67,36 @@ export default function RegisterPage() {
</p> </p>
</div> </div>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={onSubmit} className="space-y-4">
<Field <Field
label={__("Full Name")} label={__("Full Name")}
type="text" type="text"
placeholder={__("John Doe")} placeholder={__("John Doe")}
value={fullName} {...register("fullName")}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setFullName(e.target.value)
}
required required
error={formState.errors.fullName?.message}
/> />
<Field <Field
label={__("Email")} label={__("Email")}
type="email" type="email"
placeholder={__("name@example.com")} placeholder={__("name@example.com")}
value={email} {...register("email")}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setEmail(e.target.value)
}
required required
error={formState.errors.email?.message}
/> />
<Field <Field
label={__("Password")} label={__("Password")}
type="password" type="password"
placeholder="••••••••" placeholder="••••••••"
value={password} {...register("password")}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setPassword(e.target.value)
}
required required
error={formState.errors.password?.message}
/> />
<Button <Button type="submit" className="w-full" disabled={formState.isLoading}>
type="submit" {formState.isLoading
className="w-full"
disabled={registerMutation.isPending}
>
{registerMutation.isPending
? __("Creating account...") ? __("Creating account...")
: __("Sign up with email")} : __("Sign up with email")}
</Button> </Button>
@@ -150,7 +106,7 @@ export default function RegisterPage() {
<p className="text-sm text-txt-tertiary"> <p className="text-sm text-txt-tertiary">
{__("Already have an account?")}{" "} {__("Already have an account?")}{" "}
<Link <Link
to="/auth/login" to="/login"
className="underline text-txt-primary hover:text-txt-secondary" className="underline text-txt-primary hover:text-txt-secondary"
> >
{__("Log in here")} {__("Log in here")}
@@ -158,6 +114,5 @@ export default function RegisterPage() {
</p> </p>
</div> </div>
</div> </div>
</>
); );
} }