Added translation to all site with edit style
All checks were successful
Build frontend / build (push) Successful in 1m40s

This commit is contained in:
Rahaf
2026-07-01 15:43:58 +03:00
parent 3052209df8
commit dab5b62fb7
56 changed files with 5136 additions and 3190 deletions

View File

@ -3,6 +3,7 @@
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { useRouter } from 'next/navigation';
import { useTranslation } from 'react-i18next';
import toast, { Toaster } from 'react-hot-toast';
import {
FileText,
@ -19,13 +20,8 @@ import {
import { submitReport, submitReservationReport, submitSaleReport } from '../utils/api';
import AuthService from '../services/AuthService';
const tabs = [
{ id: 'general', label: 'تقرير عام', icon: FileText },
{ id: 'reservation', label: 'تقرير حجز', icon: Calendar },
{ id: 'sale', label: 'تقرير بيع', icon: DollarSign },
];
export default function ReportsPage() {
const { t } = useTranslation();
const router = useRouter();
const [activeTab, setActiveTab] = useState('general');
const [isLoading, setIsLoading] = useState(false);
@ -37,6 +33,12 @@ export default function ReportsPage() {
}
}, [router]);
const tabs = [
{ id: 'general', label: t('reports.generalReport'), icon: FileText },
{ id: 'reservation', label: t('reports.reservationReport'), icon: Calendar },
{ id: 'sale', label: t('reports.saleReport'), icon: DollarSign },
];
const [generalForm, setGeneralForm] = useState({ subject: '', body: '' });
const [reservationForm, setReservationForm] = useState({ reservationId: '', message: '', reporter: 'customer' });
const [saleForm, setSaleForm] = useState({ saleId: '', message: '', reporter: 'buyer' });
@ -45,24 +47,24 @@ export default function ReportsPage() {
const validateGeneral = () => {
const e = {};
if (!generalForm.subject.trim()) e.subject = 'الموضوع مطلوب';
if (!generalForm.body.trim()) e.body = 'الوصف مطلوب';
if (!generalForm.subject.trim()) e.subject = t('reports.subjectRequired');
if (!generalForm.body.trim()) e.body = t('reports.descriptionRequired');
setErrors(e);
return Object.keys(e).length === 0;
};
const validateReservation = () => {
const e = {};
if (!reservationForm.reservationId.trim()) e.reservationId = 'رقم الحجز مطلوب';
if (!reservationForm.message.trim()) e.message = 'الرسالة مطلوبة';
if (!reservationForm.reservationId.trim()) e.reservationId = t('reports.reservationIdRequired');
if (!reservationForm.message.trim()) e.message = t('reports.messageRequired');
setErrors(e);
return Object.keys(e).length === 0;
};
const validateSale = () => {
const e = {};
if (!saleForm.saleId.trim()) e.saleId = 'رقم البيع مطلوب';
if (!saleForm.message.trim()) e.message = 'الرسالة مطلوبة';
if (!saleForm.saleId.trim()) e.saleId = t('reports.saleIdRequired');
if (!saleForm.message.trim()) e.message = t('reports.messageRequired');
setErrors(e);
return Object.keys(e).length === 0;
};
@ -74,13 +76,13 @@ export default function ReportsPage() {
try {
await submitReport(generalForm.subject, generalForm.body);
setIsSuccess(true);
toast.success('تم إرسال التقرير بنجاح!', {
toast.success(t('reports.generalSuccess'), {
style: { background: '#dcfce7', color: '#166534' },
});
setGeneralForm({ subject: '', body: '' });
setTimeout(() => setIsSuccess(false), 2000);
} catch (err) {
toast.error(err.message || 'فشل إرسال التقرير', {
toast.error(err.message || t('reports.generalFailed'), {
style: { background: '#fee2e2', color: '#991b1b' },
});
} finally {
@ -95,13 +97,13 @@ export default function ReportsPage() {
try {
await submitReservationReport(reservationForm);
setIsSuccess(true);
toast.success('تم إرسال تقرير الحجز!', {
toast.success(t('reports.reservationSuccess'), {
style: { background: '#dcfce7', color: '#166534' },
});
setReservationForm({ reservationId: '', message: '', reporter: 'customer' });
setTimeout(() => setIsSuccess(false), 2000);
} catch (err) {
toast.error(err.message || 'فشل إرسال التقرير', {
toast.error(err.message || t('reports.reservationFailed'), {
style: { background: '#fee2e2', color: '#991b1b' },
});
} finally {
@ -116,13 +118,13 @@ export default function ReportsPage() {
try {
await submitSaleReport(saleForm);
setIsSuccess(true);
toast.success('تم إرسال تقرير البيع!', {
toast.success(t('reports.saleSuccess'), {
style: { background: '#dcfce7', color: '#166534' },
});
setSaleForm({ saleId: '', message: '', reporter: 'buyer' });
setTimeout(() => setIsSuccess(false), 2000);
} catch (err) {
toast.error(err.message || 'فشل إرسال التقرير', {
toast.error(err.message || t('reports.saleFailed'), {
style: { background: '#fee2e2', color: '#991b1b' },
});
} finally {
@ -134,7 +136,7 @@ export default function ReportsPage() {
general: (
<form onSubmit={handleGeneralSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">الموضوع</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.subjectLabel')}</label>
<div className="relative group">
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<FileText className={`w-5 h-5 ${errors.subject ? 'text-red-500' : 'text-gray-400 group-focus-within:text-amber-500'}`} />
@ -144,19 +146,19 @@ export default function ReportsPage() {
value={generalForm.subject}
onChange={(e) => { setGeneralForm({ ...generalForm, subject: e.target.value }); if (errors.subject) setErrors({ ...errors, subject: null }); }}
className={`w-full pr-12 pl-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all ${errors.subject ? 'border-red-500' : 'border-gray-300'}`}
placeholder="أدخل موضوع التقرير"
placeholder={t('reports.subjectPlaceholder')}
/>
</div>
{errors.subject && <p className="text-red-500 text-sm mt-1">{errors.subject}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">الوصف</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.descriptionLabel')}</label>
<textarea
value={generalForm.body}
onChange={(e) => { setGeneralForm({ ...generalForm, body: e.target.value }); if (errors.body) setErrors({ ...errors, body: null }); }}
rows={5}
className={`w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all resize-none ${errors.body ? 'border-red-500' : 'border-gray-300'}`}
placeholder="اشرح التفاصيل..."
placeholder={t('reports.descriptionPlaceholder')}
/>
{errors.body && <p className="text-red-500 text-sm mt-1">{errors.body}</p>}
</div>
@ -168,11 +170,11 @@ export default function ReportsPage() {
whileTap={{ scale: 0.98 }}
>
{isLoading ? (
<><Loader2 className="w-5 h-5 animate-spin" /> جاري الإرسال...</>
<><Loader2 className="w-5 h-5 animate-spin" /> {t('reports.sending')}</>
) : isSuccess ? (
<><CheckCircle className="w-5 h-5" /> تم الإرسال!</>
<><CheckCircle className="w-5 h-5" /> {t('reports.sentSuccess')}</>
) : (
<><Send className="w-5 h-5" /> إرسال التقرير</>
<><Send className="w-5 h-5" /> {t('reports.submitReport')}</>
)}
</motion.button>
</form>
@ -180,7 +182,7 @@ export default function ReportsPage() {
reservation: (
<form onSubmit={handleReservationSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">رقم الحجز</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.reservationIdLabel')}</label>
<div className="relative group">
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<Hash className={`w-5 h-5 ${errors.reservationId ? 'text-red-500' : 'text-gray-400 group-focus-within:text-amber-500'}`} />
@ -190,24 +192,24 @@ export default function ReportsPage() {
value={reservationForm.reservationId}
onChange={(e) => { setReservationForm({ ...reservationForm, reservationId: e.target.value }); if (errors.reservationId) setErrors({ ...errors, reservationId: null }); }}
className={`w-full pr-12 pl-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all ${errors.reservationId ? 'border-red-500' : 'border-gray-300'}`}
placeholder="أدخل رقم الحجز"
placeholder={t('reports.reservationIdPlaceholder')}
/>
</div>
{errors.reservationId && <p className="text-red-500 text-sm mt-1">{errors.reservationId}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">الرسالة</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('message')}</label>
<textarea
value={reservationForm.message}
onChange={(e) => { setReservationForm({ ...reservationForm, message: e.target.value }); if (errors.message) setErrors({ ...errors, message: null }); }}
rows={4}
className={`w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all resize-none ${errors.message ? 'border-red-500' : 'border-gray-300'}`}
placeholder="اشرح المشكلة..."
placeholder={t('reports.messagePlaceholder')}
/>
{errors.message && <p className="text-red-500 text-sm mt-1">{errors.message}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">المبلغ</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.reporterLabel')}</label>
<div className="flex gap-3">
{['customer', 'owner'].map((val) => (
<button
@ -221,7 +223,7 @@ export default function ReportsPage() {
}`}
>
<User className="w-4 h-4" />
{val === 'customer' ? 'مستأجر' : 'مالك'}
{val === 'customer' ? t('customer') : t('owner')}
</button>
))}
</div>
@ -234,11 +236,11 @@ export default function ReportsPage() {
whileTap={{ scale: 0.98 }}
>
{isLoading ? (
<><Loader2 className="w-5 h-5 animate-spin" /> جاري الإرسال...</>
<><Loader2 className="w-5 h-5 animate-spin" /> {t('reports.sending')}</>
) : isSuccess ? (
<><CheckCircle className="w-5 h-5" /> تم الإرسال!</>
<><CheckCircle className="w-5 h-5" /> {t('reports.sentSuccess')}</>
) : (
<><Send className="w-5 h-5" /> إرسال التقرير</>
<><Send className="w-5 h-5" /> {t('reports.submitReport')}</>
)}
</motion.button>
</form>
@ -246,7 +248,7 @@ export default function ReportsPage() {
sale: (
<form onSubmit={handleSaleSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">رقم البيع</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.saleIdLabel')}</label>
<div className="relative group">
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<Hash className={`w-5 h-5 ${errors.saleId ? 'text-red-500' : 'text-gray-400 group-focus-within:text-amber-500'}`} />
@ -256,24 +258,24 @@ export default function ReportsPage() {
value={saleForm.saleId}
onChange={(e) => { setSaleForm({ ...saleForm, saleId: e.target.value }); if (errors.saleId) setErrors({ ...errors, saleId: null }); }}
className={`w-full pr-12 pl-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all ${errors.saleId ? 'border-red-500' : 'border-gray-300'}`}
placeholder="أدخل رقم البيع"
placeholder={t('reports.saleIdPlaceholder')}
/>
</div>
{errors.saleId && <p className="text-red-500 text-sm mt-1">{errors.saleId}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">الرسالة</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('message')}</label>
<textarea
value={saleForm.message}
onChange={(e) => { setSaleForm({ ...saleForm, message: e.target.value }); if (errors.message) setErrors({ ...errors, message: null }); }}
rows={4}
className={`w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent transition-all resize-none ${errors.message ? 'border-red-500' : 'border-gray-300'}`}
placeholder="اشرح المشكلة..."
placeholder={t('reports.messagePlaceholder')}
/>
{errors.message && <p className="text-red-500 text-sm mt-1">{errors.message}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">المبلغ</label>
<label className="block text-sm font-medium text-gray-700 mb-2">{t('reports.reporterLabel')}</label>
<div className="flex gap-3">
{['buyer', 'seller'].map((val) => (
<button
@ -287,7 +289,7 @@ export default function ReportsPage() {
}`}
>
<User className="w-4 h-4" />
{val === 'buyer' ? 'مشتري' : 'بائع'}
{val === 'buyer' ? t('buyer') : t('seller')}
</button>
))}
</div>
@ -300,11 +302,11 @@ export default function ReportsPage() {
whileTap={{ scale: 0.98 }}
>
{isLoading ? (
<><Loader2 className="w-5 h-5 animate-spin" /> جاري الإرسال...</>
<><Loader2 className="w-5 h-5 animate-spin" /> {t('reports.sending')}</>
) : isSuccess ? (
<><CheckCircle className="w-5 h-5" /> تم الإرسال!</>
<><CheckCircle className="w-5 h-5" /> {t('reports.sentSuccess')}</>
) : (
<><Send className="w-5 h-5" /> إرسال التقرير</>
<><Send className="w-5 h-5" /> {t('reports.submitReport')}</>
)}
</motion.button>
</form>
@ -320,8 +322,8 @@ export default function ReportsPage() {
animate={{ opacity: 1, y: 0 }}
className="mb-8"
>
<h1 className="text-3xl font-bold text-gray-900 mb-2">الإبلاغ عن مشكلة</h1>
<p className="text-gray-600">أخبرنا عن المشكلة التي تواجهها وسنقوم بمعالجتها</p>
<h1 className="text-3xl font-bold text-gray-900 mb-2">{t('reports.pageTitle')}</h1>
<p className="text-gray-600">{t('reports.pageDescription')}</p>
</motion.div>
<div className="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">