إنجاز: تفعيل خاصية استعادة كلمة المرور وإعادة تعيينها

- إضافة نقاط نهاية لخاصيتي استعادة كلمة المرور وإعادة تعيينها في الواجهة الخلفية.

- إنشاء اختبارات لخاصية إعادة تعيين كلمة المرور لضمان كفاءتها وأمانها.

- تطوير صفحات واجهة المستخدم لخاصيتي استعادة كلمة المرور وإعادة تعيينها مع معالجة النماذج.

- دمج حدود تحميل ديناميكية لأنواع ملفات مختلفة بناءً على خطط المستخدمين.

- تقديم أداة جديدة لتغيير حجم الصور مع إمكانية تعديل الأبعاد وإعدادات الجودة.

- تحديث نظام التوجيه والتنقل ليشمل أدوات جديدة وميزات مصادقة.

- تحسين تجربة المستخدم من خلال معالجة الأخطاء ورسائل التغذية الراجعة المناسبة.

- إضافة دعم التدويل للميزات الجديدة باللغات الإنجليزية والعربية والفرنسية.
This commit is contained in:
Your Name
2026-03-07 14:23:50 +02:00
parent 0ad2ba0f02
commit 71f7d0382d
27 changed files with 1460 additions and 7 deletions

View File

@@ -0,0 +1,95 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Helmet } from 'react-helmet-async';
import { Mail } from 'lucide-react';
const API_BASE = import.meta.env.VITE_API_URL || '';
export default function ForgotPasswordPage() {
const { t } = useTranslation();
const [email, setEmail] = useState('');
const [submitted, setSubmitted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setLoading(true);
try {
const res = await fetch(`${API_BASE}/api/auth/forgot-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ email }),
});
if (!res.ok) throw new Error('Request failed');
setSubmitted(true);
} catch {
setError(t('auth.forgotPassword.error'));
} finally {
setLoading(false);
}
};
return (
<>
<Helmet>
<title>{t('auth.forgotPassword.title')} {t('common.appName')}</title>
</Helmet>
<div className="mx-auto max-w-md">
<div className="mb-8 text-center">
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-primary-100 dark:bg-primary-900/30">
<Mail className="h-8 w-8 text-primary-600 dark:text-primary-400" />
</div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-slate-100">
{t('auth.forgotPassword.title')}
</h1>
<p className="mt-2 text-slate-500 dark:text-slate-400">
{t('auth.forgotPassword.subtitle')}
</p>
</div>
{submitted ? (
<div className="rounded-2xl bg-green-50 p-6 text-center ring-1 ring-green-200 dark:bg-green-900/20 dark:ring-green-800">
<p className="text-sm text-green-700 dark:text-green-400">
{t('auth.forgotPassword.sent')}
</p>
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300">
{t('common.email')}
</label>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder={t('account.emailPlaceholder')}
className="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm dark:border-slate-600 dark:bg-slate-700 dark:text-slate-200"
/>
</div>
{error && (
<div className="rounded-xl bg-red-50 p-3 ring-1 ring-red-200 dark:bg-red-900/20 dark:ring-red-800">
<p className="text-sm text-red-700 dark:text-red-400">{error}</p>
</div>
)}
<button
type="submit"
disabled={loading}
className="btn-primary w-full disabled:opacity-50"
>
{loading ? t('common.loading') : t('auth.forgotPassword.submit')}
</button>
</form>
)}
</div>
</>
);
}