2026-01-29 19:34:28 +03:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { motion } from 'framer-motion';
|
2026-03-28 14:53:45 +00:00
|
|
|
import { useState, useEffect } from 'react';
|
2026-01-29 19:34:28 +03:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2026-03-28 16:12:21 +00:00
|
|
|
import Link from 'next/link';
|
2026-01-29 19:34:28 +03:00
|
|
|
import {
|
|
|
|
|
Home,
|
2026-02-15 01:53:37 +03:00
|
|
|
Calendar,
|
|
|
|
|
Users,
|
2026-01-29 19:34:28 +03:00
|
|
|
DollarSign,
|
2026-02-15 01:53:37 +03:00
|
|
|
TrendingUp,
|
2026-03-28 16:12:21 +00:00
|
|
|
Bell,
|
|
|
|
|
Frown
|
2026-01-29 19:34:28 +03:00
|
|
|
} from 'lucide-react';
|
2026-02-15 01:53:37 +03:00
|
|
|
import DashboardStats from '../components/admin/DashboardStats';
|
|
|
|
|
import PropertiesTable from '../components/admin/PropertiesTable';
|
|
|
|
|
import BookingRequests from '../components/admin/BookingRequests';
|
|
|
|
|
import UsersList from '../components/admin/UsersList';
|
|
|
|
|
import LedgerBook from '../components/admin/LedgerBook';
|
|
|
|
|
import AddPropertyForm from '../components/admin/AddPropertyForm';
|
|
|
|
|
import { PropertyProvider } from '../contexts/PropertyContext';
|
2026-03-28 14:53:45 +00:00
|
|
|
import AuthService from '../services/AuthService';
|
2026-02-15 01:53:37 +03:00
|
|
|
import '../i18n/config';
|
2026-01-29 19:34:28 +03:00
|
|
|
|
|
|
|
|
export default function AdminPage() {
|
|
|
|
|
const { t, i18n } = useTranslation();
|
2026-02-15 01:53:37 +03:00
|
|
|
const [activeTab, setActiveTab] = useState('dashboard');
|
|
|
|
|
const [showAddProperty, setShowAddProperty] = useState(false);
|
|
|
|
|
const [notifications, setNotifications] = useState(3);
|
2026-03-28 16:12:21 +00:00
|
|
|
const [isAdmin, setIsAdmin] = useState(false);
|
|
|
|
|
const [checked, setChecked] = useState(false);
|
2026-02-15 01:53:37 +03:00
|
|
|
|
2026-03-28 14:53:45 +00:00
|
|
|
useEffect(() => {
|
2026-03-28 16:12:21 +00:00
|
|
|
setIsAdmin(AuthService.isAuthenticated() && AuthService.isAdmin());
|
|
|
|
|
setChecked(true);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// ─── 404 for non-admins ───
|
|
|
|
|
if (checked && !isAdmin) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0, y: 20 }}
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
className="text-center max-w-md"
|
|
|
|
|
>
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<svg viewBox="0 0 200 180" className="w-72 h-52 mx-auto">
|
|
|
|
|
<circle cx="100" cy="70" r="60" fill="#fef3c7" />
|
|
|
|
|
<circle cx="80" cy="60" r="8" fill="#92400e" />
|
|
|
|
|
<circle cx="120" cy="60" r="8" fill="#92400e" />
|
|
|
|
|
<path d="M80 85 Q100 75 120 85" stroke="#92400e" strokeWidth="3" fill="none" strokeLinecap="round" />
|
|
|
|
|
<text x="100" y="140" textAnchor="middle" fontSize="16" fontWeight="bold" fill="#6b7280">عذراً!</text>
|
|
|
|
|
<text x="100" y="160" textAnchor="middle" fontSize="12" fill="#9ca3af">الصفحة غير موجودة</text>
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">404 - الصفحة غير موجودة</h2>
|
|
|
|
|
<p className="text-gray-500 mb-8">عذراً، لا يمكنك الوصول إلى هذه الصفحة</p>
|
|
|
|
|
<Link
|
|
|
|
|
href="/"
|
|
|
|
|
className="inline-flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Home className="w-5 h-5" />
|
|
|
|
|
العودة للرئيسية
|
|
|
|
|
</Link>
|
|
|
|
|
</motion.div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!checked) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
|
|
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin" />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-03-28 14:53:45 +00:00
|
|
|
|
2026-02-15 01:53:37 +03:00
|
|
|
const tabs = [
|
|
|
|
|
{ id: 'dashboard', label: 'لوحة التحكم', icon: Home },
|
|
|
|
|
{ id: 'properties', label: 'العقارات', icon: Home },
|
|
|
|
|
{ id: 'bookings', label: 'طلبات الحجز', icon: Calendar, badge: notifications },
|
|
|
|
|
{ id: 'users', label: 'المستخدمين', icon: Users },
|
|
|
|
|
{ id: 'ledger', label: 'دفتر الحسابات', icon: DollarSign },
|
2026-03-27 00:34:59 +03:00
|
|
|
// { id: 'reports', label: 'التقارير', icon: TrendingUp }
|
2026-02-15 01:53:37 +03:00
|
|
|
];
|
2026-01-29 19:34:28 +03:00
|
|
|
|
|
|
|
|
return (
|
2026-02-15 01:53:37 +03:00
|
|
|
<PropertyProvider>
|
|
|
|
|
<div className={`min-h-screen bg-gray-50 p-4 md:p-6 ${i18n.language === 'ar' ? 'text-right' : 'text-left'}`}>
|
2026-01-29 19:34:28 +03:00
|
|
|
<motion.div
|
2026-02-15 01:53:37 +03:00
|
|
|
initial={{ opacity: 0, y: -20 }}
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
className="mb-8"
|
2026-01-29 19:34:28 +03:00
|
|
|
>
|
2026-02-15 01:53:37 +03:00
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 mb-2">
|
|
|
|
|
{t('adminDashboard')}
|
|
|
|
|
</h1>
|
|
|
|
|
<p className="text-gray-600">
|
|
|
|
|
إدارة العقارات، الحجوزات، والحسابات المالية
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button className="relative p-2 hover:bg-gray-100 rounded-lg">
|
|
|
|
|
<Bell className="w-6 h-6 text-gray-600" />
|
|
|
|
|
{notifications > 0 && (
|
|
|
|
|
<span className="absolute top-0 right-0 w-4 h-4 bg-red-500 text-white text-xs rounded-full flex items-center justify-center">
|
|
|
|
|
{notifications}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</button>
|
2026-01-29 19:34:28 +03:00
|
|
|
</div>
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
2026-02-15 01:53:37 +03:00
|
|
|
<div className="mb-6 border-b border-gray-200">
|
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
|
|
|
{tabs.map((tab) => {
|
|
|
|
|
const Icon = tab.icon;
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
key={tab.id}
|
|
|
|
|
onClick={() => setActiveTab(tab.id)}
|
|
|
|
|
className={`
|
|
|
|
|
px-4 py-3 font-medium text-sm rounded-t-lg transition-all relative
|
|
|
|
|
${activeTab === tab.id
|
|
|
|
|
? 'bg-white border-t border-x border-gray-300 text-blue-700'
|
|
|
|
|
: 'text-gray-700 hover:text-blue-600 hover:bg-gray-100'
|
|
|
|
|
}
|
|
|
|
|
`}
|
2026-01-29 19:34:28 +03:00
|
|
|
>
|
2026-02-15 01:53:37 +03:00
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<Icon className="w-4 h-4" />
|
|
|
|
|
<span>{tab.label}</span>
|
|
|
|
|
{tab.badge && (
|
|
|
|
|
<span className="bg-red-500 text-white text-xs px-2 py-0.5 rounded-full">
|
|
|
|
|
{tab.badge}
|
2026-01-29 19:34:28 +03:00
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-02-15 01:53:37 +03:00
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-01-29 19:34:28 +03:00
|
|
|
|
2026-02-15 01:53:37 +03:00
|
|
|
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
|
|
|
|
|
{activeTab === 'dashboard' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<DashboardStats />
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'properties' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex justify-between items-center mb-6">
|
|
|
|
|
<div>
|
|
|
|
|
<h2 className="text-xl font-bold">إدارة العقارات</h2>
|
|
|
|
|
<p className="text-gray-600 text-sm">إضافة وتعديل العقارات مع تحديد نسب الأرباح</p>
|
|
|
|
|
</div>
|
2026-01-29 19:34:28 +03:00
|
|
|
<button
|
2026-02-15 01:53:37 +03:00
|
|
|
onClick={() => setShowAddProperty(true)}
|
|
|
|
|
className="bg-blue-700 text-white px-4 py-2 rounded-lg hover:bg-blue-800"
|
2026-01-29 19:34:28 +03:00
|
|
|
>
|
2026-02-15 01:53:37 +03:00
|
|
|
إضافة عقار جديد
|
2026-01-29 19:34:28 +03:00
|
|
|
</button>
|
|
|
|
|
</div>
|
2026-02-15 01:53:37 +03:00
|
|
|
<PropertiesTable />
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'bookings' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<BookingRequests />
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'users' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<UsersList />
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'ledger' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<LedgerBook userType="admin" />
|
|
|
|
|
</motion.div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'reports' && (
|
|
|
|
|
<motion.div
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
>
|
|
|
|
|
<div className="text-center py-12 text-gray-500">
|
|
|
|
|
قريباً... تقارير متقدمة
|
2026-01-29 19:34:28 +03:00
|
|
|
</div>
|
2026-02-15 01:53:37 +03:00
|
|
|
</motion.div>
|
|
|
|
|
)}
|
2026-01-29 19:34:28 +03:00
|
|
|
</div>
|
2026-02-15 01:53:37 +03:00
|
|
|
|
|
|
|
|
{showAddProperty && (
|
|
|
|
|
<AddPropertyForm
|
|
|
|
|
onClose={() => setShowAddProperty(false)}
|
|
|
|
|
onSuccess={() => {
|
|
|
|
|
setShowAddProperty(false);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</PropertyProvider>
|
2026-01-29 19:34:28 +03:00
|
|
|
);
|
|
|
|
|
}
|