changed the otp verification page style

This commit is contained in:
Mengisteab
2026-06-11 09:15:19 +00:00
parent 47adb10aa2
commit 99589640a3
3 changed files with 7327 additions and 24 deletions

View File

@@ -1,15 +1,17 @@
import { useEffect, useState } from 'react';
import {
Anchor,
Button,
Center,
Group,
PinInput,
Stack,
Text,
TextInput,
ThemeIcon,
Title,
} from '@mantine/core';
import { IconArrowRight, IconShieldLock } from '@tabler/icons-react';
import { useForm } from 'react-hook-form';
import { Controller, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useNavigate, useLocation } from 'react-router-dom';
@@ -17,8 +19,13 @@ import { useApiMutation } from '@ema-platform/api';
import { notify } from '@ema-platform/ui';
import { AuthShell } from '../components/AuthShell';
const CODE_LENGTH = 6;
const RESEND_SECONDS = 30;
const schema = z.object({
verificationCode: z.string().min(1, { message: 'Verification code is required' }),
verificationCode: z
.string()
.length(CODE_LENGTH, { message: `Enter the ${CODE_LENGTH}-digit code` }),
});
type FormValues = z.infer<typeof schema>;
@@ -34,15 +41,23 @@ export function OTPVerificationPage() {
const [verifyTrigger, { isLoading: loading }] = useApiMutation();
const [resendTrigger, { isLoading: resending }] = useApiMutation();
const [secondsLeft, setSecondsLeft] = useState(RESEND_SECONDS);
const {
register,
control,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: { verificationCode: '' },
});
useEffect(() => {
if (secondsLeft <= 0) return;
const id = setInterval(() => setSecondsLeft((s) => s - 1), 1000);
return () => clearInterval(id);
}, [secondsLeft]);
const onSubmit = async (values: FormValues) => {
try {
await verifyTrigger({
@@ -60,6 +75,7 @@ export function OTPVerificationPage() {
};
const handleResendOtp = async () => {
if (secondsLeft > 0 || resending) return;
try {
await resendTrigger({
url: '/auth/resend-otp',
@@ -68,6 +84,7 @@ export function OTPVerificationPage() {
}).unwrap();
notify.success('Verification code resent to your email');
setSecondsLeft(RESEND_SECONDS);
} catch (err) {
const msg = err instanceof Error ? err.message : 'Something went wrong';
notify.error(msg);
@@ -99,12 +116,30 @@ export function OTPVerificationPage() {
<form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="md">
<TextInput
label="Verification code"
placeholder="Enter the 6-digit code"
size="md"
error={errors.verificationCode?.message}
{...register('verificationCode')}
<Controller
control={control}
name="verificationCode"
render={({ field }) => (
<Stack gap={6} align="center">
<PinInput
length={CODE_LENGTH}
type="number"
inputMode="numeric"
oneTimeCode
size="md"
gap="sm"
error={!!errors.verificationCode}
value={field.value}
onChange={field.onChange}
onComplete={() => handleSubmit(onSubmit)()}
/>
{errors.verificationCode?.message && (
<Text c="red" size="sm">
{errors.verificationCode.message}
</Text>
)}
</Stack>
)}
/>
<Button
type="submit"
@@ -118,19 +153,29 @@ export function OTPVerificationPage() {
</Stack>
</form>
<Group justify="center" gap={6}>
<Text size="sm" c="dimmed">
Didn&apos;t receive a code?
</Text>
<Anchor
size="sm"
fw={600}
onClick={handleResendOtp}
style={resending ? { pointerEvents: 'none', opacity: 0.6 } : undefined}
>
Resend code
</Anchor>
</Group>
<Center>
<Group justify="center" gap={6}>
<Text size="sm" c="dimmed">
Didn&apos;t receive a code?
</Text>
{secondsLeft > 0 ? (
<Text size="sm" c="dimmed" fw={600}>
Resend in {secondsLeft}s
</Text>
) : (
<Anchor
size="sm"
fw={600}
onClick={handleResendOtp}
style={
resending ? { pointerEvents: 'none', opacity: 0.6 } : undefined
}
>
Resend code
</Anchor>
)}
</Group>
</Center>
</Stack>
</AuthShell>
);