Files
SweetHome/app/property/[id]/PropertyDetail.js
Rahaf 5d3ead55ca
All checks were successful
Build frontend / build (push) Successful in 54s
Added API for rating
2026-04-26 13:46:30 +03:00

1373 lines
68 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// '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';
// import RatingForm from '@/app/components/ratings/RatingForm.js';
// import RatingList from '@/app/components/ratings/RatingList.js';
// import StarRating from '@/app/components/ratings/StarRating.js';
// // 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);
// const [showRatingForm, setShowRatingForm] = useState(false);
// const [currentRating, setCurrentRating] = useState(0);
// const [currentComment, setCurrentComment] = useState('');
// const [userRating, setUserRating] = useState(null);
// const [canRate, setCanRate] = 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 user rating and check if they can rate
// useEffect(() => {
// async function fetchUserRatingAndCheck() {
// if (!property || !AuthService.isAuthenticated()) return;
// try {
// // Check if user has already rated
// const rating = await getUserPropertyRating(property._raw?.id || parseInt(params.id), AuthService.getUserId());
// if (rating) {
// setUserRating(rating);
// setCurrentRating(rating.rating);
// setCurrentComment(rating.comment || '');
// }
// // Check if user can rate (e.g., after renting)
// const canRateProperty = await canRateProperty(property._raw?.id || parseInt(params.id), AuthService.getUserId());
// setCanRate(canRateProperty);
// } catch (error) {
// console.error('[Property] Failed to fetch user rating:', error);
// }
// }
// fetchUserRatingAndCheck();
// }, [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 (
// <div className="min-h-screen bg-gray-50 flex items-center justify-center">
// <div className="text-center">
// <div className="w-16 h-16 border-4 border-gray-200 border-t-gray-800 rounded-full animate-spin mx-auto mb-4"></div>
// <p className="text-gray-600">جاري تحميل تفاصيل العقار...</p>
// </div>
// </div>
// );
// }
// if (!property) {
// return (
// <div className="min-h-screen bg-gray-50 flex items-center justify-center">
// <div className="text-center">
// <Home className="w-16 h-16 text-gray-400 mx-auto mb-4" />
// <h2 className="text-2xl font-bold text-gray-900 mb-2">العقار غير موجود</h2>
// <p className="text-gray-600 mb-4">لم نتمكن من العثور على العقار المطلوب</p>
// <Link href="/properties" className="bg-gray-800 text-white px-6 py-3 rounded-xl font-medium hover:bg-gray-900 transition-colors">
// العودة إلى العقارات
// </Link>
// </div>
// </div>
// );
// }
// return (
// <div className="min-h-screen bg-gray-50">
// <Toaster position="top-center" reverseOrder={false} />
// <div className="bg-white border-b sticky top-16 z-40 shadow-sm">
// <div className="container mx-auto px-4">
// <div className="flex items-center justify-between h-16">
// <Link href="/properties" className="flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors">
// <ArrowLeft className="w-5 h-5" />
// <span>العودة إلى العقارات</span>
// </Link>
// <div className="flex gap-2">
// <button
// onClick={async () => {
// if (!AuthService.isAuthenticated()) { setShowLoginDialog(true); return; }
// const propId = property?._raw?.id || parseInt(params.id);
// setFavLoading(true);
// if (isFavorite(propId)) {
// await removeFavorite(propId);
// toast.success('تمت الإزالة من المفضلة');
// } else {
// await addFavorite(propId);
// toast.success('تمت الإضافة إلى المفضلة');
// }
// setFavLoading(false);
// }}
// disabled={favLoading}
// className="p-2 hover:bg-gray-100 rounded-full transition-colors"
// >
// <Heart className={`w-5 h-5 ${isFavorite(property?._raw?.id || parseInt(params.id)) ? 'fill-red-500 text-red-500' : 'text-gray-600'}`} />
// </button>
// {/* Share Dropdown */}
// <div className="relative">
// <button
// onClick={() => setShowShareMenu(!showShareMenu)}
// className="p-2 hover:bg-gray-100 rounded-full transition-colors flex items-center gap-1"
// title="مشاركة"
// >
// <Share2 className="w-5 h-5 text-gray-500" />
// </button>
// {showShareMenu && (
// <>
// <div className="fixed inset-0 z-40" onClick={() => setShowShareMenu(false)} />
// <div className="absolute left-0 top-full mt-2 w-56 bg-white rounded-xl shadow-xl border border-gray-200 overflow-hidden z-50">
// <div className="p-2 space-y-1">
// {/* Facebook */}
// <button
// onClick={() => {
// const typeLabel = property.type === 'villa' ? 'فيلا' : property.type === 'apartment' ? 'شقة' : 'بيت';
// const priceLabel = `${formatCurrency(property.price)} / ${property.priceUnit === 'daily' ? 'يوم' : 'شهر'}`;
// const lines = [
// `🏠 ${typeLabel} مفروشة في ${property.location?.address || ''}`,
// `💰 ${priceLabel}`,
// `🛏️ ${property.bedrooms} غرف نوم | 🚿 ${property.bathrooms} حمامات | 📐 ${property.area} م²`,
// property.description ? `📝 ${property.description.substring(0, 80)}...` : '',
// '',
// '🔥 احجز الآن على SweetHome',
// ].filter(Boolean);
// const quote = encodeURIComponent(lines.join('\n'));
// const url = encodeURIComponent(window.location.href);
// window.open(`https://www.facebook.com/sharer/sharer.php?u=${url}&quote=${quote}`, '_blank', 'width=600,height=400');
// setShowShareMenu(false);
// }}
// className="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-blue-50 transition-colors"
// >
// <div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
// <svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
// </div>
// <span className="text-sm font-medium text-gray-700">فيسبوك</span>
// </button>
// {/* WhatsApp */}
// <button
// onClick={() => {
// const typeLabel = property.type === 'villa' ? 'فيلا' : property.type === 'apartment' ? 'شقة' : 'بيت';
// const priceLabel = `${formatCurrency(property.price)} / ${property.priceUnit === 'daily' ? 'يوم' : 'شهر'}`;
// const text = encodeURIComponent(
// `🏠 ${typeLabel} في ${property.location?.address || ''}\n💰 ${priceLabel}\n🛏 ${property.bedrooms} غرف | 📐 ${property.area} م²\n\n🔗 ${window.location.href}\n\n🔥 احجز على SweetHome`
// );
// window.open(`https://wa.me/?text=${text}`, '_blank');
// setShowShareMenu(false);
// }}
// className="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-green-50 transition-colors"
// >
// <div className="w-8 h-8 bg-green-500 rounded-lg flex items-center justify-center">
// <svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
// </div>
// <span className="text-sm font-medium text-gray-700">واتساب</span>
// </button>
// {/* Telegram */}
// <button
// onClick={() => {
// const typeLabel = property.type === 'villa' ? 'فيلا' : property.type === 'apartment' ? 'شقة' : 'بيت';
// const priceLabel = `${formatCurrency(property.price)} / ${property.priceUnit === 'daily' ? 'يوم' : 'شهر'}`;
// const text = encodeURIComponent(
// `🏠 ${typeLabel} في ${property.location?.address || ''}\n💰 ${priceLabel}\n🛏 ${property.bedrooms} غرف | 📐 ${property.area} م²\n\n🔥 احجز على SweetHome`
// );
// const url = encodeURIComponent(window.location.href);
// window.open(`https://t.me/share/url?url=${url}&text=${text}`, '_blank');
// setShowShareMenu(false);
// }}
// className="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-sky-50 transition-colors"
// >
// <div className="w-8 h-8 bg-sky-500 rounded-lg flex items-center justify-center">
// <svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.479.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>
// </div>
// <span className="text-sm font-medium text-gray-700">تيليجرام</span>
// </button>
// {/* Instagram (copy link) */}
// <button
// onClick={async () => {
// const ok = await copyToClipboard(window.location.href);
// if (ok) {
// toast.success('تم نسخ الرابط! الصقه في انستغرام');
// } else {
// toast.error('فشل نسخ الرابط');
// }
// window.open('https://www.instagram.com', '_blank');
// setShowShareMenu(false);
// }}
// className="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-pink-50 transition-colors"
// >
// <div className="w-8 h-8 bg-gradient-to-br from-purple-600 via-pink-500 to-orange-400 rounded-lg flex items-center justify-center">
// <svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>
// </div>
// <span className="text-sm font-medium text-gray-700">انستغرام</span>
// </button>
// {/* Copy Link */}
// <button
// onClick={async () => {
// const ok = await copyToClipboard(window.location.href);
// if (ok) {
// toast.success('✅ تم نسخ الرابط');
// } else {
// toast.error('فشل نسخ الرابط');
// }
// setShowShareMenu(false);
// }}
// className="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors"
// >
// <div className="w-8 h-8 bg-gray-500 rounded-lg flex items-center justify-center">
// <Copy className="w-4 h-4 text-white" />
// </div>
// <span className="text-sm font-medium text-gray-700">نسخ الرابط</span>
// </button>
// </div>
// </div>
// </>
// )}
// </div>
// </div>
// </div>
// </div>
// </div>
// <div className="container mx-auto px-4 py-8">
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// className="mb-8"
// >
// <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
// <div className="relative h-[500px] rounded-2xl overflow-hidden group bg-gray-100">
// <Image
// src={property.images[currentImage] || '/property-placeholder.jpg'}
// alt={property.title}
// fill
// className="object-cover"
// />
// {property.images.length > 1 && (
// <>
// <button
// onClick={() => setCurrentImage(prev => Math.max(0, prev - 1))}
// className="absolute left-4 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-white/90 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity shadow-lg hover:bg-white"
// >
// <ChevronLeft className="w-5 h-5" />
// </button>
// <button
// onClick={() => setCurrentImage(prev => Math.min(property.images.length - 1, prev + 1))}
// className="absolute right-4 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-white/90 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity shadow-lg hover:bg-white"
// >
// <ChevronRight className="w-5 h-5" />
// </button>
// </>
// )}
// <div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2">
// {property.images.map((_, idx) => (
// <button
// key={idx}
// onClick={() => setCurrentImage(idx)}
// className={`w-2 h-2 rounded-full transition-all ${idx === currentImage ? 'bg-gray-800 w-4' : 'bg-white/70 hover:bg-white'
// }`}
// />
// ))}
// </div>
// <div className="absolute bottom-4 right-4 bg-black/50 text-white px-3 py-1 rounded-full text-sm backdrop-blur-sm">
// <Camera className="w-4 h-4 inline ml-1" />
// {currentImage + 1} / {property.images.length}
// </div>
// </div>
// <div className="grid grid-cols-2 gap-4">
// {property.images.slice(1, 5).map((img, idx) => (
// <div
// key={idx}
// onClick={() => setCurrentImage(idx + 1)}
// className="relative h-[240px] rounded-2xl overflow-hidden cursor-pointer hover:opacity-90 transition-opacity bg-gray-100"
// >
// <Image src={img} alt={`${property.title} ${idx + 2}`} fill className="object-cover" />
// </div>
// ))}
// </div>
// </div>
// </motion.div>
// <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
// <div className="lg:col-span-2 space-y-6">
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.1 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <div className="flex justify-between items-start mb-4">
// <div>
// <h1 className="text-3xl font-bold text-gray-900 mb-2">{property.title}</h1>
// <div className="flex items-center gap-2 text-gray-500">
// <MapPin className="w-5 h-5" />
// <span>{property.location.address}</span>
// </div>
// </div>
// <div className="text-left">
// <div className="text-3xl font-bold text-gray-900">{formatCurrency(property.price)}</div>
// <div className="text-sm text-gray-500">/{property.priceUnit === 'daily' ? 'يوم' : 'شهر'}</div>
// </div>
// </div>
// <div className="flex items-center gap-4">
// <div className="flex items-center gap-1">
// <Star className="w-5 h-5 fill-gray-800 text-gray-800" />
// <span className="font-bold text-gray-900">{property.rating}</span>
// {property.reviews > 0 && <span className="text-gray-500">({property.reviews} تقييم)</span>}
// </div>
// <div className="w-px h-4 bg-gray-200" />
// <span className={`font-medium ${property.status === 'available' ? 'text-gray-800' : 'text-gray-500'}`}>
// {property.status === 'available' ? 'متاح للإيجار' : 'محجوز حالياً'}
// </span>
// </div>
// </motion.div>
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.2 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <h2 className="text-xl font-bold mb-4 text-gray-900">المواصفات الرئيسية</h2>
// <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
// <div className="text-center p-4 bg-gray-50 rounded-xl">
// <Bed className="w-6 h-6 text-gray-700 mx-auto mb-2" />
// <div className="font-bold text-gray-900">{property.bedrooms}</div>
// <div className="text-sm text-gray-500">غرف نوم</div>
// </div>
// <div className="text-center p-4 bg-gray-50 rounded-xl">
// <Bath className="w-6 h-6 text-gray-700 mx-auto mb-2" />
// <div className="font-bold text-gray-900">{property.bathrooms}</div>
// <div className="text-sm text-gray-500">حمامات</div>
// </div>
// <div className="text-center p-4 bg-gray-50 rounded-xl">
// <Square className="w-6 h-6 text-gray-700 mx-auto mb-2" />
// <div className="font-bold text-gray-900">{property.area}</div>
// <div className="text-sm text-gray-500">م²</div>
// </div>
// <div className="text-center p-4 bg-gray-50 rounded-xl">
// <Home className="w-6 h-6 text-gray-700 mx-auto mb-2" />
// <div className="font-bold text-gray-900">
// {property.type === 'villa' ? 'فيلا' :
// property.type === 'apartment' ? 'شقة' : 'بيت'}
// </div>
// <div className="text-sm text-gray-500">نوع العقار</div>
// </div>
// </div>
// </motion.div>
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.3 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <h2 className="text-xl font-bold mb-4 text-gray-900">وصف العقار</h2>
// <p className="text-gray-600 whitespace-pre-line leading-relaxed">{property.description || 'لا يوجد وصف متاح.'}</p>
// </motion.div>
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.4 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <h2 className="text-xl font-bold mb-4 text-gray-900">المميزات والخدمات</h2>
// <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
// {property.features.map((feature, idx) => (
// <div key={idx} className="flex items-start gap-3 p-3 bg-gray-50 rounded-xl">
// <div className={`w-6 h-6 rounded-full flex items-center justify-center flex-shrink-0 ${feature.available ? 'bg-gray-800 text-white' : 'bg-gray-200 text-gray-500'
// }`}>
// {feature.available ? (
// <Check className="w-4 h-4" />
// ) : (
// <X className="w-4 h-4" />
// )}
// </div>
// <div>
// <span className={`font-medium ${feature.available ? 'text-gray-900' : 'text-gray-400'}`}>
// {feature.name}
// </span>
// {feature.description && (
// <p className={`text-sm mt-1 ${feature.available ? 'text-gray-500' : 'text-gray-400'}`}>
// {feature.description}
// </p>
// )}
// </div>
// </div>
// ))}
// </div>
// </motion.div>
// {property.reviewList && property.reviewList.length > 0 && (
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.6 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <h2 className="text-xl font-bold mb-4 text-gray-900">تقييمات المستأجرين</h2>
// <div className="space-y-4">
// {property.reviewList.map((review, idx) => (
// <div key={idx} className="border-b border-gray-100 last:border-0 pb-4 last:pb-0">
// <div className="flex justify-between items-start mb-2">
// <div className="flex items-start gap-2">
// <div className="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0">
// <User className="w-6 h-6 text-gray-600" />
// </div>
// <div>
// <span className="font-bold text-gray-900">{review.user}</span>
// <div className="flex items-center gap-1 mt-1">
// {[...Array(5)].map((_, i) => (
// <Star key={i} className={`w-4 h-4 ${i < review.rating ? 'fill-gray-800 text-gray-800' : 'text-gray-300'}`} />
// ))}
// </div>
// </div>
// </div>
// <span className="text-sm text-gray-500">{review.date}</span>
// </div>
// <p className="text-gray-600">{review.comment}</p>
// </div>
// ))}
// </div>
// </motion.div>
// )}
// {/* New Rating Components */}
// {AuthService.isAuthenticated() && canRate && !userRating && (
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.65 }}
// className="bg-amber-50 border-2 border-amber-200 rounded-xl p-4 text-center cursor-pointer hover:border-amber-300 transition-all"
// onClick={() => setShowRatingForm(true)}
// >
// <Star className="w-8 h-8 text-amber-500 mx-auto mb-2" />
// <h3 className="font-bold text-amber-700 mb-2">قيّم هذا العقار</h3>
// <p className="text-sm text-amber-600">شارك تجربتك مع المستأجرين الآخرين</p>
// </motion.div>
// )}
// <motion.div
// initial={{ opacity: 0, y: 20 }}
// animate={{ opacity: 1, y: 0 }}
// transition={{ delay: 0.7 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-200"
// >
// <RatingList
// propertyId={property._raw?.id || parseInt(params.id)}
// userId={AuthService.getUserId()}
// />
// </motion.div>
// </div>
// <div className="space-y-6">
// <div className="sticky top-28">
// <motion.div
// initial={{ opacity: 0, x: 20 }}
// animate={{ opacity: 1, x: 0 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100 mb-6"
// >
// <h2 className="text-xl font-bold mb-4 text-gray-900">احجز هذا العقار</h2>
// {/* Selected dates display */}
// <div className="mb-4 flex gap-2 text-sm">
// <div className="flex-1 bg-gray-50 p-3 rounded-xl">
// <span className="text-gray-500 block mb-1">من</span>
// <span className="font-medium text-gray-900">{bookingDates.start || '—'}</span>
// </div>
// <div className="flex-1 bg-gray-50 p-3 rounded-xl">
// <span className="text-gray-500 block mb-1">إلى</span>
// <span className="font-medium text-gray-900">{bookingDates.end || '—'}</span>
// </div>
// </div>
// {bookingDates.start && bookingDates.end && (() => {
// const days = Math.ceil((new Date(bookingDates.end) - new Date(bookingDates.start)) / (1000 * 60 * 60 * 24));
// return days > 0 ? (
// <div className="mb-4 text-center text-sm text-amber-600 font-medium bg-amber-50 p-2 rounded-xl">
// {days} يوم{days > 1 ? 'اً' : 'اً'} {selectingEnd ? '— اضغط على تاريخ النهاية' : '✓'}
// </div>
// ) : null;
// })()}
// {/* Calendar */}
// <div className="mb-4 relative">
// <div className="flex items-center justify-between mb-3">
// <button onClick={() => setCalendarMonth(new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() - 1))} className="p-1 hover:bg-gray-100 rounded-lg">
// <ChevronRight className="w-5 h-5" />
// </button>
// <span className="font-bold text-gray-900">{monthNames[calendarMonth.getMonth()]} {calendarMonth.getFullYear()}</span>
// <button onClick={() => setCalendarMonth(new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() + 1))} className="p-1 hover:bg-gray-100 rounded-lg">
// <ChevronLeft className="w-5 h-5" />
// </button>
// </div>
// <div className="grid grid-cols-7 gap-1 mb-1">
// {dayNames.map((d) => (
// <div key={d} className="text-center text-xs text-gray-500 font-medium py-1">{d}</div>
// ))}
// </div>
// <div className="grid grid-cols-7 gap-1">
// {(() => {
// 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(<div key={`empty-${i}`} />);
// }
// 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(
// <button
// key={dateStr}
// onClick={() => !isPast && handleCalendarClick(dateStr)}
// disabled={isPast || !available}
// className={`w-full aspect-square rounded-lg text-sm font-medium transition-all ${
// isStart || isEnd
// ? 'bg-amber-500 text-white'
// : inRange
// ? 'bg-amber-100 text-amber-800'
// : available && !isPast
// ? 'bg-green-50 text-green-700 hover:bg-green-100 cursor-pointer'
// : 'text-gray-300 cursor-not-allowed'
// }`}
// >
// {day}
// </button>
// );
// }
// return cells;
// })()}
// </div>
// <div className="flex items-center gap-4 mt-3 text-xs text-gray-500">
// <div className="flex items-center gap-1">
// <div className="w-3 h-3 rounded bg-green-50 border border-green-200" />
// <span>متاح</span>
// </div>
// <div className="flex items-center gap-1">
// <div className="w-3 h-3 rounded bg-amber-500" />
// <span>محدد</span>
// </div>
// <div className="flex items-center gap-1">
// <div className="w-3 h-3 rounded bg-gray-100" />
// <span>غير متاح</span>
// </div>
// </div>
// </div>
// <div className="bg-gray-50 p-4 rounded-xl mb-6">
// {(() => {
// 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 (
// <>
// <div className="flex justify-between mb-2">
// <span className="text-gray-600">السعر لـ {effectiveDays} يوم{effectiveDays > 1 ? 'اً' : 'اً'}</span>
// <span className="font-bold text-gray-900">{formatCurrency(property.price * effectiveDays)}</span>
// </div>
// <div className="flex justify-between mb-2">
// <span className="text-gray-600">سلفة ضمان</span>
// <span className="font-bold text-gray-900">{formatCurrency(property._raw?.deposit || 0)}</span>
// </div>
// <div className="flex justify-between pt-2 border-t border-gray-200 font-bold">
// <span className="text-gray-900">الإجمالي</span>
// <span className="text-gray-900">{formatCurrency(property.price * effectiveDays + (property._raw?.deposit || 0))}</span>
// </div>
// </>
// );
// })()}
// </div>
// {bookingError && (
// <div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-xl text-red-700 text-sm">
// {bookingError}
// </div>
// )}
// {bookingSuccess && (
// <div className="mb-4 p-3 bg-green-50 border border-green-200 rounded-xl text-green-700 text-sm">
// تم إرسال طلب الحجز بنجاح. سيتم التواصل معك قريباً.
// </div>
// )}
// <button
// onClick={handleBooking}
// disabled={bookingSuccess}
// className="w-full bg-gray-800 text-white py-4 rounded-xl font-bold text-lg hover:bg-gray-900 transition-colors mb-4 disabled:opacity-50 disabled:cursor-not-allowed"
// >
// {bookingSuccess ? 'تم الإرسال ✓' : 'تأكيد الحجز'}
// </button>
// <div className="flex items-center gap-2 text-sm text-gray-500">
// <Shield className="w-4 h-4 text-gray-600" />
// <span>الدفع آمن ومضمون. سلفة الضمان قابلة للاسترداد.</span>
// </div>
// </motion.div>
// <motion.div
// initial={{ opacity: 0, x: 20 }}
// animate={{ opacity: 1, x: 0 }}
// transition={{ delay: 0.2 }}
// className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
// >
// <h3 className="font-bold mb-4 text-gray-900">معلومات المالك</h3>
// <div className="flex items-center gap-3 mb-4">
// <div className="w-12 h-12 bg-gray-100 rounded-full flex items-center justify-center">
// <span className="text-xl font-bold text-gray-700">
// {property.owner.name.charAt(0)}
// </span>
// </div>
// <div>
// <div className="font-bold text-gray-900">{property.owner.name}</div>
// <div className="flex items-center gap-1 text-sm text-gray-500">
// <Star className="w-3 h-3 fill-gray-600 text-gray-600" />
// <span>{property.owner.rating}</span>
// <span>· {property.owner.properties} عقارات</span>
// </div>
// {property.owner.responseRate && (
// <div className="flex items-center gap-1 text-xs text-gray-500 mt-1">
// <Clock className="w-3 h-3" />
// <span>استجابة: {property.owner.responseRate}</span>
// </div>
// )}
// </div>
// </div>
// {showContact ? (
// <div className="space-y-3">
// <div className="flex items-center gap-2 p-3 bg-gray-50 rounded-xl">
// <Phone className="w-4 h-4 text-gray-600" />
// <span className="font-medium text-gray-900">{property.owner.phone}</span>
// </div>
// <div className="flex items-center gap-2 p-3 bg-gray-50 rounded-xl">
// <Mail className="w-4 h-4 text-gray-600" />
// <span className="font-medium text-gray-900">{property.owner.email}</span>
// </div>
// </div>
// ) : (
// <button
// onClick={() => setShowContact(true)}
// className="w-full bg-gray-800 text-white py-3 rounded-xl font-medium hover:bg-gray-900 transition-colors flex items-center justify-center gap-2"
// >
// <Phone className="w-5 h-5" />
// عرض معلومات الاتصال
// </button>
// )}
// <button className="w-full mt-3 bg-gray-100 text-gray-700 py-3 rounded-xl font-medium hover:bg-gray-200 transition-colors flex items-center justify-center gap-2">
// <MessageCircle className="w-5 h-5" />
// مراسلة المالك
// </button>
// </motion.div>
// </div>
// </div>
// </div>
// </div>
// {/* Login/Register Dialog */}
// {showLoginDialog && (
// <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm" onClick={() => setShowLoginDialog(false)}>
// <motion.div
// initial={{ opacity: 0, scale: 0.95 }}
// animate={{ opacity: 1, scale: 1 }}
// onClick={(e) => e.stopPropagation()}
// className="bg-white rounded-2xl p-8 max-w-md w-full mx-4 shadow-2xl text-center"
// >
// <div className="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-4">
// <LogIn className="w-8 h-8 text-amber-600" />
// </div>
// <h3 className="text-xl font-bold text-gray-900 mb-2">سجّل الدخول للمتابعة</h3>
// <p className="text-gray-500 mb-6">يجب عليك إنشاء حساب أو تسجيل الدخول لحجز هذا العقار</p>
// <div className="space-y-3">
// <Link
// href="/auth/choose-role"
// className="block w-full bg-amber-500 text-white py-3 rounded-xl font-bold hover:bg-amber-600 transition-colors"
// >
// إنشاء حساب جديد
// </Link>
// <Link
// href="/login"
// className="block w-full bg-gray-100 text-gray-700 py-3 rounded-xl font-bold hover:bg-gray-200 transition-colors"
// >
// تسجيل الدخول
// </Link>
// <button
// onClick={() => setShowLoginDialog(false)}
// className="block w-full text-gray-400 py-2 text-sm hover:text-gray-600 transition-colors"
// >
// إلغاء
// </button>
// </div>
// </motion.div>
// </div>
// )}
// </div>
// );
// }
'use client';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } 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, Heart, Share2, Phone, Mail, MessageCircle,
Calendar, Shield, Star, ChevronLeft, ChevronRight, Check, X,
Camera, Home, Building2, ArrowLeft, LogIn, Copy, Clock, User, Loader2
} from 'lucide-react';
import AuthService from '../../services/AuthService';
import { useFavorites } from '@/app/contexts/FavoritesContext';
import { BuildingTypeKeys, PropertyStatusKeys, extractCity } from '../../enums';
import PropertyRatingList from '@/app/components/ratings/PropertyRatingList';
import PropertyRatingForm from '@/app/components/ratings/PropertyRatingForm';
import { getPropertyAverageRating } from '@/app/utils/ratings';
import { getRentProperty, getSaleProperty, bookReservation } from '../../utils/api';
function formatCurrency(amount) {
return amount?.toLocaleString() + ' ل.س';
}
function mapApiDetail(item) {
if (!item) return null;
const info = item.propertyInformation || {};
const buildingType = info.buildingType ?? 0;
const propType = BuildingTypeKeys[buildingType] ?? 'apartment';
const status = PropertyStatusKeys[info.status] ?? 'available';
const dailyPrice = item.dailyRent ?? item.monthlyRent ?? item.price ?? 0;
const priceUnit = item.monthlyRent ? 'monthly' : 'daily';
const apiBase = 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'];
return {
id: item.id,
title: info.address || `عقار #${item.id}`,
description: info.description || '',
type: propType,
price: dailyPrice,
priceUnit,
location: { city: extractCity(info.address) || 'دمشق', address: info.address || '' },
bedrooms: info.numberOfBedRooms || 0,
bathrooms: info.numberOfBathRooms || 0,
area: info.space || 0,
images,
status,
deposit: item.deposit || 0,
_raw: item,
};
}
export default function PropertyDetailsPage() {
const params = useParams();
const propertyId = parseInt(params.id);
const { isFavorite, addFavorite, removeFavorite } = useFavorites();
const [property, setProperty] = useState(null);
const [loading, setLoading] = useState(true);
const [currentImage, setCurrentImage] = useState(0);
const [showContact, setShowContact] = useState(false);
const [showShareMenu, setShowShareMenu] = useState(false);
const [favLoading, setFavLoading] = useState(false);
const [showLoginDialog, setShowLoginDialog] = useState(false);
const [bookingDates, setBookingDates] = useState({ start: '', end: '' });
const [bookingError, setBookingError] = useState(null);
const [bookingSuccess, setBookingSuccess] = useState(false);
const [averageRating, setAverageRating] = useState(null);
const [eligibleReservationId, setEligibleReservationId] = useState(null);
const [showRatingForm, setShowRatingForm] = useState(false);
useEffect(() => {
async function fetchProperty() {
try {
let data = null;
try { data = await getRentProperty(propertyId); } catch {}
if (!data) try { data = await getSaleProperty(propertyId); } catch {}
if (data) setProperty(mapApiDetail(data));
else throw new Error('Property not found');
} catch (err) {
console.error(err);
toast.error('فشل تحميل العقار');
} finally {
setLoading(false);
}
}
fetchProperty();
}, [propertyId]);
useEffect(() => {
async function fetchAvg() {
if (!propertyId) return;
try {
const avg = await getPropertyAverageRating(propertyId);
setAverageRating(avg);
} catch (err) { console.error(err); }
}
fetchAvg();
}, [propertyId]);
useEffect(() => {
async function checkEligibility() {
if (!propertyId || !AuthService.isAuthenticated()) return;
try {
const res = await fetch(`http://45.93.137.91/api/Reservations/GetUserReservations?userId=${AuthService.getUserId()}`);
const data = await res.json();
const reservations = data?.data || data || [];
const completed = reservations.find(r =>
r.propertyId == propertyId &&
(r.status === 'Completed' || r.status === 'Confirmed') &&
!r.hasRatedProperty
);
setEligibleReservationId(completed?.id || null);
} catch (err) {
console.error('[Eligibility]', err);
}
}
checkEligibility();
}, [propertyId]);
const handleBooking = async () => {
if (!AuthService.isAuthenticated()) { setShowLoginDialog(true); return; }
setBookingError(null);
if (!bookingDates.start || !bookingDates.end) {
setBookingError('يرجى اختيار تاريخ البداية والنهاية');
return;
}
try {
await bookReservation(propertyId, bookingDates.start, bookingDates.end);
setBookingSuccess(true);
toast.success('تم إرسال طلب الحجز بنجاح');
} catch (err) {
setBookingError(err.message || 'فشل الحجز');
}
};
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center">
<Loader2 className="w-12 h-12 animate-spin text-amber-500" />
</div>
);
}
if (!property) {
return <div className="text-center py-20 text-gray-600">العقار غير موجود</div>;
}
return (
<div className="min-h-screen bg-gray-50">
<Toaster position="top-center" />
<div className="bg-white border-b sticky top-16 z-40 shadow-sm">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<Link href="/properties" className="flex items-center gap-2 text-gray-600 hover:text-gray-900">
<ArrowLeft className="w-5 h-5" /><span>العودة</span>
</Link>
<div className="flex gap-2">
<button
onClick={async () => {
if (!AuthService.isAuthenticated()) { setShowLoginDialog(true); return; }
setFavLoading(true);
if (isFavorite(property.id)) await removeFavorite(property.id);
else await addFavorite(property.id);
setFavLoading(false);
}}
disabled={favLoading}
>
<Heart className={`w-5 h-5 ${isFavorite(property.id) ? 'fill-red-500 text-red-500' : 'text-gray-600'}`} />
</button>
{/* زر المشاركة (اختصار) */}
<button onClick={() => setShowShareMenu(!showShareMenu)} className="p-2 hover:bg-gray-100 rounded-full">
<Share2 className="w-5 h-5 text-gray-600" />
</button>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8">
<div className="relative h-96 rounded-2xl overflow-hidden mb-8">
<Image src={property.images[currentImage]} alt={property.title} fill className="object-cover" />
{property.images.length > 1 && (
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2">
{property.images.map((_, idx) => (
<button key={idx} onClick={() => setCurrentImage(idx)} className={`w-2 h-2 rounded-full ${idx === currentImage ? 'bg-amber-500 w-4' : 'bg-white/70'}`} />
))}
</div>
)}
</div>
<div className="grid lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6">
<div className="bg-white rounded-2xl p-6">
<h1 className="text-2xl font-bold">{property.title}</h1>
<div className="flex items-center gap-2 text-gray-500 mt-1"><MapPin className="w-4 h-4" />{property.location.address}</div>
<div className="flex items-center gap-4 mt-2">
<div className="flex items-center gap-1">
<Star className="w-5 h-5 fill-amber-500 text-amber-500" />
<span className="font-bold">{averageRating > 0 ? averageRating.toFixed(1) : property.rating}</span>
</div>
<span className={`px-2 py-1 rounded-full text-xs ${property.status === 'available' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>
{property.status === 'available' ? 'متاح' : 'محجوز'}
</span>
</div>
</div>
<div className="bg-white rounded-2xl p-6">
<h2 className="text-xl font-bold mb-4">المواصفات</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div><Bed className="w-6 h-6 mb-1" /><div>{property.bedrooms} غرف نوم</div></div>
<div><Bath className="w-6 h-6 mb-1" /><div>{property.bathrooms} حمامات</div></div>
<div><Square className="w-6 h-6 mb-1" /><div>{property.area} م²</div></div>
</div>
</div>
<div className="bg-white rounded-2xl p-6">
<h2 className="text-xl font-bold mb-4">الوصف</h2>
<p className="text-gray-600">{property.description}</p>
</div>
<PropertyRatingList propertyId={propertyId} />
{eligibleReservationId && !showRatingForm && (
<div className="bg-amber-50 border-2 border-amber-200 rounded-xl p-4 text-center cursor-pointer" onClick={() => setShowRatingForm(true)}>
<Star className="w-8 h-8 text-amber-500 mx-auto mb-2" />
<h3 className="font-bold text-amber-700">قيّم هذا العقار</h3>
<p className="text-sm text-amber-600">شارك تجربتك مع المستأجرين الآخرين</p>
</div>
)}
{showRatingForm && eligibleReservationId && (
<PropertyRatingForm
reservationId={eligibleReservationId}
onSuccess={() => {
setShowRatingForm(false);
setEligibleReservationId(null);
getPropertyAverageRating(propertyId).then(setAverageRating);
}}
onCancel={() => setShowRatingForm(false)}
/>
)}
</div>
<div className="space-y-6">
<div className="bg-white rounded-2xl p-6 sticky top-28">
<h2 className="text-xl font-bold mb-4">احجز هذا العقار</h2>
<div className="flex gap-2 mb-4">
<input type="date" className="border rounded-xl p-2 flex-1" value={bookingDates.start} onChange={(e) => setBookingDates({ ...bookingDates, start: e.target.value })} />
<input type="date" className="border rounded-xl p-2 flex-1" value={bookingDates.end} onChange={(e) => setBookingDates({ ...bookingDates, end: e.target.value })} />
</div>
<div className="bg-gray-50 p-4 rounded-xl mb-4">
<div className="flex justify-between"><span>السعر اليومي</span><span>{formatCurrency(property.price)}</span></div>
<div className="flex justify-between"><span>سلفة ضمان</span><span>{formatCurrency(property.deposit)}</span></div>
<div className="flex justify-between font-bold pt-2 border-t mt-2"><span>الإجمالي</span><span>{formatCurrency(property.price + property.deposit)}</span></div>
</div>
<button onClick={handleBooking} className="w-full bg-amber-500 text-white py-3 rounded-xl font-bold">تأكيد الحجز</button>
{bookingError && <p className="text-red-500 text-sm mt-2">{bookingError}</p>}
</div>
<div className="bg-white rounded-2xl p-6">
<h3 className="font-bold mb-4">معلومات المالك</h3>
{showContact ? (
<div><Phone className="w-4 h-4 inline ml-2" />{property._raw?.phoneNumber || 'غير متوفر'}</div>
) : (
<button onClick={() => setShowContact(true)} className="w-full bg-gray-800 text-white py-2 rounded-xl">عرض معلومات الاتصال</button>
)}
</div>
</div>
</div>
</div>
{showLoginDialog && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" onClick={() => setShowLoginDialog(false)}>
<div className="bg-white rounded-2xl p-6 max-w-sm text-center" onClick={(e) => e.stopPropagation()}>
<h3 className="text-xl font-bold">تسجيل الدخول مطلوب</h3>
<p className="text-gray-500 my-4">للحجز أو إضافة المفضلة، سجل دخولك.</p>
<Link href="/login" className="block w-full bg-amber-500 text-white py-2 rounded-xl mb-2">تسجيل الدخول</Link>
<Link href="/auth/choose-role" className="block w-full bg-gray-100 py-2 rounded-xl">إنشاء حساب</Link>
<button onClick={() => setShowLoginDialog(false)} className="mt-3 text-gray-400">إلغاء</button>
</div>
</div>
)}
</div>
);
}