Merge branch 'main' of http://45.93.137.91:3000/Rahaf/SweetHome
Some checks failed
Build frontend / build (push) Failing after 1m30s

This commit is contained in:
Rahaf
2026-06-14 18:04:26 +03:00
2 changed files with 627 additions and 100 deletions

View File

@ -1,105 +1,217 @@
// 'use client';
// import { motion } from 'framer-motion';
// import { Shield, Lock, Eye, Database, RefreshCw, Trash2, CheckCircle } from 'lucide-react';
// const sections = [
// {
// title: 'المقدمة',
// icon: Shield,
// content:
// 'نحن في SweetHome نلتزم بحماية خصوصية مستخدمينا. توضح سياسة الخصوصية هذه كيفية جمع واستخدام وحماية المعلومات الشخصية التي تقدمها عند استخدام منصتنا. باستخدامك للمنصة، فإنك توافق على الممارسات الموضحة في هذه السياسة.',
// },
// {
// title: 'المعلومات التي نجمعها',
// icon: Database,
// content:
// 'نجمع المعلومات التي تقدمها مباشرة عند إنشاء حساب، مثل الاسم، البريد الإلكتروني، رقم الهاتف، ومعلومات الدفع. كما نجمع معلومات حول استخدامك للمنصة، مثل العقارات التي تتصفحها، الحجوزات التي تقوم بها، وتقييماتك. قد نجمع أيضاً معلومات تقنية مثل عنوان IP ونوع المتصفح.',
// },
// {
// title: 'كيف نستخدم معلوماتك',
// icon: Eye,
// content:
// 'نستخدم معلوماتك لتقديم وتحسين خدماتنا، ومعالجة الحجوزات والمدفوعات، والتواصل معك بشأن حساباتك وحجوزاتك، وإرسال التحديثات والعروض الترويجية (بموافقتك)، وتحسين تجربة المستخدم وتطوير ميزات جديدة، والامتثال للالتزامات القانونية.',
// },
// {
// title: 'حماية البيانات وأمانها',
// icon: Lock,
// content:
// 'نحن نتخذ إجراءات أمنية مناسبة لحماية بياناتك الشخصية من الوصول غير المصرح به أو التعديل أو الإفصاح أو الإتلاف. تشمل هذه الإجراءات التشفير، وجدران الحماية، وضوابط الوصول الصارمة. ومع ذلك، لا يمكن ضمان أمان مطلق لنقل البيانات عبر الإنترنت.',
// },
// {
// title: 'مشاركة البيانات مع أطراف ثالثة',
// icon: RefreshCw,
// content:
// 'لا نبيع أو نشارك معلوماتك الشخصية مع أطراف ثالثة لأغراض تسويقية دون موافقتك الصريحة. قد نشارك معلوماتك مع مزودي الخدمة الذين يساعدوننا في تشغيل المنصة (مثل معالجة الدفعات)، مع الالتزام باتفاقيات سرية صارمة. قد نكشف عن معلوماتك إذا كان ذلك مطلوباً بموجب القانون.',
// },
// {
// title: 'حقوقك وخياراتك',
// icon: Trash2,
// content:
// 'لديك الحق في الوصول إلى بياناتك الشخصية وتحديثها أو تصحيحها أو حذفها في أي وقت. يمكنك إدارة تفضيلات الاتصال من إعدادات حسابك. يمكنك طلب حذف حسابك وجميع بياناتك المرتبطة به من خلال التواصل مع فريق الدعم. سنستجيب لطلباتك في أقرب وقت ممكن وفقاً للقوانين المعمول بها.',
// },
// ];
// export default function PrivacyPage() {
// return (
// <div className="min-h-screen bg-gradient-to-b from-amber-50/50 to-white py-12" dir="rtl">
// <div className="container mx-auto px-4 max-w-4xl">
// <motion.div
// initial={{ opacity: 0, y: -20 }}
// animate={{ opacity: 1, y: 0 }}
// className="text-center mb-12"
// >
// <div className="w-20 h-20 bg-amber-100 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-amber-100">
// <Shield className="w-10 h-10 text-amber-600" />
// </div>
// <h1 className="text-4xl font-bold text-gray-900 mb-4">سياسة الخصوصية</h1>
// <p className="text-lg text-gray-600 max-w-2xl mx-auto">
// نلتزم بحماية خصوصيتك وأمان بياناتك الشخصية
// </p>
// </motion.div>
// <div className="space-y-6">
// {sections.map((section, index) => {
// const Icon = section.icon;
// return (
// <motion.div
// key={index}
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: index * 0.1 }}
// className="bg-white rounded-2xl shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow"
// >
// <div className="flex items-start gap-4">
// <div className="w-12 h-12 bg-amber-100 rounded-xl flex items-center justify-center shrink-0">
// <Icon className="w-6 h-6 text-amber-600" />
// </div>
// <div>
// <h2 className="text-xl font-bold text-gray-900 mb-3">{section.title}</h2>
// <p className="text-gray-600 leading-relaxed">{section.content}</p>
// </div>
// </div>
// </motion.div>
// );
// })}
// </div>
// <motion.div
// initial={{ opacity: 0 }}
// animate={{ opacity: 1 }}
// transition={{ delay: 0.6 }}
// className="mt-8 bg-amber-50 rounded-2xl border border-amber-200 p-6 flex items-start gap-4"
// >
// <CheckCircle className="w-6 h-6 text-amber-600 shrink-0 mt-0.5" />
// <div>
// <p className="font-bold text-amber-800 mb-1">آخر تحديث</p>
// <p className="text-amber-700">
// تم آخر تحديث لسياسة الخصوصية في 1 مايو 2026. للمزيد من المعلومات أو الاستفسارات، يرجى التواصل مع فريق الدعم.
// </p>
// </div>
// </motion.div>
// </div>
// </div>
// );
// }
'use client';
import { motion } from 'framer-motion';
import { Shield, Lock, Eye, Database, RefreshCw, Trash2, CheckCircle } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Languages, Loader2, Shield } from 'lucide-react';
const sections = [
{
title: 'المقدمة',
icon: Shield,
content:
'نحن في SweetHome نلتزم بحماية خصوصية مستخدمينا. توضح سياسة الخصوصية هذه كيفية جمع واستخدام وحماية المعلومات الشخصية التي تقدمها عند استخدام منصتنا. باستخدامك للمنصة، فإنك توافق على الممارسات الموضحة في هذه السياسة.',
},
{
title: 'المعلومات التي نجمعها',
icon: Database,
content:
'نجمع المعلومات التي تقدمها مباشرة عند إنشاء حساب، مثل الاسم، البريد الإلكتروني، رقم الهاتف، ومعلومات الدفع. كما نجمع معلومات حول استخدامك للمنصة، مثل العقارات التي تتصفحها، الحجوزات التي تقوم بها، وتقييماتك. قد نجمع أيضاً معلومات تقنية مثل عنوان IP ونوع المتصفح.',
},
{
title: 'كيف نستخدم معلوماتك',
icon: Eye,
content:
'نستخدم معلوماتك لتقديم وتحسين خدماتنا، ومعالجة الحجوزات والمدفوعات، والتواصل معك بشأن حساباتك وحجوزاتك، وإرسال التحديثات والعروض الترويجية (بموافقتك)، وتحسين تجربة المستخدم وتطوير ميزات جديدة، والامتثال للالتزامات القانونية.',
},
{
title: 'حماية البيانات وأمانها',
icon: Lock,
content:
'نحن نتخذ إجراءات أمنية مناسبة لحماية بياناتك الشخصية من الوصول غير المصرح به أو التعديل أو الإفصاح أو الإتلاف. تشمل هذه الإجراءات التشفير، وجدران الحماية، وضوابط الوصول الصارمة. ومع ذلك، لا يمكن ضمان أمان مطلق لنقل البيانات عبر الإنترنت.',
},
{
title: 'مشاركة البيانات مع أطراف ثالثة',
icon: RefreshCw,
content:
'لا نبيع أو نشارك معلوماتك الشخصية مع أطراف ثالثة لأغراض تسويقية دون موافقتك الصريحة. قد نشارك معلوماتك مع مزودي الخدمة الذين يساعدوننا في تشغيل المنصة (مثل معالجة الدفعات)، مع الالتزام باتفاقيات سرية صارمة. قد نكشف عن معلوماتك إذا كان ذلك مطلوباً بموجب القانون.',
},
{
title: 'حقوقك وخياراتك',
icon: Trash2,
content:
'لديك الحق في الوصول إلى بياناتك الشخصية وتحديثها أو تصحيحها أو حذفها في أي وقت. يمكنك إدارة تفضيلات الاتصال من إعدادات حسابك. يمكنك طلب حذف حسابك وجميع بياناتك المرتبطة به من خلال التواصل مع فريق الدعم. سنستجيب لطلباتك في أقرب وقت ممكن وفقاً للقوانين المعمول بها.',
},
];
const API_BASE = 'http://45.93.137.91/api';
const ENDPOINTS = {
ar: '/Configuration/GetARPrivacyPolicy',
en: '/Configuration/GetENPrivacyPolicy',
};
export default function PrivacyPage() {
return (
<div className="min-h-screen bg-gradient-to-b from-amber-50/50 to-white py-12" dir="rtl">
<div className="container mx-auto px-4 max-w-4xl">
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="text-center mb-12"
>
<div className="w-20 h-20 bg-amber-100 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg shadow-amber-100">
<Shield className="w-10 h-10 text-amber-600" />
</div>
<h1 className="text-4xl font-bold text-gray-900 mb-4">سياسة الخصوصية</h1>
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
نلتزم بحماية خصوصيتك وأمان بياناتك الشخصية
</p>
</motion.div>
const [language, setLanguage] = useState('ar');
const [policyText, setPolicyText] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
<div className="space-y-6">
{sections.map((section, index) => {
const Icon = section.icon;
return (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
className="bg-white rounded-2xl shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow"
>
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-amber-100 rounded-xl flex items-center justify-center shrink-0">
<Icon className="w-6 h-6 text-amber-600" />
</div>
<div>
<h2 className="text-xl font-bold text-gray-900 mb-3">{section.title}</h2>
<p className="text-gray-600 leading-relaxed">{section.content}</p>
</div>
</div>
</motion.div>
);
})}
useEffect(() => {
const controller = new AbortController();
const loadPolicy = async () => {
try {
setLoading(true);
setError('');
const response = await fetch(`${API_BASE}${ENDPOINTS[language]}`, {
method: 'GET',
cache: 'no-store',
signal: controller.signal,
headers: {
Accept: 'text/plain',
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const text = await response.text();
console.log('API RESPONSE:', text);
setPolicyText(text.trim());
} catch (err) {
if (err.name !== 'AbortError') {
setPolicyText('');
setError(
language === 'ar'
? 'تعذر تحميل النص من الخادم.'
: 'Failed to load text from the server.'
);
}
} finally {
setLoading(false);
}
};
loadPolicy();
return () => controller.abort();
}, [language]);
return (
<div
dir={language === 'ar' ? 'rtl' : 'ltr'}
className="min-h-screen bg-gradient-to-b from-amber-50/50 to-white py-12"
>
<div className="mx-auto max-w-3xl px-4">
<div className="mb-8 flex items-center justify-between">
<div className="flex items-center gap-2 text-gray-900">
<Shield className="h-6 w-6 text-amber-600" />
<span className="text-lg font-bold">
{language === 'ar' ? 'سياسة الخصوصية' : 'Privacy Policy'}
</span>
</div>
<button
type="button"
onClick={() => setLanguage(language === 'ar' ? 'en' : 'ar')}
className="inline-flex items-center gap-2 rounded-full border border-amber-200 bg-white px-4 py-2 text-sm font-semibold text-gray-700 shadow-sm transition hover:shadow-md"
>
<Languages className="h-4 w-4" />
{language === 'ar' ? 'English' : 'العربية'}
</button>
</div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.6 }}
className="mt-8 bg-amber-50 rounded-2xl border border-amber-200 p-6 flex items-start gap-4"
>
<CheckCircle className="w-6 h-6 text-amber-600 shrink-0 mt-0.5" />
<div>
<p className="font-bold text-amber-800 mb-1">آخر تحديث</p>
<p className="text-amber-700">
تم آخر تحديث لسياسة الخصوصية في 1 مايو 2026. للمزيد من المعلومات أو الاستفسارات، يرجى التواصل مع فريق الدعم.
</p>
{loading && (
<div className="mb-6 flex items-center gap-3 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-amber-800">
<Loader2 className="h-5 w-5 animate-spin" />
<span>{language === 'ar' ? 'جاري التحميل...' : 'Loading...'}</span>
</div>
</motion.div>
)}
{error && (
<div className="mb-6 rounded-2xl border border-red-200 bg-red-50 px-4 py-3 text-red-700">
{error}
</div>
)}
<div className="rounded-2xl border border-gray-200 bg-white p-6 shadow-sm">
<div className="whitespace-pre-wrap leading-8 text-gray-800">
{policyText}
</div>
</div>
</div>
</div>
);
}
}

View File

@ -1,3 +1,260 @@
// '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 (
// <div className="min-h-screen bg-gray-50 py-8" dir="rtl">
// <Toaster position="top-center" reverseOrder={false} />
// <div className="container mx-auto px-4 max-w-2xl">
// <motion.div
// initial={{ opacity: 0, y: -20 }}
// animate={{ opacity: 1, y: 0 }}
// className="flex items-center gap-3 mb-8"
// >
// <Link
// href="/profile"
// className="p-2 rounded-xl hover:bg-gray-200 transition-colors text-gray-600"
// >
// <ChevronLeft className="w-5 h-5" />
// </Link>
// <h1 className="text-2xl font-bold text-gray-900">الإعدادات</h1>
// </motion.div>
// <motion.div
// variants={containerVariants}
// initial="hidden"
// animate="visible"
// className="space-y-6"
// >
// {sections.map((section) => (
// <motion.div
// key={section.title}
// variants={itemVariants}
// className="bg-white rounded-2xl shadow-sm overflow-hidden"
// >
// <div className="px-6 py-4 border-b border-gray-100">
// <h2 className="text-lg font-semibold text-gray-800">{section.title}</h2>
// </div>
// <div className="divide-y divide-gray-50">
// {section.items.map((item) => {
// const Icon = item.icon;
// return (
// <Link
// key={item.label}
// href={item.href}
// className="flex items-center gap-4 px-6 py-4 hover:bg-gray-50 transition-colors group"
// >
// <div className="w-10 h-10 rounded-xl bg-amber-50 flex items-center justify-center flex-shrink-0 group-hover:bg-amber-100 transition-colors">
// <Icon className="w-5 h-5 text-amber-600" />
// </div>
// <div className="flex-1 min-w-0">
// <p className="text-sm font-medium text-gray-900">{item.label}</p>
// <p className="text-xs text-gray-500 truncate">{item.desc}</p>
// </div>
// <ChevronLeft className="w-4 h-4 text-gray-400" />
// </Link>
// );
// })}
// </div>
// </motion.div>
// ))}
// <motion.div variants={itemVariants} className="space-y-4">
// <div className="bg-white rounded-2xl shadow-sm overflow-hidden">
// <div className="px-6 py-4 border-b border-gray-100">
// <h2 className="text-lg font-semibold text-gray-800">الأمان</h2>
// </div>
// <div className="p-6">
// <button
// onClick={() => setShowDeleteDialog(true)}
// className="w-full flex items-center gap-3 px-4 py-3 rounded-xl border border-red-200 text-red-600 hover:bg-red-50 transition-colors"
// >
// <Trash2 className="w-5 h-5" />
// <span className="text-sm font-medium">حذف الحساب</span>
// </button>
// <p className="text-xs text-gray-500 mt-2 pr-12">
// سيتم حذف جميع بياناتك بشكل دائم ولا يمكن التراجع عن هذا الإجراء
// </p>
// </div>
// </div>
// <div className="bg-white rounded-2xl shadow-sm overflow-hidden">
// <div className="p-6">
// <button
// onClick={handleSignOut}
// className="w-full flex items-center gap-3 px-4 py-3 rounded-xl border border-gray-200 text-gray-700 hover:bg-gray-50 transition-colors"
// >
// <LogOut className="w-5 h-5" />
// <span className="text-sm font-medium">تسجيل الخروج</span>
// </button>
// </div>
// </div>
// </motion.div>
// </motion.div>
// </div>
// {showDeleteDialog && (
// <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50">
// <motion.div
// initial={{ opacity: 0, scale: 0.95 }}
// animate={{ opacity: 1, scale: 1 }}
// className="bg-white rounded-2xl shadow-xl max-w-md w-full p-6"
// >
// <div className="flex items-center gap-3 mb-4">
// <div className="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center">
// <AlertTriangle className="w-5 h-5 text-red-600" />
// </div>
// <div>
// <h3 className="text-lg font-semibold text-gray-900">حذف الحساب</h3>
// <p className="text-sm text-gray-500">هذا الإجراء لا يمكن التراجع عنه</p>
// </div>
// <button
// onClick={() => { setShowDeleteDialog(false); setDeletePassword(''); }}
// className="mr-auto p-1 hover:bg-gray-100 rounded-lg transition-colors"
// >
// <X className="w-5 h-5 text-gray-400" />
// </button>
// </div>
// <p className="text-sm text-gray-600 mb-4">
// أدخل كلمة المرور لتأكيد حذف حسابك نهائياً. سيتم حذف جميع بياناتك وملفاتك بشكل دائم.
// </p>
// <input
// type="password"
// value={deletePassword}
// onChange={(e) => 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"
// />
// <div className="flex gap-3">
// <button
// onClick={() => { setShowDeleteDialog(false); setDeletePassword(''); }}
// className="flex-1 px-4 py-3 rounded-xl border border-gray-200 text-gray-700 hover:bg-gray-50 transition-colors text-sm font-medium"
// >
// إلغاء
// </button>
// <button
// onClick={handleDeleteAccount}
// disabled={isDeleting}
// className="flex-1 px-4 py-3 rounded-xl bg-red-600 text-white hover:bg-red-700 transition-colors text-sm font-medium disabled:opacity-50 flex items-center justify-center gap-2"
// >
// {isDeleting ? <Loader2 className="w-4 h-4 animate-spin" /> : <Trash2 className="w-4 h-4" />}
// {isDeleting ? 'جاري الحذف...' : 'تأكيد الحذف'}
// </button>
// </div>
// </motion.div>
// </div>
// )}
// </div>
// );
// }
'use client';
import { useState } from 'react';
@ -31,6 +288,11 @@ export default function SettingsPage() {
const [isDeleting, setIsDeleting] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [showReportDialog, setShowReportDialog] = useState(false);
const [reportSubject, setReportSubject] = useState('');
const [reportBody, setReportBody] = useState('');
const [isSendingReport, setIsSendingReport] = useState(false);
const handleSignOut = () => {
AuthService.deleteToken();
toast.success('تم تسجيل الخروج بنجاح');
@ -49,6 +311,7 @@ export default function SettingsPage() {
toast.success('تم حذف الحساب بنجاح');
router.push('/');
} catch (err) {
console.error('Delete account error:', err);
toast.error(err.message || 'فشل حذف الحساب');
} finally {
setIsDeleting(false);
@ -57,6 +320,70 @@ export default function SettingsPage() {
}
};
const handleSendGeneralReport = async () => {
if (!reportSubject.trim() || !reportBody.trim()) {
toast.error('الرجاء تعبئة عنوان البلاغ ونصه');
return;
}
if (reportSubject.trim().length > 300) {
toast.error('عنوان البلاغ يجب ألا يتجاوز 300 حرف');
return;
}
const token =
AuthService.getToken?.() ||
(typeof window !== 'undefined'
? localStorage.getItem('token') ||
localStorage.getItem('accessToken') ||
localStorage.getItem('authToken')
: null);
if (!token) {
console.error('No token found. Checked AuthService.getToken and localStorage keys: token, accessToken, authToken');
toast.error('لم يتم العثور على التوكن');
return;
}
setIsSendingReport(true);
try {
const res = await fetch('http://45.93.137.91/api/Reports/SendGeneralReport', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
subject: reportSubject.trim(),
body: reportBody.trim(),
}),
});
const responseText = await res.text();
if (!res.ok) {
console.error('Send report failed:', {
status: res.status,
statusText: res.statusText,
responseText,
});
throw new Error(responseText || `فشل إرسال البلاغ (HTTP ${res.status})`);
}
console.log('Send report success:', responseText);
toast.success(responseText || 'تم إرسال البلاغ بنجاح');
setShowReportDialog(false);
setReportSubject('');
setReportBody('');
} catch (err) {
console.error('Send report error:', err);
toast.error(err.message || 'حدث خطأ أثناء إرسال البلاغ');
} finally {
setIsSendingReport(false);
}
};
const sections = [
{
title: 'الحساب',
@ -79,6 +406,7 @@ export default function SettingsPage() {
{ icon: MessageCircle, label: 'تواصل معنا', href: '/support', desc: 'الحصول على المساعدة والدعم' },
{ icon: FileText, label: 'الشروط والأحكام', href: '/terms', desc: 'سياسة الاستخدام والخصوصية' },
{ icon: Eye, label: 'سياسة الخصوصية', href: '/privacy', desc: 'كيف نحمي بياناتك' },
{ icon: AlertTriangle, label: 'إرسال بلاغ عام', desc: 'إرسال مشكلة أو ملاحظة إلى الإدارة', action: () => setShowReportDialog(true) },
]
},
];
@ -133,12 +461,9 @@ export default function SettingsPage() {
<div className="divide-y divide-gray-50">
{section.items.map((item) => {
const Icon = item.icon;
return (
<Link
key={item.label}
href={item.href}
className="flex items-center gap-4 px-6 py-4 hover:bg-gray-50 transition-colors group"
>
const content = (
<>
<div className="w-10 h-10 rounded-xl bg-amber-50 flex items-center justify-center flex-shrink-0 group-hover:bg-amber-100 transition-colors">
<Icon className="w-5 h-5 text-amber-600" />
</div>
@ -147,6 +472,28 @@ export default function SettingsPage() {
<p className="text-xs text-gray-500 truncate">{item.desc}</p>
</div>
<ChevronLeft className="w-4 h-4 text-gray-400" />
</>
);
if (item.action) {
return (
<button
key={item.label}
onClick={item.action}
className="w-full flex items-center gap-4 px-6 py-4 hover:bg-gray-50 transition-colors group text-right"
>
{content}
</button>
);
}
return (
<Link
key={item.label}
href={item.href}
className="flex items-center gap-4 px-6 py-4 hover:bg-gray-50 transition-colors group"
>
{content}
</Link>
);
})}
@ -242,6 +589,74 @@ export default function SettingsPage() {
</motion.div>
</div>
)}
{showReportDialog && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="bg-white rounded-2xl shadow-xl max-w-md w-full p-6"
>
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 rounded-full bg-amber-100 flex items-center justify-center">
<MessageCircle className="w-5 h-5 text-amber-600" />
</div>
<div>
<h3 className="text-lg font-semibold text-gray-900">إرسال بلاغ عام</h3>
<p className="text-sm text-gray-500">سيتم إرسال البلاغ إلى الإدارة</p>
</div>
<button
onClick={() => {
setShowReportDialog(false);
setReportSubject('');
setReportBody('');
}}
className="mr-auto p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<X className="w-5 h-5 text-gray-400" />
</button>
</div>
<input
type="text"
value={reportSubject}
onChange={(e) => setReportSubject(e.target.value)}
placeholder="عنوان البلاغ"
maxLength={300}
className="w-full px-4 py-3 border border-gray-300 rounded-xl mb-4 focus:ring-2 focus:ring-amber-500 focus:border-transparent outline-none"
/>
<textarea
value={reportBody}
onChange={(e) => setReportBody(e.target.value)}
placeholder="اكتب تفاصيل البلاغ هنا..."
rows={5}
className="w-full px-4 py-3 border border-gray-300 rounded-xl mb-4 focus:ring-2 focus:ring-amber-500 focus:border-transparent outline-none resize-none"
/>
<div className="flex gap-3">
<button
onClick={() => {
setShowReportDialog(false);
setReportSubject('');
setReportBody('');
}}
className="flex-1 px-4 py-3 rounded-xl border border-gray-200 text-gray-700 hover:bg-gray-50 transition-colors text-sm font-medium"
>
إلغاء
</button>
<button
onClick={handleSendGeneralReport}
disabled={isSendingReport}
className="flex-1 px-4 py-3 rounded-xl bg-amber-600 text-white hover:bg-amber-700 transition-colors text-sm font-medium disabled:opacity-50 flex items-center justify-center gap-2"
>
{isSendingReport ? <Loader2 className="w-4 h-4 animate-spin" /> : <MessageCircle className="w-4 h-4" />}
{isSendingReport ? 'جاري الإرسال...' : 'إرسال البلاغ'}
</button>
</div>
</motion.div>
</div>
)}
</div>
);
}
}