122 lines
4.3 KiB
TypeScript
122 lines
4.3 KiB
TypeScript
|
|
|
|
import { AuthCard } from '@/components/auth/AuthCard';
|
|
import { AuthFooterLinks } from '@/components/auth/AuthFooterLinks';
|
|
import { AuthForm } from '@/components/auth/AuthForm';
|
|
import { routes } from '@/lib/routing/RouteConfig';
|
|
import { ForgotPasswordViewData } from '@/lib/view-data/ForgotPasswordViewData';
|
|
import { Button } from '@/ui/Button';
|
|
import { Group } from '@/ui/Group';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Input } from '@/ui/Input';
|
|
import { Link } from '@/ui/Link';
|
|
import { LoadingSpinner } from '@/ui/LoadingSpinner';
|
|
import { Text } from '@/ui/Text';
|
|
import { AlertCircle, ArrowLeft, CheckCircle2, Mail, Shield } from 'lucide-react';
|
|
import React from 'react';
|
|
|
|
interface ForgotPasswordTemplateProps {
|
|
viewData: ForgotPasswordViewData;
|
|
formActions: {
|
|
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => Promise<void>;
|
|
setShowSuccess: (show: boolean) => void;
|
|
};
|
|
mutationState: {
|
|
isPending: boolean;
|
|
error: string | null;
|
|
};
|
|
}
|
|
|
|
export function ForgotPasswordTemplate({ viewData, formActions, mutationState }: ForgotPasswordTemplateProps) {
|
|
const isSubmitting = mutationState.isPending;
|
|
|
|
return (
|
|
<AuthCard
|
|
title="Reset Password"
|
|
description={viewData.showSuccess ? undefined : "Enter your email and we'll send you a reset link"}
|
|
>
|
|
{!viewData.showSuccess ? (
|
|
<AuthForm onSubmit={formActions.handleSubmit}>
|
|
<Input
|
|
label="Email Address"
|
|
id="email"
|
|
name="email"
|
|
type="email"
|
|
value={viewData.formState.fields.email.value}
|
|
onChange={formActions.handleChange}
|
|
errorMessage={viewData.formState.fields.email.error}
|
|
placeholder="you@example.com"
|
|
disabled={isSubmitting}
|
|
autoComplete="email"
|
|
icon={<Mail size={16} />}
|
|
/>
|
|
|
|
{mutationState.error && (
|
|
<Group direction="row" align="start" gap={3} fullWidth>
|
|
<Icon icon={AlertCircle} size={4.5} color="var(--color-critical)" />
|
|
<Text size="sm" color="text-critical-red">{mutationState.error}</Text>
|
|
</Group>
|
|
)}
|
|
|
|
<Button
|
|
type="submit"
|
|
variant="primary"
|
|
disabled={isSubmitting}
|
|
fullWidth
|
|
icon={isSubmitting ? <LoadingSpinner size={4} /> : <Shield size={16} />}
|
|
>
|
|
{isSubmitting ? 'Sending...' : 'Send Reset Link'}
|
|
</Button>
|
|
|
|
<Group justify="center" fullWidth>
|
|
<Link href={routes.auth.login}>
|
|
<Group direction="row" align="center" justify="center" gap={2}>
|
|
<Icon icon={ArrowLeft} size={3.5} color="var(--color-primary)" />
|
|
<Text size="sm" weight="bold" color="text-primary-accent">Back to Login</Text>
|
|
</Group>
|
|
</Link>
|
|
</Group>
|
|
</AuthForm>
|
|
) : (
|
|
<Group direction="column" gap={6} fullWidth>
|
|
<Group direction="row" align="start" gap={3} fullWidth>
|
|
<Icon icon={CheckCircle2} size={5} color="var(--color-success)" />
|
|
<Group direction="column" gap={1}>
|
|
<Text size="sm" color="text-success-green" weight="bold" block>Check your email</Text>
|
|
<Text size="xs" color="text-gray-400" block>{viewData.successMessage}</Text>
|
|
</Group>
|
|
</Group>
|
|
|
|
{viewData.magicLink && (
|
|
<Group direction="column" gap={2} fullWidth>
|
|
<Text size="xs" color="text-gray-500" block weight="bold">DEVELOPMENT MAGIC LINK</Text>
|
|
<Link href={viewData.magicLink}>
|
|
<Text size="xs" color="text-primary-accent" block>
|
|
{viewData.magicLink}
|
|
</Text>
|
|
</Link>
|
|
</Group>
|
|
)}
|
|
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
onClick={() => window.location.href = '/auth/login'}
|
|
fullWidth
|
|
>
|
|
Return to Login
|
|
</Button>
|
|
</Group>
|
|
)}
|
|
|
|
<AuthFooterLinks>
|
|
<Text size="xs" color="text-gray-600">
|
|
Need help?{' '}
|
|
<Link href="/support">Contact support</Link>
|
|
</Text>
|
|
</AuthFooterLinks>
|
|
</AuthCard>
|
|
);
|
|
}
|