This commit is contained in:
@ -17,7 +17,11 @@ export const useFavorites = () => {
|
|||||||
function mapApiFavorite(item) {
|
function mapApiFavorite(item) {
|
||||||
const info = item.propertyInformation || {};
|
const info = item.propertyInformation || {};
|
||||||
let details = {};
|
let details = {};
|
||||||
|
if (typeof info.detailsJSON === 'object' && info.detailsJSON) {
|
||||||
|
details = info.detailsJSON;
|
||||||
|
} else {
|
||||||
try { details = JSON.parse(info.detailsJSON || '{}'); } catch {}
|
try { details = JSON.parse(info.detailsJSON || '{}'); } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
const price = item.monthlyRent || item.dailyRent || 0;
|
const price = item.monthlyRent || item.dailyRent || 0;
|
||||||
const priceUnit = item.monthlyRent ? 'monthly' : 'daily';
|
const priceUnit = item.monthlyRent ? 'monthly' : 'daily';
|
||||||
|
|||||||
@ -46,6 +46,11 @@ import {
|
|||||||
Star,
|
Star,
|
||||||
Ban,
|
Ban,
|
||||||
Check,
|
Check,
|
||||||
|
School,
|
||||||
|
Hospital,
|
||||||
|
Store,
|
||||||
|
GraduationCap,
|
||||||
|
TreePine,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import toast, { Toaster } from "react-hot-toast";
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
import AuthService from "../../services/AuthService";
|
import AuthService from "../../services/AuthService";
|
||||||
@ -153,6 +158,21 @@ const termLabels = {
|
|||||||
OnlyMales: "ذكور فقط",
|
OnlyMales: "ذكور فقط",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const proximityLabels = {
|
||||||
|
School: "مدرسة",
|
||||||
|
Hospital: "مستشفى",
|
||||||
|
Restaurant: "مطعم",
|
||||||
|
University: "جامعة",
|
||||||
|
Park: "حديقة",
|
||||||
|
Mall: "مركز تسوق",
|
||||||
|
Supermarket: "سوبر ماركت",
|
||||||
|
Pharmacy: "صيدلية",
|
||||||
|
Mosque: "مسجد",
|
||||||
|
Bank: "بنك",
|
||||||
|
Airport: "مطار",
|
||||||
|
BusStation: "موقف باص",
|
||||||
|
};
|
||||||
|
|
||||||
const PropertyViewModal = ({ isOpen, onClose, property }) => {
|
const PropertyViewModal = ({ isOpen, onClose, property }) => {
|
||||||
if (!isOpen || !property) return null;
|
if (!isOpen || !property) return null;
|
||||||
|
|
||||||
@ -220,6 +240,30 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
|
|||||||
{property.propertyTypeLabel || "عقار"}
|
{property.propertyTypeLabel || "عقار"}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
<p className="text-sm">
|
||||||
|
<span className="text-gray-500">نوع العرض:</span>
|
||||||
|
<span className="font-medium text-gray-900 mr-2">
|
||||||
|
{property.displayType === "Daily rent"
|
||||||
|
? "إيجار يومي"
|
||||||
|
: property.displayType === "Monthly rent"
|
||||||
|
? "إيجار شهري"
|
||||||
|
: property.displayType === "Both"
|
||||||
|
? "يومي وشهري"
|
||||||
|
: property.displayType === "For sale"
|
||||||
|
? "للبيع"
|
||||||
|
: property.rentType === "daily"
|
||||||
|
? "إيجار يومي"
|
||||||
|
: property.rentType === "monthly"
|
||||||
|
? "إيجار شهري"
|
||||||
|
: (property.dailyPrice > 0 && property.monthlyPrice > 0)
|
||||||
|
? "يومي وشهري"
|
||||||
|
: property.monthlyPrice > 0
|
||||||
|
? "إيجار شهري"
|
||||||
|
: property.dailyPrice > 0
|
||||||
|
? "إيجار يومي"
|
||||||
|
: property.purpose === "sale" ? "للبيع" : "عرض"}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
{property.purpose === "rent" && (
|
{property.purpose === "rent" && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
<span className="text-gray-500">حالة التأثيث:</span>
|
<span className="text-gray-500">حالة التأثيث:</span>
|
||||||
@ -359,6 +403,36 @@ const PropertyViewModal = ({ isOpen, onClose, property }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{property.proximity && Object.keys(property.proximity).length > 0 && (
|
||||||
|
<div className="bg-gray-50 p-4 rounded-xl mb-6">
|
||||||
|
<h4 className="font-bold text-gray-700 mb-3">القرب من الخدمات</h4>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
|
||||||
|
{Object.entries(property.proximity).map(([key, val]) => {
|
||||||
|
if (!val) return null;
|
||||||
|
const dist = typeof val === "object" ? val.distance : val;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className="flex items-center gap-2 p-2 bg-white rounded-lg"
|
||||||
|
>
|
||||||
|
{key === "School" && <School className="w-4 h-4 text-amber-500" />}
|
||||||
|
{key === "Hospital" && <Hospital className="w-4 h-4 text-amber-500" />}
|
||||||
|
{key === "Restaurant" && <Store className="w-4 h-4 text-amber-500" />}
|
||||||
|
{key === "University" && <GraduationCap className="w-4 h-4 text-amber-500" />}
|
||||||
|
{key === "Park" && <TreePine className="w-4 h-4 text-amber-500" />}
|
||||||
|
{key === "Mall" && <Building className="w-4 h-4 text-amber-500" />}
|
||||||
|
{!["School","Hospital","Restaurant","University","Park","Mall"].includes(key) && <MapPin className="w-4 h-4 text-amber-500" />}
|
||||||
|
<div>
|
||||||
|
<span className="text-sm text-gray-700">{proximityLabels[key] || key}</span>
|
||||||
|
<span className="text-xs text-gray-500 mr-1">{dist} {typeof dist === "number" ? "كم" : ""}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{property.terms && Object.keys(property.terms).length > 0 && (
|
{property.terms && Object.keys(property.terms).length > 0 && (
|
||||||
<div className="bg-gray-50 p-4 rounded-xl mb-6">
|
<div className="bg-gray-50 p-4 rounded-xl mb-6">
|
||||||
<h4 className="font-bold text-gray-700 mb-3">شروط الاستخدام</h4>
|
<h4 className="font-bold text-gray-700 mb-3">شروط الاستخدام</h4>
|
||||||
@ -956,7 +1030,7 @@ export default function OwnerPropertiesPage() {
|
|||||||
|
|
||||||
const mappedRent = rentList.map((item) => {
|
const mappedRent = rentList.map((item) => {
|
||||||
const info = item.propertyInformation || {};
|
const info = item.propertyInformation || {};
|
||||||
const details = (() => {
|
const details = typeof info.detailsJSON === 'object' && info.detailsJSON ? info.detailsJSON : (() => {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(info.detailsJSON || "{}");
|
return JSON.parse(info.detailsJSON || "{}");
|
||||||
} catch {
|
} catch {
|
||||||
@ -1037,6 +1111,7 @@ export default function OwnerPropertiesPage() {
|
|||||||
: ["/property-placeholder.jpg"],
|
: ["/property-placeholder.jpg"],
|
||||||
createdAt: item.createdAt || new Date().toISOString(),
|
createdAt: item.createdAt || new Date().toISOString(),
|
||||||
furnished: details.furnished || false,
|
furnished: details.furnished || false,
|
||||||
|
displayType: details.displayType || (item.dailyRent && item.monthlyRent ? 'Both' : item.monthlyRent ? 'Monthly rent' : item.dailyRent ? 'Daily rent' : 'Both'),
|
||||||
description: info.description || "",
|
description: info.description || "",
|
||||||
address: info.address || "",
|
address: info.address || "",
|
||||||
city: "",
|
city: "",
|
||||||
@ -1052,7 +1127,7 @@ export default function OwnerPropertiesPage() {
|
|||||||
|
|
||||||
const mappedSale = saleList.map((item) => {
|
const mappedSale = saleList.map((item) => {
|
||||||
const info = item.propertyInformation || {};
|
const info = item.propertyInformation || {};
|
||||||
const details = (() => {
|
const details = typeof info.detailsJSON === 'object' && info.detailsJSON ? info.detailsJSON : (() => {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(info.detailsJSON || "{}");
|
return JSON.parse(info.detailsJSON || "{}");
|
||||||
} catch {
|
} catch {
|
||||||
@ -1125,6 +1200,7 @@ export default function OwnerPropertiesPage() {
|
|||||||
: ["/property-placeholder.jpg"],
|
: ["/property-placeholder.jpg"],
|
||||||
createdAt: item.createdAt || new Date().toISOString(),
|
createdAt: item.createdAt || new Date().toISOString(),
|
||||||
furnished: details.furnished || false,
|
furnished: details.furnished || false,
|
||||||
|
displayType: details.displayType || 'For sale',
|
||||||
description: info.description || "",
|
description: info.description || "",
|
||||||
address: info.address || "",
|
address: info.address || "",
|
||||||
city: "",
|
city: "",
|
||||||
|
|||||||
@ -75,7 +75,7 @@ const proximityLabels = {
|
|||||||
function mapApiDetail(item) {
|
function mapApiDetail(item) {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
const info = item.propertyInformation || {};
|
const info = item.propertyInformation || {};
|
||||||
const details = (() => { try { return JSON.parse(info.detailsJSON || '{}'); } catch { return {}; } })();
|
const details = typeof info.detailsJSON === 'object' && info.detailsJSON ? info.detailsJSON : (() => { try { return JSON.parse(info.detailsJSON || '{}'); } catch { return {}; } })();
|
||||||
|
|
||||||
const isRent = item.dailyRent != null || item.monthlyRent != null;
|
const isRent = item.dailyRent != null || item.monthlyRent != null;
|
||||||
const dailyPrice = item.dailyRent || 0;
|
const dailyPrice = item.dailyRent || 0;
|
||||||
@ -117,6 +117,10 @@ function mapApiDetail(item) {
|
|||||||
});
|
});
|
||||||
const roomDetails = details.room || details.roomDetails || {};
|
const roomDetails = details.room || details.roomDetails || {};
|
||||||
|
|
||||||
|
const displayType = details.displayType || (isRent ? (monthlyPrice && dailyPrice ? 'Both' : monthlyPrice ? 'Monthly' : 'Daily') : 'Sale');
|
||||||
|
const propertyCondition = details.propertyCondition || '';
|
||||||
|
const furnished = propertyCondition.toLowerCase().includes('furniture') ? propertyCondition.toLowerCase() === 'withfurniture' : !!item.isFurnished;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
propertyInformationId: info.id,
|
propertyInformationId: info.id,
|
||||||
@ -128,6 +132,9 @@ function mapApiDetail(item) {
|
|||||||
priceUnit,
|
priceUnit,
|
||||||
priceDisplay: { daily: dailyPrice, monthly: monthlyPrice, sale: salePrice },
|
priceDisplay: { daily: dailyPrice, monthly: monthlyPrice, sale: salePrice },
|
||||||
isRent,
|
isRent,
|
||||||
|
displayType,
|
||||||
|
propertyCondition,
|
||||||
|
furnished,
|
||||||
location: {
|
location: {
|
||||||
city: extractCity(info.address) || 'دمشق',
|
city: extractCity(info.address) || 'دمشق',
|
||||||
address: info.address || '',
|
address: info.address || '',
|
||||||
@ -374,9 +381,23 @@ export default function PropertyDetailsPage() {
|
|||||||
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="bg-white rounded-2xl p-5 shadow-sm border border-gray-200">
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="bg-white rounded-2xl p-5 shadow-sm border border-gray-200">
|
||||||
<div className="flex justify-between items-start mb-3">
|
<div className="flex justify-between items-start mb-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-1.5 mb-1 flex-wrap">
|
||||||
<span className="px-2 py-0.5 bg-amber-100 text-amber-800 rounded-full text-xs">{property.typeLabel}</span>
|
<span className="px-2 py-0.5 bg-amber-100 text-amber-800 rounded-full text-xs">{property.typeLabel}</span>
|
||||||
<span className={`px-2 py-0.5 rounded-full text-xs ${property.status === 'available' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'}`}>{property.statusLabel}</span>
|
<span className={`px-2 py-0.5 rounded-full text-xs ${property.status === 'available' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'}`}>{property.statusLabel}</span>
|
||||||
|
{property.isRent && property.displayType && (
|
||||||
|
<span className="px-2 py-0.5 bg-blue-100 text-blue-800 rounded-full text-xs">
|
||||||
|
{(() => {
|
||||||
|
const dt = property.displayType.toLowerCase();
|
||||||
|
if (dt === 'both' || dt.includes('both')) return 'يومي وشهري';
|
||||||
|
if (dt.includes('daily')) return 'يومي';
|
||||||
|
if (dt.includes('monthly')) return 'شهري';
|
||||||
|
return dt;
|
||||||
|
})()}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className={`px-2 py-0.5 rounded-full text-xs ${property.furnished ? 'bg-purple-100 text-purple-800' : 'bg-gray-100 text-gray-600'}`}>
|
||||||
|
{property.furnished ? 'مفروش' : 'غير مفروش'}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-xl font-bold text-gray-900">{property.title}</h1>
|
<h1 className="text-xl font-bold text-gray-900">{property.title}</h1>
|
||||||
<div className="flex items-center gap-1 text-gray-500 text-xs mt-0.5">
|
<div className="flex items-center gap-1 text-gray-500 text-xs mt-0.5">
|
||||||
|
|||||||
@ -19,7 +19,13 @@ async function fetchPropertyForMeta(id) {
|
|||||||
function mapProperty(item) {
|
function mapProperty(item) {
|
||||||
const info = item.propertyInformation || item.PropertyInformation || {};
|
const info = item.propertyInformation || item.PropertyInformation || {};
|
||||||
let details = {};
|
let details = {};
|
||||||
|
if (typeof info.detailsJSON === 'object' && info.detailsJSON) {
|
||||||
|
details = info.detailsJSON;
|
||||||
|
} else if (typeof info.DetailsJSON === 'object' && info.DetailsJSON) {
|
||||||
|
details = info.DetailsJSON;
|
||||||
|
} else {
|
||||||
try { details = JSON.parse(info.detailsJSON || info.DetailsJSON || '{}'); } catch {}
|
try { details = JSON.parse(info.detailsJSON || info.DetailsJSON || '{}'); } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
const price = item.monthlyRent || item.MonthlyRent || item.dailyRent || item.DailyRent || 0;
|
const price = item.monthlyRent || item.MonthlyRent || item.dailyRent || item.DailyRent || 0;
|
||||||
const priceUnit = item.monthlyRent || item.MonthlyRent ? 'monthly' : 'daily';
|
const priceUnit = item.monthlyRent || item.MonthlyRent ? 'monthly' : 'daily';
|
||||||
|
|||||||
Reference in New Issue
Block a user