diff --git a/app/components/FloatingSidebar.js b/app/components/FloatingSidebar.js index 4e30afc..c9b8b77 100644 --- a/app/components/FloatingSidebar.js +++ b/app/components/FloatingSidebar.js @@ -27,14 +27,14 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { if (!AuthService.isAuthenticated()) return null; - const positionStyle = { - left: '24px', + const positionStyle = { + left: '16px', top: '50%', transform: 'translateY(-50%)', }; const cardVariants = { - initial: { opacity: 0, x: isRTL ? -20 : 20 }, + initial: { opacity: 0, x: 20 }, animate: { opacity: 1, x: 0, transition: { duration: 0.4, ease: 'easeOut' } }, }; @@ -47,17 +47,8 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { const renderTooltip = (id, label) => { if (tooltip !== id) return null; return ( -
- - {label} - - +
+ {label}
); }; @@ -70,7 +61,7 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { initial="initial" animate="animate" > -
+
{isAdmin ? ( <> - + {renderTooltip('addAdmin', 'إضافة أدمن')} @@ -102,9 +93,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('editPrivacy', 'تعديل سياسة الخصوصية')} @@ -122,15 +113,15 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { >
- + {favorites.length > 0 && ( {favorites.length} @@ -150,15 +141,15 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { >
- + {unreadCount > 0 && ( {unreadCount} @@ -178,9 +169,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('payments', 'المدفوعات')} @@ -195,9 +186,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('booked', 'حجوزاتي')} @@ -212,9 +203,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('myRates', 'تقييماتي')} @@ -229,9 +220,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('reports', 'البلاغات')} @@ -246,9 +237,9 @@ export default function FloatingSidebar({ isRTL, isAdmin }) { > - + {renderTooltip('settings', 'الإعدادات')} diff --git a/app/owner/properties/page.js b/app/owner/properties/page.js index b6fc349..e2aa893 100644 --- a/app/owner/properties/page.js +++ b/app/owner/properties/page.js @@ -688,11 +688,16 @@ export default function OwnerPropertiesPage() { const [properties, setProperties] = useState([]); const [isLoading, setIsLoading] = useState(true); const [showAddMenu, setShowAddMenu] = useState(false); + const [activeTab, setActiveTab] = useState('rent'); const [deleteModal, setDeleteModal] = useState({ isOpen: false, property: null }); const [viewModal, setViewModal] = useState({ isOpen: false, property: null }); const [editModal, setEditModal] = useState({ isOpen: false, property: null }); + const filteredProperties = properties.filter(p => p.purpose === activeTab); + const rentCount = properties.filter(p => p.purpose === 'rent').length; + const saleCount = properties.filter(p => p.purpose === 'sale').length; + useEffect(() => { const authUser = AuthService.getUser(); if (authUser && AuthService.isOwner()) { @@ -740,7 +745,8 @@ export default function OwnerPropertiesPage() { return { id: item.id, title: info.address || `عقار #${item.id}`, - propertyType: { 0: 'apartment', 1: 'villa', 2: 'house' }[info.buildingType] || 'apartment', + propertyType: { 0: 'apartment', 1: 'villa', 2: 'sweet', 3: 'room', 4: 'studio', 5: 'office', 6: 'farms', 7: 'shop', 8: 'warehouse' }[info.buildingType] || 'apartment', + propertyTypeLabel: { 0: 'شقة', 1: 'فيلا', 2: 'سويت', 3: 'غرفة', 4: 'استوديو', 5: 'مكتب', 6: 'مزرعة', 7: 'متجر', 8: 'مستودع' }[info.buildingType] || 'عقار', purpose: 'rent', rentType: { 0: 'daily', 1: 'monthly' }[item.rentType] || 'daily', dailyPrice: item.dailyRent || 0, @@ -776,7 +782,8 @@ export default function OwnerPropertiesPage() { return { id: item.id, title: info.address || `عقار للبيع #${item.id}`, - propertyType: { 0: 'apartment', 1: 'villa', 2: 'house' }[info.buildingType] || 'apartment', + propertyType: { 0: 'apartment', 1: 'villa', 2: 'sweet', 3: 'room', 4: 'studio', 5: 'office', 6: 'farms', 7: 'shop', 8: 'warehouse' }[info.buildingType] || 'apartment', + propertyTypeLabel: { 0: 'شقة', 1: 'فيلا', 2: 'سويت', 3: 'غرفة', 4: 'استوديو', 5: 'مكتب', 6: 'مزرعة', 7: 'متجر', 8: 'مستودع' }[info.buildingType] || 'عقار', purpose: 'sale', dailyPrice: 0, monthlyPrice: 0, @@ -986,7 +993,27 @@ export default function OwnerPropertiesPage() {
- {properties.length === 0 ? ( + {/* Tab Switcher */} +
+ + +
+ + {filteredProperties.length === 0 ? (
-

لا توجد عقارات بعد

-

ابدأ بإضافة أول عقار لك الآن

+

+ {activeTab === 'rent' ? 'لا توجد عقارات للإيجار' : 'لا توجد عقارات للبيع'} +

+

ابدأ بإضافة أول عقار {activeTab === 'rent' ? 'للإيجار' : 'للبيع'} الآن

@@ -1007,7 +1036,7 @@ export default function OwnerPropertiesPage() { ) : (
- {properties.map((property, index) => ( + {filteredProperties.map((property, index) => (
)} -
- + {property.status === 'available' ? 'متاح' : 'مؤجر'} + {property.purpose === 'rent' && property.furnished && ( + + مفروش + + )} + {property.purpose === 'rent' && !property.furnished && property.furnished !== undefined && ( + + غير مفروش + + )}
+
+ {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}

@@ -1060,6 +1102,12 @@ export default function OwnerPropertiesPage() { {property.area}م²
+ {property.rating > 0 && ( +
+ + {property.rating.toFixed(1)} +
+ )}
diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js index acc6c02..786d4ff 100644 --- a/app/property/[id]/PropertyDetail.js +++ b/app/property/[id]/PropertyDetail.js @@ -94,13 +94,25 @@ function mapApiDetail(item) { const allRaw = rawImages.length > 0 ? rawImages : photosFallback; const images = allRaw.length > 0 ? allRaw.map(buildImageUrl) : []; - const services = details.services || {}; + // Normalize services: Flutter sends list of strings or object with boolean values + 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; }); + const terms = details.terms || {}; - const proximity = details.proximity || {}; - const roomDetails = details.roomDetails || {}; + + // Try multiple key aliases like Flutter does + const floor = details.floorNumber ?? details.floor ?? 0; + const salons = details.numberOfSalons ?? details.salonsCount ?? details.salons ?? 0; + const balconies = details.numberOfBalconies ?? details.balconiesCount ?? details.balconies ?? 0; + const proximity = details.nearbyDistances || details.proximity || {}; + const roomDetails = details.room || details.roomDetails || {}; return { id: item.id, + propertyInformationId: info.id, title: details.description || info.address || `عقار #${item.id}`, description: details.description || info.description || '', type: propType, @@ -118,9 +130,9 @@ function mapApiDetail(item) { bedrooms: info.numberOfBedRooms || 0, bathrooms: info.numberOfBathRooms || 0, area: info.space || 0, - floor: details.floor || 0, - salons: details.salons || 0, - balconies: details.balconies || 0, + floor, + salons, + balconies, images, status, statusLabel, @@ -499,66 +511,31 @@ export default function PropertyDetailsPage() { تفاصيل الغرفة
- {property.roomDetails.areaType && ( -
-
نوع المساحة
-
{property.roomDetails.areaType}
-
- )} - {property.roomDetails.peopleAllowed && ( -
-
عدد الأشخاص
-
{property.roomDetails.peopleAllowed}
-
- )} - {property.roomDetails.furniture && ( -
-
الأثاث
-
{property.roomDetails.furniture}
-
- )} - {property.roomDetails.entranceType && ( -
-
نوع المدخل
-
{property.roomDetails.entranceType}
-
- )} - {property.roomDetails.bathroomType && ( -
-
الحمام
-
{property.roomDetails.bathroomType}
-
- )} - {property.roomDetails.kitchenType && ( -
-
المطبخ
-
{property.roomDetails.kitchenType}
-
- )} - {property.roomDetails.residents && ( -
-
عدد السكان
-
{property.roomDetails.residents}
-
- )} - {property.roomDetails.dedicatedTo && ( -
-
مخصص لـ
-
{property.roomDetails.dedicatedTo}
-
- )} - {property.roomDetails.visitors && ( -
-
الزوار
-
{property.roomDetails.visitors ? 'مسموح' : 'ممنوع'}
-
- )} - {property.roomDetails.quietTimes && ( -
-
أوقات الهدوء
-
{property.roomDetails.quietTimes}
-
- )} + {(() => { + const rd = property.roomDetails; + const items = []; + if (rd.areaType) items.push({ label: 'نوع المساحة', value: rd.areaType === 'private room' ? 'غرفة خاصة' : rd.areaType === 'shared room' ? 'غرفة مشتركة' : rd.areaType }); + if (rd.peopleAllowed) items.push({ label: 'عدد الأشخاص', value: rd.peopleAllowed }); + if (rd.furnitureDetails || rd.furniture) items.push({ label: 'الأثاث', value: rd.furnitureDetails || rd.furniture }); + if (rd.entranceType) items.push({ label: 'نوع المدخل', value: rd.entranceType === 'shared entrance' ? 'مدخل مشترك' : rd.entranceType === 'independent entrance' ? 'مدخل مستقل' : rd.entranceType }); + if (rd.bathroomType) items.push({ label: 'الحمام', value: rd.bathroomType === 'room specific' ? 'خاص بالغرفة' : rd.bathroomType === 'shared' ? 'مشترك' : rd.bathroomType }); + if (rd.kitchenType) items.push({ label: 'المطبخ', value: rd.kitchenType === 'shared' ? 'مشترك' : rd.kitchenType === 'not available' ? 'غير متوفر' : rd.kitchenType }); + if (rd.homeResidentsCount ?? rd.residents) items.push({ label: 'عدد السكان', value: rd.homeResidentsCount ?? rd.residents }); + if (rd.currentPopulationGender) items.push({ label: 'جنس السكان', value: rd.currentPopulationGender === 'men' ? 'رجال' : rd.currentPopulationGender === 'women' ? 'نساء' : rd.currentPopulationGender === 'family' ? 'عائلة' : rd.currentPopulationGender }); + if (rd.dedicatedTo) items.push({ label: 'مخصص لـ', value: rd.dedicatedTo === 'men only' ? 'رجال فقط' : rd.dedicatedTo === 'women only' ? 'نساء فقط' : rd.dedicatedTo === 'families only' ? 'عائلات فقط' : rd.dedicatedTo === 'everyone' ? 'الجميع' : rd.dedicatedTo }); + if (rd.hasRestrictedOwnerAreas !== undefined) items.push({ label: 'مناطق ممنوعة', value: rd.hasRestrictedOwnerAreas ? 'نعم' : 'لا' }); + if (rd.hasChildren !== undefined) items.push({ label: 'أطفال', value: rd.hasChildren ? 'مسموح' : 'غير مسموح' }); + if (rd.hasPets !== undefined) items.push({ label: 'حيوانات أليفة', value: rd.hasPets ? 'مسموح' : 'غير مسموح' }); + if (rd.languageDialect) items.push({ label: 'اللغة', value: rd.languageDialect }); + if (rd.visitorsAllowed !== undefined) items.push({ label: 'الزوار', value: rd.visitorsAllowed ? 'مسموح' : 'ممنوع' }); + if (rd.quietTimesEnabled ?? rd.quietTimes) items.push({ label: 'أوقات الهدوء', value: rd.quietTimesDetails || rd.quietTimes || (rd.quietTimesEnabled ? 'مفعلة' : '') }); + return items.map((item, i) => ( +
+
{item.label}
+
{item.value}
+
+ )); + })()}
)}