mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user