+
{Object.entries(property.terms).map(([key, value]) => {
if (!value) return null;
return (
-
- {key === 'noSmoking' && ' ممنوع التدخين'}
- {key === 'noPets' && ' ممنوع الحيوانات'}
- {key === 'noParties' && ' ممنوع الحفلات'}
- {key === 'noAlcohol' && ' ممنوع الكحول'}
- {key === 'suitableForChildren' && ' مناسب للأطفال'}
- {key === 'suitableForElderly' && ' مناسب لكبار السن'}
-
+
+ {key.startsWith('No') || key.startsWith('Only') ? (
+
+ ) : (
+
+ )}
+ {termLabels[key] || key}
+
);
})}
@@ -285,24 +297,36 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
معلومات السعر
{property.purpose === 'rent' ? (
- {property.dailyPrice && (
+ {property.dailyPrice > 0 && (
السعر اليومي:
{Number(property.dailyPrice).toLocaleString()} ل.س
)}
- {property.monthlyPrice && (
+ {property.monthlyPrice > 0 && (
السعر الشهري:
{Number(property.monthlyPrice).toLocaleString()} ل.س
)}
+ {property.deposit > 0 && (
+
+ التأمين:
+ {Number(property.deposit).toLocaleString()} ل.س
+
+ )}
نوع الإيجار: {
property.rentType === 'daily' ? 'يومي' :
property.rentType === 'monthly' ? 'شهري' : 'يومي وشهري'
}
+ {property.rating > 0 && (
+
+ التقييم:
+ {Number(property.rating).toFixed(1)}
+
+ )}
) : (
From 427dc74e7f1bd7544bdfc966f2fcf5d2f91d630e Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 22:42:53 +0300
Subject: [PATCH 08/47] fixed my propries page and fixed the sidebar again
mouaz is the best in the west
---
app/components/FloatingSidebar.js | 53 +------
app/owner/properties/page.js | 164 ++++++++++----------
app/property/[id]/PropertyDetail.js | 226 ++++++++++++++--------------
3 files changed, 190 insertions(+), 253 deletions(-)
diff --git a/app/components/FloatingSidebar.js b/app/components/FloatingSidebar.js
index 1f1a275..3f9698c 100644
--- a/app/components/FloatingSidebar.js
+++ b/app/components/FloatingSidebar.js
@@ -3,7 +3,7 @@
import { useState } from 'react';
import { motion } from 'framer-motion';
import Link from 'next/link';
-import { Heart, Bell, CreditCard, Shield, UserPlus, Settings, CalendarDays, Star, FileText } from 'lucide-react';
+import { Heart, Bell, CreditCard, Shield, UserPlus, Settings } from 'lucide-react';
import { useFavorites } from '@/app/contexts/FavoritesContext';
import { useNotifications } from '@/app/contexts/NotificationsContext';
import AuthService from '@/app/services/AuthService';
@@ -177,57 +177,6 @@ export default function FloatingSidebar({ isRTL, isAdmin }) {
{renderTooltip('payments', 'المدفوعات')}
- showTooltip('booked')}
- onMouseLeave={hideTooltip}
- >
-
-
-
- {renderTooltip('booked', 'حجوزاتي')}
-
- showTooltip('myRates')}
- onMouseLeave={hideTooltip}
- >
-
-
-
- {renderTooltip('myRates', 'تقييماتي')}
-
- showTooltip('reports')}
- onMouseLeave={hideTooltip}
- >
-
-
-
- {renderTooltip('reports', 'البلاغات')}
-
-
+
{property.images && property.images.length > 0 ? (

) : (
@@ -1089,133 +1089,123 @@ export default function OwnerPropertiesPage() {
)}
-
{property.status === 'available' ? 'متاح' : 'مؤجر'}
- {property.purpose === 'rent' && property.furnished && (
-
- مفروش
-
- )}
- {property.purpose === 'rent' && !property.furnished && property.furnished !== undefined && (
-
- غير مفروش
+ {property.purpose === 'rent' && property.furnished !== undefined && (
+
+ {property.furnished ? 'مفروش' : 'غير مفروش'}
)}
+
+
+
+ {property.propertyTypeLabel || (property.propertyType === 'apartment' ? 'شقة' : property.propertyType === 'villa' ? 'فيلا' : property.propertyType === 'sweet' ? 'سويت' : property.propertyType === 'room' ? 'غرفة' : property.propertyType === 'studio' ? 'استوديو' : property.propertyType === 'office' ? 'مكتب' : property.propertyType === 'farms' ? 'مزرعة' : property.propertyType === 'shop' ? 'متجر' : property.propertyType === 'warehouse' ? 'مستودع' : 'عقار')}
+
+
-
-
-
{property.propertyTypeLabel || (property.propertyType === 'apartment' ? 'شقة' : property.propertyType === 'villa' ? 'فيلا' : property.propertyType === 'sweet' ? 'سويت' : property.propertyType === 'room' ? 'غرفة' : property.propertyType === 'studio' ? 'استوديو' : property.propertyType === 'office' ? 'مكتب' : property.propertyType === 'farms' ? 'مزرعة' : property.propertyType === 'shop' ? 'متجر' : property.propertyType === 'warehouse' ? 'مستودع' : 'عقار')}
+
+
+
{property.title}
+ {property.rating > 0 && (
+
+
+ {Number(property.rating).toFixed(1)}
+
+ )}
-
{property.title}
-
-
- {property.address || property.location || 'موقع غير محدد'}
+
+
+ {property.address || property.location || 'موقع غير محدد'}
-
-
-
- {property.bedrooms}
-
-
-
- {property.bathrooms}
-
-
-
- {property.area}م²
-
+
+ {property.bedrooms > 0 && (
+
+
+ {property.bedrooms}
+
+ )}
+ {property.bathrooms > 0 && (
+
+
+ {property.bathrooms}
+
+ )}
+ {property.area > 0 && (
+
+
+ {property.area}م²
+
+ )}
{property.floor > 0 && (
-
-
+
+
ط {property.floor}
)}
{property.salons > 0 && (
-
-
+
+
{property.salons}
)}
{property.balconies > 0 && (
-
-
+
+
{property.balconies}
)}
- {property.rating > 0 && (
-
-
- {Number(property.rating).toFixed(1)}
-
- )}
-
+
{property.purpose === 'rent' ? (
-
- {property.rentType === 'monthly' && property.monthlyPrice > 0 && (
-
- {Number(property.monthlyPrice).toLocaleString()}
- ل.س /شهر
+
+ {property.monthlyPrice > 0 && (
+
+ {Number(property.monthlyPrice).toLocaleString()}
+ ل.س /شهر
)}
- {property.rentType === 'daily' && property.dailyPrice > 0 && (
-
- {Number(property.dailyPrice).toLocaleString()}
- ل.س /يوم
-
- )}
- {property.rentType === 'daily' && property.monthlyPrice > 0 && (
-
- {Number(property.monthlyPrice).toLocaleString()}
- ل.س /شهر
+ {property.dailyPrice > 0 && !property.monthlyPrice && (
+
+ {Number(property.dailyPrice).toLocaleString()}
+ ل.س /يوم
)}
{property.deposit > 0 && (
- تأمين: {Number(property.deposit).toLocaleString()}
+ تأمين: {Number(property.deposit).toLocaleString()} ل.س
)}
) : (
-
-
- {Number(property.salePrice).toLocaleString()} ل.س
-
- للبيع
-
+
+ {Number(property.salePrice).toLocaleString()} ل.س
+
)}
-
-
diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js
index 786d4ff..84e6573 100644
--- a/app/property/[id]/PropertyDetail.js
+++ b/app/property/[id]/PropertyDetail.js
@@ -302,15 +302,15 @@ export default function PropertyDetailsPage() {
-
-
+
+
{/* Image Gallery */}
-
+
{property.images.length > 0 ? (

+ style={{ minHeight: '380px', maxHeight: '460px' }} />
) : (
@@ -363,29 +363,27 @@ export default function PropertyDetailsPage() {
{/* Property Info */}
-
-
+
+
-
-
{property.typeLabel}
-
{property.statusLabel}
+
+ {property.typeLabel}
+ {property.statusLabel}
-
{property.title}
-
-
+
{property.title}
+
+
{property.location.address || property.location.city}
-
-
-
-
-
+
+
+
{/* Price */}
-
+
{property.isRent ? (
{property.priceDisplay.monthly > 0 && (
@@ -416,79 +414,79 @@ export default function PropertyDetailsPage() {
{/* Specs Tiles */}
-
+
{property.bedrooms > 0 && (
-
-
-
{property.bedrooms}
-
غرف نوم
+
+
+
{property.bedrooms}
+
غرف نوم
)}
{property.bathrooms > 0 && (
-
-
-
{property.bathrooms}
-
حمامات
+
+
+
{property.bathrooms}
+
حمامات
)}
{property.area > 0 && (
-
-
-
{property.area}
-
م²
+
)}
{property.floor > 0 && (
-
-
-
{property.floor}
-
طابق
+
+
+
{property.floor}
+
طابق
)}
{property.salons > 0 && (
-
-
-
{property.salons}
-
صالونات
+
+
+
{property.salons}
+
صالونات
)}
{property.balconies > 0 && (
-
-
-
{property.balconies}
-
بلكونات
+
+
+
{property.balconies}
+
بلكونات
)}
{avgRating !== null && avgRating > 0 && (
-
-
-
{avgRating.toFixed(1)}
-
التقييم
+
+
+
{avgRating.toFixed(1)}
+
التقييم
)}
{/* Description */}
{property.description && (
-
-
الوصف
-
{property.description}
+
+
الوصف
+
{property.description}
)}
{/* Features */}
-
- {property.isSmokeAllow &&
يسمح بالتدخين}
- {!property.isSmokeAllow &&
ممنوع التدخين}
- {property.isVisitorAllow &&
يسمح بالزوار}
- {property.specializedFor &&
{property.specializedFor}}
+
+ {property.isSmokeAllow && يسمح بالتدخين}
+ {!property.isSmokeAllow && ممنوع التدخين}
+ {property.isVisitorAllow && يسمح بالزوار}
+ {property.specializedFor && {property.specializedFor}}
{/* Services with detail text */}
{Object.keys(property.services).length > 0 && (
-
-
الخدمات
-
+
+
الخدمات
+
{Object.entries(property.services).map(([key, val]) => {
if (!val) return null;
const detail = typeof val === 'object' && val.detail ? val.detail : null;
@@ -505,12 +503,12 @@ export default function PropertyDetailsPage() {
{/* Room Details (only for room type) */}
{isRoomType && Object.keys(property.roomDetails).length > 0 && (
-
-
-
+
+
+
تفاصيل الغرفة
-
+
{(() => {
const rd = property.roomDetails;
const items = [];
@@ -542,24 +540,24 @@ export default function PropertyDetailsPage() {
{/* Proximity */}
{Object.keys(property.proximity).length > 0 && (
-
-
القرب من الخدمات
-
+
+
القرب من الخدمات
+
{Object.entries(property.proximity).map(([key, val]) => {
if (!val) return null;
const dist = typeof val === 'object' ? val.distance : val;
return (
-
- {key === 'School' &&
}
- {key === 'Hospital' &&
}
- {key === 'Restaurant' &&
}
- {key === 'University' &&
}
- {key === 'Park' &&
}
- {key === 'Mall' &&
}
- {!['School','Hospital','Restaurant','University','Park','Mall'].includes(key) &&
}
+
+ {key === 'School' &&
}
+ {key === 'Hospital' &&
}
+ {key === 'Restaurant' &&
}
+ {key === 'University' &&
}
+ {key === 'Park' &&
}
+ {key === 'Mall' &&
}
+ {!['School','Hospital','Restaurant','University','Park','Mall'].includes(key) &&
}
-
{proximityLabels[key] || key}
-
{dist} {typeof dist === 'number' ? 'كم' : ''}
+
{proximityLabels[key] || key}
+
{dist} {typeof dist === 'number' ? 'كم' : ''}
);
@@ -570,19 +568,19 @@ export default function PropertyDetailsPage() {
{/* Terms as checklist */}
{Object.keys(property.terms).length > 0 && (
-
-
الشروط
-
+
+
الشروط
+
{Object.entries(property.terms).map(([key, val]) => {
if (!val) return null;
return (
-
+
{key.startsWith('No') || key.startsWith('Only') ? (
-
+
) : (
-
+
)}
- {termLabels[key] || key}
+ {termLabels[key] || key}
);
})}
@@ -641,45 +639,45 @@ export default function PropertyDetailsPage() {
{/* Sidebar */}
-
+
{/* Booking Card */}
{property.isRent && (
-
-
-
-
حجز العقار
+
+
+
+
حجز العقار
{bookingSuccess ? (
-
-
-
+
+
+
-
تم إرسال طلب الحجز
-
سيتم مراجعة طلبك من قبل المالك
+
تم إرسال طلب الحجز
+
سيتم مراجعة طلبك من قبل المالك
) : (
<>
-
+
{bookingError && (
-
{bookingError}
+
{bookingError}
)}
- {bookingLoading ? : }
+ className="w-full bg-amber-500 hover:bg-amber-600 text-white py-2.5 rounded-xl font-bold text-sm transition-all disabled:opacity-50 flex items-center justify-center gap-2">
+ {bookingLoading ? : }
{bookingLoading ? 'جاري الحجز...' : 'حجز الآن'}
>
@@ -688,30 +686,30 @@ export default function PropertyDetailsPage() {
)}
{/* Contact Card */}
-
-
-
-
معلومات المالك
+
+
{showContact && contactInfo ? (
-
-
-
-
{contactInfo.phone || contactInfo.phoneNumber || '—'}
+
) : (
-
+ className="w-full bg-gray-800 hover:bg-gray-900 text-white py-2.5 rounded-xl font-medium text-sm transition-colors flex items-center justify-center gap-2">
+
عرض معلومات الاتصال
)}
From 4988302bc1079ec438700be83235f007887fd89a Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 22:50:38 +0300
Subject: [PATCH 09/47] fixed my propries page and fixed the sidebar again
mouaz is the best in the west
---
app/components/FloatingSidebar.js | 8 +++-----
app/owner/properties/page.js | 20 ++++++++++++--------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/app/components/FloatingSidebar.js b/app/components/FloatingSidebar.js
index 3f9698c..51ab56a 100644
--- a/app/components/FloatingSidebar.js
+++ b/app/components/FloatingSidebar.js
@@ -29,10 +29,8 @@ export default function FloatingSidebar({ isRTL, isAdmin }) {
const positionStyle = {
left: '16px',
- top: 0,
- bottom: 0,
- display: 'flex',
- alignItems: 'center',
+ top: '50%',
+ transform: 'translateY(-50%)',
};
const cardVariants = {
@@ -57,7 +55,7 @@ export default function FloatingSidebar({ isRTL, isAdmin }) {
return (
{
className="bg-white rounded-2xl w-full max-w-4xl max-h-[90vh] overflow-y-auto shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
-
+
{property.title}
تم الإضافة: {new Date(property.createdAt).toLocaleDateString('ar-SA')}
@@ -468,12 +468,15 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
className="bg-white rounded-2xl w-full max-w-4xl max-h-[90vh] overflow-y-auto shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
-
+
تعديل العقار
-
يمكنك تعديل أي حقل بالضغط على أيقونة القلم
+
قم بتحديث معلومات العقار
-
+
@@ -936,7 +939,7 @@ export default function OwnerPropertiesPage() {
}
return (
-
+
-
+
{property.images && property.images.length > 0 ? (

) : (
@@ -1196,8 +1199,9 @@ export default function OwnerPropertiesPage() {
setViewModal({ isOpen: true, property })}
- className="p-1.5 hover:bg-blue-50 rounded-lg transition-colors group" title="عرض التفاصيل">
+ className="px-3 py-1.5 bg-gray-50 hover:bg-blue-50 border border-gray-200 hover:border-blue-200 rounded-lg transition-all group flex items-center gap-1.5" title="عرض التفاصيل">
+ عرض
setEditModal({ isOpen: true, property })}
className="p-1.5 hover:bg-amber-50 rounded-lg transition-colors group" title="تعديل العقار">
From af54bded138c8768a50fe355a566a706b4232040 Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 22:54:38 +0300
Subject: [PATCH 10/47] fixed my propries page and fixed the sidebar again
mouaz is the best in the west
---
app/owner/properties/page.js | 28 ++++++++++++++++++----------
app/property/[id]/PropertyDetail.js | 28 ++++++++++++++++++----------
2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js
index eb34b16..e9594f3 100644
--- a/app/owner/properties/page.js
+++ b/app/owner/properties/page.js
@@ -254,20 +254,28 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
- {property.services && Object.keys(property.services).length > 0 && (
+ {property.services && (Array.isArray(property.services) ? property.services.length > 0 : Object.keys(property.services).length > 0) && (
الخدمات المتوفرة
- {Object.entries(property.services).map(([key, value]) => {
- if (!value) return null;
- const detail = typeof value === 'object' && value.detail ? value.detail : null;
- return (
-
- {serviceLabels[key] || key}
- {detail && · {detail}}
+ {Array.isArray(property.services) ? (
+ property.services.map((svc, i) => (
+
+ {serviceLabels[svc] || svc}
- );
- })}
+ ))
+ ) : (
+ Object.entries(property.services).map(([key, value]) => {
+ if (!value) return null;
+ const detail = typeof value === 'object' && value.detail ? value.detail : null;
+ return (
+
+ {serviceLabels[key] || key}
+ {detail && · {detail}}
+
+ );
+ })
+ )}
)}
diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js
index 84e6573..97ba66c 100644
--- a/app/property/[id]/PropertyDetail.js
+++ b/app/property/[id]/PropertyDetail.js
@@ -483,20 +483,28 @@ export default function PropertyDetailsPage() {
{/* Services with detail text */}
- {Object.keys(property.services).length > 0 && (
+ {property.services && (Array.isArray(property.services) ? property.services.length > 0 : Object.keys(property.services).length > 0) && (
الخدمات
- {Object.entries(property.services).map(([key, val]) => {
- if (!val) return null;
- const detail = typeof val === 'object' && val.detail ? val.detail : null;
- return (
-
- {serviceLabels[key] || key}
- {detail && · {detail}}
+ {Array.isArray(property.services) ? (
+ property.services.map((svc, i) => (
+
+ {serviceLabels[svc] || svc}
- );
- })}
+ ))
+ ) : (
+ Object.entries(property.services).map(([key, val]) => {
+ if (!val) return null;
+ const detail = typeof val === 'object' && val.detail ? val.detail : null;
+ return (
+
+ {serviceLabels[key] || key}
+ {detail && · {detail}}
+
+ );
+ })
+ )}
)}
From 8d48fcae998b71e75f6429900379f8ae6796c8af Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 23:07:29 +0300
Subject: [PATCH 11/47] fixed my propries page and fixed the sidebar again
mouaz is the best in the west
---
app/owner/properties/page.js | 26 ++++++++++++++++++++++----
app/property/[id]/PropertyDetail.js | 10 +++++++++-
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js
index e9594f3..bf831be 100644
--- a/app/owner/properties/page.js
+++ b/app/owner/properties/page.js
@@ -201,7 +201,7 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
التفاصيل
-
+
{property.bedrooms}
@@ -238,6 +238,13 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
بلكونات
)}
+ {property.bookedCount > 0 && (
+
+
+ {property.bookedCount}
+ حجوزات
+
+ )}
@@ -267,7 +274,7 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
) : (
Object.entries(property.services).map(([key, value]) => {
if (!value) return null;
- const detail = typeof value === 'object' && value.detail ? value.detail : null;
+ const detail = typeof value === 'object' && value.detail ? value.detail : (typeof value === 'string' ? value : null);
return (
{serviceLabels[key] || key}
@@ -773,6 +780,15 @@ export default function OwnerPropertiesPage() {
console.log('[OwnerProperties] Rent:', rentList.length, 'Sale:', saleList.length);
+ const normalizeServices = (details) => {
+ const rawServices = details.services || {};
+ const serviceList = Array.isArray(rawServices) ? rawServices : Object.keys(rawServices).filter(k => rawServices[k]);
+ const serviceDetails = details.serviceDetails || {};
+ const services = {};
+ serviceList.forEach(s => { services[s] = serviceDetails[s] || true; });
+ return services;
+ };
+
const mappedRent = rentList.map((item) => {
const info = item.propertyInformation || {};
const details = (() => { try { return JSON.parse(info.detailsJSON || '{}'); } catch { return {}; } })();
@@ -797,6 +813,7 @@ export default function OwnerPropertiesPage() {
floor: details.floorNumber ?? details.floor ?? 0,
salons: details.numberOfSalons ?? details.salonsCount ?? details.salons ?? 0,
balconies: details.numberOfBalconies ?? details.balconiesCount ?? details.balconies ?? 0,
+ bookedCount: details.bookedCount || 0,
status: { 0: 'available', 1: 'booked', 2: 'maintenance' }[info.status] || 'available',
images: raw.length > 0 ? raw.map(img => img.startsWith('http') ? img : `${apiBase}${img.startsWith('/') ? '' : '/Pictures/'}${img}`) : ['/property-placeholder.jpg'],
createdAt: item.createdAt || new Date().toISOString(),
@@ -805,7 +822,7 @@ export default function OwnerPropertiesPage() {
address: info.address || '',
city: '',
district: '',
- services: details.services || {},
+ services: normalizeServices(details),
terms: details.terms || {},
rating: item.rating || 0,
currencyId: item.currencyId,
@@ -836,6 +853,7 @@ export default function OwnerPropertiesPage() {
floor: details.floorNumber ?? details.floor ?? 0,
salons: details.numberOfSalons ?? details.salonsCount ?? details.salons ?? 0,
balconies: details.numberOfBalconies ?? details.balconiesCount ?? details.balconies ?? 0,
+ bookedCount: details.bookedCount || 0,
status: 'available',
images: raw.length > 0 ? raw.map(img => img.startsWith('http') ? img : `${apiBase}${img.startsWith('/') ? '' : '/Pictures/'}${img}`) : ['/property-placeholder.jpg'],
createdAt: item.createdAt || new Date().toISOString(),
@@ -844,7 +862,7 @@ export default function OwnerPropertiesPage() {
address: info.address || '',
city: '',
district: '',
- services: details.services || {},
+ services: normalizeServices(details),
terms: details.terms || {},
rating: item.rating || 0,
currencyId: item.currencyId,
diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js
index 97ba66c..4f12c91 100644
--- a/app/property/[id]/PropertyDetail.js
+++ b/app/property/[id]/PropertyDetail.js
@@ -141,6 +141,7 @@ function mapApiDetail(item) {
proximity,
roomDetails,
details,
+ bookedCount: details.bookedCount || 0,
deposit: item.deposit || 0,
currencyId: item.currencyId,
isSmokeAllow: item.isSmokeAllow,
@@ -464,6 +465,13 @@ export default function PropertyDetailsPage() {
التقييم
)}
+ {property.bookedCount > 0 && (
+
+
+
{property.bookedCount}
+
حجوزات
+
+ )}
{/* Description */}
@@ -496,7 +504,7 @@ export default function PropertyDetailsPage() {
) : (
Object.entries(property.services).map(([key, val]) => {
if (!val) return null;
- const detail = typeof val === 'object' && val.detail ? val.detail : null;
+ const detail = typeof val === 'object' && val.detail ? val.detail : (typeof val === 'string' ? val : null);
return (
{serviceLabels[key] || key}
From 2c4a163cdb3b3a051b0e40d72c6a3bba5dd4f10b Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 23:18:03 +0300
Subject: [PATCH 12/47] editing the add rent property mouaz is the best in the
west
---
app/owner/properties/add/page.js | 153 +++++++++++++++++++++++++------
1 file changed, 124 insertions(+), 29 deletions(-)
diff --git a/app/owner/properties/add/page.js b/app/owner/properties/add/page.js
index 62585af..dc6bbe7 100644
--- a/app/owner/properties/add/page.js
+++ b/app/owner/properties/add/page.js
@@ -100,6 +100,10 @@ export default function AddPropertyPage() {
bedrooms: 1,
bathrooms: 1,
livingRooms: 1,
+ floorNumber: '',
+ salons: '',
+ balconies: '',
+ space: '',
services: {
[PropertyService.ELECTRICITY]: false,
@@ -123,6 +127,7 @@ export default function AddPropertyPage() {
dailyPrice: '',
monthlyPrice: '',
+ deposit: '',
city: '',
district: '',
@@ -132,7 +137,31 @@ export default function AddPropertyPage() {
description: '',
- images: []
+ images: [],
+
+ nearbySchool: '',
+ nearbyHospital: '',
+ nearbyRestaurant: '',
+ nearbyUniversity: '',
+ nearbyPark: '',
+ nearbyMall: '',
+
+ roomAreaType: 'Private room',
+ roomPeopleAllowed: '',
+ roomFurniture: '',
+ roomEntrance: 'Shared entrance',
+ roomBathroom: 'Shared',
+ roomKitchen: 'Not available',
+ roomRestrictedAreas: false,
+ roomResidents: '',
+ roomGender: 'Family',
+ roomLanguage: '',
+ roomChildren: false,
+ roomPets: false,
+ roomDedicatedTo: 'Everyone',
+ roomVisitors: true,
+ roomQuietTimes: false,
+ roomQuietTimesDetails: '',
});
const [imagePreviews, setImagePreviews] = useState([]);
@@ -559,44 +588,63 @@ const handleMapClick = async (coords) => {
.filter(([, v]) => v)
.map(([k]) => k);
- const detailsJSON = JSON.stringify({
+ const details = {
+ description: formData.description || '',
services: selectedServices,
- serviceDetails: selectedServices.reduce((acc, s) => ({ ...acc, [s]: 'in general' }), {}),
- terms: selectedTerms,
+ serviceDetails: selectedServices.reduce((acc, s) => ({ ...acc, [s]: formData.serviceDetails[s] || 'in general' }), {}),
+ terms: selectedTerms.reduce((acc, k) => ({ ...acc, [k]: true }), {}),
displayType: formData.offerType === 'both' ? 'Both' : formData.offerType === 'daily' ? 'Daily' : 'Monthly',
- propertyCondition: formData.furnished ? 'Furnished' : 'Unfurnished',
- photos: imagePreviews.map((_, i) => `photo_${i}.jpg`),
- room: {
- areaType: formData.propertyType === 'room' ? 'Shared room' : 'Private room',
- peopleAllowed: String(formData.bedrooms),
- entranceType: formData.propertyType === 'room' ? 'Shared entrance' : 'Private entrance',
- bathroomType: formData.bathrooms > 1 ? 'Private' : 'Shared',
- kitchenType: 'Not available',
- hasRestrictedOwnerAreas: false,
- languageDialect: '',
- hasChildren: false,
- hasPets: false,
- dedicatedTo: 'Everyone',
- visitorsAllowed: true,
- quietTimesEnabled: false,
- quietTimes: '',
- }
- });
+ propertyCondition: formData.furnished ? 'WithFurniture' : 'WithoutFurniture',
+ floorNumber: parseInt(formData.floorNumber) || 0,
+ numberOfSalons: parseInt(formData.salons) || 0,
+ numberOfBalconies: parseInt(formData.balconies) || 0,
+ nearbyDistances: {
+ school: formData.nearbySchool || '',
+ hospital: formData.nearbyHospital || '',
+ restaurant: formData.nearbyRestaurant || '',
+ university: formData.nearbyUniversity || '',
+ park: formData.nearbyPark || '',
+ mall: formData.nearbyMall || '',
+ },
+ };
+
+ if (formData.propertyType === 'room') {
+ details.room = {
+ areaType: formData.roomAreaType || 'Private room',
+ peopleAllowed: formData.roomPeopleAllowed || String(formData.bedrooms),
+ furnitureDetails: formData.roomFurniture || '',
+ entranceType: formData.roomEntrance || 'Shared entrance',
+ bathroomType: formData.roomBathroom || 'Shared',
+ kitchenType: formData.roomKitchen || 'Not available',
+ hasRestrictedOwnerAreas: formData.roomRestrictedAreas || false,
+ homeResidentsCount: formData.roomResidents || '',
+ currentPopulationGender: formData.roomGender || 'Family',
+ languageDialect: formData.roomLanguage || '',
+ hasChildren: formData.roomChildren || false,
+ hasPets: formData.roomPets || false,
+ dedicatedTo: formData.roomDedicatedTo || 'Everyone',
+ visitorsAllowed: formData.roomVisitors ?? true,
+ quietTimesEnabled: formData.roomQuietTimes ?? false,
+ quietTimes: formData.roomQuietTimesDetails || '',
+ };
+ }
+
+ const detailsJSON = JSON.stringify(details);
const propInfo = {
cordsX: formData.lat ? String(formData.lat) : '',
cordsY: formData.lng ? String(formData.lng) : '',
+ images: uploadedImagePaths,
address: `${formData.city} - ${formData.district} - ${formData.address}`.trim(),
description: formData.description || '',
numberOfBathRooms: formData.bathrooms || 0,
- numberOfRooms: (formData.bedrooms || 0) + (formData.livingRooms || 0),
+ numberOfRooms: formData.bedrooms || 0,
numberOfBedRooms: formData.bedrooms || 0,
space: parseFloat(formData.space) || 0,
detailsJSON,
buildingType: buildingTypeMap[formData.propertyType] ?? BuildingType.APARTMENT,
status: 0,
propertyType: formData.furnished ? RentPropertyCondition.WITH_FURNITURE : RentPropertyCondition.WITHOUT_FURNITURE,
- images: uploadedImagePaths,
};
try {
@@ -617,13 +665,11 @@ const handleMapClick = async (coords) => {
deposit: parseFloat(formData.deposit) || 0,
monthlyRent: parseFloat(formData.monthlyPrice) || 0,
dailyRent: parseFloat(formData.dailyPrice) || 0,
- rating: 0,
+ rating: 1,
currencyId: selectedCurrencyId,
rentType: rentTypeMap[formData.offerType] ?? RentType.MONTHLY,
- isSmokeAllow: !formData.terms[PropertyTerm.NO_SMOKING],
- specializedFor: false,
- isVisitorAllow: !formData.terms[PropertyTerm.NO_PARTIES],
type: formData.furnished ? RentPropertyType.FURNISHED : RentPropertyType.UNFURNISHED,
+ allowedPaymentPeriod: '01:00:00:00',
};
console.log('[AddProperty] Rent payload:', JSON.stringify(payload, null, 2));
const res = await addRentProperty(payload);
@@ -786,7 +832,23 @@ const handleMapClick = async (coords) => {
أدخل التفاصيل والخدمات المتاحة
-
+
+
+
+
+
+ setFormData({...formData, space: e.target.value})}
+ className="w-full pr-10 pl-3 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500"
+ placeholder="مثال: 120"
+ />
+
+
+
+
+
الخدمات المتوفرة *
From 085c60ec3327d1f49c842e85b9928176c601a4ad Mon Sep 17 00:00:00 2001
From: mouazkh
Date: Mon, 25 May 2026 23:55:02 +0300
Subject: [PATCH 13/47] editing the add rent property mouaz is the best in the
west
---
app/owner/properties/page.js | 997 +++++++++++++++++++---------
app/property/[id]/PropertyDetail.js | 11 +-
2 files changed, 697 insertions(+), 311 deletions(-)
diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js
index bf831be..ef6f41f 100644
--- a/app/owner/properties/page.js
+++ b/app/owner/properties/page.js
@@ -1,9 +1,9 @@
-'use client';
+"use client";
-import { useState, useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { useRouter } from 'next/navigation';
-import Link from 'next/link';
+import { useState, useEffect } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import { useRouter } from "next/navigation";
+import Link from "next/link";
import {
PlusCircle,
Building,
@@ -45,13 +45,22 @@ import {
X,
Star,
Ban,
- Check
-} from 'lucide-react';
-import toast, { Toaster } from 'react-hot-toast';
-import AuthService from '../../services/AuthService';
-import { getMyRentListings, getMySaleListings, editRentProperty } from '../../utils/api';
+ Check,
+} from "lucide-react";
+import toast, { Toaster } from "react-hot-toast";
+import AuthService from "../../services/AuthService";
+import {
+ getMyRentListings,
+ getMySaleListings,
+ editRentProperty,
+} from "../../utils/api";
-const DeleteConfirmationModal = ({ isOpen, onClose, onConfirm, propertyTitle }) => {
+const DeleteConfirmationModal = ({
+ isOpen,
+ onClose,
+ onConfirm,
+ propertyTitle,
+}) => {
if (!isOpen) return null;
return (
@@ -75,9 +84,12 @@ const DeleteConfirmationModal = ({ isOpen, onClose, onConfirm, propertyTitle })
تأكيد الحذف
- هل أنت متأكد من حذف العقار: "{propertyTitle}"؟
+ هل أنت متأكد من حذف العقار:{" "}
+ "{propertyTitle}"؟
+
+
+ هذا الإجراء لا يمكن التراجع عنه
-
هذا الإجراء لا يمكن التراجع عنه
@@ -100,23 +112,45 @@ const DeleteConfirmationModal = ({ isOpen, onClose, onConfirm, propertyTitle })
};
const serviceLabels = {
- Electricity: 'كهرباء', Internet: 'إنترنت', Heating: 'تدفئة', Water: 'ماء',
- Pool: 'مسبح', PrivateGarden: 'حديقة خاصة', Parking: 'موقف سيارات',
- Security247: 'حراسة 24 س', CentralHeating: 'تدفئة مركزية',
- CentralAirConditioning: 'تكييف مركزي', EquippedKitchen: 'مطبخ مجهز',
- MaidsRoom: 'غرفة خادمة', Elevator: 'مصعد', Gym: 'نادي رياضي',
- Sauna: 'ساونا', Jacuzzi: 'جاكوزي', Balcony: 'بلكونة',
- Rooftop: 'سطح', Furnished: 'مفروش', AirConditioning: 'تكييف',
- SatelliteTV: 'تلفاز', Fireplace: 'مدفأة', StudyRoom: 'غرفة دراسة',
- Storage: 'مستودع', Laundry: 'غرفة غسيل', SmartHome: 'منزل ذكي',
+ Electricity: "كهرباء",
+ Internet: "إنترنت",
+ Heating: "تدفئة",
+ Water: "ماء",
+ Pool: "مسبح",
+ PrivateGarden: "حديقة خاصة",
+ Parking: "موقف سيارات",
+ Security247: "حراسة 24 س",
+ CentralHeating: "تدفئة مركزية",
+ CentralAirConditioning: "تكييف مركزي",
+ EquippedKitchen: "مطبخ مجهز",
+ MaidsRoom: "غرفة خادمة",
+ Elevator: "مصعد",
+ Gym: "نادي رياضي",
+ Sauna: "ساونا",
+ Jacuzzi: "جاكوزي",
+ Balcony: "بلكونة",
+ Rooftop: "سطح",
+ Furnished: "مفروش",
+ AirConditioning: "تكييف",
+ SatelliteTV: "تلفاز",
+ Fireplace: "مدفأة",
+ StudyRoom: "غرفة دراسة",
+ Storage: "مستودع",
+ Laundry: "غرفة غسيل",
+ SmartHome: "منزل ذكي",
};
const termLabels = {
- NoSmoking: 'ممنوع التدخين', NoAnimals: 'ممنوع الحيوانات الأليفة',
- NoParties: 'ممنوع الحفلات', NoAlcohol: 'ممنوع الكحول',
- SuitableForChildren: 'مناسب للأطفال', SuitableForFamilies: 'مناسب للعائلات',
- SuitableForStudents: 'مناسب للطلاب', SuitableForElderly: 'مناسب لكبار السن',
- OnlyFemales: 'إناث فقط', OnlyMales: 'ذكور فقط',
+ NoSmoking: "ممنوع التدخين",
+ NoAnimals: "ممنوع الحيوانات الأليفة",
+ NoParties: "ممنوع الحفلات",
+ NoAlcohol: "ممنوع الكحول",
+ SuitableForChildren: "مناسب للأطفال",
+ SuitableForFamilies: "مناسب للعائلات",
+ SuitableForStudents: "مناسب للطلاب",
+ SuitableForElderly: "مناسب لكبار السن",
+ OnlyFemales: "إناث فقط",
+ OnlyMales: "ذكور فقط",
};
const PropertyViewModal = ({ isOpen, onClose, property }) => {
@@ -140,7 +174,10 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
{property.title}
-
تم الإضافة: {new Date(property.createdAt).toLocaleDateString('ar-SA')}
+
+ تم الإضافة:{" "}
+ {new Date(property.createdAt).toLocaleDateString("ar-SA")}
+
{
{property.images && property.images.length > 0 && (
-
صور العقار
+
+ صور العقار
+
{property.images.map((image, index) => (
-
+

{
نوع العقار:
- {property.propertyTypeLabel || 'عقار'}
+
+ {property.propertyTypeLabel || "عقار"}
+
- {property.purpose === 'rent' && (
+ {property.purpose === "rent" && (
حالة التأثيث:
-
- {property.furnished ? 'مفروش' : 'غير مفروش'}
+
+ {property.furnished ? "مفروش" : "غير مفروش"}
)}
حالة العقار:
-
- {property.status === 'available' ? 'متاح' : 'مؤجر'}
+
+ {property.status === "available" ? "متاح" : "مؤجر"}
{property.description && (
الوصف:
- {property.description}
+
+ {property.description}
+
)}
@@ -209,7 +259,9 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
- {property.bathrooms}
+
+ {property.bathrooms}
+
حمامات
@@ -234,14 +286,18 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
{property.balconies > 0 && (
- {property.balconies}
+
+ {property.balconies}
+
بلكونات
)}
{property.bookedCount > 0 && (
- {property.bookedCount}
+
+ {property.bookedCount}
+
حجوزات
)}
@@ -255,37 +311,53 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
الموقع
- {property.address || 'لم يتم تحديد العنوان'}
+ {property.address || "لم يتم تحديد العنوان"}
{property.city && `، ${property.city}`}
{property.district && `، ${property.district}`}
- {property.services && (Array.isArray(property.services) ? property.services.length > 0 : Object.keys(property.services).length > 0) && (
-
-
الخدمات المتوفرة
-
- {Array.isArray(property.services) ? (
- property.services.map((svc, i) => (
-
- {serviceLabels[svc] || svc}
-
- ))
- ) : (
- Object.entries(property.services).map(([key, value]) => {
- if (!value) return null;
- const detail = typeof value === 'object' && value.detail ? value.detail : (typeof value === 'string' ? value : null);
- return (
-
- {serviceLabels[key] || key}
- {detail && · {detail}}
-
- );
- })
- )}
+ {property.services &&
+ (Array.isArray(property.services)
+ ? property.services.length > 0
+ : Object.keys(property.services).length > 0) && (
+
+
+ الخدمات المتوفرة
+
+
+ {Array.isArray(property.services)
+ ? property.services.map((svc, i) => (
+
+ {serviceLabels[svc] || svc}
+
+ ))
+ : Object.entries(property.services).map(([key, value]) => {
+ if (!value) return null;
+ const detail =
+ typeof value === "object" && value.detail
+ ? value.detail
+ : typeof value === "string"
+ ? value
+ : null;
+ return (
+
+ {serviceLabels[key] || key}
+ {detail && (
+ · {detail}
+ )}
+
+ );
+ })}
+
-
- )}
+ )}
{property.terms && Object.keys(property.terms).length > 0 && (
@@ -294,13 +366,18 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
{Object.entries(property.terms).map(([key, value]) => {
if (!value) return null;
return (
-
- {key.startsWith('No') || key.startsWith('Only') ? (
+
+ {key.startsWith("No") || key.startsWith("Only") ? (
) : (
)}
- {termLabels[key] || key}
+
+ {termLabels[key] || key}
+
);
})}
@@ -310,43 +387,56 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
معلومات السعر
- {property.purpose === 'rent' ? (
+ {property.purpose === "rent" ? (
{property.dailyPrice > 0 && (
السعر اليومي:
- {Number(property.dailyPrice).toLocaleString()} ل.س
+
+ {Number(property.dailyPrice).toLocaleString()} ل.س
+
)}
{property.monthlyPrice > 0 && (
السعر الشهري:
- {Number(property.monthlyPrice).toLocaleString()} ل.س
+
+ {Number(property.monthlyPrice).toLocaleString()} ل.س
+
)}
{property.deposit > 0 && (
التأمين:
- {Number(property.deposit).toLocaleString()} ل.س
+
+ {Number(property.deposit).toLocaleString()} ل.س
+
)}
- نوع الإيجار: {
- property.rentType === 'daily' ? 'يومي' :
- property.rentType === 'monthly' ? 'شهري' : 'يومي وشهري'
- }
+ نوع الإيجار:{" "}
+ {property.rentType === "daily"
+ ? "يومي"
+ : property.rentType === "monthly"
+ ? "شهري"
+ : "يومي وشهري"}
{property.rating > 0 && (
التقييم:
- {Number(property.rating).toFixed(1)}
+
+ {Number(property.rating).toFixed(1)}{" "}
+
+
)}
) : (
سعر البيع:
- {Number(property.salePrice).toLocaleString()} ل.س
+
+ {Number(property.salePrice).toLocaleString()} ل.س
+
)}
@@ -364,70 +454,69 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
const sections = [
{
- title: 'معلومات أساسية',
+ title: "معلومات أساسية",
fields: [
- { id: 'title', label: 'عنوان العقار', type: 'text' },
- { id: 'description', label: 'الوصف', type: 'textarea' },
- {
- id: 'propertyType',
- label: 'نوع العقار',
- type: 'select',
+ { id: "title", label: "عنوان العقار", type: "text" },
+ { id: "description", label: "الوصف", type: "textarea" },
+ {
+ id: "propertyType",
+ label: "نوع العقار",
+ type: "select",
options: [
- { value: 'apartment', label: 'شقة' },
- { value: 'villa', label: 'فيلا' },
- { value: 'suite', label: 'سويت' },
- { value: 'room', label: 'غرفة ضمن شقة' }
- ],
-
+ { value: "apartment", label: "شقة" },
+ { value: "villa", label: "فيلا" },
+ { value: "suite", label: "سويت" },
+ { value: "room", label: "غرفة ضمن شقة" },
+ ],
},
- {
- id: 'furnished',
- label: 'حالة العقار',
- type: 'radio',
+ {
+ id: "furnished",
+ label: "حالة العقار",
+ type: "radio",
options: [
- { value: true, label: 'مفروش' },
- { value: false, label: 'غير مفروش' }
- ],
-
- }
- ]
+ { value: true, label: "مفروش" },
+ { value: false, label: "غير مفروش" },
+ ],
+ },
+ ],
},
{
- title: 'التفاصيل',
+ title: "التفاصيل",
fields: [
- { id: 'bedrooms', label: 'عدد الغرف', type: 'number' },
- { id: 'bathrooms', label: 'عدد الحمامات', type: 'number' },
- { id: 'livingRooms', label: 'عدد الصالونات', type: 'number' },
- { id: 'area', label: 'المساحة (م²)', type: 'number' }
- ]
+ { id: "bedrooms", label: "عدد الغرف", type: "number" },
+ { id: "bathrooms", label: "عدد الحمامات", type: "number" },
+ { id: "livingRooms", label: "عدد الصالونات", type: "number" },
+ { id: "area", label: "المساحة (م²)", type: "number" },
+ ],
},
{
- title: 'الموقع',
+ title: "الموقع",
fields: [
- { id: 'address', label: 'العنوان الكامل', type: 'text' },
- { id: 'city', label: 'المدينة', type: 'text' },
- { id: 'district', label: 'الحي', type: 'text' }
- ]
+ { id: "address", label: "العنوان الكامل", type: "text" },
+ { id: "city", label: "المدينة", type: "text" },
+ { id: "district", label: "الحي", type: "text" },
+ ],
},
{
- title: 'السعر',
- fields: formData?.purpose === 'rent' ? [
- { id: 'dailyPrice', label: 'السعر اليومي', type: 'number' },
- { id: 'monthlyPrice', label: 'السعر الشهري', type: 'number' },
- {
- id: 'rentType',
- label: 'نوع الإيجار',
- type: 'select',
- options: [
- { value: 'daily', label: 'يومي' },
- { value: 'monthly', label: 'شهري' },
- { value: 'both', label: 'يومي وشهري' }
- ],
- }
- ] : [
- { id: 'salePrice', label: 'سعر البيع', type: 'number' }
- ]
- }
+ title: "السعر",
+ fields:
+ formData?.purpose === "rent"
+ ? [
+ { id: "dailyPrice", label: "السعر اليومي", type: "number" },
+ { id: "monthlyPrice", label: "السعر الشهري", type: "number" },
+ {
+ id: "rentType",
+ label: "نوع الإيجار",
+ type: "select",
+ options: [
+ { value: "daily", label: "يومي" },
+ { value: "monthly", label: "شهري" },
+ { value: "both", label: "يومي وشهري" },
+ ],
+ },
+ ]
+ : [{ id: "salePrice", label: "سعر البيع", type: "number" }],
+ },
];
const startEditing = (fieldId) => {
@@ -443,11 +532,13 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
const saveField = (fieldId) => {
setFormData({
...formData,
- [fieldId]: tempValues[fieldId]
+ [fieldId]: tempValues[fieldId],
});
setEditingField(null);
setTempValues({});
- const fieldLabel = sections.flatMap(s => s.fields).find(f => f.id === fieldId)?.label;
+ const fieldLabel = sections
+ .flatMap((s) => s.fields)
+ .find((f) => f.id === fieldId)?.label;
toast.success(`تم تحديث ${fieldLabel}`);
};
@@ -457,12 +548,12 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
const handleSave = () => {
setIsSaving(true);
-
+
setTimeout(() => {
onSave(formData);
setIsSaving(false);
onClose();
- toast.success('تم تحديث العقار بنجاح');
+ toast.success("تم تحديث العقار بنجاح");
}, 1000);
};
@@ -486,7 +577,9 @@ const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
تعديل العقار
-
قم بتحديث معلومات العقار
+
+ قم بتحديث معلومات العقار
+
{
{sections.map((section, sectionIndex) => (
-
{section.title}
+
+ {section.title}
+
{section.fields.map((field) => (
-
+