'use client'; import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import toast, { Toaster } from 'react-hot-toast'; import Image from 'next/image'; import Link from 'next/link'; import { useParams } from 'next/navigation'; import { MapPin, Bed, Bath, Square, DollarSign, Heart, Share2, Phone, Mail, MessageCircle, Calendar, Shield, Star, ChevronLeft, ChevronRight, Check, X, Wifi, Car, Coffee, Wind, Thermometer, Lock, Camera, Home, Building2, Users, Ruler, CalendarDays, Clock, Award, FileText, Printer, Download, ArrowLeft, LogIn, Copy } from 'lucide-react'; import { getRentProperty, getSaleProperty, bookReservation, checkAvailability, getAvailableDateRanges } from '../../utils/api'; import AuthService from '../../services/AuthService'; import { useFavorites } from '@/app/contexts/FavoritesContext'; import { BuildingTypeKeys, PropertyStatusKeys, extractCity } from '../../enums'; // Copy to clipboard that works on HTTP too async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); return true; } catch { // Fallback for HTTP / older browsers const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; textarea.style.opacity = '0'; document.body.appendChild(textarea); textarea.select(); try { document.execCommand('copy'); return true; } catch { return false; } finally { document.body.removeChild(textarea); } } } // Map API response to the UI format function mapApiDetail(item) { if (!item) return null; const info = item.propertyInformation || {}; const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0; const monthlyPrice = item.monthlyRent ?? 0; const propType = BuildingTypeKeys[info.buildingType] ?? BuildingTypeKeys[item.type] ?? 'apartment'; const status = PropertyStatusKeys[info.status] ?? PropertyStatusKeys[item.status] ?? 'available'; const features = []; if (item.isSmokeAllow) features.push({ name: 'يسمح بالتدخين', available: true, description: '' }); if (item.isVisitorAllow) features.push({ name: 'يسمح بالزوار', available: true, description: '' }); if (item.specializedFor) features.push({ name: 'متخصص', available: true, description: '' }); if (info.numberOfBedRooms) features.push({ name: 'غرف النوم', available: true, description: `${info.numberOfBedRooms} غرف` }); if (info.numberOfBathRooms) features.push({ name: 'الحمامات', available: true, description: `${info.numberOfBathRooms} حمامات` }); if (info.space) features.push({ name: 'المساحة', available: true, description: `${info.space} م²` }); const typeLabels = { 0: 'شقة', 1: 'فيلا', 2: 'بيت' }; // Extract images from API and build full URLs const apiBase = typeof window !== 'undefined' ? (process.env.NEXT_PUBLIC_API_URL || 'https://45.93.137.91.nip.io/api') : ''; const rawImages = Array.isArray(info.images) ? info.images : []; const images = rawImages.length > 0 ? rawImages.map(img => img.startsWith('http') ? img : `${apiBase}${img.startsWith('/') ? '' : '/Pictures/'}${img}`) : ['/property-placeholder.jpg', '/villa1.jpg', '/villa2.jpg']; return { id: item.id, title: info.address || `عقار #${item.id}`, description: info.description || 'عقار سكني مميز في موقع استراتيجي.', type: propType, price: dailyPrice, priceUnit: 'daily', location: { city: extractCity(info.address) || 'دمشق', district: info.address || '', address: info.address || '', lat: parseFloat(info.cordsX) || 0, lng: parseFloat(info.cordsY) || 0, }, bedrooms: info.numberOfBedRooms || 0, bathrooms: info.numberOfBathRooms || 0, area: info.space || 0, features: features.length > 0 ? features : [ { name: 'متاح للإيجار', available: true, description: '' }, ], images, status, rating: item.rating || 4.5, reviews: 0, reviewList: [], owner: { name: 'المالك', phone: '—', email: '—', rating: 4.8, properties: 1, memberSince: '2024', responseRate: '95%', responseTime: 'خلال ساعات', }, nearby: [], specifications: { constructionYear: null, floor: '-', parking: 0, gardenArea: 0, poolArea: 0, furnished: false, airConditioning: '-', heating: '-', electricity: '220V', water: 'شبكة عامة', }, rules: [], _raw: item, }; } // extractCity is now imported from @/app/enums // API-only — no fallback data export default function PropertyDetailsPage() { const params = useParams(); const { isFavorite, addFavorite, removeFavorite } = useFavorites(); const [currentImage, setCurrentImage] = useState(0); const [showContact, setShowContact] = useState(false); const [showShareMenu, setShowShareMenu] = useState(false); const [bookingDates, setBookingDates] = useState({ start: '', end: '' }); const [selectedDuration, setSelectedDuration] = useState(1); const [property, setProperty] = useState(null); const [loading, setLoading] = useState(true); const [bookingError, setBookingError] = useState(null); const [bookingSuccess, setBookingSuccess] = useState(false); const [availableRanges, setAvailableRanges] = useState([]); const [calendarMonth, setCalendarMonth] = useState(new Date()); const [favLoading, setFavLoading] = useState(false); const [selectingEnd, setSelectingEnd] = useState(false); const [showLoginDialog, setShowLoginDialog] = useState(false); useEffect(() => { const id = params.id; setLoading(true); setBookingError(null); setBookingSuccess(false); async function fetchProperty() { try { // Try RentProperties first, then SaleProperties let data = null; try { data = await getRentProperty(id); } catch { try { data = await getSaleProperty(id); } catch { // neither worked } } if (data) { const mapped = mapApiDetail(data); if (mapped) { setProperty(mapped); setLoading(false); return; } } setProperty(null); } catch (err) { console.error('[Property] Failed to fetch property:', err); setProperty(null); } finally { setLoading(false); } } fetchProperty(); }, [params.id]); // Fetch available date ranges useEffect(() => { if (!property) return; const propId = property._raw?.id || params.id; console.log('[Property] Fetching available dates for:', propId); getAvailableDateRanges(propId) .then((data) => { const ranges = Array.isArray(data) ? data : []; console.log('[Property] Available date ranges:', ranges); setAvailableRanges(ranges); }) .catch((err) => { console.warn('[Property] Failed to fetch available dates:', err); }); }, [property, params.id]); // Set Open Graph meta tags dynamically for Facebook/Twitter sharing useEffect(() => { if (!property) return; const typeLabel = property.type === 'villa' ? 'فيلا' : property.type === 'apartment' ? 'شقة' : 'بيت'; const priceLabel = `${formatCurrency(property.price)} / ${property.priceUnit === 'daily' ? 'يوم' : 'شهر'}`; const desc = `${typeLabel} في ${property.location?.address || ''} · ${property.bedrooms} غرف نوم · ${property.bathrooms} حمامات · ${property.area} م²`; const imageUrl = property.images?.[0] ? (property.images[0].startsWith('http') ? property.images[0] : `http://45.93.137.91${property.images[0]}`) : ''; const setMeta = (prop, content) => { let tag = document.querySelector(`meta[property="${prop}"]`); if (!tag) { tag = document.createElement('meta'); tag.setAttribute('property', prop); document.head.appendChild(tag); } tag.setAttribute('content', content); }; const setMetaName = (name, content) => { let tag = document.querySelector(`meta[name="${name}"]`); if (!tag) { tag = document.createElement('meta'); tag.setAttribute('name', name); document.head.appendChild(tag); } tag.setAttribute('content', content); }; setMeta('og:title', `${property.title} - ${priceLabel}`); setMeta('og:description', desc); if (imageUrl) setMeta('og:image', imageUrl); setMeta('og:url', window.location.href); setMeta('og:type', 'website'); setMeta('og:site_name', 'SweetHome'); // Twitter cards setMetaName('twitter:card', 'summary_large_image'); setMetaName('twitter:title', `${property.title} - ${priceLabel}`); setMetaName('twitter:description', desc); if (imageUrl) setMetaName('twitter:image', imageUrl); }, [property]); const formatCurrency = (amount) => { return amount?.toLocaleString() + ' ل.س'; }; const calculateTotalPrice = () => { if (!property) return 0; const days = bookingDates.start && bookingDates.end ? Math.ceil((new Date(bookingDates.end) - new Date(bookingDates.start)) / (1000 * 60 * 60 * 24)) : selectedDuration; return property.price * (days > 0 ? days : 1); }; // Calendar helpers const isDateAvailable = (dateStr) => { const d = new Date(dateStr + 'T00:00:00'); return availableRanges.some((range) => { const start = new Date(range.startDate); const end = new Date(range.endDate); return d >= start && d <= end; }); }; const isInRange = (dateStr) => { if (!bookingDates.start) return false; const d = new Date(dateStr + 'T00:00:00'); const start = new Date(bookingDates.start + 'T00:00:00'); const end = bookingDates.end ? new Date(bookingDates.end + 'T00:00:00') : start; return d >= start && d <= end; }; const isRangeFullyAvailable = (startStr, endStr) => { const start = new Date(startStr + 'T00:00:00'); const end = new Date(endStr + 'T00:00:00'); for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { if (!isDateAvailable(d.toISOString().split('T')[0])) return false; } return true; }; const handleCalendarClick = (dateStr) => { if (!isDateAvailable(dateStr)) return; if (!bookingDates.start || selectingEnd) { if (!bookingDates.start) { setBookingDates({ start: dateStr, end: '' }); setSelectingEnd(true); } else { const start = bookingDates.start; const end = dateStr; const [s, e] = end > start ? [start, end] : [end, start]; if (isRangeFullyAvailable(s, e)) { setBookingDates({ start: s, end: e }); setSelectingEnd(false); } else { toast.error('بعض التواريخ في هذه الفترة غير متاحة'); } } } else { setBookingDates({ start: dateStr, end: '' }); setSelectingEnd(true); } }; const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate(); const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay(); const formatDateStr = (year, month, day) => { return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; }; const monthNames = ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر']; const dayNames = ['أح', 'إث', 'ثل', 'أر', 'خم', 'جم', 'سب']; const handleBooking = async () => { if (!AuthService.isAuthenticated()) { setShowLoginDialog(true); return; } setBookingError(null); setBookingSuccess(false); if (!bookingDates.start || !bookingDates.end) { setBookingError('يرجى اختيار تاريخ البداية والنهاية'); return; } const propId = property?._raw?.id || parseInt(params.id); const startDate = new Date(bookingDates.start).toISOString(); const endDate = new Date(bookingDates.end).toISOString(); console.log('[Booking] Reserving:', { propertyId: propId, startDate, endDate }); try { const res = await bookReservation(propId, startDate, endDate); console.log('[Booking] Success:', res); setBookingSuccess(true); toast.success('تم إرسال طلب الحجز بنجاح!'); } catch (err) { console.error('[Booking] Failed:', err); setBookingError(err.message || 'فشل في إرسال طلب الحجز'); } }; if (loading) { return (

