From 2ea48df8a8efff11489ef3248a2230a0a482ad12 Mon Sep 17 00:00:00 2001 From: Rahaf Date: Fri, 20 Mar 2026 13:20:30 +0300 Subject: [PATCH] Added calendar, profits and booking for owner --- app/ClientLayout.js | 4 +- app/admin/page.js | 2 - app/owner/bookings/page.js | 762 +++++++++++++++++++++++++++++++++++++ app/owner/calendar/page.js | 736 +++++++++++++++++++++++++++++++++++ app/owner/profits/page.js | 466 +++++++++++++++++++++++ app/page.js | 4 +- 6 files changed, 1968 insertions(+), 6 deletions(-) create mode 100644 app/owner/bookings/page.js create mode 100644 app/owner/calendar/page.js create mode 100644 app/owner/profits/page.js diff --git a/app/ClientLayout.js b/app/ClientLayout.js index ef59356..30862ee 100644 --- a/app/ClientLayout.js +++ b/app/ClientLayout.js @@ -228,14 +228,14 @@ export default function ClientLayout({ children }) { )} - changeLanguage(currentLanguage === 'en' ? 'ar' : 'en')} className="flex items-center justify-center w-10 h-10 bg-gray-100 hover:bg-gray-200 rounded-full transition-all duration-200 ml-4" > - + */} {user && (
diff --git a/app/admin/page.js b/app/admin/page.js index 088b2e0..93103be 100644 --- a/app/admin/page.js +++ b/app/admin/page.js @@ -1,5 +1,3 @@ -// app/admin/page.js (محدث) - 'use client'; import { motion } from 'framer-motion'; diff --git a/app/owner/bookings/page.js b/app/owner/bookings/page.js new file mode 100644 index 0000000..c3ecb84 --- /dev/null +++ b/app/owner/bookings/page.js @@ -0,0 +1,762 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { + Calendar, + Home, + User, + Mail, + Phone, + DollarSign, + CheckCircle, + XCircle, + Clock, + MapPin, + Bed, + Bath, + Square, + CalendarDays, + ChevronLeft, + ChevronRight, + Eye, + MessageCircle, + ArrowLeft, + Loader2, + Filter, + Search, + Download, + TrendingUp, + Users, + Building +} from 'lucide-react'; +import toast, { Toaster } from 'react-hot-toast'; +import Image from 'next/image'; + +const OwnerBookingCalendar = ({ property, onDateSelect, selectedDates }) => { + const [currentMonth, setCurrentMonth] = useState(new Date()); + const [hoverDate, setHoverDate] = useState(null); + + const daysInMonth = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth() + 1, + 0 + ).getDate(); + + const firstDayOfMonth = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth(), + 1 + ).getDay(); + + const monthNames = [ + 'يناير', 'فبراير', 'مارس', 'إبريل', 'مايو', 'يونيو', + 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر' + ]; + + const isDateBooked = (date) => { + if (!property?.bookings) return false; + const dateStr = date.toISOString().split('T')[0]; + return property.bookings.some(booking => { + const start = new Date(booking.startDate); + const end = new Date(booking.endDate); + const current = new Date(date); + return current >= start && current <= end; + }); + }; + + const isDateSelected = (date) => { + if (!selectedDates) return false; + const dateStr = date.toISOString().split('T')[0]; + return dateStr === selectedDates.start || dateStr === selectedDates.end; + }; + + const isInRange = (date) => { + if (!selectedDates?.start || !selectedDates?.end) return false; + const dateStr = date.toISOString().split('T')[0]; + return dateStr > selectedDates.start && dateStr < selectedDates.end; + }; + + const handleDateClick = (date) => { + if (isDateBooked(date)) return; + onDateSelect?.(date); + }; + + const renderDays = () => { + const days = []; + const totalDays = daysInMonth + firstDayOfMonth; + + for (let i = 0; i < totalDays; i++) { + if (i < firstDayOfMonth) { + days.push(
); + } else { + const dayNumber = i - firstDayOfMonth + 1; + const date = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth(), + dayNumber + ); + + const isBooked = isDateBooked(date); + const isSelected = isDateSelected(date); + const inRange = isInRange(date); + const isToday = date.toDateString() === new Date().toDateString(); + + days.push( + + ); + } + } + return days; + }; + + return ( +
+ {/* رأس التقويم */} +
+ + +

+ + {monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()} +

+ + +
+ + {/* أيام الأسبوع */} +
+
أحد
+
إثنين
+
ثلاثاء
+
أربعاء
+
خميس
+
جمعة
+
سبت
+
+ +
+ {renderDays()} +
+ +
+
+
+ محجوز +
+
+
+ محدد +
+
+
+ ضمن الفترة +
+
+
+ اليوم +
+
+
+ ); +}; + +const BookingCard = ({ booking, onViewDetails, onContact }) => { + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + const getStatusBadge = (status) => { + const statusConfig = { + pending: { label: 'قيد الانتظار', color: 'bg-yellow-100 text-yellow-800', icon: Clock }, + confirmed: { label: 'مؤكد', color: 'bg-green-100 text-green-800', icon: CheckCircle }, + cancelled: { label: 'ملغي', color: 'bg-red-100 text-red-800', icon: XCircle }, + completed: { label: 'منتهي', color: 'bg-gray-100 text-gray-800', icon: CheckCircle } + }; + + const config = statusConfig[status] || statusConfig.pending; + const Icon = config.icon; + + return ( + + + {config.label} + + ); + }; + + return ( + +
+
+
+
+

{booking.propertyTitle}

+ {getStatusBadge(booking.status)} +
+
+ + {booking.location} +
+
+
+
{formatCurrency(booking.totalAmount)}
+
إجمالي المبلغ
+
+
+ +
+
+
+ +
+
+

{booking.tenantName}

+
+ + {booking.tenantPhone} + + {booking.tenantEmail} +
+
+
+
+ +
+
+ +
من
+
{booking.startDate}
+
+
+ +
إلى
+
{booking.endDate}
+
+
+ +
المدة
+
{booking.days} يوم
+
+
+ +
+ + {/* */} +
+
+
+ ); +}; + +const BookingDetailsModal = ({ booking, isOpen, onClose }) => { + if (!isOpen || !booking) return null; + + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + return ( + + e.stopPropagation()} + > +
+
+

تفاصيل الحجز

+ +
+

رقم الحجز: #{booking.id}

+
+ +
+
+

معلومات العقار

+
+

العقار: {booking.propertyTitle}

+

الموقع: {booking.location}

+ {booking.propertyDetails && ( +
+ {booking.propertyDetails.bedrooms} غرف + {booking.propertyDetails.bathrooms} حمامات + {booking.propertyDetails.area} م² +
+ )} +
+
+ +
+

معلومات المستأجر

+
+

الاسم: {booking.tenantName}

+

البريد الإلكتروني: {booking.tenantEmail}

+

رقم الهاتف: {booking.tenantPhone}

+
+
+ +
+

تفاصيل الحجز

+
+
+

تاريخ البداية

+

{booking.startDate}

+
+
+

تاريخ النهاية

+

{booking.endDate}

+
+
+

عدد الأيام

+

{booking.days} يوم

+
+
+

حالة الحجز

+

{booking.status === 'pending' ? 'قيد الانتظار' : + booking.status === 'confirmed' ? 'مؤكد' : + booking.status === 'cancelled' ? 'ملغي' : 'منتهي'}

+
+
+
+ +
+

المعلومات المالية

+
+
+ السعر اليومي + {formatCurrency(booking.dailyPrice)} +
+
+ المدة ({booking.days} أيام) + {formatCurrency(booking.dailyPrice * booking.days)} +
+
+ سلفة الضمان + {formatCurrency(booking.securityDeposit || 0)} +
+
+ الإجمالي + {formatCurrency(booking.totalAmount)} +
+
+
+ + {booking.notes && ( +
+

ملاحظات

+

{booking.notes}

+
+ )} +
+
+
+ ); +}; + +export default function OwnerBookingsPage() { + const router = useRouter(); + const [user, setUser] = useState(null); + const [bookings, setBookings] = useState([]); + const [filteredBookings, setFilteredBookings] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [selectedBooking, setSelectedBooking] = useState(null); + const [filterStatus, setFilterStatus] = useState('all'); + const [searchTerm, setSearchTerm] = useState(''); + const [dateRange, setDateRange] = useState({ start: '', end: '' }); + const [showCalendar, setShowCalendar] = useState(false); + + useEffect(() => { + const storedUser = localStorage.getItem('user'); + if (storedUser) { + const userData = JSON.parse(storedUser); + if (userData.role !== 'owner') { + router.push('/'); + } else { + setUser(userData); + loadBookings(); + } + } else { + router.push('/auth/choose-role'); + } + }, [router]); + + const loadBookings = () => { + const storedBookings = localStorage.getItem('ownerBookings'); + if (storedBookings) { + setBookings(JSON.parse(storedBookings)); + setFilteredBookings(JSON.parse(storedBookings)); + } else { + const mockBookings = [ + { + id: 'BK001', + propertyId: 1, + propertyTitle: 'فيلا فاخرة في المزة', + location: 'دمشق، المزة', + propertyDetails: { bedrooms: 5, bathrooms: 4, area: 450 }, + tenantName: 'أحمد محمد', + tenantEmail: 'ahmed@example.com', + tenantPhone: '0933111222', + startDate: '2024-03-10', + endDate: '2024-03-15', + days: 5, + dailyPrice: 500000, + totalAmount: 2500000, + securityDeposit: 500000, + status: 'confirmed', + createdAt: '2024-02-25', + notes: 'طلب الحجز من خلال الموقع' + }, + { + id: 'BK002', + propertyId: 2, + propertyTitle: 'شقة حديثة في الشهباء', + location: 'حلب، الشهباء', + propertyDetails: { bedrooms: 3, bathrooms: 2, area: 180 }, + tenantName: 'سارة أحمد', + tenantEmail: 'sara@example.com', + tenantPhone: '0945123789', + startDate: '2024-03-05', + endDate: '2024-03-08', + days: 3, + dailyPrice: 250000, + totalAmount: 750000, + securityDeposit: 250000, + status: 'pending', + createdAt: '2024-02-24', + notes: 'تحتاج إلى تأكيد' + }, + { + id: 'BK003', + propertyId: 3, + propertyTitle: 'بيت عائلي في بابا عمرو', + location: 'حمص، بابا عمرو', + propertyDetails: { bedrooms: 4, bathrooms: 3, area: 300 }, + tenantName: 'محمد الحلبي', + tenantEmail: 'mohammed@example.com', + tenantPhone: '0956123456', + startDate: '2024-02-20', + endDate: '2024-03-20', + days: 30, + dailyPrice: 350000, + totalAmount: 10500000, + securityDeposit: 500000, + status: 'completed', + createdAt: '2024-02-15', + notes: 'تم إنهاء الإيجار بنجاح' + } + ]; + setBookings(mockBookings); + setFilteredBookings(mockBookings); + localStorage.setItem('ownerBookings', JSON.stringify(mockBookings)); + } + setIsLoading(false); + }; + + useEffect(() => { + let filtered = [...bookings]; + + if (filterStatus !== 'all') { + filtered = filtered.filter(b => b.status === filterStatus); + } + + if (searchTerm) { + filtered = filtered.filter(b => + b.propertyTitle.includes(searchTerm) || + b.tenantName.includes(searchTerm) || + b.id.includes(searchTerm) + ); + } + + if (dateRange.start) { + filtered = filtered.filter(b => b.startDate >= dateRange.start); + } + if (dateRange.end) { + filtered = filtered.filter(b => b.endDate <= dateRange.end); + } + + setFilteredBookings(filtered); + }, [filterStatus, searchTerm, dateRange, bookings]); + + const handleViewDetails = (booking) => { + setSelectedBooking(booking); + }; + + const handleContact = (booking) => { + toast.success(`جاري فتح محادثة مع ${booking.tenantName}`, { + icon: '💬', + style: { background: '#dcfce7', color: '#166534' } + }); + }; + + const handleStatusChange = (bookingId, newStatus) => { + const updatedBookings = bookings.map(b => + b.id === bookingId ? { ...b, status: newStatus } : b + ); + setBookings(updatedBookings); + setFilteredBookings(updatedBookings); + localStorage.setItem('ownerBookings', JSON.stringify(updatedBookings)); + toast.success(`تم تحديث حالة الحجز بنجاح`); + }; + + const statusCounts = { + all: bookings.length, + pending: bookings.filter(b => b.status === 'pending').length, + confirmed: bookings.filter(b => b.status === 'confirmed').length, + completed: bookings.filter(b => b.status === 'completed').length, + cancelled: bookings.filter(b => b.status === 'cancelled').length + }; + + if (isLoading) { + return ( +
+
+ +

جاري تحميل الحجوزات...

+
+
+ ); + } + + return ( +
+ + + setSelectedBooking(null)} + /> + +
+ +
+

حجوزاتي

+

مرحباً {user?.name}، لديك {bookings.length} حجز

+
+ +
+ + {/* */} +
+
+ +
+ setFilterStatus('all')} + > +
{statusCounts.all}
+
جميع الحجوزات
+
+ setFilterStatus('pending')} + > +
{statusCounts.pending}
+
قيد الانتظار
+
+ setFilterStatus('confirmed')} + > +
{statusCounts.confirmed}
+
مؤكدة
+
+ setFilterStatus('completed')} + > +
{statusCounts.completed}
+
منتهية
+
+ setFilterStatus('cancelled')} + > +
{statusCounts.cancelled}
+
ملغية
+
+
+ +
+
+ + setSearchTerm(e.target.value)} + className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500" + /> +
+
+ setDateRange({...dateRange, start: e.target.value})} + className="px-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500" + placeholder="من تاريخ" + /> + setDateRange({...dateRange, end: e.target.value})} + className="px-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500" + placeholder="إلى تاريخ" + /> + {(dateRange.start || dateRange.end) && ( + + )} +
+
+ + {showCalendar && ( + + console.log('Date selected:', date)} + /> + + )} + + {filteredBookings.length === 0 ? ( + +
+ +
+

لا توجد حجوزات

+

+ {filterStatus !== 'all' ? 'لا توجد حجوزات في هذه الفئة' : 'لم يتم استلام أي حجوزات بعد'} +

+ {filterStatus !== 'all' && ( + + )} +
+ ) : ( +
+ {filteredBookings.map((booking) => ( + + ))} +
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/app/owner/calendar/page.js b/app/owner/calendar/page.js new file mode 100644 index 0000000..29cf948 --- /dev/null +++ b/app/owner/calendar/page.js @@ -0,0 +1,736 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { + Calendar, + ChevronLeft, + ChevronRight, + Home, + Building, + MapPin, + Bed, + Bath, + Square, + DollarSign, + Eye, + ArrowLeft, + Loader2, + Filter, + Download, + Printer, + ChevronDown, + X, + CheckCircle, + XCircle, + Clock, + Users, + TrendingUp, + CalendarDays, + LayoutGrid, + List, + AlertCircle, + XCircle as XCircleIcon, + Calendar as CalendarIcon +} from 'lucide-react'; +import toast, { Toaster } from 'react-hot-toast'; + +const MonthlyCalendar = ({ properties, selectedPropertyId, onDateClick, onPropertySelect }) => { + const [currentMonth, setCurrentMonth] = useState(new Date()); + const [selectedDate, setSelectedDate] = useState(null); + const [viewType, setViewType] = useState('grid'); + + const monthNames = [ + 'يناير', 'فبراير', 'مارس', 'إبريل', 'مايو', 'يونيو', + 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر' + ]; + + const daysInMonth = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth() + 1, + 0 + ).getDate(); + + const firstDayOfMonth = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth(), + 1 + ).getDay(); + + const isDateBookedForProperty = (date, property) => { + if (!property?.bookings) return false; + const dateStr = date.toISOString().split('T')[0]; + return property.bookings.some(booking => { + const start = new Date(booking.startDate); + const end = new Date(booking.endDate); + const current = new Date(date); + return current >= start && current <= end; + }); + }; + + const getDayStatus = (date) => { + if (selectedPropertyId === 'all') { + const totalProperties = properties.length; + const bookedCount = properties.filter(p => isDateBookedForProperty(date, p)).length; + + if (bookedCount === 0) return { status: 'all_available', label: 'جميع العقارات متاحة', color: 'bg-green-100 text-green-800' }; + if (bookedCount === totalProperties) return { status: 'all_booked', label: 'جميع العقارات محجوزة', color: 'bg-red-100 text-red-800' }; + return { status: 'partial', label: `${bookedCount}/${totalProperties} محجوز`, color: 'bg-yellow-100 text-yellow-800' }; + } else { + const property = properties.find(p => p.id === selectedPropertyId); + if (!property) return { status: 'no_property', label: 'غير متاح', color: 'bg-gray-100 text-gray-500' }; + + const isBooked = isDateBookedForProperty(date, property); + return { + status: isBooked ? 'booked' : 'available', + label: isBooked ? 'محجوز' : 'متاح', + color: isBooked ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-800' + }; + } + }; + + const handleDateClick = (date) => { + setSelectedDate(date); + onDateClick?.(date); + }; + + const changeMonth = (direction) => { + setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + direction, 1)); + }; + + const renderDays = () => { + const days = []; + const totalDays = daysInMonth + firstDayOfMonth; + + for (let i = 0; i < totalDays; i++) { + if (i < firstDayOfMonth) { + days.push(
); + } else { + const dayNumber = i - firstDayOfMonth + 1; + const date = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth(), + dayNumber + ); + + const isToday = date.toDateString() === new Date().toDateString(); + const status = getDayStatus(date); + const isSelected = selectedDate?.toDateString() === date.toDateString(); + + days.push( + + ); + } + } + return days; + }; + + return ( +
+
+
+
+ +

+ {monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()} +

+ +
+ +
+ +
+ + +
+
+
+
+ +
+ {['أحد', 'إثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'].map((day, index) => ( +
+ {day} +
+ ))} +
+ +
+
+ {renderDays()} +
+
+ +
+
+
+
+ متاح +
+
+
+ محجوز +
+
+
+ محجوز جزئياً +
+
+
+ اليوم +
+
+
+ محدد +
+
+
+
+ ); +}; + +const PropertyCalendarList = ({ properties, selectedDate, onPropertyClick }) => { + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + const isDateBooked = (property, date) => { + if (!property?.bookings || !date) return false; + const dateStr = date.toISOString().split('T')[0]; + return property.bookings.some(booking => { + const start = new Date(booking.startDate); + const end = new Date(booking.endDate); + const current = new Date(date); + return current >= start && current <= end; + }); + }; + + const getBookingForDate = (property, date) => { + if (!property?.bookings || !date) return null; + const dateStr = date.toISOString().split('T')[0]; + return property.bookings.find(booking => { + const start = new Date(booking.startDate); + const end = new Date(booking.endDate); + const current = new Date(date); + return current >= start && current <= end; + }); + }; + + if (!selectedDate) { + return ( +
+ +

اختر تاريخاً

+

اضغط على أي يوم في التقويم لعرض حالة العقارات في ذلك التاريخ

+
+ ); + } + + const formattedDate = selectedDate.toLocaleDateString('ar-SA', { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric' + }); + + return ( +
+
+

+ + حالة العقارات في تاريخ: {formattedDate} +

+
+ +
+ {properties.map((property) => { + const isBooked = isDateBooked(property, selectedDate); + const booking = getBookingForDate(property, selectedDate); + + return ( + onPropertyClick(property)} + > +
+
+
+

{property.title}

+ + {isBooked ? 'محجوز' : 'متاح'} + +
+
+ + {property.location} +
+
+
+ + {property.bedrooms} غرف +
+
+ + {property.bathrooms} حمامات +
+
+ + {property.area} م² +
+
+
+ +
+
{formatCurrency(property.price)}
+
/يوم
+ {isBooked && booking && ( +
+
مستأجر: {booking.tenantName || 'غير معروف'}
+
من: {booking.startDate} إلى {booking.endDate}
+
+ )} +
+
+
+ ); + })} +
+
+ ); +}; + +const PropertyDetailsModal = ({ property, isOpen, onClose }) => { + if (!isOpen || !property) return null; + + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + return ( + + e.stopPropagation()} + > +
+
+
+

{property.title}

+

{property.location}

+
+ +
+
+ +
+ {property.images && property.images.length > 0 && ( +
+

صور العقار

+
+ {property.images.slice(0, 4).map((image, index) => ( +
+ {`${property.title} +
+ ))} +
+
+ )} + +
+
+ +
{property.bedrooms}
+
غرف نوم
+
+
+ +
{property.bathrooms}
+
حمامات
+
+
+ +
{property.area}
+
م²
+
+
+ +
{formatCurrency(property.price)}
+
/يوم
+
+
+ + {property.features && property.features.length > 0 && ( +
+

المميزات

+
+ {property.features.map((feature, index) => ( + + {feature} + + ))} +
+
+ )} + + {property.bookings && property.bookings.length > 0 && ( +
+

+ + الحجوزات القادمة +

+
+ {property.bookings.slice(0, 3).map((booking, index) => ( +
+
+

{booking.startDate} - {booking.endDate}

+

مستأجر: {booking.tenantName || 'غير معروف'}

+
+ {formatCurrency(booking.totalAmount)} +
+ ))} +
+
+ )} +
+ +
+ + تعديل العقار + + +
+
+
+ ); +}; + +export default function OwnerCalendarPage() { + const router = useRouter(); + const [user, setUser] = useState(null); + const [properties, setProperties] = useState([]); + const [filteredProperties, setFilteredProperties] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [selectedPropertyId, setSelectedPropertyId] = useState('all'); + const [selectedDate, setSelectedDate] = useState(null); + const [selectedProperty, setSelectedProperty] = useState(null); + const [showFilters, setShowFilters] = useState(false); + + useEffect(() => { + const storedUser = localStorage.getItem('user'); + if (storedUser) { + const userData = JSON.parse(storedUser); + if (userData.role !== 'owner') { + router.push('/'); + } else { + setUser(userData); + loadProperties(); + } + } else { + router.push('/auth/choose-role'); + } + }, [router]); + + const loadProperties = () => { + const storedProperties = localStorage.getItem('ownerProperties'); + if (storedProperties) { + const props = JSON.parse(storedProperties); + setProperties(props); + setFilteredProperties(props); + } else { + const mockProperties = [ + { + id: 1, + title: 'فيلا فاخرة في المزة', + location: 'دمشق، المزة', + bedrooms: 5, + bathrooms: 4, + area: 450, + price: 500000, + features: ['مسبح', 'حديقة خاصة', 'موقف سيارات', 'أمن 24/7'], + images: ['/villa1.jpg'], + status: 'available', + bookings: [ + { startDate: '2024-03-10', endDate: '2024-03-15', totalAmount: 2500000, tenantName: 'أحمد محمد' }, + { startDate: '2024-03-20', endDate: '2024-03-25', totalAmount: 2500000, tenantName: 'سارة أحمد' } + ] + }, + { + id: 2, + title: 'شقة حديثة في الشهباء', + location: 'حلب، الشهباء', + bedrooms: 3, + bathrooms: 2, + area: 180, + price: 250000, + features: ['مطبخ مجهز', 'بلكونة', 'موقف سيارات', 'مصعد'], + images: ['/apartment1.jpg'], + status: 'available', + bookings: [ + { startDate: '2024-03-05', endDate: '2024-03-08', totalAmount: 750000, tenantName: 'محمد علي' } + ] + }, + { + id: 3, + title: 'بيت عائلي في بابا عمرو', + location: 'حمص، بابا عمرو', + bedrooms: 4, + bathrooms: 3, + area: 300, + price: 350000, + features: ['حديقة كبيرة', 'موقف سيارات', 'مدفأة', 'كراج'], + images: ['/house1.jpg'], + status: 'booked', + bookings: [] + } + ]; + setProperties(mockProperties); + setFilteredProperties(mockProperties); + localStorage.setItem('ownerProperties', JSON.stringify(mockProperties)); + } + setIsLoading(false); + }; + + const calendarStats = { + totalProperties: properties.length, + availableToday: properties.filter(p => { + const today = new Date(); + const isBooked = p.bookings?.some(b => { + const start = new Date(b.startDate); + const end = new Date(b.endDate); + return today >= start && today <= end; + }); + return !isBooked; + }).length, + bookedToday: properties.filter(p => { + const today = new Date(); + return p.bookings?.some(b => { + const start = new Date(b.startDate); + const end = new Date(b.endDate); + return today >= start && today <= end; + }); + }).length, + upcomingBookings: properties.reduce((sum, p) => sum + (p.bookings?.length || 0), 0) + }; + + if (isLoading) { + return ( +
+
+ +

جاري تحميل التقويم...

+
+
+ ); + } + + return ( +
+ + + setSelectedProperty(null)} + /> + +
+ +
+

تقويم العقارات

+

مرحباً {user?.name}، تتبع حالة عقاراتك عبر التقويم

+
+ +
+ + {/* */} +
+
+ +
+ + +
{calendarStats.totalProperties}
+
إجمالي العقارات
+
+ + +
{calendarStats.availableToday}
+
متاح اليوم
+
+ + +
{calendarStats.bookedToday}
+
محجوز اليوم
+
+ + +
{calendarStats.upcomingBookings}
+
حجوزات قادمة
+
+
+ + + {showFilters && ( + +
+
+ + + +
+
+
+ )} +
+ +
+ +
+ +
+ +
+ + {selectedDate && ( + + + اضغط على أي عقار لعرض التفاصيل الكاملة + + )} +
+
+ ); +} \ No newline at end of file diff --git a/app/owner/profits/page.js b/app/owner/profits/page.js new file mode 100644 index 0000000..779222c --- /dev/null +++ b/app/owner/profits/page.js @@ -0,0 +1,466 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { motion } from 'framer-motion'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import { + DollarSign, + TrendingUp, + TrendingDown, + Calendar, + Home, + Building, + Download, + Filter, + ChevronLeft, + ChevronRight, + ArrowLeft, + Loader2, + Eye, + PieChart, + BarChart, + LineChart, + Wallet, + CreditCard, + Clock, + CheckCircle, + XCircle +} from 'lucide-react'; +import toast, { Toaster } from 'react-hot-toast'; + +const StatCard = ({ title, value, change, icon: Icon, color, trend }) => { + return ( + +
+
+ +
+
+ {trend === 'up' ? : } + {Math.abs(change)}% +
+
+

{title}

+
{value}
+
+ ); +}; + +const PropertyProfitCard = ({ property, onViewDetails }) => { + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + return ( + +
+
+
+

{property.title}

+

{property.location}

+
+ + {property.status === 'active' ? 'نشط' : 'غير نشط'} + +
+ +
+
+ +
إجمالي الأرباح
+
{formatCurrency(property.totalProfit)}
+
+
+ +
عدد الحجوزات
+
{property.totalBookings}
+
+
+ +
+
+ هذا الشهر + {formatCurrency(property.monthlyProfit)} +
+
+ الأسبوع الماضي + {formatCurrency(property.weeklyProfit)} +
+
+ متوسط السعر اليومي + {formatCurrency(property.avgDailyPrice)} +
+
+ + +
+
+ ); +}; + +const ProfitDetailsModal = ({ property, isOpen, onClose }) => { + if (!isOpen || !property) return null; + + const formatCurrency = (amount) => { + return amount?.toLocaleString() + ' ل.س'; + }; + + const monthlyData = [ + { month: 'يناير', profit: 1250000 }, + { month: 'فبراير', profit: 1500000 }, + { month: 'مارس', profit: 1800000 }, + { month: 'إبريل', profit: 2100000 }, + { month: 'مايو', profit: 2500000 }, + { month: 'يونيو', profit: 2300000 } + ]; + + const maxProfit = Math.max(...monthlyData.map(d => d.profit)); + + return ( + + e.stopPropagation()} + > +
+
+
+

{property.title}

+

{property.location}

+
+ +
+
+ +
+
+
+
{formatCurrency(property.totalProfit)}
+
إجمالي الأرباح
+
+
+
{property.totalBookings}
+
عدد الحجوزات
+
+
+
{property.occupancyRate}%
+
نسبة الإشغال
+
+
+
{formatCurrency(property.avgDailyPrice)}
+
متوسط السعر اليومي
+
+
+ +
+

الأرباح الشهرية

+
+ {monthlyData.map((data, index) => ( +
+
+ {data.month} + {formatCurrency(data.profit)} +
+
+ +
+
+ ))} +
+
+ +
+

آخر الحجوزات

+
+ {property.recentBookings?.map((booking, index) => ( +
+
+

{booking.tenantName}

+

{booking.startDate} - {booking.endDate}

+
+
+

{formatCurrency(booking.amount)}

+

{booking.status === 'completed' ? 'مكتمل' : 'قيد التنفيذ'}

+
+
+ ))} +
+
+
+
+
+ ); +}; + +export default function OwnerProfitsPage() { + const router = useRouter(); + const [user, setUser] = useState(null); + const [properties, setProperties] = useState([]); + const [filteredProperties, setFilteredProperties] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [selectedProperty, setSelectedProperty] = useState(null); + const [dateRange, setDateRange] = useState({ start: '', end: '' }); + const [selectedPeriod, setSelectedPeriod] = useState('month'); // month, year, all + + useEffect(() => { + const storedUser = localStorage.getItem('user'); + if (storedUser) { + const userData = JSON.parse(storedUser); + if (userData.role !== 'owner') { + router.push('/'); + } else { + setUser(userData); + loadProfitsData(); + } + } else { + router.push('/auth/choose-role'); + } + }, [router]); + + const loadProfitsData = () => { + const storedProfits = localStorage.getItem('ownerProfits'); + if (storedProfits) { + setProperties(JSON.parse(storedProfits)); + setFilteredProperties(JSON.parse(storedProfits)); + } else { + const mockProperties = [ + { + id: 1, + title: 'فيلا فاخرة في المزة', + location: 'دمشق، المزة', + status: 'active', + totalProfit: 12500000, + totalBookings: 24, + monthlyProfit: 3200000, + weeklyProfit: 850000, + avgDailyPrice: 500000, + occupancyRate: 78, + recentBookings: [ + { tenantName: 'أحمد محمد', startDate: '2024-03-10', endDate: '2024-03-15', amount: 2500000, status: 'completed' }, + { tenantName: 'سارة أحمد', startDate: '2024-03-05', endDate: '2024-03-08', amount: 1500000, status: 'completed' } + ] + }, + { + id: 2, + title: 'شقة حديثة في الشهباء', + location: 'حلب، الشهباء', + status: 'active', + totalProfit: 5800000, + totalBookings: 18, + monthlyProfit: 1500000, + weeklyProfit: 400000, + avgDailyPrice: 250000, + occupancyRate: 65, + recentBookings: [ + { tenantName: 'محمد علي', startDate: '2024-03-12', endDate: '2024-03-14', amount: 750000, status: 'completed' } + ] + }, + { + id: 3, + title: 'بيت عائلي في بابا عمرو', + location: 'حمص، بابا عمرو', + status: 'active', + totalProfit: 8400000, + totalBookings: 12, + monthlyProfit: 2100000, + weeklyProfit: 525000, + avgDailyPrice: 350000, + occupancyRate: 45, + recentBookings: [] + } + ]; + setProperties(mockProperties); + setFilteredProperties(mockProperties); + localStorage.setItem('ownerProfits', JSON.stringify(mockProperties)); + } + setIsLoading(false); + }; + + const totalStats = { + totalProfit: properties.reduce((sum, p) => sum + p.totalProfit, 0), + totalBookings: properties.reduce((sum, p) => sum + p.totalBookings, 0), + avgOccupancy: Math.round(properties.reduce((sum, p) => sum + p.occupancyRate, 0) / properties.length), + activeProperties: properties.filter(p => p.status === 'active').length + }; + + const formatCurrency = (amount) => { + if (amount >= 1000000) { + return (amount / 1000000).toFixed(1) + ' مليون ل.س'; + } + return amount?.toLocaleString() + ' ل.س'; + }; + + if (isLoading) { + return ( +
+
+ +

جاري تحميل بيانات الأرباح...

+
+
+ ); + } + + return ( +
+ + + setSelectedProperty(null)} + /> + +
+ +
+

الأرباح والإحصائيات

+

مرحباً {user?.name}، إليك ملخص أرباحك

+
+ +
+ + {/* */} +
+
+ +
+ + + + +
+ +
+
+

أرباح العقارات

+
+ +
+
+ + {filteredProperties.length === 0 ? ( +
+
+ +
+

لا توجد بيانات

+

لا توجد أرباح مسجلة حتى الآن

+
+ ) : ( +
+ {filteredProperties.map((property) => ( + + ))} +
+ )} +
+ + +
+
+

احصل على المزيد من الأرباح

+

أضف عقارات جديدة وحسّن أسعارك لزيادة الإشغال

+
+ + إضافة عقار جديد + +
+
+
+
+ ); +} diff --git a/app/page.js b/app/page.js index 6bde01b..c8e5e45 100644 --- a/app/page.js +++ b/app/page.js @@ -379,13 +379,13 @@ export default function HomePage() {

يمكنك إدارة عقاراتك من خلال لوحة التحكم الخاصة بك

- {/* إدارة عقاراتي - */} + )}