diff --git a/app/ClientLayout.js b/app/ClientLayout.js index cb54fb7..b595261 100644 --- a/app/ClientLayout.js +++ b/app/ClientLayout.js @@ -256,16 +256,7 @@ 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/owner/bookings/page.js b/app/owner/bookings/page.js index a19f601..ace9616 100644 --- a/app/owner/bookings/page.js +++ b/app/owner/bookings/page.js @@ -383,7 +383,7 @@ export default function OwnerBookingsPage() { const fetchData = async () => { try { - const [response, rentProps] = await Promise.all([getOwnerReservationsByStatuses([0, 1, 2, 3, 4]), getRentProperties().catch(() => [])]); + const [response, rentProps] = await Promise.all([getOwnerReservationsByStatuses([0, 1, 2, 3, 4, 5]), getRentProperties().catch(() => [])]); let rawData = response; @@ -419,8 +419,6 @@ export default function OwnerBookingsPage() { propMap[rp.propertyInformation?.id] = propertyData; }); - console.log("PROP MAP:", propMap); - // ربط الـ reservation بالعقار عن طريق propertyId const enriched = list.map((item) => { if (item.propertyId && propMap[item.propertyId]) { @@ -430,8 +428,6 @@ export default function OwnerBookingsPage() { return item; }); - console.log("ENRICHED BOOKINGS:", enriched); - const mappedBookings = enriched.map((item) => { const property = item._prop || {}; @@ -450,7 +446,8 @@ export default function OwnerBookingsPage() { 1: "pending", 2: "confirmed", 3: "completed", - 4: "cancelled", + 4: "منتهية", + 5: "cancelled", }; const statusKey = statusMap[item?.status] || "pending"; diff --git a/app/owner/properties/add/page.js b/app/owner/properties/add/page.js index d059f9c..e5fab4b 100644 --- a/app/owner/properties/add/page.js +++ b/app/owner/properties/add/page.js @@ -1731,7 +1731,6 @@ export default function AddPropertyPage() {

{t("addProperty.imagesTitle")}

-
fileInputRef.current?.click()} className={`border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-all ${ diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js index b687d1b..0991c92 100644 --- a/app/owner/properties/page.js +++ b/app/owner/properties/page.js @@ -18,30 +18,16 @@ import { Trash2, Eye, Calendar, - TrendingUp, - Users, - FileText, - Image as ImageIcon, + Layers, + Sofa, + DoorOpen, + ImageIcon, CheckCircle, XCircle, AlertCircle, ChevronRight, ChevronLeft, Loader2, - Clock, - Wifi, - Zap, - Flame, - Droplets, - Cigarette, - Dog, - Music, - Warehouse, - Layers, - Sofa, - DoorOpen, - Wind, - Pencil, Save, X, Star, @@ -52,10 +38,23 @@ import { Store, GraduationCap, TreePine, + CreditCard, + Banknote, // تم إضافة Banknote هنا } from "lucide-react"; import toast, { Toaster } from "react-hot-toast"; import AuthService from "../../services/AuthService"; -import { buildRentPropertyPayload, getMyRentListings, getMySaleListings, editRentProperty, editSaleProperty, updateRentPropertyStatus, updateSalePropertyStatus, uploadPicture } from "../../utils/api"; +import { + buildRentPropertyPayload, + getMyRentListings, + getMySaleListings, + editRentProperty, + editSaleProperty, + updateRentPropertyStatus, + updateSalePropertyStatus, + uploadPicture, + getPaymentTypes, + OwnerPaymentForSaleProperite, // تم إضافة استيراد الدالة هنا +} from "../../utils/api"; import { PropertyService } from "../../enums/PropertyService"; import { PropertyTerm } from "../../enums/PropertyTerm"; import Loading from "@/app/loading"; @@ -97,6 +96,249 @@ const proximityI18nKeys = { BusStation: "proximity.busStation", }; +const CommissionPaymentDialog = ({ + isOpen, + property, + onClose, + selectedPayment, + onSelectPayment, + onConfirmPay, + payingId, + paymentMethods, + loadingPaymentMethods, + receiptImage, + onSetReceiptImage, + commissionDetails, + setCommissionDetails, +}) => { + const { t } = useTranslation(); + + if (!isOpen || !property) return null; + + const commission = Number(property.commission || 0); + + const selectedMethod = paymentMethods?.find((m) => String(m?.id ?? m?.name) === String(selectedPayment)); + + const isHaram = selectedMethod?.name?.toLowerCase?.() === "haram"; + + const hasSelectedMethod = !!selectedMethod; + + const hasHaramDetails = commissionDetails?.fullName?.trim() && commissionDetails?.governorate?.trim() && commissionDetails?.phoneNumber?.trim(); + + const canPay = payingId !== property.id && hasSelectedMethod && (!isHaram || (!!receiptImage && !!hasHaramDetails)); + + return ( +
+ e.stopPropagation()} + > + {/* Header */} +
+
+
+ +
+ +
+

{property.title}

+ +

{t("commission")}

+
+
+
+ + {/* Commission amount */} +
+
+

{t("commission")}

+ +

+ {commission.toLocaleString()} {t("syp")} +

+
+
+ + {/* Payment methods */} +
+

{t("paymentMethod")}

+ + {loadingPaymentMethods ? ( +
+ {t("loadingPaymentMethods", { + defaultValue: "جاري تحميل طرق الدفع...", + })} +
+ ) : !Array.isArray(paymentMethods) || paymentMethods.length === 0 ? ( +
+ {t("noPaymentMethodsAvailable", { + defaultValue: "لا توجد طرق دفع متاحة حالياً.", + })} +
+ ) : ( +
+ {paymentMethods.map((method, index) => { + const isActive = method?.isActive === true || method?.active === true; + + const optionId = method?.id ?? method?.name ?? `payment-method-${index}`; + + const label = + method?.name || + t("paymentMethod", { + defaultValue: "طريقة الدفع", + }); + + const isSelected = selectedPayment === optionId; + + return ( + + ); + })} +
+ )} +
+ {/* Haram payment details */} + {isHaram && ( +
+

بيانات الدفع

+ +
+ {commissionDetails.split("\n").map((line, idx) => ( +
{line}
+ ))} +
+
+ )} + {/* Receipt */} + {isHaram && ( +
+

+ {t("uploadReceipt", { + defaultValue: "إيصال الدفع", + })} +

+ + {receiptImage ? ( +
+ receipt + + + +
+

{receiptImage.name}

+
+
+ ) : ( + + )} +
+ )} + + {/* Pay */} +
+ onConfirmPay(property)} + whileHover={{ scale: 1.01 }} + whileTap={{ scale: 0.99 }} + className="w-full bg-amber-500 hover:bg-amber-600 disabled:bg-amber-300 text-white font-bold py-4 px-6 rounded-2xl text-lg transition-all flex items-center justify-center gap-3" + > + {payingId === property.id ? ( + <> + + {t("processingPayment")} + + ) : ( + <> + + {t("payCommission", { + defaultValue: "دفع الكمسيون", + })} + + )} + +
+ +
+ +
+
+
+ ); +}; + const DeleteConfirmationModal = ({ isOpen, onClose, onConfirm, propertyTitle }) => { const { t } = useTranslation(); if (!isOpen) return null; @@ -503,9 +745,11 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => { nearbyUniversity: "", nearbyPark: "", nearbyMall: "", + nearbyMosque: "", purpose: "rent", currencyId: 1, dailyPrice: 0, + commission: "", monthlyPrice: 0, deposit: 0, rentType: "monthly", @@ -591,6 +835,7 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => { serviceDetails, terms, customTerms: details.customTerms || [], + nearbyMosque: prox.nearbyMosque || prox.neaebymosque || "", nearbySchool: prox.School ?? prox.school ?? prox.nearbySchool ?? "", nearbyHospital: prox.Hospital ?? prox.hospital ?? prox.nearbyHospital ?? "", nearbyRestaurant: prox.Restaurant ?? prox.restaurant ?? prox.nearbyRestaurant ?? "", @@ -599,6 +844,7 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => { nearbyMall: prox.Mall ?? prox.mall ?? prox.nearbyMall ?? "", purpose: property.purpose || "rent", currencyId: property.currencyId || 1, + commission: property.commission || prox.commission || "", ...(property.purpose === "rent" ? { dailyPrice: property.dailyPrice || 0, @@ -791,7 +1037,7 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => { handleChange("commission", Number(e.target.value))} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500" + /> +
+
handleChange("allowedPaymentPeriod", e.target.value)} - className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500" + className="w-full px-3 py-2 border bg-[#0f172a] text-white border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500" > @@ -1155,7 +1413,17 @@ export default function OwnerPropertiesPage() { const [isLoading, setIsLoading] = useState(true); const [showAddMenu, setShowAddMenu] = useState(false); const [activeTab, setActiveTab] = useState("rent"); + const [commissionPayment, setCommissionPayment] = useState({ + open: false, + property: null, + }); + const [selectedCommissionPayment, setSelectedCommissionPayment] = useState(null); + const [commissionPaymentMethods, setCommissionPaymentMethods] = useState([]); + const [loadingCommissionPaymentMethods, setLoadingCommissionPaymentMethods] = useState(false); + const [commissionReceiptImage, setCommissionReceiptImage] = useState(null); + const [commissionPayingId, setCommissionPayingId] = useState(null); + const [commissionDetails, setCommissionDetails] = useState(""); const [deleteModal, setDeleteModal] = useState({ isOpen: false, property: null, @@ -1186,6 +1454,29 @@ export default function OwnerPropertiesPage() { } }, [router]); + const openCommissionPayment = async (property) => { + setCommissionPayment({ + open: true, + property, + }); + + setSelectedCommissionPayment(null); + setCommissionReceiptImage(null); + setLoadingCommissionPaymentMethods(true); + + try { + const result = await getPaymentTypes(); + + setCommissionDetails(result[0].details); + + setCommissionPaymentMethods(result?.value || result?.data || result || []); + } catch (error) { + toast.error(error?.message || "فشل تحميل طرق الدفع"); + } finally { + setLoadingCommissionPaymentMethods(false); + } + }; + const loadProperties = async () => { const authUser = AuthService.getUser(); const userId = authUser?.id; @@ -1275,6 +1566,7 @@ export default function OwnerPropertiesPage() { monthlyPrice: item.monthlyRent || 0, salePrice: item.price || 0, deposit: item.deposit || 0, + commission: item.commission || details.commission || 0, location: info.address || "", bedrooms: info.numberOfBedRooms || 0, bathrooms: info.numberOfBathRooms || 0, @@ -1299,6 +1591,7 @@ export default function OwnerPropertiesPage() { rating: item.rating || 0, currencyId: item.currencyId, _raw: item, + status2: item.status, }; }); @@ -1314,6 +1607,7 @@ export default function OwnerPropertiesPage() { return {}; } })(); + const apiBase = typeof window !== "undefined" ? process.env.NEXT_PUBLIC_API_URL || "https://45.93.137.91.nip.io/api" : ""; const raw = Array.isArray(info.images) ? info.images : []; return { @@ -1348,6 +1642,7 @@ export default function OwnerPropertiesPage() { monthlyPrice: 0, salePrice: item.price || 0, deposit: 0, + commission: item.commission || details.commission || 0, location: info.address || "", bedrooms: info.numberOfBedRooms || 0, bathrooms: info.numberOfBathRooms || 0, @@ -1372,6 +1667,7 @@ export default function OwnerPropertiesPage() { rating: item.rating || 0, currencyId: item.currencyId, _raw: item, + status2: item.status, }; }); @@ -1531,6 +1827,7 @@ export default function OwnerPropertiesPage() { try { if (prop.purpose === "rent") { await updateRentPropertyStatus(prop.id, statusCode); + await updateRentPropertyStatus(prop.id, statusCode); } else { await updateSalePropertyStatus(prop.id, statusCode); } @@ -1551,10 +1848,47 @@ export default function OwnerPropertiesPage() { transition: { duration: 0.5 }, }; + const handleCommissionPayment = async (property) => { + if (!property) return; + + if (!selectedCommissionPayment) { + toast.error("اختر طريقة الدفع"); + return; + } + + const selectedMethod = commissionPaymentMethods.find((m) => String(m?.id ?? m?.name) === String(selectedCommissionPayment)); + + const isHaram = selectedMethod?.name?.toLowerCase?.() === "haram"; + + if (isHaram && !commissionReceiptImage) { + toast.error("يرجى رفع إيصال الدفع"); + return; + } + + setCommissionPayingId(property.id); + + try { + await OwnerPaymentForSaleProperite(property.id, selectedCommissionPayment, 1, commissionReceiptImage); + + toast.success("تم إرسال طلب دفع الكمسيون"); + await loadProperties(); + setCommissionPayment({ + open: false, + property: null, + }); + + setCommissionReceiptImage(null); + setSelectedCommissionPayment(null); + } catch (error) { + console.error("COMMISSION PAYMENT ERROR:", error); + toast.error(error?.message || "فشل دفع الكمسيون"); + } finally { + setCommissionPayingId(null); + } + }; + if (isLoading) { - return ( - - ); + return ; } return ( @@ -1604,7 +1938,7 @@ export default function OwnerPropertiesPage() {
setShowAddMenu(false)} >
@@ -1618,7 +1952,7 @@ export default function OwnerPropertiesPage() { setShowAddMenu(false)} >
@@ -1684,196 +2018,233 @@ export default function OwnerPropertiesPage() { initial="initial" animate="animate" transition={{ delay: index * 0.1 }} - className="bg-white rounded-2xl shadow-sm hover:shadow-md transition-all overflow-hidden border border-gray-200" + className="bg-white rounded-2xl shadow-sm hover:shadow-md transition-all overflow-hidden border border-gray-200 flex flex-col justify-between" > -
- {property.images && property.images.length > 0 ? ( - {property.title} - ) : ( -
- -
- )} -
- - {property.status === "notAvailable" ? t("notAvailable") : property.status === "available" ? t("available") : t("postponed")} - - {property.purpose === "rent" && property.furnished !== undefined && ( - - {property.furnished ? t("furnished") : t("unfurnished")} - - )} -
- -
- - {property.propertyTypeLabel || - (property.propertyType === "apartment" - ? t("buildingType.apartment") - : property.propertyType === "villa" - ? t("buildingType.villa") - : property.propertyType === "sweet" - ? t("buildingType.sweet") - : property.propertyType === "room" - ? t("buildingType.room") - : property.propertyType === "studio" - ? t("buildingType.studio") - : property.propertyType === "office" - ? t("buildingType.office") - : property.propertyType === "farms" - ? t("buildingType.farms") - : property.propertyType === "shop" - ? t("buildingType.shop") - : property.propertyType === "warehouse" - ? t("buildingType.warehouse") - : t("offer"))} - -
-
- -
-
-

{property.title}

- {property.rating > 0 && ( -
- - {Number(property.rating).toFixed(1)} +
+
+ {property.images && property.images.length > 0 ? ( + {property.title} + ) : ( +
+
)} -
- -
- - {property.address || property.location || t("locationUnknown")} -
- - {property.description &&

{property.description}

} - -
- {property.bedrooms > 0 && ( -
- - {property.bedrooms} -
- )} - {property.bathrooms > 0 && ( -
- - {property.bathrooms} -
- )} - {property.area > 0 && ( -
- - - {property.area} - {t("sqm")} - -
- )} - {property.floor > 0 && ( -
- - - {t("floor")} {property.floor} - -
- )} - {property.salons > 0 && ( -
- - {property.salons} -
- )} - {property.balconies > 0 && ( -
- - {property.balconies} -
- )} -
- -
-
- {property.purpose === "rent" ? ( -
- {property.monthlyPrice > 0 && ( - - {Number(property.monthlyPrice).toLocaleString()} - {t("perMonth")} - - )} - {property.dailyPrice > 0 && !property.monthlyPrice && ( - - {Number(property.dailyPrice).toLocaleString()} - {t("perDay")} - - )} - {property.deposit > 0 &&
{t("depositAmount", { amount: Number(property.deposit).toLocaleString() })}
} -
- ) : ( - - {Number(property.salePrice).toLocaleString()} {t("syp")} - - )} -
- -
- {property.status === "notAvailable" ? ( - - ) : ( - - )} - - - + {property.status === "notAvailable" ? t("notAvailable") : property.status === "available" ? t("available") : t("postponed")} + + {property.purpose === "rent" && property.furnished !== undefined && ( + + {property.furnished ? t("furnished") : t("unfurnished")} + + )} +
+ +
+ + {property.propertyTypeLabel || + (property.propertyType === "apartment" + ? t("buildingType.apartment") + : property.propertyType === "villa" + ? t("buildingType.villa") + : property.propertyType === "sweet" + ? t("buildingType.sweet") + : property.propertyType === "room" + ? t("buildingType.room") + : property.propertyType === "studio" + ? t("buildingType.studio") + : property.propertyType === "office" + ? t("buildingType.office") + : property.propertyType === "farms" + ? t("buildingType.farms") + : property.propertyType === "shop" + ? t("buildingType.shop") + : property.propertyType === "warehouse" + ? t("buildingType.warehouse") + : t("offer"))} + +
+
+ +
+
+

{property.title}

+ {property.rating > 0 && ( +
+ + {Number(property.rating).toFixed(1)} +
+ )} +
+ +
+ + {property.address || property.location || t("locationUnknown")} +
+ + {property.description &&

{property.description}

} + +
+ {property.bedrooms > 0 && ( +
+ + {property.bedrooms} +
+ )} + {property.bathrooms > 0 && ( +
+ + {property.bathrooms} +
+ )} + {property.area > 0 && ( +
+ + + {property.area} + {t("sqm")} + +
+ )} + {property.floor > 0 && ( +
+ + + {t("floor")} {property.floor} + +
+ )} + {property.salons > 0 && ( +
+ + {property.salons} +
+ )} + {property.balconies > 0 && ( +
+ + {property.balconies} +
+ )} +
+ +
+
+ {property.purpose === "rent" ? ( +
+ {property.monthlyPrice > 0 && ( + + {Number(property.monthlyPrice).toLocaleString()} + {t("perMonth")} + + )} + {property.dailyPrice > 0 && !property.monthlyPrice && ( + + {Number(property.dailyPrice).toLocaleString()} + {t("perDay")} + + )} + {property.deposit > 0 &&
{t("depositAmount", { amount: Number(property.deposit).toLocaleString() })}
} +
+ ) : ( + + {Number(property.salePrice).toLocaleString()} {t("syp")} + + )} +
+ +
+ {property.status === "notAvailable" ? ( + + ) : ( + + )} + + + +
+ + {property.purpose === "sale" && Number(property.status2) === 0 && ( + + )} + {property.purpose === "sale" && Number(property.status2) === 1 && ( +
قيد الانتظار
+ )} + + {property.purpose === "sale" && Number(property.status2) === 2 &&
تم التأكيد
} ))}
)}
+ + setCommissionPayment({ + open: false, + property: null, + }) + } + selectedPayment={selectedCommissionPayment} + onSelectPayment={setSelectedCommissionPayment} + onConfirmPay={handleCommissionPayment} + payingId={commissionPayingId} + paymentMethods={commissionPaymentMethods} + loadingPaymentMethods={loadingCommissionPaymentMethods} + receiptImage={commissionReceiptImage} + onSetReceiptImage={setCommissionReceiptImage} + commissionDetails={commissionDetails} + setCommissionDetails={setCommissionDetails} + />
); } diff --git a/app/properties/page.js b/app/properties/page.js index 68e960a..6fee86f 100644 --- a/app/properties/page.js +++ b/app/properties/page.js @@ -692,7 +692,7 @@ export default function PropertiesPage() { const filteredProperties = properties // العقارات يلي 0 ما تنعرض .filter((p) => p.purpose === purposeTab) - .filter((p) => p.purpose === "rent" || p.status === 1) + // .filter((p) => p.purpose === "rent" || p.status === 1) .filter((property) => { if (filters.search && !property.title.includes(filters.search) && !property.description.includes(filters.search)) { return false; @@ -788,9 +788,9 @@ export default function PropertiesPage() {
{/* شرط مشان ينعرض او لا */} {filteredProperties.map((property) => - property.purpose === "rent" || property.status === 1 ? ( + // property.purpose === "rent" || property.status === 1 ? ( setShowLoginDialog(true)} /> - ) : null, + // ) : null, )}
diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js index 484d222..01325c0 100644 --- a/app/property/[id]/PropertyDetail.js +++ b/app/property/[id]/PropertyDetail.js @@ -433,11 +433,15 @@ export default function PropertyDetailsPage({ type }) { const propInfoId = property._raw?.propertyInformationId || property.id; const startDate = new Date(selectedStart + "T00:00:00.000").toISOString(); const endDate = new Date(selectedEnd + "T00:00:00.000").toISOString(); - await bookReservation(propInfoId, startDate, endDate); + await bookReservation(propInfoId, startDate, endDate); + setBookingSuccess(true); toast.success(t("bookingSentSuccess")); } catch (err) { - setBookingError(err.message || t("bookingFailed")); + if (err.message=="API 400: Cannot book a reservation for an inactive property."){ + setBookingError("لا يمكنك حجز هذا العقار لانه غير نشط" || t("bookingFailed")); + } + } finally { setBookingLoading(false); } diff --git a/app/reservations/page.js b/app/reservations/page.js index 959580e..d5396f4 100644 --- a/app/reservations/page.js +++ b/app/reservations/page.js @@ -1,393 +1,3 @@ -// 'use client'; - -// import { useState, useEffect, useCallback } from 'react'; -// import { motion } from 'framer-motion'; -// import { useRouter } from 'next/navigation'; -// import { -// Calendar, Clock, CheckCircle, XCircle, Eye, Loader2, Search, -// MapPin, DollarSign, Home, ArrowLeft, CreditCard, Timer, Star, -// } from 'lucide-react'; -// import toast, { Toaster } from 'react-hot-toast'; -// import AuthService from '../services/AuthService'; -// import { getRentProperties, getUserReservations, payDeposit } from '../utils/api'; -// import { addPropertyRating } from '../utils/ratings'; - -// const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'https://45.93.137.91.nip.io/api'; - -// const STATUS_MAP = ['pending','ownerConfirmed','depositPaid','depositConfirmed','completed','cancelled']; - -// const STATUS_UI = { -// pending: { label: 'قيد الانتظار', color: 'bg-yellow-100 text-yellow-800', icon: Clock }, -// ownerConfirmed: { label: 'مؤكد من المالك', color: 'bg-blue-100 text-blue-800', icon: CheckCircle }, -// depositPaid: { label: 'تم دفع السلفة', color: 'bg-indigo-100 text-indigo-800', icon: DollarSign }, -// depositConfirmed: { label: 'مؤكد', color: 'bg-green-100 text-green-800', icon: CheckCircle }, -// completed: { label: 'منتهي', color: 'bg-green-100 text-green-800', icon: CheckCircle }, -// cancelled: { label: 'ملغي', color: 'bg-gray-100 text-gray-800', icon: XCircle }, -// }; - -// function statusLabel(code) { return STATUS_UI[STATUS_MAP[code]]?.label ?? String(code); } -// function statusColor(code) { return STATUS_UI[STATUS_MAP[code]]?.color ?? 'bg-gray-100 text-gray-700'; } -// function statusIcon(code) { return STATUS_UI[STATUS_MAP[code]]?.icon ?? Clock; } - -// function StatusBadge({ code }) { -// const Icon = statusIcon(code); -// return ( -// -// {statusLabel(code)} -// -// ); -// } - -// const propAddr = (p, r) => p?.address ?? r?.propertyAddress ?? ''; -// const propImages = (p, r) => { -// if (p?.images && Array.isArray(p.images)) return p.images; -// if (r?.property?.images && Array.isArray(r.property.images)) return r.property.images; -// return []; -// }; -// const propBeds = (p, r) => p?.numberOfBedRooms ?? r?.property?.numberOfBedRooms ?? 0; -// const propBaths = (p, r) => p?.numberOfBathRooms ?? r?.property?.numberOfBathRooms ?? 0; - -// function parseTimeSpan(str) { -// if (!str) return 0; -// const clean = str.replace(/-/g, ''); -// const dotIdx = clean.indexOf('.'); -// let days = 0, timePart = clean; -// if (dotIdx !== -1) { -// days = parseInt(clean.substring(0, dotIdx), 10) || 0; -// timePart = clean.substring(dotIdx + 1); -// } -// const parts = timePart.split(':'); -// if (parts.length < 2) return days * 86400000; -// const hh = parseInt(parts[0], 10) || 0; -// const mm = parseInt(parts[1], 10) || 0; -// const ss = parts.length > 2 ? (parseInt(parts[2], 10) || 0) : 0; -// return ((days * 86400) + (hh * 3600) + (mm * 60) + ss) * 1000; -// } - -// function formatWindowDuration(str) { -// if (!str) return ''; -// const clean = str.replace(/-/g, ''); -// const dotIdx = clean.indexOf('.'); -// let totalHours = 0, timePart = clean; -// if (dotIdx !== -1) { -// const days = parseInt(clean.substring(0, dotIdx), 10) || 0; -// totalHours += days * 24; -// timePart = clean.substring(dotIdx + 1); -// } -// const parts = timePart.split(':'); -// if (parts.length >= 2) { -// totalHours += parseInt(parts[0], 10) || 0; -// } -// if (totalHours > 0) return `${String(totalHours).padStart(2, '0')}:00:00`; -// return timePart.substring(0, 8); -// } - -// function CountdownTimer({ deadline }) { -// const [remaining, setRemaining] = useState(deadline ? Math.max(0, deadline - Date.now()) : 0); -// useEffect(() => { -// if (!deadline) return; -// const tick = () => setRemaining(Math.max(0, deadline - Date.now())); -// tick(); -// const id = setInterval(tick, 1000); -// return () => clearInterval(id); -// }, [deadline]); -// if (remaining <= 0) return انتهت المهلة; -// const h = Math.floor(remaining / 3600000); -// const m = Math.floor((remaining % 3600000) / 60000); -// const s = Math.floor((remaining % 60000) / 1000); -// const pad = (n) => String(n).padStart(2, '0'); -// return {pad(h)}:{pad(m)}:{pad(s)}; -// } - -// function ReservationCard({ r, onViewDetails, onPay, payingId }) { -// const p = r._prop; -// const imgs = propImages(p, r); -// const img = imgs.length > 0 ? `${API_BASE}${imgs[0]}` : null; -// const addr = propAddr(p, r); -// const beds = propBeds(p, r); -// const baths = propBaths(p, r); -// const isOwnerConfirmed = STATUS_MAP[r.status] === 'ownerConfirmed'; -// const canRate = STATUS_MAP[r.status] === 'depositPaid' || STATUS_MAP[r.status] === 'completed'; -// const hasTimeWindow = r.ownerApprovalDate && p?.allowedPaymentPeriod; -// const deadline = hasTimeWindow -// ? new Date(r.ownerApprovalDate).getTime() + parseTimeSpan(p.allowedPaymentPeriod) -// : null; -// const isExpired = deadline ? Date.now() > deadline : false; -// const isPaying = payingId === r.id; -// const [showRating, setShowRating] = useState(false); -// const [ratings, setRatings] = useState({ clean: 0, services: 0, ownerBehavior: 0, experience: 0 }); -// const [ratingComment, setRatingComment] = useState(''); -// const [submittingRating, setSubmittingRating] = useState(false); - -// return ( -// -//
-// {img &&
} -//
-//
-// -// {addr &&
{addr}
} -//
-//
-//
{r.totalPrice?.toLocaleString() ?? '—'}
-//
السعر الإجمالي
-//
-//
-// {(beds||baths) &&
{beds>0&&{beds} غرف}{baths>0&&{baths} حمامات}
} -//
-//
-//
من
-//
{new Date(r.startDate).toLocaleDateString('ar')}
-//
-//
-//
إلى
-//
{new Date(r.endDate).toLocaleDateString('ar')}
-//
-//
-// {isOwnerConfirmed && hasTimeWindow &&
-//
-// متبقي للدفع: -// -//
-//
مدة الدفع: {formatWindowDuration(p.allowedPaymentPeriod)}
-//
} -//
-// -// {isOwnerConfirmed && !isExpired && } -//
-// {canRate && !showRating && } -// {canRate && showRating &&
-//
-// {[ -// { key: 'clean', label: 'النظافة' }, -// { key: 'services', label: 'الخدمات' }, -// { key: 'ownerBehavior', label: 'تعامل المالك' }, -// { key: 'experience', label: 'التجربة العامة' }, -// ].map(cat =>
-// {cat.label} -//
-// {[1,2,3,4,5].map(n => ( -// -// ))} -//
-//
)} -//
-//