This commit is contained in:
Nathnael
2026-07-08 11:05:46 +00:00
parent 9e98600a5f
commit 38577cdd26

View File

@@ -242,270 +242,259 @@ export default function SignupPage() {
return (
<AuthShell
tagline= "Smart Freight Operations"
taglineBody = "Join EDR Freight to manage shipments, track consignments, and streamline logistics workflows across Ethiopia and Djibouti."
tagline="Smart Freight Operations"
taglineBody="Join EDR Freight to manage shipments, track consignments, and streamline logistics workflows across Ethiopia and Djibouti."
>
<div className="flex w-full flex-col" >
{ stage === "form" ? (
<form
onSubmit= { handleSubmit(requestOtp) }
className = "flex w-full flex-col"
>
<div className="mb-4 space-y-1.5 text-center sm:mb-5" >
<h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl" >
Create account
</h1>
< p className = "text-sm leading-relaxed text-gray-500" >
Register to access EDR Freight services.
<div className="flex w-full flex-col">
{stage === "form" ? (
<form
onSubmit={handleSubmit(requestOtp)}
className="flex w-full flex-col"
>
<div className="mb-4 space-y-1.5 text-center sm:mb-5">
<h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
Create account
</h1>
<p className="text-sm leading-relaxed text-gray-500">
Register to access EDR Freight services.
</p>
</div>
</div>
< Stack gap = "sm" >
<SimpleGrid cols={ { base: 1, sm: 2 } } spacing = "md" >
<TextInput
<Stack gap="sm">
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="md">
<TextInput
label="First name"
placeholder = "John"
required
disabled = { sending }
error = { errors.firstName?.en?.message }
{...register("firstName.en") }
placeholder="John"
required
disabled={sending}
error={errors.firstName?.en?.message}
{...register("firstName.en")}
/>
< TextInput
label = "Last name"
placeholder = "Doe"
required
disabled = { sending }
error = { errors.lastName?.en?.message }
{...register("lastName.en") }
<TextInput
label="Last name"
placeholder="Doe"
required
disabled={sending}
error={errors.lastName?.en?.message}
{...register("lastName.en")}
/>
</SimpleGrid>
</SimpleGrid>
< TextInput
label = "Email"
type = "email"
placeholder = "john@example.com"
required
disabled = { sending }
error = { errors.email?.message }
{...register("email") }
<TextInput
label="Email"
type="email"
placeholder="john@example.com"
required
disabled={sending}
error={errors.email?.message}
{...register("email")}
/>
< ControlledPhoneField
control = { control }
name = "phone"
label = "Phone"
required
disabled = { sending }
/>
<ControlledPhoneField
control={control}
name="phone"
label="Phone"
required
disabled={sending}
/>
<div className="space-y-1.5" >
<Text size="sm" fw = { 500} c = "edr-text" >
Send verification code via
</Text>
< SegmentedControl
fullWidth
disabled = { sending }
value = { channel }
onChange = {(v) => setChannel(v as OtpChannel)
}
data = {
[
{
value: "phone",
label: (
<span className= "flex items-center justify-center gap-1.5" >
<Smartphone size={ 14} /> Phone
</span>
<div className="space-y-1.5">
<Text size="sm" fw={500} c="edr-text">
Send verification code via
</Text>
<SegmentedControl
fullWidth
disabled={sending}
value={channel}
onChange={(v) => setChannel(v as OtpChannel)}
data={[
{
value: "phone",
label: (
<span className="flex items-center justify-center gap-1.5">
<Smartphone size={14} /> Phone
</span>
),
},
{
value: "email",
label: (
<span className= "flex items-center justify-center gap-1.5" >
<Mail size={ 14 } /> Email
</span>
},
{
value: "email",
label: (
<span className="flex items-center justify-center gap-1.5">
<Mail size={14} /> Email
</span>
),
},
]}
/>
</div>
</div>
< div >
<PasswordInput
<div>
<PasswordInput
label="Password"
placeholder = "Create a strong password"
required
disabled = { sending }
error = { errors.password?.message }
{...register("password") }
placeholder="Create a strong password"
required
disabled={sending}
error={errors.password?.message}
{...register("password")}
/>
{
passwordValue.length > 0 ? (
<div className= "mt-2 space-y-1" >
{
passwordRequirements.map((req) => {
const met = req.test(passwordValue);
return (
<div
key= { req.label }
className = "flex items-center gap-2"
>
<span
className={
`flex h-4 w-4 shrink-0 items-center justify-center rounded-full ${met
? "bg-primary text-primary-foreground"
: "bg-gray-200 text-gray-500"
}`
}
{passwordValue.length > 0 ? (
<div className="mt-2 space-y-1">
{passwordRequirements.map((req) => {
const met = req.test(passwordValue);
return (
<div
key={req.label}
className="flex items-center gap-2"
>
<span
className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-full ${met
? "bg-primary text-primary-foreground"
: "bg-gray-200 text-gray-500"
}`}
>
{
met?(
<Check className = "h-2.5 w-2.5" />
): (
<X className = "h-2.5 w-2.5" />
)
}
</span>
< span
className = {`text-xs ${met ? "text-primary" : "text-gray-500"}`
}
{met ? (
<Check className="h-2.5 w-2.5" />
) : (
<X className="h-2.5 w-2.5" />
)}
</span>
<span
className={`text-xs ${met ? "text-primary" : "text-gray-500"}`}
>
{ req.label }
</span>
</div>
{req.label}
</span>
</div>
);
})}
</div>
</div>
) : null}
</div>
</div>
< PasswordInput
label = "Confirm password"
placeholder = "Re-enter your password"
required
disabled = { sending }
error = { errors.confirmPassword?.message }
{...register("confirmPassword") }
<PasswordInput
label="Confirm password"
placeholder="Re-enter your password"
required
disabled={sending}
error={errors.confirmPassword?.message}
{...register("confirmPassword")}
/>
{
error ? (
<Alert
color= "red"
variant = "light"
icon = {< AlertCircle size = { 18} />}
{error ? (
<Alert
color="red"
variant="light"
icon={<AlertCircle size={18} />}
>
{ error }
</Alert>
{error}
</Alert>
) : null}
<Button
<Button
type="submit"
color = "edr-green"
fullWidth
loading = { sending }
rightSection = {!sending ? <ArrowRight size={ 16 } /> : undefined}
color="edr-green"
fullWidth
loading={sending}
rightSection={!sending ? <ArrowRight size={16} /> : undefined}
>
Continue
</Button>
Continue
</Button>
< p className = "text-center text-sm text-gray-500" >
Already have an account ? { " "}
< button
type = "button"
onClick = {() => navigate("/login")}
className = "font-semibold text-primary hover:underline"
>
Sign In
</button>
</p>
</Stack>
</form>
) : (
<Stack gap= "md" >
<div className="mb-1 flex justify-center" >
<span className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary" >
<ShieldCheck size={ 22 } />
</span>
</div>
< div className = "space-y-1.5 text-center" >
<h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl" >
Verify your { otpChannel === "email" ? "email" : "phone" }
</h1>
< p className = "text-sm leading-relaxed text-gray-500" >
We sent a 6 - digit code to{ " " }
<span className="font-medium text-gray-700" >
{ otpChannel === "email"
? maskEmail(pendingData?.email ?? "")
: maskPhone(pendingData?.phone ?? "")}
</span>
.Enter it to finish creating your account.
<p className="text-center text-sm text-gray-500">
Already have an account ?{" "}
<button
type="button"
onClick={() => navigate("/login")}
className="font-semibold text-primary hover:underline"
>
Sign In
</button>
</p>
</div>
</Stack>
</form>
) : (
<Stack gap="md">
<div className="mb-1 flex justify-center">
<span className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
<ShieldCheck size={22} />
</span>
</div>
<div className="space-y-1.5 text-center">
<h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
Verify your {otpChannel === "email" ? "email" : "phone"}
</h1>
<p className="text-sm leading-relaxed text-gray-500">
We sent a 6 - digit code to{" "}
<span className="font-medium text-gray-700">
{otpChannel === "email"
? maskEmail(pendingData?.email ?? "")
: maskPhone(pendingData?.phone ?? "")}
</span>
.Enter it to finish creating your account.
</p>
</div>
{
otpError ? (
<Alert
color= "red"
variant = "light"
icon = {< AlertCircle size = { 18} />}
{otpError ? (
<Alert
color="red"
variant="light"
icon={<AlertCircle size={18} />}
>
{ otpError }
</Alert>
{otpError}
</Alert>
) : null}
<Stack gap={ 6 } align = "center" >
<Text size="sm" fw = { 500} c = "edr-text" >
Verification code
</Text>
< PinInput
length = { 6}
type = "number"
oneTimeCode
value = { otpCode }
placeholder = "0"
disabled = { verifying }
styles = {{ input: { textAlign: "center" } }}
onChange = { setOtpCode }
/>
</Stack>
<Stack gap={6} align="center">
<Text size="sm" fw={500} c="edr-text">
Verification code
</Text>
<PinInput
length={6}
type="number"
oneTimeCode
value={otpCode}
placeholder="0"
disabled={verifying}
styles={{ input: { textAlign: "center" } }}
onChange={setOtpCode}
/>
</Stack>
< Button
color = "edr-green"
fullWidth
loading = { verifying }
disabled = { verifying || otpCode.trim().length !== 6}
onClick = { confirmOtp }
>
Verify & amp; create account
</Button>
<Button
color="edr-green"
fullWidth
loading={verifying}
disabled={verifying || otpCode.trim().length !== 6}
onClick={confirmOtp}
>
Verify & create account
</Button>
< div className = "flex items-center justify-between" >
<Button
<div className="flex items-center justify-between">
<Button
variant="subtle"
color = "gray"
leftSection = {< ArrowLeft size = { 14} />}
disabled = { sending || verifying}
onClick = {() => {
setStage("form");
setOtpError(null);
}}
color="gray"
leftSection={<ArrowLeft size={14} />}
disabled={sending || verifying}
onClick={() => {
setStage("form");
setOtpError(null);
}}
>
Back
</Button>
< Button
variant = "subtle"
color = "edr-green"
leftSection = {< RotateCw size = { 14} />}
disabled = { resendIn > 0 || sending || verifying}
onClick = { resendOtp }
>
{ resendIn > 0 ? `Resend in ${resendIn}s` : "Resend code"}
</Button>
</div>
</Stack>
Back
</Button>
<Button
variant="subtle"
color="edr-green"
leftSection={<RotateCw size={14} />}
disabled={resendIn > 0 || sending || verifying}
onClick={resendOtp}
>
{resendIn > 0 ? `Resend in ${resendIn}s` : "Resend code"}
</Button>
</div>
</Stack>
)}
</div>
</AuthShell>
</div>
</AuthShell>
);
}