setShowLoginDialog(false)}
- >
-
e.stopPropagation()}
- >
+
setShowLoginDialog(false)}>
+
e.stopPropagation()}>
-
-
تسجيل الدخول مطلوب
-
-
- للحجز أو إضافة المفضلة، سجل دخولك.
-
-
-
- تسجيل الدخول
-
-
-
- إنشاء حساب
-
-
-
+
تسجيل الدخول مطلوب
+
للحجز أو إضافة المفضلة، سجل دخولك.
+
تسجيل الدخول
+
إنشاء حساب
+
)}
);
-}
\ No newline at end of file
+}
diff --git a/app/register/agent/page.js b/app/register/agent/page.js
new file mode 100644
index 0000000..c5e76a9
--- /dev/null
+++ b/app/register/agent/page.js
@@ -0,0 +1,648 @@
+// app/register/agent/page.js
+
+'use client';
+
+import { useState, useRef, useMemo } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
+import { useRouter } from 'next/navigation';
+import Link from 'next/link';
+import Image from 'next/image';
+import {
+ User, Mail, Phone, Lock, Eye, EyeOff, MessageCircle,
+ Camera, X, CheckCircle, XCircle, ArrowLeft, Building,
+ Loader2, Shield, KeyRound, MapPin, FileText, BadgeCheck, Briefcase
+} from 'lucide-react';
+import toast, { Toaster } from 'react-hot-toast';
+import { registerRealEstateAgent, loginWithEmail, sendEmailOTP, verifyEmail } from '../../utils/api';
+import AuthService from '../../services/AuthService';
+
+export default function AgentRegisterPage() {
+ const router = useRouter();
+ const [step, setStep] = useState(1);
+ const [showOtpModal, setShowOtpModal] = useState(false);
+ const [showPassword, setShowPassword] = useState(false);
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const [formData, setFormData] = useState({
+ firstName: '',
+ lastName: '',
+ email: '',
+ phone: '',
+ whatsapp: '',
+ nationalNumber: '',
+ password: '',
+ confirmPassword: '',
+ agencyAddress: '',
+ licenseNumber: '',
+ agreeTerms: false
+ });
+
+ const [idImages, setIdImages] = useState({ front: null, back: null, license: null });
+ const [idImagePreviews, setIdImagePreviews] = useState({ front: '', back: '', license: '' });
+ const [otpCode, setOtpCode] = useState('');
+ const [errors, setErrors] = useState({});
+
+ const fileInputFrontRef = useRef(null);
+ const fileInputBackRef = useRef(null);
+ const fileInputLicenseRef = useRef(null);
+ const fileInputLicenseStep3Ref = useRef(null);
+
+ const handleImageUpload = (side, file) => {
+ if (!file) return;
+ if (!file.type.startsWith('image/')) {
+ toast.error('الرجاء اختيار صورة صالحة');
+ return;
+ }
+ if (file.size > 5 * 1024 * 1024) {
+ toast.error('حجم الصورة يجب أن يكون أقل من 5 ميجابايت');
+ return;
+ }
+ const reader = new FileReader();
+ reader.onloadend = () => {
+ setIdImagePreviews(prev => ({ ...prev, [side]: reader.result }));
+ };
+ reader.readAsDataURL(file);
+ setIdImages(prev => ({ ...prev, [side]: file }));
+ toast.success('تم رفع الصورة بنجاح', { style: { background: '#dcfce7', color: '#166534' } });
+ };
+
+ const validateEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
+ const validatePhone = (phone) => /^(09|05)[0-9]{8}$/.test(phone);
+
+ const validateStep1 = () => {
+ const newErrors = {};
+ if (!formData.firstName) newErrors.firstName = 'الاسم الأول مطلوب';
+ if (!formData.lastName) newErrors.lastName = 'اسم العائلة مطلوب';
+ if (!formData.email) newErrors.email = 'البريد الإلكتروني مطلوب';
+ else if (!validateEmail(formData.email)) newErrors.email = 'البريد الإلكتروني غير صالح';
+ if (!formData.phone) newErrors.phone = 'رقم الهاتف مطلوب';
+ else if (!validatePhone(formData.phone)) newErrors.phone = 'رقم الهاتف غير صالح (يجب أن يبدأ 09 أو 05)';
+ if (!formData.password) newErrors.password = 'كلمة المرور مطلوبة';
+ else if (formData.password.length < 6) newErrors.password = 'كلمة المرور يجب أن تكون 6 أحرف على الأقل';
+ if (formData.password !== formData.confirmPassword) newErrors.confirmPassword = 'كلمات المرور غير متطابقة';
+ setErrors(newErrors);
+ return Object.keys(newErrors).length === 0;
+ };
+
+ const validateStep2 = () => {
+ const newErrors = {};
+ if (!formData.nationalNumber) newErrors.nationalNumber = 'الرقم الوطني مطلوب';
+ if (!formData.whatsapp) newErrors.whatsapp = 'رقم الواتساب مطلوب';
+ else if (!validatePhone(formData.whatsapp)) newErrors.whatsapp = 'رقم الواتساب غير صالح (يجب أن يبدأ 09 أو 05)';
+ if (!idImages.front) newErrors.front = 'صورة الوجه الأمامي للهوية مطلوبة';
+ if (!idImages.back) newErrors.back = 'صورة الوجه الخلفي للهوية مطلوبة';
+ setErrors(newErrors);
+ return Object.keys(newErrors).length === 0;
+ };
+
+ const validateStep3 = () => {
+ const newErrors = {};
+ if (!formData.agencyAddress) newErrors.agencyAddress = 'عنوان الوكالة مطلوب';
+ if (!formData.licenseNumber) newErrors.licenseNumber = 'رقم الترخيص مطلوب';
+ if (!idImages.license) newErrors.license = 'صورة الترخيص مطلوبة';
+ setErrors(newErrors);
+ return Object.keys(newErrors).length === 0;
+ };
+
+ const handleNextStep = () => {
+ if (step === 1 && validateStep1()) {
+ setStep(2);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else if (step === 2 && validateStep2()) {
+ setStep(3);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else if (step === 3 && validateStep3()) {
+ setStep(4);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else {
+ toast.error('يرجى تصحيح الأخطاء في النموذج');
+ }
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ if (!formData.agreeTerms) {
+ toast.error('يجب الموافقة على الشروط والأحكام');
+ return;
+ }
+
+ setIsLoading(true);
+ try {
+ const fd = new FormData();
+ fd.append('FirstName', formData.firstName);
+ fd.append('LastName', formData.lastName);
+ fd.append('Email', formData.email);
+ fd.append('PhoneNumber', formData.phone);
+ fd.append('WhatsAppNumber', formData.whatsapp);
+ fd.append('NationalNumber', formData.nationalNumber);
+ fd.append('Password', formData.password);
+ fd.append('AgencyAddress', formData.agencyAddress);
+ fd.append('LicenseNumber', formData.licenseNumber);
+ fd.append('Language', '0');
+
+ if (idImages.front) fd.append('FrontIdCarImagePath', idImages.front);
+ if (idImages.back) fd.append('RearIdCarImagePath', idImages.back);
+ if (idImages.license) fd.append('LicenseImagePath', idImages.license);
+
+ const res = await registerRealEstateAgent(fd);
+ if (res.ok || res.status === 200) {
+ const tempToken = res.data;
+ if (tempToken) AuthService.addToken(tempToken);
+ toast.success(res.message || 'تم إنشاء الحساب! يرجى التحقق من بريدك الإلكتروني', { duration: 4000 });
+
+ const loginRes = await loginWithEmail(formData.email, formData.password);
+ if (loginRes.status === 206) {
+ const otpToken = loginRes.data;
+ if (otpToken) AuthService.addToken(otpToken);
+ toast(loginRes.message || 'تم إرسال رمز التحقق إلى بريدك الإلكتروني', { icon: '📧' });
+ setShowOtpModal(true);
+ } else if (loginRes.status === 200) {
+ const loginToken = loginRes.data;
+ if (loginToken) AuthService.addToken(loginToken);
+ toast.success(loginRes.message || 'تم تسجيل الدخول بنجاح!');
+ router.push('/');
+ } else {
+ toast.success('تم إنشاء الحساب بنجاح! يرجى تسجيل الدخول');
+ setTimeout(() => router.push('/login'), 1500);
+ }
+ } else {
+ toast.error(res.message || res.data?.message || 'فشل في إنشاء الحساب');
+ }
+ } catch (err) {
+ toast.error(err.message || 'حدث خطأ أثناء التسجيل');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleVerifyOTP = async () => {
+ if (!otpCode || otpCode.length < 4) {
+ toast.error('يرجى إدخال رمز التحقق');
+ return;
+ }
+ setIsLoading(true);
+ try {
+ const res = await verifyEmail(otpCode);
+ if (res.status === 200) {
+ AuthService.deleteToken();
+ toast.success(res.message || 'تم التحقق من البريد الإلكتروني بنجاح!');
+ setShowOtpModal(false);
+ setTimeout(() => router.push('/login'), 1500);
+ } else {
+ toast.error(res.message || res.data?.message || 'رمز التحقق غير صحيح');
+ }
+ } catch (err) {
+ toast.error(err.message || 'حدث خطأ أثناء التحقق');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleResendOTP = async () => {
+ setIsLoading(true);
+ try {
+ await sendEmailOTP();
+ toast.success('تم إرسال رمز تحقق جديد');
+ } catch (err) {
+ toast.error('فشل في إرسال الرمز');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const fadeInUp = {
+ initial: { opacity: 0, y: 20 },
+ animate: { opacity: 1, y: 0 },
+ transition: { duration: 0.5 }
+ };
+
+ const staggerContainer = {
+ animate: { transition: { staggerChildren: 0.1 } }
+ };
+
+ const backgroundElements = useMemo(() => {
+ const circles = [
+ { style: { top: '20%', right: '20%', width: '256px', height: '256px' }, className: 'bg-purple-500/5' },
+ { style: { bottom: '20%', left: '20%', width: '320px', height: '320px' }, className: 'bg-amber-500/5' },
+ { style: { top: '50%', left: '50%', width: '384px', height: '384px', transform: 'translate(-50%, -50%)' }, className: 'bg-purple-500/5' },
+ ];
+ const dots = Array.from({ length: 10 }).map((_, i) => ({
+ left: `${5 + i * 10}%`,
+ top: `${10 + (i * 7) % 80}%`,
+ size: `${80 + (i % 5) * 15}px`
+ }));
+ return (
+ <>
+ {circles.map((circle, i) => (
+
+ ))}
+ {dots.map((dot, i) => (
+
+ ))}
+ >
+ );
+ }, []);
+
+ const stepTitles = ['المعلومات الأساسية', 'معلومات الهوية', 'معلومات الوكالة', 'تأكيد التسجيل'];
+ const stepDescriptions = ['أدخل معلوماتك الأساسية', 'يرجى رفع صور الهوية للتحقق', 'أدخل بيانات الوكالة والترخيص', 'راجع معلوماتك قبل الإرسال'];
+
+ const renderStepFields = () => {
+ switch (step) {
+ case 1:
+ return (
+ <>
+
+
+
+
+
+
+
+
{ setFormData({...formData, firstName: e.target.value}); setErrors({...errors, firstName: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.firstName ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="الاسم الأول" />
+
+ {errors.firstName &&
{errors.firstName}
}
+
+
+
+
{ setFormData({...formData, lastName: e.target.value}); setErrors({...errors, lastName: null}); }}
+ className={`w-full px-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.lastName ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="اسم العائلة" />
+ {errors.lastName &&
{errors.lastName}
}
+
+
+
+
+
+
+
+
+
+
{ setFormData({...formData, email: e.target.value}); setErrors({...errors, email: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.email ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل بريدك الإلكتروني" />
+
+ {errors.email && {errors.email}
}
+
+
+
+
+
+
+
{ setFormData({...formData, phone: e.target.value}); setErrors({...errors, phone: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.phone ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل رقم هاتفك" />
+
+ {errors.phone && {errors.phone}
}
+
+
+
+
+
+
+
+
+
{ setFormData({...formData, password: e.target.value}); setErrors({...errors, password: null}); }}
+ className={`w-full pr-12 pl-12 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.password ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل كلمة المرور" />
+
+
+ {errors.password && {errors.password}
}
+
+
+
+
+
+
+
+
+
{ setFormData({...formData, confirmPassword: e.target.value}); setErrors({...errors, confirmPassword: null}); }}
+ className={`w-full pr-12 pl-12 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.confirmPassword ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أعد إدخال كلمة المرور" />
+
+ {formData.confirmPassword && (
+
+ {formData.password === formData.confirmPassword ? : }
+
+ )}
+
+ {errors.confirmPassword && {errors.confirmPassword}
}
+
+ >
+ );
+
+ case 2:
+ return (
+ <>
+
+
+
+
+
+
+
{ setFormData({...formData, nationalNumber: e.target.value}); setErrors({...errors, nationalNumber: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.nationalNumber ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل الرقم الوطني" />
+
+ {errors.nationalNumber && {errors.nationalNumber}
}
+
+
+
+
+
+
+
+
+
{ setFormData({...formData, whatsapp: e.target.value}); setErrors({...errors, whatsapp: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.whatsapp ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل رقم الواتساب" />
+
+ {errors.whatsapp && {errors.whatsapp}
}
+
+
+
+
+ fileInputFrontRef.current?.click()}
+ className={`relative border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-all ${idImagePreviews.front ? 'border-green-500 bg-green-500/10' : errors.front ? 'border-red-500 bg-red-500/10' : 'border-gray-700 hover:border-purple-500 hover:bg-white/5'}`}>
+
handleImageUpload('front', e.target.files?.[0])} className="hidden" />
+ {idImagePreviews.front ? (
+
+
+
+
+ ) : (<>
اضغط لرفع الصورة
JPEG, PNG, JPG • حتى 5MB
>)}
+
+ {errors.front && {errors.front}
}
+
+
+
+
+ fileInputBackRef.current?.click()}
+ className={`relative border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-all ${idImagePreviews.back ? 'border-green-500 bg-green-500/10' : errors.back ? 'border-red-500 bg-red-500/10' : 'border-gray-700 hover:border-purple-500 hover:bg-white/5'}`}>
+
handleImageUpload('back', e.target.files?.[0])} className="hidden" />
+ {idImagePreviews.back ? (
+
+
+
+
+ ) : (<>
اضغط لرفع الصورة
JPEG, PNG, JPG • حتى 5MB
>)}
+
+ {errors.back && {errors.back}
}
+
+ >
+ );
+
+ case 3:
+ return (
+ <>
+
+
+
+
+
+
+
{ setFormData({...formData, agencyAddress: e.target.value}); setErrors({...errors, agencyAddress: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.agencyAddress ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل عنوان الوكالة" />
+
+ {errors.agencyAddress && {errors.agencyAddress}
}
+
+
+
+
+
+
+
+
+
{ setFormData({...formData, licenseNumber: e.target.value}); setErrors({...errors, licenseNumber: null}); }}
+ className={`w-full pr-12 pl-4 py-3 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-gray-500 transition-all ${errors.licenseNumber ? 'border-red-500' : 'border-gray-700'}`}
+ placeholder="أدخل رقم الترخيص العقاري" />
+
+ {errors.licenseNumber && {errors.licenseNumber}
}
+
+
+
+
+ fileInputLicenseStep3Ref.current?.click()}
+ className={`relative border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-all ${idImagePreviews.license ? 'border-green-500 bg-green-500/10' : errors.license ? 'border-red-500 bg-red-500/10' : 'border-gray-700 hover:border-purple-500 hover:bg-white/5'}`}>
+
handleImageUpload('license', e.target.files?.[0])} className="hidden" />
+ {idImagePreviews.license ? (
+
+
+
+
+ ) : (<>
اضغط لرفع صورة الترخيص
JPEG, PNG, JPG • حتى 5MB
>)}
+
+ {errors.license && {errors.license}
}
+
+ >
+ );
+
+ case 4:
+ return (
+
+
+
+
+ المعلومات الأساسية
+
+
+
الاسم الأول: {formData.firstName}
+
اسم العائلة: {formData.lastName}
+
البريد الإلكتروني: {formData.email}
+
رقم الهاتف: {formData.phone}
+
+
+
+
+
+
+ معلومات الهوية
+
+
+
الرقم الوطني: {formData.nationalNumber}
+
رقم الواتساب: {formData.whatsapp}
+
+
+ {idImagePreviews.front && (
+
+ )}
+ {idImagePreviews.back && (
+
+ )}
+
+
+
+
+
+
+ معلومات الوكالة
+
+
+
عنوان الوكالة: {formData.agencyAddress}
+
رقم الترخيص: {formData.licenseNumber}
+
+ {idImagePreviews.license && (
+
+ )}
+
+
+
+ setFormData({...formData, agreeTerms: e.target.checked})}
+ className="w-4 h-4 rounded border-gray-600 bg-white/5 text-purple-500 focus:ring-purple-500" required />
+
+
+
+ );
+
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+
+
{backgroundElements}
+
+
+
+
+
+
+
العودة
+
+
خطوة {step} من 4
+
+
+ {[1, 2, 3, 4].map((s) => (
+ = s ? 'bg-purple-500' : 'bg-gray-700'}`} animate={{ scaleX: step >= s ? 1 : 0.5 }} />
+ ))}
+
+
+
+
+
+
+
+
+
+
+ {stepTitles[step - 1]}
+ {stepDescriptions[step - 1]}
+
+
+
+
+
{ e.preventDefault(); handleNextStep(); } : handleSubmit}
+ className="space-y-6">
+ {renderStepFields()}
+
+
+ {step > 1 && (
+
+ )}
+ {step < 4 ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+ {showOtpModal && (
+
+
+
+
+
+
+
التحقق من البريد
+
تم إرسال رمز التحقق إلى
+
{formData.email}
+
+
+
+
+
+
+
+
setOtpCode(e.target.value)}
+ className="w-full pr-12 pl-4 py-3 bg-white/5 border border-gray-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 text-white text-center tracking-[0.5em] text-xl"
+ placeholder="------" />
+
+
+
+
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/app/reports/page.js b/app/reports/page.js
new file mode 100644
index 0000000..9c97f32
--- /dev/null
+++ b/app/reports/page.js
@@ -0,0 +1,371 @@
+'use client';
+
+import { useState, useEffect } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
+import { useRouter } from 'next/navigation';
+import toast, { Toaster } from 'react-hot-toast';
+import {
+ FileText,
+ Calendar,
+ DollarSign,
+ Send,
+ Loader2,
+ CheckCircle,
+ AlertCircle,
+ User,
+ MessageSquare,
+ Hash,
+} from 'lucide-react';
+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 router = useRouter();
+ const [activeTab, setActiveTab] = useState('general');
+ const [isLoading, setIsLoading] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+
+ useEffect(() => {
+ if (!AuthService.isAuthenticated()) {
+ router.push('/login');
+ }
+ }, [router]);
+
+ const [generalForm, setGeneralForm] = useState({ subject: '', body: '' });
+ const [reservationForm, setReservationForm] = useState({ reservationId: '', message: '', reporter: 'customer' });
+ const [saleForm, setSaleForm] = useState({ saleId: '', message: '', reporter: 'buyer' });
+
+ const [errors, setErrors] = useState({});
+
+ const validateGeneral = () => {
+ const e = {};
+ if (!generalForm.subject.trim()) e.subject = 'الموضوع مطلوب';
+ if (!generalForm.body.trim()) e.body = 'الوصف مطلوب';
+ setErrors(e);
+ return Object.keys(e).length === 0;
+ };
+
+ const validateReservation = () => {
+ const e = {};
+ if (!reservationForm.reservationId.trim()) e.reservationId = 'رقم الحجز مطلوب';
+ if (!reservationForm.message.trim()) e.message = 'الرسالة مطلوبة';
+ setErrors(e);
+ return Object.keys(e).length === 0;
+ };
+
+ const validateSale = () => {
+ const e = {};
+ if (!saleForm.saleId.trim()) e.saleId = 'رقم البيع مطلوب';
+ if (!saleForm.message.trim()) e.message = 'الرسالة مطلوبة';
+ setErrors(e);
+ return Object.keys(e).length === 0;
+ };
+
+ const handleGeneralSubmit = async (e) => {
+ e.preventDefault();
+ if (!validateGeneral()) return;
+ setIsLoading(true);
+ try {
+ await submitReport(generalForm.subject, generalForm.body);
+ setIsSuccess(true);
+ toast.success('تم إرسال التقرير بنجاح!', {
+ style: { background: '#dcfce7', color: '#166534' },
+ });
+ setGeneralForm({ subject: '', body: '' });
+ setTimeout(() => setIsSuccess(false), 2000);
+ } catch (err) {
+ toast.error(err.message || 'فشل إرسال التقرير', {
+ style: { background: '#fee2e2', color: '#991b1b' },
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleReservationSubmit = async (e) => {
+ e.preventDefault();
+ if (!validateReservation()) return;
+ setIsLoading(true);
+ try {
+ await submitReservationReport(reservationForm);
+ setIsSuccess(true);
+ toast.success('تم إرسال تقرير الحجز!', {
+ style: { background: '#dcfce7', color: '#166534' },
+ });
+ setReservationForm({ reservationId: '', message: '', reporter: 'customer' });
+ setTimeout(() => setIsSuccess(false), 2000);
+ } catch (err) {
+ toast.error(err.message || 'فشل إرسال التقرير', {
+ style: { background: '#fee2e2', color: '#991b1b' },
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleSaleSubmit = async (e) => {
+ e.preventDefault();
+ if (!validateSale()) return;
+ setIsLoading(true);
+ try {
+ await submitSaleReport(saleForm);
+ setIsSuccess(true);
+ toast.success('تم إرسال تقرير البيع!', {
+ style: { background: '#dcfce7', color: '#166534' },
+ });
+ setSaleForm({ saleId: '', message: '', reporter: 'buyer' });
+ setTimeout(() => setIsSuccess(false), 2000);
+ } catch (err) {
+ toast.error(err.message || 'فشل إرسال التقرير', {
+ style: { background: '#fee2e2', color: '#991b1b' },
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const tabContent = {
+ general: (
+
+ ),
+ reservation: (
+
+ ),
+ sale: (
+
+ ),
+ };
+
+ return (
+
+
+
+
+ الإبلاغ عن مشكلة
+ أخبرنا عن المشكلة التي تواجهها وسنقوم بمعالجتها
+
+
+
+
+ {tabs.map((tab) => {
+ const Icon = tab.icon;
+ return (
+
+ );
+ })}
+
+
+
+
+
+ {tabContent[activeTab]}
+
+
+
+
+
+
+ );
+}
diff --git a/app/settings/page.js b/app/settings/page.js
new file mode 100644
index 0000000..ef76b5f
--- /dev/null
+++ b/app/settings/page.js
@@ -0,0 +1,247 @@
+'use client';
+
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import Link from 'next/link';
+import { motion } from 'framer-motion';
+import {
+ User,
+ Shield,
+ Trash2,
+ LogOut,
+ ChevronLeft,
+ Bell,
+ Lock,
+ Eye,
+ FileText,
+ HelpCircle,
+ MessageCircle,
+ Loader2,
+ AlertTriangle,
+ X
+} from 'lucide-react';
+import toast, { Toaster } from 'react-hot-toast';
+import AuthService from '../services/AuthService';
+import { changePassword, deleteMyAccount } from '../utils/api';
+
+export default function SettingsPage() {
+ const router = useRouter();
+ const [showDeleteDialog, setShowDeleteDialog] = useState(false);
+ const [deletePassword, setDeletePassword] = useState('');
+ const [isDeleting, setIsDeleting] = useState(false);
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
+
+ const handleSignOut = () => {
+ AuthService.deleteToken();
+ toast.success('تم تسجيل الخروج بنجاح');
+ router.push('/');
+ };
+
+ const handleDeleteAccount = async () => {
+ if (!deletePassword) {
+ toast.error('الرجاء إدخال كلمة المرور');
+ return;
+ }
+ setIsDeleting(true);
+ try {
+ await deleteMyAccount(deletePassword);
+ AuthService.deleteToken();
+ toast.success('تم حذف الحساب بنجاح');
+ router.push('/');
+ } catch (err) {
+ toast.error(err.message || 'فشل حذف الحساب');
+ } finally {
+ setIsDeleting(false);
+ setShowDeleteDialog(false);
+ setDeletePassword('');
+ }
+ };
+
+ const sections = [
+ {
+ title: 'الحساب',
+ items: [
+ { icon: User, label: 'الملف الشخصي', href: '/profile', desc: 'عرض وتعديل معلوماتك الشخصية' },
+ { icon: Lock, label: 'تغيير كلمة المرور', href: '/change-password', desc: 'تحديث كلمة المرور الخاصة بك' },
+ { icon: Shield, label: 'التحقق من الحساب', href: '/account-verification', desc: 'تأكيد البريد الإلكتروني ورقم الهاتف' },
+ ]
+ },
+ {
+ title: 'الإشعارات',
+ items: [
+ { icon: Bell, label: 'الإشعارات', href: '/notifications', desc: 'إدارة تفضيلات الإشعارات' },
+ ]
+ },
+ {
+ title: 'الدعم',
+ items: [
+ { icon: HelpCircle, label: 'الأسئلة الشائعة', href: '/faq', desc: 'إجابات للأسئلة المتكررة' },
+ { icon: MessageCircle, label: 'تواصل معنا', href: '/support', desc: 'الحصول على المساعدة والدعم' },
+ { icon: FileText, label: 'الشروط والأحكام', href: '/terms', desc: 'سياسة الاستخدام والخصوصية' },
+ { icon: Eye, label: 'سياسة الخصوصية', href: '/privacy', desc: 'كيف نحمي بياناتك' },
+ ]
+ },
+ ];
+
+ const containerVariants = {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: { staggerChildren: 0.08 }
+ }
+ };
+
+ const itemVariants = {
+ hidden: { opacity: 0, y: 20 },
+ visible: { opacity: 1, y: 0 }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ الإعدادات
+
+
+
+ {sections.map((section) => (
+
+
+
{section.title}
+
+
+ {section.items.map((item) => {
+ const Icon = item.icon;
+ return (
+
+
+
+
+
+
{item.label}
+
{item.desc}
+
+
+
+ );
+ })}
+
+
+ ))}
+
+
+
+
+
الأمان
+
+
+
+
+ سيتم حذف جميع بياناتك بشكل دائم ولا يمكن التراجع عن هذا الإجراء
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {showDeleteDialog && (
+
+
+
+
+
+
حذف الحساب
+
هذا الإجراء لا يمكن التراجع عنه
+
+
+
+
+
+ أدخل كلمة المرور لتأكيد حذف حسابك نهائياً. سيتم حذف جميع بياناتك وملفاتك بشكل دائم.
+
+
+ setDeletePassword(e.target.value)}
+ placeholder="كلمة المرور"
+ className="w-full px-4 py-3 border border-gray-300 rounded-xl mb-4 focus:ring-2 focus:ring-red-500 focus:border-transparent outline-none"
+ />
+
+
+
+
+
+
+
+ )}
+
+ );
+}
diff --git a/app/support/page.js b/app/support/page.js
new file mode 100644
index 0000000..1c4f626
--- /dev/null
+++ b/app/support/page.js
@@ -0,0 +1,165 @@
+'use client';
+
+import { useState } from 'react';
+import { motion } from 'framer-motion';
+import { MessageCircle, Mail, Phone, MapPin, Send, Loader2 } from 'lucide-react';
+import toast, { Toaster } from 'react-hot-toast';
+import { submitReport } from '../utils/api';
+import AuthService from '../services/AuthService';
+
+export default function SupportPage() {
+ const [subject, setSubject] = useState('');
+ const [body, setBody] = useState('');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ if (!subject.trim() || !body.trim()) {
+ toast.error('يرجى تعبئة جميع الحقول');
+ return;
+ }
+
+ if (!AuthService.isAuthenticated()) {
+ toast.error('يرجى تسجيل الدخول أولاً لإرسال طلب دعم');
+ return;
+ }
+
+ setIsSubmitting(true);
+ try {
+ await submitReport(subject, body);
+ toast.success('تم إرسال طلب الدعم بنجاح');
+ setSubject('');
+ setBody('');
+ } catch (error) {
+ toast.error('حدث خطأ أثناء إرسال الطلب. حاول مرة أخرى');
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+ خدمة العملاء
+
+ نحن هنا لمساعدتك. تواصل معنا عبر النموذج أدناه أو من خلال معلومات الاتصال المباشرة
+
+
+
+
+
+
+
أرسل لنا رسالة
+
+
+
+
+
+
+
معلومات الاتصال
+
+
+
+
+
+
+
البريد الإلكتروني
+
support@sweethome.com
+
+
+
+
+
+
رقم الهاتف
+
+963 11 234 5678
+
+
+
+
+
+
+
+
العنوان
+
دمشق، سورية
+
+
+
+
+
+
+
ساعات العمل
+
+
+ السبت - الخميس
+ 9:00 - 18:00
+
+
+ الجمعة
+ مغلق
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/terms/page.js b/app/terms/page.js
new file mode 100644
index 0000000..4f64b52
--- /dev/null
+++ b/app/terms/page.js
@@ -0,0 +1,114 @@
+'use client';
+
+import { useState, useEffect } from 'react';
+import { motion } from 'framer-motion';
+import { FileText, Shield, CheckCircle } from 'lucide-react';
+import { getTerms } from '../utils/api';
+
+const staticTerms = [
+ {
+ title: 'مقدمة',
+ content:
+ 'مرحباً بك في منصة SweetHome. باستخدامك للمنصة، فإنك توافق على الالتزام بشروط الاستخدام هذه. إذا كنت لا توافق على أي جزء من هذه الشروط، يرجى عدم استخدام المنصة. تحتفظ المنصة بحق تعديل هذه الشروط في أي وقت مع إشعار المستخدمين.',
+ },
+ {
+ title: 'استخدام المنصة',
+ content:
+ 'يُسمح باستخدام المنصة للأغراض المشروعة فقط. يلتزم المستخدم بعدم استخدام المنصة في أي نشاط غير قانوني أو مخالف للقوانين السارية. كما يلتزم المستخدم بعدم محاولة الوصول غير المصرح به إلى أي جزء من المنصة أو الخوادم أو الأنظمة المتصلة بها.',
+ },
+ {
+ title: 'حقوق ومسؤوليات المالك',
+ content:
+ 'يتحمل المالك مسؤولية دقة المعلومات المقدمة عن العقار بما في ذلك الصور والوصف والسعر والتوفر. يلتزم المالك بتحديث معلومات العقار بشكل دوري. المنصة غير مسؤولة عن أي نزاعات تنشأ بين المالك والمستأجر. يجب على المالك الالتزام بجميع القوانين المحلية المتعلقة بتأجير العقارات.',
+ },
+ {
+ title: 'حقوق ومسؤوليات المستأجر',
+ content:
+ 'يلتزم المستأجر باستخدام العقار بطريقة مسؤولة وعدم التسبب في أي ضرر للممتلكات. يجب على المستأجر الالتزام بقوانين المنزل ومواعيد تسجيل الوصول والمغادرة. المنصة غير مسؤولة عن أي سلوك غير لائق من قبل المستأجرين.',
+ },
+ {
+ title: 'الدفع والعمولات',
+ content:
+ 'تتقاضى المنصة عمولة على كل حصة ناجحة وفقاً للنسبة المحددة في وقت الحجز. جميع المدفوعات تتم عبر قنوات الدفع الآمنة في المنصة. أي رسوم إلغاء أو استرداد تخضع لسياسة الإلغاء المحددة في كل عقار.',
+ },
+ {
+ title: 'خصوصية البيانات',
+ content:
+ 'نحن نأخذ خصوصية بياناتك على محمل الجد. يتم جمع واستخدام البيانات الشخصية وفقاً لسياسة الخصوصية الخاصة بنا. نحن لا نشارك معلوماتك مع أطراف ثالثة دون موافقتك، إلا عندما يقتضي القانون ذلك.',
+ },
+];
+
+export default function TermsPage() {
+ const [terms, setTerms] = useState(staticTerms);
+
+ useEffect(() => {
+ async function fetchTerms() {
+ try {
+ const data = await getTerms();
+ if (data && Array.isArray(data) && data.length > 0) {
+ setTerms(data);
+ }
+ } catch {
+ // fall back to static terms
+ }
+ }
+ fetchTerms();
+ }, []);
+
+ return (
+
+
+
+
+
+
+ شروط الاستخدام
+
+ يرجى قراءة شروط الاستخدام التالية بعناية قبل استخدام المنصة
+
+
+
+
+ {terms.map((term, index) => (
+
+
+
+
+
+
+
{term.title}
+
{term.content}
+
+
+
+ ))}
+
+
+
+
+
+
آخر تحديث
+
+ تم آخر تحديث لشروط الاستخدام في 1 مايو 2026. يرجى مراجعة هذه الصفحة بشكل دوري للاطلاع على أي تغييرات.
+
+
+
+
+
+ );
+}
diff --git a/app/utils/api.js b/app/utils/api.js
index 638db0b..e958bf0 100644
--- a/app/utils/api.js
+++ b/app/utils/api.js
@@ -664,6 +664,31 @@ export async function addRentProperty(data) {
});
}
+export async function editRentProperty(id, data) {
+ console.log('[API] Editing rent property:', id, data.PropertyInformation?.Address);
+ return apiFetch(`/RentProperties/EditRentProperty/${id}`, {
+ method: 'PUT',
+ body: JSON.stringify(data),
+ });
+}
+
+export async function addSaleProperty(data) {
+ console.log('[API] Adding sale property');
+ return apiFetch('/SaleProperties/AddSaleProperty', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ });
+}
+
+export async function getMySaleListings() {
+ console.log('[API] Fetching my sale listings');
+ return apiFetch('/SaleProperties/GetMySaleListings');
+}
+
+export async function getSalePropertyById(id) {
+ return apiFetch(`/SaleProperties/${id}`);
+}
+
// ─── Currencies ───
export async function getCurrencies() {
@@ -920,4 +945,160 @@ export async function updateBookingStatus(bookingId, status) {
method: 'PUT',
body: JSON.stringify({ bookingId, status }),
});
+}
+
+// ─── Owner / Reservations ───
+
+export async function getOwnerReservationRequests() {
+ return apiFetch('/Reservations/GetOwnerResevationRequests');
+}
+
+export async function getOwnerReservationsByStatuses(filterStatuses) {
+ return apiFetch('/Reservations/GetAllReservationsByStateForOwner', {
+ method: 'POST',
+ body: JSON.stringify({ filterStatuses }),
+ });
+}
+
+export async function getUserReservations() {
+ return apiFetch('/Reservations/GetUserResevations');
+}
+
+export async function ownerConfirmReservation(id) {
+ return apiFetch(`/Reservations/OwnerConfirmReservation/owner-confirm/${id}`, {
+ method: 'PUT',
+ });
+}
+
+// ─── Payments ───
+
+export async function payDeposit(data) {
+ return apiFetch('/Reservations/PayDeposit/pay-deposit', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ });
+}
+
+// ─── Owner Contact & Stats ───
+
+export async function getOwnerContactInformation(propertyInformationId) {
+ return apiFetch(`/Owner/GetOwnerContactInformation?propertyInformationId=${propertyInformationId}`);
+}
+
+export async function getOwnerStatistics() {
+ return apiFetch('/Statistics/GetOwnerStatistics');
+}
+
+// ─── Agent Registration ───
+
+export async function registerRealEstateAgent(formData) {
+ console.log('[API] Registering real estate agent (multipart)');
+ const token = AuthService.getToken();
+ const res = await fetch(`${API_BASE}/RealEstateAgent/Add`, {
+ method: 'POST',
+ headers: { ...(token && { Authorization: `Bearer ${token}` }) },
+ body: formData,
+ });
+ const text = await res.text();
+ let data = null;
+ try { data = text ? JSON.parse(text) : null; if (data && typeof data === 'object' && 'data' in data) data = data.data; } catch { data = text; }
+ return { status: res.status, data, ok: res.ok || res.status === 206, message: data?.message };
+}
+
+// ─── Change Password ───
+
+export async function changePassword(oldPassword, newPassword) {
+ return apiFetch(`/User/ChangePassword?oldPassword=${encodeURIComponent(oldPassword)}&newPassword=${encodeURIComponent(newPassword)}`, {
+ method: 'PUT',
+ });
+}
+
+// ─── Forget Password (OTP flow) ───
+
+export async function requestForgetPasswordOtp(email) {
+ return apiFetch(`/User/ForgetPassword?email=${encodeURIComponent(email)}`, { method: 'POST' });
+}
+
+export async function verifyForgetPasswordOtp(email, code, newPassword) {
+ return apiFetch(`/User/VerifyForgetPasswordOTP?email=${encodeURIComponent(email)}&code=${encodeURIComponent(code)}&newPassword=${encodeURIComponent(newPassword)}`, {
+ method: 'POST',
+ });
+}
+
+// ─── Reset Password (token flow) ───
+
+export async function resetPassword(token) {
+ return apiFetch(`/Auth/ResetPassword?token=${encodeURIComponent(token)}`);
+}
+
+// ─── Delete Account ───
+
+export async function deleteMyAccount(password) {
+ return apiFetch(`/User/DeleteMyAccount?password=${encodeURIComponent(password)}`, {
+ method: 'DELETE',
+ });
+}
+
+// ─── Set FCM Token ───
+
+export async function setFCMToken(token, deviceType = 2) {
+ return apiFetch('/User/SetFCMToken', {
+ method: 'POST',
+ body: JSON.stringify({ token, deviceType }),
+ });
+}
+
+// ─── Filter Rent Properties ───
+
+export async function filterRentProperties(params = {}) {
+ const qs = new URLSearchParams();
+ Object.entries(params).forEach(([k, v]) => { if (v != null && v !== '') qs.set(k, v); });
+ const query = qs.toString();
+ return apiFetch(`/RentProperties/FilterRentProperties${query ? `?${query}` : ''}`);
+}
+
+// ─── Reports ───
+
+export async function submitReport(subject, body) {
+ return apiFetch('/Reports', {
+ method: 'POST',
+ body: JSON.stringify({ subject, body }),
+ });
+}
+
+export async function submitReservationReport(data) {
+ return apiFetch('/ReservationReports', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ });
+}
+
+export async function updateReservationReport(id, data) {
+ return apiFetch(`/ReservationReports/${id}`, {
+ method: 'PUT',
+ body: JSON.stringify(data),
+ });
+}
+
+export async function submitSaleReport(data) {
+ return apiFetch('/SaleReports', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ });
+}
+
+export async function updateSaleReport(id, data) {
+ return apiFetch(`/SaleReports/${id}`, {
+ method: 'PUT',
+ body: JSON.stringify(data),
+ });
+}
+
+// ─── Terms (Add) ───
+
+export async function addTerm(name, description) {
+ return apiFetch('/Terms', {
+ method: 'POST',
+ body: JSON.stringify({ name, description }),
+ });
}
\ No newline at end of file