diff --git a/app/ClientLayout.js b/app/ClientLayout.js
index 760e4fe..4a74c66 100644
--- a/app/ClientLayout.js
+++ b/app/ClientLayout.js
@@ -5,6 +5,8 @@ import { useTranslation } from "react-i18next";
import Link from "next/link";
import Image from "next/image";
import { NavLink, MobileNavLink } from "./components/NavLinks";
+import { FavoritesProvider } from '@/app/contexts/FavoritesContext';
+import FloatingSidebar from '@/app/components/FloatingSidebar';
import {
Globe,
LogIn,
@@ -705,7 +707,10 @@ export default function ClientLayout({ children }) {
+
{children}
+ {!isAdmin && }
+
{!isAuthPage && !isProfilePage && (
diff --git a/app/components/FloatingSidebar.js b/app/components/FloatingSidebar.js
new file mode 100644
index 0000000..2f4082f
--- /dev/null
+++ b/app/components/FloatingSidebar.js
@@ -0,0 +1,165 @@
+'use client';
+
+import { useState } from 'react';
+import { motion } from 'framer-motion';
+import Link from 'next/link';
+import { Heart, Bell, CreditCard } from 'lucide-react';
+import { useFavorites } from '@/app/contexts/FavoritesContext';
+
+export default function FloatingSidebar({ isRTL }) {
+ const { favorites } = useFavorites();
+ const [tooltip, setTooltip] = useState(null);
+ let timeoutId = null;
+
+ const showTooltip = (id) => {
+ timeoutId = setTimeout(() => {
+ setTooltip(id);
+ }, 300);
+ };
+
+ const hideTooltip = () => {
+ clearTimeout(timeoutId);
+ setTooltip(null);
+ };
+
+ const side = isRTL ? 'left' : 'right';
+ const positionStyle = {
+ [side]: 0,
+ top: '50%',
+ transform: 'translateY(-50%)',
+ };
+
+ const cardVariants = {
+ initial: { opacity: 0, x: isRTL ? -20 : 20 },
+ animate: { opacity: 1, x: 0, transition: { duration: 0.4, ease: 'easeOut' } },
+ };
+
+ const buttonVariants = {
+ rest: { scale: 1, backgroundColor: 'rgba(255,255,255,0)' },
+ hover: { scale: 1.05, backgroundColor: 'rgba(245,158,11,0.1)', transition: { duration: 0.2 } },
+ tap: { scale: 0.95 },
+ };
+
+ return (
+
+
+
showTooltip('favorites')}
+ onMouseLeave={hideTooltip}
+ >
+
+
+
+ {favorites.length > 0 && (
+
+ {favorites.length}
+
+ )}
+
+
+ {tooltip === 'favorites' && (
+
+
+ المفضلة
+
+
+
+ )}
+
+
showTooltip('notifications')}
+ onMouseLeave={hideTooltip}
+ >
+
+
+
+
+ 3
+
+
+
+ {tooltip === 'notifications' && (
+
+
+ الإشعارات
+
+
+
+ )}
+
+
showTooltip('payments')}
+ onMouseLeave={hideTooltip}
+ >
+
+
+
+ {tooltip === 'payments' && (
+
+
+ المدفوعات
+
+
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/contexts/FavoritesContext.js b/app/contexts/FavoritesContext.js
new file mode 100644
index 0000000..e31c161
--- /dev/null
+++ b/app/contexts/FavoritesContext.js
@@ -0,0 +1,53 @@
+'use client';
+
+import { createContext, useContext, useState, useEffect } from 'react';
+
+const FavoritesContext = createContext();
+
+export const useFavorites = () => {
+ const context = useContext(FavoritesContext);
+ if (!context) {
+ throw new Error('useFavorites must be used within FavoritesProvider');
+ }
+ return context;
+};
+
+export const FavoritesProvider = ({ children }) => {
+ const [favorites, setFavorites] = useState([]);
+
+ useEffect(() => {
+ const stored = localStorage.getItem('favorites');
+ if (stored) {
+ try {
+ setFavorites(JSON.parse(stored));
+ } catch (e) {
+ console.error('Failed to parse favorites', e);
+ }
+ }
+ }, []);
+
+ useEffect(() => {
+ localStorage.setItem('favorites', JSON.stringify(favorites));
+ }, [favorites]);
+
+ const addFavorite = (property) => {
+ setFavorites(prev => {
+ if (prev.some(p => p.id === property.id)) return prev;
+ return [...prev, property];
+ });
+ };
+
+ const removeFavorite = (propertyId) => {
+ setFavorites(prev => prev.filter(p => p.id !== propertyId));
+ };
+
+ const isFavorite = (propertyId) => {
+ return favorites.some(p => p.id === propertyId);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
\ No newline at end of file
diff --git a/app/favorites/page.js b/app/favorites/page.js
new file mode 100644
index 0000000..600c9dd
--- /dev/null
+++ b/app/favorites/page.js
@@ -0,0 +1,146 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { motion } from 'framer-motion';
+import Link from 'next/link';
+import Image from 'next/image';
+import { Heart, MapPin, Bed, Bath, Square, X, ImageIcon } from 'lucide-react';
+import { useFavorites } from '@/app/contexts/FavoritesContext';
+import AuthService from '@/app/services/AuthService';
+
+export default function FavoritesPage() {
+ const router = useRouter();
+ const { favorites, removeFavorite } = useFavorites();
+ const [isLoading, setIsLoading] = useState(true);
+ const [isAdmin, setIsAdmin] = useState(false);
+
+ useEffect(() => {
+ if (AuthService.isAdmin()) {
+ router.push('/');
+ return;
+ }
+ setIsAdmin(AuthService.isAdmin());
+ setIsLoading(false);
+ }, [router]);
+
+ const formatCurrency = (amount) => {
+ return amount?.toLocaleString() + ' ل.س';
+ };
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
المفضلة
+
العقارات التي قمت بحفظها
+
+
+ {favorites.length === 0 ? (
+
+
+
لا توجد عقارات في المفضلة
+
يمكنك إضافة العقارات التي تعجبك بالنقر على أيقونة القلب
+
+ استعرض العقارات
+
+
+ ) : (
+
+ {favorites.map((property) => (
+
+
+ {property.images && property.images[0] ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ {property.type === 'apartment' ? 'شقة' : property.type === 'villa' ? 'فيلا' : 'بيت'}
+
+
+
{property.title}
+
+
+
+ {property.location.city}، {property.location.district}
+
+
+
+
+
{formatCurrency(property.price)}
+
/{property.priceUnit === 'daily' ? 'يوم' : 'شهر'}
+
+
+
+
+
+
+
+ {property.bedrooms}
+
+
+
+ {property.bathrooms}
+
+
+
+ {property.area}م²
+
+
+
+
+
+ عرض التفاصيل
+
+
+
+ ))}
+
+ )}
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/notifications/page.js b/app/notifications/page.js
new file mode 100644
index 0000000..aee174e
--- /dev/null
+++ b/app/notifications/page.js
@@ -0,0 +1,132 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { Bell, CheckCircle, XCircle, Calendar, MessageCircle } from 'lucide-react';
+import AuthService from '@/app/services/AuthService';
+
+const mockNotifications = [
+ {
+ id: 1,
+ type: 'booking',
+ title: 'تأكيد الحجز',
+ message: 'تم تأكيد حجزك في فيلا المزة للفترة 10-15 مارس',
+ date: '2024-03-01',
+ read: false,
+ icon: CheckCircle,
+ color: 'text-green-600',
+ bgColor: 'bg-green-50'
+ },
+ {
+ id: 2,
+ type: 'payment',
+ title: 'دفعة مستلمة',
+ message: 'تم استلام دفعة الإيجار بقيمة 500,000 ل.س',
+ date: '2024-02-28',
+ read: false,
+ icon: MessageCircle,
+ color: 'text-blue-600',
+ bgColor: 'bg-blue-50'
+ },
+ {
+ id: 3,
+ type: 'reminder',
+ title: 'تذكير بالإيجار',
+ message: 'ينتهي عقد الإيجار خلال 3 أيام',
+ date: '2024-02-25',
+ read: true,
+ icon: Calendar,
+ color: 'text-amber-600',
+ bgColor: 'bg-amber-50'
+ }
+];
+
+export default function NotificationsPage() {
+ const router = useRouter();
+ const [notifications, setNotifications] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ if (AuthService.isAdmin()) {
+ router.push('/');
+ return;
+ }
+ setTimeout(() => {
+ setNotifications(mockNotifications);
+ setIsLoading(false);
+ }, 500);
+ }, [router]);
+
+ const markAsRead = (id) => {
+ setNotifications(prev =>
+ prev.map(n => (n.id === id ? { ...n, read: true } : n))
+ );
+ };
+
+ const markAllAsRead = () => {
+ setNotifications(prev => prev.map(n => ({ ...n, read: true })));
+ };
+
+ const unreadCount = notifications.filter(n => !n.read).length;
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
الإشعارات
+
+ {unreadCount > 0 ? `لديك ${unreadCount} إشعار غير مقروء` : 'جميع الإشعارات مقروءة'}
+
+
+
+
+ {notifications.length === 0 ? (
+
+
+
لا توجد إشعارات
+
ستظهر هنا الإشعارات المتعلقة بحجوزاتك ومدفوعاتك
+
+ ) : (
+
+ {notifications.map((notification) => {
+ const Icon = notification.icon;
+ return (
+
+
+
+
+
+
+
+
+
{notification.title}
+
{notification.message}
+
{notification.date}
+
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/payments/page.js b/app/payments/page.js
new file mode 100644
index 0000000..7b86ee2
--- /dev/null
+++ b/app/payments/page.js
@@ -0,0 +1,96 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { CreditCard, Download, Eye } from 'lucide-react';
+import AuthService from '@/app/services/AuthService';
+import Link from 'next/link';
+
+const mockPayments = [
+ {
+ id: 1,
+ property: 'فيلا فاخرة في المزة',
+ amount: 2500000,
+ date: '2024-03-10',
+ status: 'completed',
+ invoiceId: 'INV-001'
+ },
+ {
+ id: 2,
+ property: 'شقة حديثة في الشهباء',
+ amount: 750000,
+ date: '2024-03-05',
+ status: 'completed',
+ invoiceId: 'INV-002'
+ }
+];
+
+export default function PaymentsPage() {
+ const router = useRouter();
+ const [payments, setPayments] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ if (AuthService.isAdmin()) {
+ router.push('/');
+ return;
+ }
+ setTimeout(() => {
+ setPayments(mockPayments);
+ setIsLoading(false);
+ }, 500);
+ }, [router]);
+
+ const formatCurrency = (amount) => amount?.toLocaleString() + ' ل.س';
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
المدفوعات
+
سجل المعاملات المالية والفواتير
+
+
+ {payments.length === 0 ? (
+
+
+
لا توجد معاملات
+
ستظهر هنا مدفوعاتك للحجوزات
+
+ ) : (
+
+ {payments.map((payment) => (
+
+
+
+
{payment.property}
+
رقم الفاتورة: {payment.invoiceId}
+
{payment.date}
+
+
+
{formatCurrency(payment.amount)}
+
+ مكتمل
+
+
+
+
+
+ ))}
+
+ )}
+
+
+ );
+}
\ No newline at end of file