Files
carmanagement/apps/homepage/src/components/auth/ForgotPasswordForm.tsx
T
root d7fb7b7a7b
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
redesign the homepage
2026-06-26 16:27:21 -04:00

190 lines
6.3 KiB
TypeScript

'use client'
import { Button } from '@/components/actions/Button'
import { TextInput } from '@/components/forms/TextInput'
import { FormField } from '@/components/forms/FormField'
import { AuthShell } from '@/components/auth/AuthShell'
import { API_BASE } from '@/lib/api'
import { localizedPath, type Locale } from '@/lib/localization/config'
import { useState } from 'react'
interface Dict {
title: string
subtitle: string
email: string
emailPlaceholder: string
submit: string
submitting: string
backToLogin: string
successTitle: string
successBody: string
error: string
}
const dicts: Record<string, Dict> = {
en: {
title: 'Forgot your password?',
subtitle: "Enter your work email and we'll send you a reset link.",
email: 'Email',
emailPlaceholder: 'owner@company.com',
submit: 'Send reset link',
submitting: 'Sending…',
backToLogin: 'Back to sign in',
successTitle: 'Check your email',
successBody: 'If that email is registered, a reset link has been sent. It expires in 60 minutes.',
error: 'Something went wrong. Please try again.',
},
fr: {
title: 'Mot de passe oublié ?',
subtitle: "Entrez votre email professionnel et nous vous enverrons un lien de réinitialisation.",
email: 'Email',
emailPlaceholder: 'owner@company.com',
submit: 'Envoyer le lien',
submitting: 'Envoi…',
backToLogin: 'Retour à la connexion',
successTitle: 'Vérifiez votre email',
successBody: "Si cet email est enregistré, un lien de réinitialisation a été envoyé. Il expire dans 60 minutes.",
error: 'Une erreur est survenue. Veuillez réessayer.',
},
ar: {
title: 'نسيت كلمة المرور؟',
subtitle: 'أدخل بريدك الإلكتروني وسنرسل لك رابط إعادة التعيين.',
email: 'البريد الإلكتروني',
emailPlaceholder: 'owner@company.com',
submit: 'إرسال رابط إعادة التعيين',
submitting: 'جارٍ الإرسال…',
backToLogin: 'العودة إلى تسجيل الدخول',
successTitle: 'تحقق من بريدك الإلكتروني',
successBody: 'إذا كان البريد الإلكتروني مسجلاً، فقد تم إرسال رابط إعادة التعيين. تنتهي صلاحيته خلال 60 دقيقة.',
error: 'حدث خطأ ما. يرجى المحاولة مرة أخرى.',
},
}
export function ForgotPasswordForm({ locale }: { locale: Locale }) {
const dict = (dicts[locale] ?? dicts.en) as Dict
const [email, setEmail] = useState('')
const [loading, setLoading] = useState(false)
const [sent, setSent] = useState(false)
const [error, setError] = useState<string | null>(null)
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
setLoading(true)
setError(null)
try {
const [empRes, adminRes] = await Promise.all([
fetch(`${API_BASE}/auth/employee/forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
}),
fetch(`${API_BASE}/admin/auth/forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
}),
])
if (!empRes.ok && !adminRes.ok) throw new Error()
setSent(true)
} catch {
setError(dict.error)
} finally {
setLoading(false)
}
}
const signInHref = localizedPath('sign-in', locale)
return (
<AuthShell locale={locale} title={dict.title} subtitle={dict.subtitle}>
{sent ? (
<div style={{ textAlign: 'center' }}>
<div
style={{
margin: '0 auto 1rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '3.5rem',
height: '3.5rem',
borderRadius: '50%',
background: 'var(--color-success-bg, #ecfdf5)',
}}
>
<svg
style={{ width: '1.75rem', height: '1.75rem', color: 'var(--color-success-text, #059669)' }}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 style={{ fontSize: '1.25rem', fontWeight: 700, color: 'var(--color-heading)' }}>
{dict.successTitle}
</h2>
<p style={{ marginTop: '0.5rem', fontSize: '0.875rem', color: 'var(--color-text-secondary)' }}>
{dict.successBody}
</p>
</div>
) : (
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>
{error ? (
<div
style={{
borderRadius: '1.5rem',
border: '1px solid var(--color-error-border, #fecaca)',
background: 'var(--color-error-bg, #fef2f2)',
padding: '0.75rem 1rem',
fontSize: '0.875rem',
color: 'var(--color-error-text, #b91c1c)',
}}
>
{error}
</div>
) : null}
<FormField id="forgot-email" label={dict.email} required>
<TextInput
id="forgot-email"
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder={dict.emailPlaceholder}
autoComplete="email"
/>
</FormField>
<Button type="submit" intent="primary" fullWidth loading={loading} disabled={loading}>
{loading ? dict.submitting : dict.submit}
</Button>
</form>
)}
<div
style={{
marginTop: '1.5rem',
borderTop: '1px solid var(--color-border)',
paddingTop: '1.5rem',
textAlign: 'center',
fontSize: '0.875rem',
}}
>
<a
href={signInHref}
style={{
fontWeight: 600,
color: 'var(--color-heading)',
textDecoration: 'underline',
textUnderlineOffset: '4px',
}}
>
{dict.backToLogin}
</a>
</div>
</AuthShell>
)
}