"use client";
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { useTranslation } from "react-i18next";
import {
PlusCircle,
Building,
Home,
DollarSign,
MapPin,
Bed,
Bath,
Square,
Edit,
Trash2,
Eye,
Calendar,
TrendingUp,
Users,
FileText,
Image as ImageIcon,
CheckCircle,
XCircle,
AlertCircle,
ChevronRight,
ChevronLeft,
Loader2,
Clock,
Wifi,
Zap,
Flame,
Droplets,
Cigarette,
Dog,
Music,
Warehouse,
Layers,
Sofa,
DoorOpen,
Wind,
Pencil,
Save,
X,
Star,
Ban,
Check,
School,
Hospital,
Store,
GraduationCap,
TreePine,
} from "lucide-react";
import toast, { Toaster } from "react-hot-toast";
import AuthService from "../../services/AuthService";
import {
buildRentPropertyPayload,
getMyRentListings,
getMySaleListings,
editRentProperty,
editSaleProperty,
updateRentPropertyStatus,
updateSalePropertyStatus,
} from "../../utils/api";
import { PropertyService } from "../../enums/PropertyService";
import { PropertyTerm } from "../../enums/PropertyTerm";
const serviceI18nKeys = {
[PropertyService.ELECTRICITY]: "propertyService.electricity",
[PropertyService.INTERNET]: "propertyService.internet",
[PropertyService.HEATING]: "propertyService.heating",
[PropertyService.WATER]: "propertyService.water",
[PropertyService.POOL]: "propertyService.pool",
[PropertyService.PRIVATE_GARDEN]: "propertyService.privateGarden",
[PropertyService.PARKING]: "propertyService.parking",
[PropertyService.SECURITY_247]: "propertyService.security247",
[PropertyService.CENTRAL_HEATING]: "propertyService.centralHeating",
[PropertyService.CENTRAL_AIR_CONDITIONING]: "propertyService.centralAirConditioning",
[PropertyService.EQUIPPED_KITCHEN]: "propertyService.equippedKitchen",
[PropertyService.MAIDS_ROOM]: "propertyService.maidsRoom",
[PropertyService.ELEVATOR]: "propertyService.elevator",
};
const termI18nKeys = {
[PropertyTerm.NO_SMOKING]: "propertyTerm.noSmoking",
[PropertyTerm.NO_ANIMALS]: "propertyTerm.noAnimals",
[PropertyTerm.NO_PARTIES]: "propertyTerm.noParties",
};
const proximityI18nKeys = {
School: "proximity.school",
Hospital: "proximity.hospital",
Restaurant: "proximity.restaurant",
University: "proximity.university",
Park: "proximity.park",
Mall: "proximity.mall",
Supermarket: "proximity.supermarket",
Pharmacy: "proximity.pharmacy",
Mosque: "proximity.mosque",
Bank: "proximity.bank",
Airport: "proximity.airport",
BusStation: "proximity.busStation",
};
const DeleteConfirmationModal = ({
isOpen,
onClose,
onConfirm,
propertyTitle,
}) => {
const { t } = useTranslation();
if (!isOpen) return null;
return (
e.stopPropagation()}
>
{t('deleteConfirmTitle')}
{t('deleteConfirmMessage', { title: propertyTitle })}
{t('deleteIrreversible')}
);
};
const DeactivateConfirmationModal = ({
isOpen,
onClose,
onConfirm,
propertyTitle,
isActivating,
}) => {
const { t } = useTranslation();
if (!isOpen) return null;
return (
e.stopPropagation()}
>
{isActivating ? t('activateTitle') : t('deactivateTitle')}
"{propertyTitle}"
{!isActivating ? (
⚠️ {t('warning')}
{t('deactivateWarning')}
) : (
✅ {t('activateInfoTitle')}
{t('activateInfo')}
)}
);
};
const PropertyViewModal = ({ isOpen, onClose, property }) => {
const { t } = useTranslation();
if (!isOpen || !property) return null;
return (
e.stopPropagation()}
>
{property.title}
{t('addedOn')}
{new Date(property.createdAt).toLocaleDateString("ar-SA")}
{property.images && property.images.length > 0 && (
{t('propertyImages')}
{property.images.map((image, index) => (
))}
)}
{t('basicInfo')}
{t('propertyTypeLabel')}
{property.propertyTypeLabel || t('offer')}
{t('displayTypeLabel')}
{property.displayType === "Daily rent"
? t('dailyRent')
: property.displayType === "Monthly rent"
? t('monthlyRent')
: property.displayType === "Both"
? t('dailyAndMonthly')
: property.displayType === "For sale"
? t('forSale')
: property.rentType === "daily"
? t('dailyRent')
: property.rentType === "monthly"
? t('monthlyRent')
: (property.dailyPrice > 0 && property.monthlyPrice > 0)
? t('dailyAndMonthly')
: property.monthlyPrice > 0
? t('monthlyRent')
: property.dailyPrice > 0
? t('dailyRent')
: property.purpose === "sale" ? t('forSale') : t('offer')}
{property.purpose === "rent" && (
{t('furnishedStatusLabel')}
{property.furnished ? t('furnished') : t('unfurnished')}
)}
{t('propertyStatusLabel')}
{property.status === "available" ? t('available') : t('rented')}
{property.description && (
{t('descriptionLabel')}
{property.description}
)}
{t('basicInfo')}
{property.bedrooms}
{t('rooms')}
{property.bathrooms}
{t('bathrooms')}
{property.area}
{t('sqm')}
{property.floor > 0 && (
{property.floor}
{t('floor')}
)}
{property.salons > 0 && (
{property.salons}
{t('salons')}
)}
{property.balconies > 0 && (
{property.balconies}
{t('balconies')}
)}
{property.bookedCount > 0 && (
{property.bookedCount}
{t('bookings')}
)}
{t('location')}
{property.address || t('addressNotSpecified')}
{property.city && `، ${property.city}`}
{property.district && `، ${property.district}`}
{property.services &&
(Array.isArray(property.services)
? property.services.length > 0
: Object.keys(property.services).length > 0) && (
{t('availableServices')}
{Array.isArray(property.services)
? property.services.map((svc, i) => (
{t(serviceI18nKeys[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 (
{t(serviceI18nKeys[key]) || key}
{detail && (
· {detail}
)}
);
})}
)}
{property.proximity && Object.keys(property.proximity).length > 0 && (
{t('proximityToServices')}
{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) &&
}
{t(proximityI18nKeys[key]) || key}
{dist} {typeof dist === "number" ? t('km') : ""}
);
})}
)}
{property.terms && Object.keys(property.terms).length > 0 && (
{t('termsOfUse')}
{Object.entries(property.terms).map(([key, value]) => {
if (!value) return null;
return (
{key.startsWith("No") || key.startsWith("Only") ? (
) : (
)}
{t(termI18nKeys[key]) || key}
);
})}
)}
{t('priceInfo')}
{property.purpose === "rent" ? (
{property.dailyPrice > 0 && (
{t('dailyPriceLabel')}
{Number(property.dailyPrice).toLocaleString()} {t('syp')}
)}
{property.monthlyPrice > 0 && (
{t('monthlyPriceLabel')}
{Number(property.monthlyPrice).toLocaleString()} {t('syp')}
)}
{property.deposit > 0 && (
{t('depositLabel')}
{Number(property.deposit).toLocaleString()} {t('syp')}
)}
{t('rentTypeLabel')}{" "}
{property.rentType === "daily"
? t('daily')
: property.rentType === "monthly"
? t('monthly')
: t('dailyAndMonthly')}
{property.rating > 0 && (
{t('ratingLabel')}
{Number(property.rating).toFixed(1)}{" "}
)}
) : (
{t('salePriceLabel')}
{Number(property.salePrice).toLocaleString()} {t('syp')}
)}
);
};
const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
const { t } = useTranslation();
const [formData, setFormData] = useState({
propertyType: 'apartment',
furnished: false,
description: '',
bedrooms: 0,
bathrooms: 0,
floor: 0,
salons: 0,
balconies: 0,
livingRooms: 0,
area: 0,
services: {},
serviceDetails: {},
terms: {},
customTerms: [],
nearbySchool: '',
nearbyHospital: '',
nearbyRestaurant: '',
nearbyUniversity: '',
nearbyPark: '',
nearbyMall: '',
purpose: 'rent',
currencyId: 1,
dailyPrice: 0,
monthlyPrice: 0,
deposit: 0,
rentType: 'monthly',
allowedPaymentPeriod: '',
salePrice: 0,
});
const [newCustomTerm, setNewCustomTerm] = useState('');
const [isSaving, setIsSaving] = useState(false);
useEffect(() => {
if (!property || !isOpen) return;
const raw = property._raw || {};
const info = raw.propertyInformation || {};
let details = {};
try {
details =
typeof info.detailsJSON === 'object' && info.detailsJSON
? info.detailsJSON
: JSON.parse(info.detailsJSON || '{}');
} catch {
details = {};
}
const propServices = property.services || {};
const services = {};
const serviceDetails = {};
Object.keys(serviceI18nKeys).forEach((key) => {
const val = propServices[key];
if (val && typeof val === 'string') {
services[key] = true;
serviceDetails[key] = val;
} else if (val && typeof val === 'object' && val.detail) {
services[key] = true;
serviceDetails[key] = val.detail;
} else {
services[key] = !!val;
serviceDetails[key] = details.serviceDetails?.[key] || '';
}
});
const rawSvcArray = Array.isArray(details.services) ? details.services : [];
rawSvcArray.forEach((key) => {
if (!(key in services)) {
services[key] = true;
serviceDetails[key] = details.serviceDetails?.[key] || '';
}
});
const propTerms = property.terms || {};
const terms = {};
Object.keys(termI18nKeys).forEach((key) => {
terms[key] = !!propTerms[key];
});
if (details.terms && typeof details.terms === 'object') {
Object.entries(details.terms).forEach(([key, val]) => {
if (val && !(key in terms)) {
terms[key] = true;
}
});
}
const prox = property.proximity || details.nearbyDistances || {};
setFormData({
propertyType: property.propertyType || 'apartment',
furnished: property.furnished ?? false,
description: property.description || details.description || '',
bedrooms: property.bedrooms || 0,
bathrooms: property.bathrooms || 0,
floor: property.floor ?? details.floorNumber ?? details.floor ?? 0,
salons: property.salons ?? details.numberOfSalons ?? details.salons ?? 0,
balconies:
property.balconies ??
details.numberOfBalconies ??
details.balconies ??
0,
livingRooms: property.livingRooms ?? details.numberOfLivingRooms ?? details.livingRooms ?? 0,
area: property.area || 0,
services,
serviceDetails,
terms,
customTerms: details.customTerms || [],
nearbySchool: prox.School ?? prox.school ?? prox.nearbySchool ?? '',
nearbyHospital: prox.Hospital ?? prox.hospital ?? prox.nearbyHospital ?? '',
nearbyRestaurant: prox.Restaurant ?? prox.restaurant ?? prox.nearbyRestaurant ?? '',
nearbyUniversity: prox.University ?? prox.university ?? prox.nearbyUniversity ?? '',
nearbyPark: prox.Park ?? prox.park ?? prox.nearbyPark ?? '',
nearbyMall: prox.Mall ?? prox.mall ?? prox.nearbyMall ?? '',
purpose: property.purpose || 'rent',
currencyId: property.currencyId || 1,
...(property.purpose === 'rent'
? {
dailyPrice: property.dailyPrice || 0,
monthlyPrice: property.monthlyPrice || 0,
deposit: property.deposit || 0,
rentType: property.rentType || 'monthly',
allowedPaymentPeriod:
property.allowedPaymentPeriod ||
details.allowedPaymentPeriod ||
'',
}
: { salePrice: property.salePrice || 0 }),
});
setNewCustomTerm('');
}, [property, isOpen]);
const handleChange = (field, value) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleServiceToggle = (key, checked) => {
setFormData((prev) => ({
...prev,
services: { ...prev.services, [key]: checked },
}));
};
const handleServiceDetail = (key, value) => {
setFormData((prev) => ({
...prev,
serviceDetails: { ...prev.serviceDetails, [key]: value },
}));
};
const handleTermToggle = (key, checked) => {
setFormData((prev) => ({
...prev,
terms: { ...prev.terms, [key]: checked },
}));
};
const addCustomTerm = () => {
const term = newCustomTerm.trim();
if (!term) return;
setFormData((prev) => ({
...prev,
customTerms: [...(prev.customTerms || []), term],
}));
setNewCustomTerm('');
};
const removeCustomTerm = (index) => {
setFormData((prev) => ({
...prev,
customTerms: prev.customTerms.filter((_, i) => i !== index),
}));
};
const handleSave = async () => {
const errors = [];
if (!formData.description?.trim()) errors.push(t('descriptionRequired') || 'الوصف مطلوب');
if (formData.bedrooms < 1) errors.push(t('bedroomsRequired') || 'يجب أن يكون عدد الغرف على الأقل 1');
if (formData.bathrooms < 1) errors.push(t('bathroomsRequired') || 'يجب أن يكون عدد الحمامات على الأقل 1');
if (!formData.area || formData.area <= 0) errors.push(t('areaRequired') || 'المساحة مطلوبة');
if (formData.purpose === 'rent') {
if ((!formData.dailyPrice || formData.dailyPrice <= 0) && (!formData.monthlyPrice || formData.monthlyPrice <= 0)) {
errors.push(t('priceRequired') || 'يجب إدخال سعر الأجر الشهري أو اليومي');
}
} else if (formData.purpose === 'sale') {
if (!formData.salePrice || formData.salePrice <= 0) errors.push(t('priceRequired') || 'السعر مطلوب');
}
if (errors.length > 0) {
toast.error(errors[0]);
return;
}
setIsSaving(true);
try {
await onSave(formData);
} catch {
setIsSaving(false);
}
};
if (!isOpen || !property) return null;
return (
e.stopPropagation()}
>
{t('editProperty')}
{t('editSubtitle')}
{/* Basic Info */}
{t('basicInfo')}
{/* Details */}
{t('basicInfo')}
{[
{ id: 'bedrooms', label: t('bedroomsCount') },
{ id: 'bathrooms', label: t('bathroomsCount') },
{ id: 'livingRooms', label: t('livingRoomsCount') },
{ id: 'floor', label: t('floorLabel') },
{ id: 'salons', label: t('salonsCount') },
{ id: 'balconies', label: t('balconiesCount') },
{ id: 'area', label: t('areaSqm') },
].map((field) => (
handleChange(field.id, 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"
/>
))}
{/* Services */}
{t('services')}
{Object.entries(serviceI18nKeys).map(([key, i18nKey]) => (
))}
{/* Terms - rent only */}
{formData.purpose === 'rent' && (
)}
{/* Nearby Distances */}
{t('proximityToServices')}
{[
{ id: 'nearbySchool', label: t('school') },
{ id: 'nearbyHospital', label: t('hospital') },
{ id: 'nearbyRestaurant', label: t('restaurant') },
{ id: 'nearbyUniversity', label: t('university') },
{ id: 'nearbyPark', label: t('park') },
{ id: 'nearbyMall', label: t('mall') },
].map((field) => (
handleChange(field.id, e.target.value)}
placeholder={t('distancePlaceholder')}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
/>
))}
{/* Pricing */}
{formData.purpose === 'rent'
? t('priceInfoRent')
: t('salePriceSimple')}
{formData.purpose === 'rent' ? (
handleChange('deposit', 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('salePrice', 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"
/>
)}
);
};
export default function OwnerPropertiesPage() {
const { t } = useTranslation();
const router = useRouter();
const [user, setUser] = useState(null);
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 [deactivateModal, setDeactivateModal] = useState({
isOpen: false,
property: null,
isActivating: false,
});
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()) {
setUser({
name: authUser.name || authUser.email,
email: authUser.email,
role: "owner",
});
loadProperties();
} else {
router.push("/auth/choose-role");
}
}, [router]);
const loadProperties = async () => {
const authUser = AuthService.getUser();
const userId = authUser?.id;
if (!userId) {
console.warn("[OwnerProperties] No user ID found");
setIsLoading(false);
return;
}
try {
const [rentData, saleData] = await Promise.allSettled([
getMyRentListings(),
getMySaleListings(),
]);
const rentList =
rentData.status === "fulfilled"
? Array.isArray(rentData.value)
? rentData.value.filter(Boolean)
: rentData.value
? [rentData.value]
: []
: [];
const saleList =
saleData.status === "fulfilled"
? Array.isArray(saleData.value)
? saleData.value.filter(Boolean)
: saleData.value
? [saleData.value]
: []
: [];
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 normalizeTerms = (terms) => {
if (!terms) return {};
return Array.isArray(terms)
? terms.reduce((acc, t) => ({ ...acc, [t]: true }), {})
: terms;
};
const normalizeProximity = (prox) => {
if (!prox) return {};
const result = {};
Object.entries(prox).forEach(([k, v]) => {
if (!v) return;
result[k.charAt(0).toUpperCase() + k.slice(1)] = v;
});
return result;
};
const mappedRent = rentList.map((item) => {
const info = item.propertyInformation || {};
const details = typeof info.detailsJSON === 'object' && info.detailsJSON ? info.detailsJSON : (() => {
try {
return JSON.parse(info.detailsJSON || "{}");
} catch {
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 {
id: item.id,
title: info.address || `عقار #${item.id}`,
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:
item.rentType === 0
? "monthly"
: item.rentType === 1
? "daily"
: "daily",
dailyPrice: item.dailyRent || 0,
monthlyPrice: item.monthlyRent || 0,
salePrice: item.price || 0,
deposit: item.deposit || 0,
location: info.address || "",
bedrooms: info.numberOfBedRooms || 0,
bathrooms: info.numberOfBathRooms || 0,
area: info.space || 0,
livingRooms: details.livingRooms || 0,
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(),
furnished: details.furnished || false,
displayType: details.displayType || (item.dailyRent && item.monthlyRent ? 'Both' : item.monthlyRent ? 'Monthly rent' : item.dailyRent ? 'Daily rent' : 'Both'),
description: info.description || "",
address: info.address || "",
city: "",
district: "",
services: normalizeServices(details),
terms: normalizeTerms(details.terms),
proximity: normalizeProximity(details.nearbyDistances),
rating: item.rating || 0,
currencyId: item.currencyId,
_raw: item,
};
});
const mappedSale = saleList.map((item) => {
const info = item.propertyInformation || {};
const details = typeof info.detailsJSON === 'object' && info.detailsJSON ? info.detailsJSON : (() => {
try {
return JSON.parse(info.detailsJSON || "{}");
} catch {
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 {
id: item.id,
title: info.address || `عقار للبيع #${item.id}`,
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,
salePrice: item.price || 0,
deposit: 0,
location: info.address || "",
bedrooms: info.numberOfBedRooms || 0,
bathrooms: info.numberOfBathRooms || 0,
area: info.space || 0,
livingRooms: details.livingRooms || 0,
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(),
furnished: details.furnished || false,
displayType: details.displayType || 'For sale',
description: info.description || "",
address: info.address || "",
city: "",
district: "",
services: normalizeServices(details),
terms: normalizeTerms(details.terms),
proximity: normalizeProximity(details.nearbyDistances),
rating: item.rating || 0,
currencyId: item.currencyId,
_raw: item,
};
});
setProperties([...mappedRent, ...mappedSale]);
} catch (err) {
console.error("[OwnerProperties] Failed to load properties:", err);
toast.error(t('loadFailed'));
} finally {
setIsLoading(false);
}
};
const updatePropertiesInStorage = (newProperties) => {
setProperties(newProperties);
localStorage.setItem("ownerProperties", JSON.stringify(newProperties));
};
const handleDelete = () => {
if (deleteModal.property) {
const newProperties = properties.filter(
(p) => p.id !== deleteModal.property.id,
);
updatePropertiesInStorage(newProperties);
setDeleteModal({ isOpen: false, property: null });
toast.success(t('deleteSuccess'));
}
};
const handleSaveEdit = async (formData) => {
try {
const property = editModal.property;
const raw = property._raw || {};
const rawInfo = raw.propertyInformation || {};
const buildingTypeMap = {
apartment: 0,
villa: 1,
sweet: 2,
room: 3,
studio: 4,
office: 5,
farms: 6,
shop: 7,
warehouse: 8,
};
const activeServices = Object.entries(formData.services || {})
.filter(([, v]) => v)
.map(([k]) => k);
const activeTerms = Object.entries(formData.terms || {})
.filter(([, v]) => v)
.reduce((acc, [k]) => ({ ...acc, [k]: true }), {});
if (formData.customTerms?.length) {
formData.customTerms.forEach((t) => {
activeTerms[t] = true;
});
}
const details = {
description: formData.description || '',
services: activeServices,
serviceDetails: Object.fromEntries(
Object.entries(formData.serviceDetails || {}).filter(
([k, v]) => activeServices.includes(k) && v,
),
),
...(formData.purpose === 'rent' ? { terms: activeTerms } : {}),
displayType:
formData.purpose === 'rent'
? formData.rentType === 'both'
? 'Both'
: formData.rentType === 'daily'
? 'Daily rent'
: 'Monthly rent'
: 'For sale',
propertyCondition: formData.furnished
? 'WithFurniture'
: 'WithoutFurniture',
floorNumber: parseInt(formData.floor) || 0,
numberOfSalons: parseInt(formData.salons) || 0,
numberOfBalconies: parseInt(formData.balconies) || 0,
numberOfLivingRooms: parseInt(formData.livingRooms) || 0,
nearbyDistances: {
school: formData.nearbySchool || '',
hospital: formData.nearbyHospital || '',
restaurant: formData.nearbyRestaurant || '',
university: formData.nearbyUniversity || '',
park: formData.nearbyPark || '',
mall: formData.nearbyMall || '',
},
};
if (
formData.purpose === 'rent' &&
formData.propertyType === 'room'
) {
const roomDetails = rawInfo.detailsJSON || {};
let parsedDetails = {};
try {
parsedDetails =
typeof roomDetails === 'object'
? roomDetails
: JSON.parse(roomDetails);
} catch {
parsedDetails = {};
}
details.room = parsedDetails.room || {};
}
const detailsJSON = JSON.stringify(details);
const propInfo = {
cordsX: rawInfo.cordsX || '',
cordsY: rawInfo.cordsY || '',
images: rawInfo.images || [],
address: property.address || rawInfo.address || '',
description:
formData.description || rawInfo.description || '',
numberOfBathRooms: parseInt(formData.bathrooms) || 0,
numberOfRooms: parseInt(formData.bedrooms) || 0,
numberOfBedRooms: parseInt(formData.bedrooms) || 0,
space: parseFloat(formData.area) || 0,
detailsJSON,
buildingType: buildingTypeMap[formData.propertyType] ?? 0,
status: 0,
propertyType: formData.furnished ? 0 : 1,
};
if (formData.purpose === 'rent') {
const rentTypeMap = { daily: 1, monthly: 0, both: 0 };
const payload = buildRentPropertyPayload({
propertyInformation: propInfo,
city: formData.city || property?.city || property?.governorate || "",
governorate: formData.city || property?.city || property?.governorate || "",
documentType: formData.documentType || property?.documentType || "",
deposit: parseFloat(formData.deposit) || 0,
monthlyRent: parseFloat(formData.monthlyPrice) || 0,
dailyRent: parseFloat(formData.dailyPrice) || 0,
rating: 1,
currencyId:
formData.currencyId || property.currencyId || 1,
rentType: rentTypeMap[formData.rentType] ?? 0,
type: formData.furnished ? 0 : 1,
allowedPaymentPeriod: formData.allowedPaymentPeriod || '1.00:00:00',
});
await editRentProperty(property.id, payload);
} else {
const payload = {
propInfo,
price: parseFloat(formData.salePrice) || 0,
currencyId:
formData.currencyId || property.currencyId || 1,
};
await editSaleProperty(property.id, payload);
}
const updatedProperty = { ...property, ...formData };
const newProperties = properties.map((p) =>
p.id === property.id ? updatedProperty : p,
);
updatePropertiesInStorage(newProperties);
setEditModal({ isOpen: false, property: null });
toast.success(t('updateSuccess'));
} catch (err) {
console.error('[OwnerProperties] Edit failed:', err);
toast.error(t('updateFailed'));
throw err;
}
};
const handleToggleActivation = async () => {
const prop = deactivateModal.property;
if (!prop) return;
const willActivate = deactivateModal.isActivating;
const newStatus = willActivate ? "available" : "notAvailable";
const statusCode = willActivate ? 0 : 1;
setDeactivateModal({ isOpen: false, property: null, isActivating: false });
try {
if (prop.purpose === "rent") {
await updateRentPropertyStatus(prop.id, statusCode);
} else {
await updateSalePropertyStatus(prop.id, statusCode);
}
const newProperties = properties.map((p) =>
p.id === prop.id ? { ...p, status: newStatus } : p,
);
setProperties(newProperties);
localStorage.setItem("ownerProperties", JSON.stringify(newProperties));
toast.success(
willActivate
? t('activateSuccess')
: t('deactivateSuccess'),
);
} catch (err) {
console.error("[OwnerProperties] Toggle status failed:", err);
toast.error(t('statusUpdateFailed'));
}
};
const fadeInUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.5 },
};
if (isLoading) {
return (
);
}
return (
setDeleteModal({ isOpen: false, property: null })}
onConfirm={handleDelete}
propertyTitle={deleteModal.property?.title}
/>
setViewModal({ isOpen: false, property: null })}
property={viewModal.property}
/>
setEditModal({ isOpen: false, property: null })}
property={editModal.property}
onSave={handleSaveEdit}
/>
setDeactivateModal({ isOpen: false, property: null, isActivating: false })
}
onConfirm={handleToggleActivation}
propertyTitle={deactivateModal.property?.title}
isActivating={deactivateModal.isActivating}
/>
{t('myProperties')}
{t('welcomeUser', { name: user?.name, count: properties.length })}
setShowAddMenu(!showAddMenu)}
className="bg-gradient-to-r from-amber-500 to-amber-600 text-white px-6 py-3 rounded-xl font-medium flex items-center gap-2 shadow-lg hover:shadow-xl transition-all"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{t('addNewProperty')}
{showAddMenu && (
setShowAddMenu(false)}
>
{t('rentProperty')}
{t('rentPropertyDesc')}
setShowAddMenu(false)}
>
{t('saleProperty')}
{t('salePropertyDesc')}
)}
{/* Tab Switcher */}
{filteredProperties.length === 0 ? (
{activeTab === "rent"
? t('noRentProperties')
: t('noSaleProperties')}
{t('startAdding', { type: activeTab === "rent" ? t('forRent') : t('forSaleTab') })}
{t('addNewProperty')}
) : (
{filteredProperties.map((property, index) => (
{property.images && property.images.length > 0 ? (

) : (
)}
{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" ? (
) : (
)}
))}
)}
);
}