Files
SweetHome/app/owner/properties/page.js
mouazkh 1ae3a635f7
All checks were successful
Build frontend / build (push) Successful in 44s
added the descption
2026-05-26 17:06:01 +03:00

1902 lines
73 KiB
JavaScript

"use client";
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useRouter } from "next/navigation";
import Link from "next/link";
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 {
getMyRentListings,
getMySaleListings,
editRentProperty,
editSaleProperty,
} from "../../utils/api";
const DeleteConfirmationModal = ({
isOpen,
onClose,
onConfirm,
propertyTitle,
}) => {
if (!isOpen) return null;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50"
onClick={onClose}
>
<motion.div
initial={{ scale: 0.9, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.9, y: 20 }}
className="bg-white rounded-2xl w-full max-w-md p-6 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<div className="text-center mb-4">
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-3">
<AlertCircle className="w-8 h-8 text-red-600" />
</div>
<h3 className="text-xl font-bold text-gray-900">تأكيد الحذف</h3>
<p className="text-sm text-gray-500 mt-2">
هل أنت متأكد من حذف العقار:{" "}
<span className="font-bold text-gray-700">"{propertyTitle}"</span>؟
</p>
<p className="text-xs text-red-500 mt-1">
هذا الإجراء لا يمكن التراجع عنه
</p>
</div>
<div className="flex gap-3 pt-3">
<button
onClick={onClose}
className="flex-1 bg-gray-100 text-gray-700 py-3 rounded-xl font-medium hover:bg-gray-200 transition-colors"
>
إلغاء
</button>
<button
onClick={onConfirm}
className="flex-1 bg-red-600 text-white py-3 rounded-xl font-medium hover:bg-red-700 transition-colors"
>
نعم، احذف
</button>
</div>
</motion.div>
</motion.div>
);
};
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: "منزل ذكي",
};
const termLabels = {
NoSmoking: "ممنوع التدخين",
NoAnimals: "ممنوع الحيوانات الأليفة",
NoParties: "ممنوع الحفلات",
NoAlcohol: "ممنوع الكحول",
SuitableForChildren: "مناسب للأطفال",
SuitableForFamilies: "مناسب للعائلات",
SuitableForStudents: "مناسب للطلاب",
SuitableForElderly: "مناسب لكبار السن",
OnlyFemales: "إناث فقط",
OnlyMales: "ذكور فقط",
};
const proximityLabels = {
School: "مدرسة",
Hospital: "مستشفى",
Restaurant: "مطعم",
University: "جامعة",
Park: "حديقة",
Mall: "مركز تسوق",
Supermarket: "سوبر ماركت",
Pharmacy: "صيدلية",
Mosque: "مسجد",
Bank: "بنك",
Airport: "مطار",
BusStation: "موقف باص",
};
const PropertyViewModal = ({ isOpen, onClose, property }) => {
if (!isOpen || !property) return null;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50"
onClick={onClose}
>
<motion.div
initial={{ scale: 0.9, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.9, y: 20 }}
className="bg-white rounded-2xl w-full max-w-4xl max-h-[90vh] overflow-y-auto shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<div className="sticky top-0 z-10 bg-gradient-to-r from-amber-500 to-amber-600 p-6 text-white flex justify-between items-center">
<div>
<h2 className="text-2xl font-bold">{property.title}</h2>
<p className="text-amber-100 text-sm mt-1">
تم الإضافة:{" "}
{new Date(property.createdAt).toLocaleDateString("ar-SA")}
</p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-white/20 rounded-full transition-colors"
>
<XCircle className="w-6 h-6" />
</button>
</div>
<div className="p-6">
{property.images && property.images.length > 0 && (
<div className="mb-6">
<h3 className="text-lg font-bold text-gray-900 mb-3">
صور العقار
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{property.images.map((image, index) => (
<div
key={index}
className="relative aspect-square rounded-lg overflow-hidden border border-gray-200"
>
<img
src={image}
alt={`${property.title} - صورة ${index + 1}`}
className="w-full h-full object-cover"
/>
</div>
))}
</div>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div className="bg-gray-50 p-4 rounded-xl">
<h4 className="font-bold text-gray-700 mb-3">معلومات أساسية</h4>
<div className="space-y-2">
<p className="text-sm">
<span className="text-gray-500">نوع العقار:</span>
<span className="font-medium text-gray-900 mr-2">
{property.propertyTypeLabel || "عقار"}
</span>
</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" && (
<p className="text-sm">
<span className="text-gray-500">حالة التأثيث:</span>
<span
className={`font-medium mr-2 ${property.furnished ? "text-green-600" : "text-gray-600"}`}
>
{property.furnished ? "مفروش" : "غير مفروش"}
</span>
</p>
)}
<p className="text-sm">
<span className="text-gray-500">حالة العقار:</span>
<span
className={`font-medium mr-2 ${property.status === "available" ? "text-green-600" : "text-yellow-600"}`}
>
{property.status === "available" ? "متاح" : "مؤجر"}
</span>
</p>
{property.description && (
<p className="text-sm mt-2">
<span className="text-gray-500">الوصف:</span>
<span className="text-gray-700 mr-2">
{property.description}
</span>
</p>
)}
</div>
</div>
<div className="bg-gray-50 p-4 rounded-xl">
<h4 className="font-bold text-gray-700 mb-3">التفاصيل</h4>
<div className="grid grid-cols-4 gap-2">
<div className="text-center">
<Bed className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">{property.bedrooms}</span>
<span className="text-xs text-gray-500 block">غرف</span>
</div>
<div className="text-center">
<Bath className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">
{property.bathrooms}
</span>
<span className="text-xs text-gray-500 block">حمامات</span>
</div>
<div className="text-center">
<Square className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">{property.area}</span>
<span className="text-xs text-gray-500 block">م²</span>
</div>
{property.floor > 0 && (
<div className="text-center">
<Layers className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">{property.floor}</span>
<span className="text-xs text-gray-500 block">طابق</span>
</div>
)}
{property.salons > 0 && (
<div className="text-center">
<Sofa className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">{property.salons}</span>
<span className="text-xs text-gray-500 block">صالونات</span>
</div>
)}
{property.balconies > 0 && (
<div className="text-center">
<DoorOpen className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">
{property.balconies}
</span>
<span className="text-xs text-gray-500 block">بلكونات</span>
</div>
)}
{property.bookedCount > 0 && (
<div className="text-center">
<Calendar className="w-5 h-5 text-amber-500 mx-auto mb-1" />
<span className="text-sm font-bold">
{property.bookedCount}
</span>
<span className="text-xs text-gray-500 block">حجوزات</span>
</div>
)}
</div>
</div>
</div>
<div className="bg-gray-50 p-4 rounded-xl mb-6">
<h4 className="font-bold text-gray-700 mb-3 flex items-center gap-2">
<MapPin className="w-5 h-5 text-amber-500" />
الموقع
</h4>
<p className="text-gray-700">
{property.address || "لم يتم تحديد العنوان"}
{property.city && `، ${property.city}`}
{property.district && `، ${property.district}`}
</p>
</div>
{property.services &&
(Array.isArray(property.services)
? property.services.length > 0
: Object.keys(property.services).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="flex flex-wrap gap-2">
{Array.isArray(property.services)
? property.services.map((svc, i) => (
<span
key={i}
className="inline-flex items-center gap-1 px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm"
>
{serviceLabels[svc] || svc}
</span>
))
: 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 (
<span
key={key}
className="inline-flex items-center gap-1 px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm"
>
{serviceLabels[key] || key}
{detail && (
<span className="text-green-400">· {detail}</span>
)}
</span>
);
})}
</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 && (
<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-1 md:grid-cols-2 gap-2">
{Object.entries(property.terms).map(([key, value]) => {
if (!value) return null;
return (
<div
key={key}
className="flex items-center gap-2 p-2 bg-white rounded-lg"
>
{key.startsWith("No") || key.startsWith("Only") ? (
<Ban className="w-4 h-4 text-red-500 flex-shrink-0" />
) : (
<Check className="w-4 h-4 text-green-500 flex-shrink-0" />
)}
<span className="text-sm text-gray-700">
{termLabels[key] || key}
</span>
</div>
);
})}
</div>
</div>
)}
<div className="bg-amber-50 p-4 rounded-xl">
<h4 className="font-bold text-amber-700 mb-3">معلومات السعر</h4>
{property.purpose === "rent" ? (
<div className="space-y-2">
{property.dailyPrice > 0 && (
<p className="flex justify-between">
<span className="text-gray-600">السعر اليومي:</span>
<span className="font-bold text-amber-600">
{Number(property.dailyPrice).toLocaleString()} ل.س
</span>
</p>
)}
{property.monthlyPrice > 0 && (
<p className="flex justify-between">
<span className="text-gray-600">السعر الشهري:</span>
<span className="font-bold text-amber-600">
{Number(property.monthlyPrice).toLocaleString()} ل.س
</span>
</p>
)}
{property.deposit > 0 && (
<p className="flex justify-between">
<span className="text-gray-600">التأمين:</span>
<span className="font-bold text-gray-700">
{Number(property.deposit).toLocaleString()} ل.س
</span>
</p>
)}
<p className="text-sm text-gray-500 mt-1">
نوع الإيجار:{" "}
{property.rentType === "daily"
? "يومي"
: property.rentType === "monthly"
? "شهري"
: "يومي وشهري"}
</p>
{property.rating > 0 && (
<p className="flex justify-between mt-2 pt-2 border-t border-amber-200">
<span className="text-gray-600">التقييم:</span>
<span className="font-bold text-amber-600 flex items-center gap-1">
{Number(property.rating).toFixed(1)}{" "}
<Star className="w-4 h-4 fill-amber-500" />
</span>
</p>
)}
</div>
) : (
<p className="flex justify-between">
<span className="text-gray-600">سعر البيع:</span>
<span className="font-bold text-blue-600">
{Number(property.salePrice).toLocaleString()} ل.س
</span>
</p>
)}
</div>
</div>
</motion.div>
</motion.div>
);
};
const PropertyEditModal = ({ isOpen, onClose, property, onSave }) => {
const [formData, setFormData] = useState({});
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(serviceLabels).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 propTerms = property.terms || {};
const terms = {};
Object.keys(termLabels).forEach((key) => {
terms[key] = !!propTerms[key];
});
const prox = property.proximity || details.nearbyDistances || {};
setFormData({
propertyType: property.propertyType || 'apartment',
furnished: property.furnished ?? false,
description: property.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,
area: property.area || 0,
services,
serviceDetails,
terms,
customTerms: details.customTerms || [],
nearbySchool: prox.School ?? prox.school ?? '',
nearbyHospital: prox.Hospital ?? prox.hospital ?? '',
nearbyRestaurant: prox.Restaurant ?? prox.restaurant ?? '',
nearbyUniversity: prox.University ?? prox.university ?? '',
nearbyPark: prox.Park ?? prox.park ?? '',
nearbyMall: prox.Mall ?? prox.mall ?? '',
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 () => {
setIsSaving(true);
try {
await onSave(formData);
} catch {
setIsSaving(false);
}
};
if (!isOpen || !property) return null;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50"
onClick={onClose}
>
<motion.div
initial={{ scale: 0.9, y: 20 }}
animate={{ scale: 1, y: 0 }}
exit={{ scale: 0.9, y: 20 }}
className="bg-white rounded-2xl w-full max-w-4xl max-h-[90vh] flex flex-col shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<div className="sticky top-0 z-10 bg-gradient-to-r from-amber-500 to-amber-600 p-6 text-white flex justify-between items-center">
<div>
<h2 className="text-2xl font-bold">تعديل العقار</h2>
<p className="text-amber-100 text-sm mt-1">
قم بتحديث معلومات العقار
</p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-white/20 rounded-full transition-colors"
>
<XCircle className="w-6 h-6" />
</button>
</div>
<div className="p-6 space-y-6 overflow-y-auto flex-1">
{/* Basic Info */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">
معلومات أساسية
</h3>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
نوع العقار
</label>
<select
value={formData.propertyType}
onChange={(e) =>
handleChange('propertyType', 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"
>
<option value="apartment">شقة</option>
<option value="villa">فيلا</option>
<option value="sweet">سويت</option>
<option value="room">غرفة ضمن شقة</option>
<option value="studio">استوديو</option>
<option value="office">مكتب</option>
<option value="farms">مزرعة</option>
<option value="shop">متجر</option>
<option value="warehouse">مستودع</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
حالة التأثيث
</label>
<div className="flex gap-4">
{[
{ value: true, label: 'مفروش' },
{ value: false, label: 'غير مفروش' },
].map((opt) => (
<label
key={String(opt.value)}
className="flex items-center gap-2 cursor-pointer"
>
<input
type="radio"
name="furnished"
checked={formData.furnished === opt.value}
onChange={() => handleChange('furnished', opt.value)}
className="w-4 h-4 text-amber-500"
/>
<span className="text-sm">{opt.label}</span>
</label>
))}
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
الوصف
</label>
<textarea
value={formData.description}
onChange={(e) =>
handleChange('description', 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"
rows={3}
/>
</div>
</div>
</div>
{/* Details */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">التفاصيل</h3>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{[
{ id: 'bedrooms', label: 'عدد غرف النوم' },
{ id: 'bathrooms', label: 'عدد الحمامات' },
{ id: 'floor', label: 'الطابق' },
{ id: 'salons', label: 'عدد الصالونات' },
{ id: 'balconies', label: 'عدد البلكونات' },
{ id: 'area', label: 'المساحة (م²)' },
].map((field) => (
<div key={field.id}>
<label className="block text-sm font-medium text-gray-700 mb-1">
{field.label}
</label>
<input
type="number"
min="0"
value={formData[field.id]}
onChange={(e) =>
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"
/>
</div>
))}
</div>
</div>
{/* Services */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">الخدمات</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{Object.entries(serviceLabels).map(([key, label]) => (
<div
key={key}
className="flex items-start gap-2 p-2 border rounded-lg bg-white"
>
<input
type="checkbox"
checked={formData.services?.[key] || false}
onChange={(e) =>
handleServiceToggle(key, e.target.checked)
}
className="w-4 h-4 text-amber-500 mt-1"
/>
<div className="flex-1">
<span className="text-sm font-medium">{label}</span>
{formData.services?.[key] && (
<input
type="text"
value={formData.serviceDetails?.[key] || ''}
onChange={(e) =>
handleServiceDetail(key, e.target.value)
}
placeholder="تفاصيل الخدمة..."
className="w-full mt-1 px-2 py-1 text-xs border border-gray-200 rounded focus:outline-none focus:ring-1 focus:ring-amber-500"
/>
)}
</div>
</div>
))}
</div>
</div>
{/* Terms - rent only */}
{formData.purpose === 'rent' && (
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">
شروط الاستخدام
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{Object.entries(termLabels).map(([key, label]) => (
<label
key={key}
className="flex items-center gap-2 p-2 border rounded-lg cursor-pointer bg-white hover:bg-amber-50"
>
<input
type="checkbox"
checked={formData.terms?.[key] || false}
onChange={(e) =>
handleTermToggle(key, e.target.checked)
}
className="w-4 h-4 text-amber-500"
/>
<span className="text-sm">{label}</span>
</label>
))}
</div>
<div className="mt-4">
<label className="block text-sm font-medium text-gray-700 mb-2">
شروط مخصصة
</label>
<div className="flex gap-2 mb-2">
<input
type="text"
value={newCustomTerm}
onChange={(e) => setNewCustomTerm(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && addCustomTerm()}
placeholder="أضف شرطاً مخصصاً..."
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500 text-sm"
/>
<button
onClick={addCustomTerm}
className="px-3 py-2 bg-amber-500 text-white rounded-lg text-sm hover:bg-amber-600"
>
إضافة
</button>
</div>
{formData.customTerms?.length > 0 && (
<div className="flex flex-wrap gap-2">
{formData.customTerms.map((term, i) => (
<span
key={i}
className="inline-flex items-center gap-1 px-3 py-1 bg-amber-100 text-amber-800 rounded-full text-sm"
>
{term}
<button
onClick={() => removeCustomTerm(i)}
className="hover:text-red-600"
>
<X className="w-3 h-3" />
</button>
</span>
))}
</div>
)}
</div>
</div>
)}
{/* Nearby Distances */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">
القرب من الخدمات
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{[
{ id: 'nearbySchool', label: 'المدرسة' },
{ id: 'nearbyHospital', label: 'المستشفى' },
{ id: 'nearbyRestaurant', label: 'المطعم' },
{ id: 'nearbyUniversity', label: 'الجامعة' },
{ id: 'nearbyPark', label: 'الحديقة' },
{ id: 'nearbyMall', label: 'مركز التسوق' },
].map((field) => (
<div key={field.id}>
<label className="block text-sm font-medium text-gray-700 mb-1">
{field.label}
</label>
<input
type="text"
value={formData[field.id] || ''}
onChange={(e) => handleChange(field.id, e.target.value)}
placeholder="المسافة (كم)"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
/>
</div>
))}
</div>
</div>
{/* Pricing */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">
{formData.purpose === 'rent'
? 'معلومات السعر (إيجار)'
: 'سعر البيع'}
</h3>
{formData.purpose === 'rent' ? (
<div className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
السعر اليومي
</label>
<input
type="number"
min="0"
value={formData.dailyPrice}
onChange={(e) =>
handleChange('dailyPrice', 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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
السعر الشهري
</label>
<input
type="number"
min="0"
value={formData.monthlyPrice}
onChange={(e) =>
handleChange('monthlyPrice', 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"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
التأمين
</label>
<input
type="number"
min="0"
value={formData.deposit}
onChange={(e) =>
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
نوع الإيجار
</label>
<select
value={formData.rentType}
onChange={(e) =>
handleChange('rentType', 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"
>
<option value="daily">يومي</option>
<option value="monthly">شهري</option>
<option value="both">يومي وشهري</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
مدة السداد المسموحة
</label>
<select
value={formData.allowedPaymentPeriod}
onChange={(e) =>
handleChange('allowedPaymentPeriod', e.target.value)
}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">اختر المدة</option>
<option value="1.00:00:00">يومي</option>
<option value="7.00:00:00">أسبوعي</option>
<option value="30.00:00:00">شهري</option>
<option value="90.00:00:00">ربع سنوي</option>
<option value="365.00:00:00">سنوي</option>
</select>
</div>
</div>
) : (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
سعر البيع
</label>
<input
type="number"
min="0"
value={formData.salePrice}
onChange={(e) =>
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"
/>
</div>
)}
</div>
</div>
<div className="p-6 border-t flex gap-3">
<button
onClick={onClose}
className="flex-1 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-colors"
>
إلغاء
</button>
<button
onClick={handleSave}
disabled={isSaving}
className="flex-1 bg-gradient-to-r from-amber-500 to-amber-600 text-white py-3 rounded-xl hover:from-amber-600 hover:to-amber-700 transition-all disabled:opacity-50 flex items-center justify-center gap-2"
>
{isSaving ? (
<>
<Loader2 className="w-5 h-5 animate-spin" />
جاري الحفظ...
</>
) : (
<>
<Save className="w-5 h-5" />
حفظ التغييرات
</>
)}
</button>
</div>
</motion.div>
</motion.div>
);
};
export default function OwnerPropertiesPage() {
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 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 {
console.log("[OwnerProperties] Fetching listings for user:", userId);
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]
: []
: [];
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 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("فشل في تحميل العقارات");
} 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("تم حذف العقار بنجاح");
}
};
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,
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 = {
propertyInformation: propInfo,
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 || '',
};
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('تم تحديث العقار بنجاح');
} catch (err) {
console.error('[OwnerProperties] Edit failed:', err);
toast.error('فشل تحديث العقار');
throw err;
}
};
const fadeInUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.5 },
};
if (isLoading) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<Loader2 className="w-12 h-12 text-amber-500 animate-spin mx-auto mb-4" />
<p className="text-gray-600">جاري تحميل عقاراتك...</p>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-50 py-8 relative">
<Toaster position="top-center" reverseOrder={false} />
<DeleteConfirmationModal
isOpen={deleteModal.isOpen}
onClose={() => setDeleteModal({ isOpen: false, property: null })}
onConfirm={handleDelete}
propertyTitle={deleteModal.property?.title}
/>
<PropertyViewModal
isOpen={viewModal.isOpen}
onClose={() => setViewModal({ isOpen: false, property: null })}
property={viewModal.property}
/>
<PropertyEditModal
isOpen={editModal.isOpen}
onClose={() => setEditModal({ isOpen: false, property: null })}
property={editModal.property}
onSave={handleSaveEdit}
/>
<div className="container mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="flex justify-between items-center mb-8"
>
<div>
<h1 className="text-3xl font-bold text-gray-900 mb-2">عقاراتي</h1>
<p className="text-gray-600">
مرحباً {user?.name}، لديك {properties.length} عقار
</p>
</div>
<div className="relative">
<motion.button
onClick={() => 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 }}
>
<PlusCircle className="w-5 h-5" />
إضافة عقار جديد
</motion.button>
<AnimatePresence>
{showAddMenu && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="absolute left-0 mt-2 w-64 bg-white rounded-xl shadow-xl border border-gray-200 overflow-hidden z-50"
>
<div className="p-2">
<Link
href="/owner/properties/add?purpose=rent"
className="flex items-center gap-3 px-4 py-3 text-gray-700 hover:bg-amber-50 rounded-lg transition-colors"
onClick={() => setShowAddMenu(false)}
>
<div className="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center">
<Home className="w-4 h-4 text-green-600" />
</div>
<div>
<p className="font-medium">عقار للإيجار</p>
<p className="text-xs text-gray-500">
أضف عقار متاح للإيجار
</p>
</div>
</Link>
<Link
href="/owner/properties/add?purpose=sale"
className="flex items-center gap-3 px-4 py-3 text-gray-700 hover:bg-amber-50 rounded-lg transition-colors"
onClick={() => setShowAddMenu(false)}
>
<div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center">
<DollarSign className="w-4 h-4 text-blue-600" />
</div>
<div>
<p className="font-medium">عقار للبيع</p>
<p className="text-xs text-gray-500">
أضف عقار متاح للبيع
</p>
</div>
</Link>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
</motion.div>
{/* Tab Switcher */}
<div className="flex gap-1 mb-6 bg-gray-100 rounded-xl p-1 w-fit">
<button
onClick={() => setActiveTab("rent")}
className={`px-6 py-2 rounded-lg text-sm font-medium transition-all ${activeTab === "rent" ? "bg-white text-amber-600 shadow-sm" : "text-gray-600 hover:text-gray-800"}`}
>
<span className="flex items-center gap-2">
<Home className="w-4 h-4" />
للإيجار
{rentCount > 0 && (
<span className="bg-amber-100 text-amber-800 text-xs px-2 py-0.5 rounded-full">
{rentCount}
</span>
)}
</span>
</button>
<button
onClick={() => setActiveTab("sale")}
className={`px-6 py-2 rounded-lg text-sm font-medium transition-all ${activeTab === "sale" ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-800"}`}
>
<span className="flex items-center gap-2">
<DollarSign className="w-4 h-4" />
للبيع
{saleCount > 0 && (
<span className="bg-blue-100 text-blue-800 text-xs px-2 py-0.5 rounded-full">
{saleCount}
</span>
)}
</span>
</button>
</div>
{filteredProperties.length === 0 ? (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-white rounded-2xl p-12 text-center border-2 border-dashed border-gray-300"
>
<div className="w-24 h-24 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Building className="w-12 h-12 text-amber-600" />
</div>
<h3 className="text-xl font-bold text-gray-900 mb-2">
{activeTab === "rent"
? "لا توجد عقارات للإيجار"
: "لا توجد عقارات للبيع"}
</h3>
<p className="text-gray-600 mb-6">
ابدأ بإضافة أول عقار {activeTab === "rent" ? "للإيجار" : "للبيع"}{" "}
الآن
</p>
<Link
href={`/owner/properties/add?purpose=${activeTab}`}
className="inline-flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors"
>
<PlusCircle className="w-5 h-5" />
إضافة عقار جديد
</Link>
</motion.div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredProperties.map((property, index) => (
<motion.div
key={property.id}
variants={fadeInUp}
initial="initial"
animate="animate"
transition={{ delay: index * 0.1 }}
className="bg-white rounded-2xl shadow-sm hover:shadow-md transition-all overflow-hidden border border-gray-200"
>
<div className="relative aspect-[16/10] bg-gray-100 overflow-hidden">
{property.images && property.images.length > 0 ? (
<img
src={property.images[0]}
alt={property.title}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full flex items-center justify-center">
<ImageIcon className="w-12 h-12 text-gray-400" />
</div>
)}
<div className="absolute top-2 right-2 flex gap-1">
<span
className={`px-2 py-0.5 rounded-md text-xs font-medium shadow-sm backdrop-blur-sm ${
property.status === "available"
? "bg-white/90 text-green-700"
: "bg-white/90 text-yellow-700"
}`}
>
{property.status === "available" ? "متاح" : "مؤجر"}
</span>
{property.purpose === "rent" &&
property.furnished !== undefined && (
<span
className={`px-2 py-0.5 rounded-md text-xs font-medium shadow-sm backdrop-blur-sm ${
property.furnished
? "bg-white/90 text-amber-700"
: "bg-white/90 text-gray-600"
}`}
>
{property.furnished ? "مفروش" : "غير مفروش"}
</span>
)}
</div>
<div className="absolute top-2 left-2">
<span className="px-2 py-0.5 rounded-md text-xs font-medium bg-white/90 text-amber-700 shadow-sm backdrop-blur-sm">
{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"
? "مستودع"
: "عقار")}
</span>
</div>
</div>
<div className="p-3">
<div className="flex items-start justify-between mb-1">
<h3 className="font-bold text-gray-900 truncate flex-1 ml-2">
{property.title}
</h3>
{property.rating > 0 && (
<div className="flex items-center gap-0.5 text-amber-600 shrink-0">
<Star className="w-3 h-3 fill-amber-500" />
<span className="text-xs font-medium">
{Number(property.rating).toFixed(1)}
</span>
</div>
)}
</div>
<div className="flex items-center gap-1 text-gray-500 text-xs mb-2">
<MapPin className="w-3 h-3" />
<span className="truncate">
{property.address || property.location || "موقع غير محدد"}
</span>
</div>
{property.description && (
<p className="text-xs text-gray-600 leading-relaxed mb-2 line-clamp-2">
{property.description}
</p>
)}
<div className="flex flex-wrap items-center gap-2 text-xs text-gray-600 mb-2">
{property.bedrooms > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<Bed className="w-3 h-3" />
<span>{property.bedrooms}</span>
</div>
)}
{property.bathrooms > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<Bath className="w-3 h-3" />
<span>{property.bathrooms}</span>
</div>
)}
{property.area > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<Square className="w-3 h-3" />
<span>{property.area}م²</span>
</div>
)}
{property.floor > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<Layers className="w-3 h-3" />
<span>ط {property.floor}</span>
</div>
)}
{property.salons > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<Sofa className="w-3 h-3" />
<span>{property.salons}</span>
</div>
)}
{property.balconies > 0 && (
<div className="flex items-center gap-0.5 bg-gray-50 px-2 py-0.5 rounded-md">
<DoorOpen className="w-3 h-3" />
<span>{property.balconies}</span>
</div>
)}
</div>
<div className="flex justify-between items-center pt-2 border-t border-gray-100">
<div>
{property.purpose === "rent" ? (
<div>
{property.monthlyPrice > 0 && (
<span className="text-base font-bold text-amber-600">
{Number(property.monthlyPrice).toLocaleString()}
<span className="text-xs text-gray-500 font-normal mr-1">
ل.س /شهر
</span>
</span>
)}
{property.dailyPrice > 0 &&
!property.monthlyPrice && (
<span className="text-base font-bold text-amber-600">
{Number(property.dailyPrice).toLocaleString()}
<span className="text-xs text-gray-500 font-normal mr-1">
ل.س /يوم
</span>
</span>
)}
{property.deposit > 0 && (
<div className="text-[10px] text-gray-400">
تأمين: {Number(property.deposit).toLocaleString()}{" "}
ل.س
</div>
)}
</div>
) : (
<span className="text-base font-bold text-blue-600">
{Number(property.salePrice).toLocaleString()} ل.س
</span>
)}
</div>
<div className="flex gap-1">
<button
onClick={() => setViewModal({ isOpen: true, property })}
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="عرض التفاصيل"
>
<Eye className="w-3.5 h-3.5 text-gray-400 group-hover:text-blue-600" />
<span className="text-xs text-gray-500 group-hover:text-blue-600 font-medium">
عرض
</span>
</button>
<button
onClick={() => setEditModal({ isOpen: true, property })}
className="p-1.5 hover:bg-amber-50 rounded-lg transition-colors group"
title="تعديل العقار"
>
<Edit className="w-3.5 h-3.5 text-gray-400 group-hover:text-amber-600" />
</button>
<button
onClick={() =>
setDeleteModal({ isOpen: true, property })
}
className="p-1.5 hover:bg-red-50 rounded-lg transition-colors group"
title="حذف العقار"
>
<Trash2 className="w-3.5 h-3.5 text-gray-400 group-hover:text-red-600" />
</button>
</div>
</div>
</div>
</motion.div>
))}
</div>
)}
</div>
</div>
);
}