جاري تحميل تفاصيل العقار...

); } if (!property) { return (

العقار غير موجود

لم نتمكن من العثور على العقار المطلوب

العودة إلى العقارات
); } return (
العودة إلى العقارات
{/* Share Dropdown */}
{showShareMenu && ( <>
setShowShareMenu(false)} />
{/* Facebook */} {/* WhatsApp */} {/* Telegram */} {/* Instagram (copy link) */} {/* Copy Link */}
)}
{property.title} {property.images.length > 1 && ( <> )}
{property.images.map((_, idx) => (
{currentImage + 1} / {property.images.length}
{property.images.slice(1, 5).map((img, idx) => (
setCurrentImage(idx + 1)} className="relative h-[240px] rounded-2xl overflow-hidden cursor-pointer hover:opacity-90 transition-opacity bg-gray-100" > {`${property.title}
))}

{property.title}

{property.location.address}
{formatCurrency(property.price)}
/{property.priceUnit === 'daily' ? 'يوم' : 'شهر'}
{property.rating} {property.reviews > 0 && ({property.reviews} تقييم)}
{property.status === 'available' ? 'متاح للإيجار' : 'محجوز حالياً'}

المواصفات الرئيسية

{property.bedrooms}
غرف نوم
{property.bathrooms}
حمامات
{property.area}
م²
{property.type === 'villa' ? 'فيلا' : property.type === 'apartment' ? 'شقة' : 'بيت'}
نوع العقار

وصف العقار

{property.description || 'لا يوجد وصف متاح.'}

المميزات والخدمات

{property.features.map((feature, idx) => (
{feature.available ? ( ) : ( )}
{feature.name} {feature.description && (

{feature.description}

)}
))}
{property.reviewList && property.reviewList.length > 0 && (

تقييمات المستأجرين

{property.reviewList.map((review, idx) => (
{review.user}
{[...Array(5)].map((_, i) => ( ))}
{review.date}

{review.comment}

))}
)} {property.rules && property.rules.length > 0 && (

قوانين المنزل

    {property.rules.map((rule, idx) => (
  • {rule}
  • ))}
)}

احجز هذا العقار

{/* Selected dates display */}
من {bookingDates.start || '—'}
إلى {bookingDates.end || '—'}
{bookingDates.start && bookingDates.end && (() => { const days = Math.ceil((new Date(bookingDates.end) - new Date(bookingDates.start)) / (1000 * 60 * 60 * 24)); return days > 0 ? (
{days} يوم{days > 1 ? 'اً' : 'اً'} {selectingEnd ? '— اضغط على تاريخ النهاية' : '✓'}
) : null; })()} {/* Calendar */}
{monthNames[calendarMonth.getMonth()]} {calendarMonth.getFullYear()}
{dayNames.map((d) => (
{d}
))}
{(() => { const year = calendarMonth.getFullYear(); const month = calendarMonth.getMonth(); const daysInMonth = getDaysInMonth(year, month); const firstDay = getFirstDayOfMonth(year, month); const today = new Date().toISOString().split('T')[0]; const cells = []; // Empty cells before first day for (let i = 0; i < firstDay; i++) { cells.push(
); } for (let day = 1; day <= daysInMonth; day++) { const dateStr = formatDateStr(year, month, day); const available = isDateAvailable(dateStr); const isStart = bookingDates.start === dateStr; const isEnd = bookingDates.end === dateStr; const inRange = isInRange(dateStr); const isPast = dateStr < today; cells.push( ); } return cells; })()}
متاح
محدد
غير متاح
{(() => { const days = bookingDates.start && bookingDates.end ? Math.ceil((new Date(bookingDates.end) - new Date(bookingDates.start)) / (1000 * 60 * 60 * 24)) : 0; const effectiveDays = days > 0 ? days : 1; return ( <>
السعر لـ {effectiveDays} يوم{effectiveDays > 1 ? 'اً' : 'اً'} {formatCurrency(property.price * effectiveDays)}
سلفة ضمان {formatCurrency(property._raw?.deposit || 0)}
الإجمالي {formatCurrency(property.price * effectiveDays + (property._raw?.deposit || 0))}
); })()}
{bookingError && (
{bookingError}
)} {bookingSuccess && (
تم إرسال طلب الحجز بنجاح. سيتم التواصل معك قريباً.
)}
الدفع آمن ومضمون. سلفة الضمان قابلة للاسترداد.

معلومات المالك

{property.owner.name.charAt(0)}
{property.owner.name}
{property.owner.rating} · {property.owner.properties} عقارات
{property.owner.responseRate && (
استجابة: {property.owner.responseRate}
)}
{showContact ? (
{property.owner.phone}
{property.owner.email}
) : ( )}
{/* Login/Register Dialog */} {showLoginDialog && (
setShowLoginDialog(false)}> e.stopPropagation()} className="bg-white rounded-2xl p-8 max-w-md w-full mx-4 shadow-2xl text-center" >

سجّل الدخول للمتابعة

يجب عليك إنشاء حساب أو تسجيل الدخول لحجز هذا العقار

إنشاء حساب جديد تسجيل الدخول
)}
); }