Files
SweetHome/app/owner/properties/page.js

1896 lines
73 KiB
JavaScript
Raw Normal View History

"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,
2026-05-26 00:20:20 +03:00
School,
Hospital,
Store,
GraduationCap,
TreePine,
} from "lucide-react";
import toast, { Toaster } from "react-hot-toast";
import AuthService from "../../services/AuthService";
import {
getMyRentListings,
getMySaleListings,
editRentProperty,
2026-05-26 04:35:03 +03:00
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: "ذكور فقط",
};
2026-05-26 00:20:20 +03:00
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>
2026-05-26 00:20:20 +03:00
<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>
2026-05-26 00:20:20 +03:00
</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 }) => {
2026-05-26 04:35:03 +03:00
const [formData, setFormData] = useState({});
const [newCustomTerm, setNewCustomTerm] = useState('');
const [isSaving, setIsSaving] = useState(false);
2026-05-26 04:35:03 +03:00
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({
2026-05-26 04:35:03 +03:00
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 }),
});
2026-05-26 04:35:03 +03:00
setNewCustomTerm('');
}, [property, isOpen]);
const handleChange = (field, value) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
2026-05-26 04:35:03 +03:00
const handleServiceToggle = (key, checked) => {
setFormData((prev) => ({
...prev,
services: { ...prev.services, [key]: checked },
}));
};
2026-05-26 04:35:03 +03:00
const handleServiceDetail = (key, value) => {
setFormData((prev) => ({
...prev,
serviceDetails: { ...prev.serviceDetails, [key]: value },
}));
};
const handleTermToggle = (key, checked) => {
setFormData((prev) => ({
...prev,
terms: { ...prev.terms, [key]: checked },
}));
};
2026-05-26 04:35:03 +03:00
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);
2026-05-26 04:35:03 +03:00
}
};
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 }}
2026-05-26 04:35:03 +03:00
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>
2026-05-26 04:35:03 +03:00
<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>
2026-05-26 04:35:03 +03:00
<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>
2026-05-26 04:35:03 +03:00
</div>
2026-05-26 04:35:03 +03:00
{/* 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>
2026-05-26 04:35:03 +03:00
{/* 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>
2026-05-26 04:35:03 +03:00
</div>
))}
</div>
2026-05-26 04:35:03 +03:00
</div>
2026-05-26 04:35:03 +03:00
{/* 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}
2026-05-26 04:35:03 +03:00
className="flex items-center gap-2 p-2 border rounded-lg cursor-pointer bg-white hover:bg-amber-50"
>
<input
type="checkbox"
2026-05-26 04:35:03 +03:00
checked={formData.terms?.[key] || false}
onChange={(e) =>
handleTermToggle(key, e.target.checked)
}
className="w-4 h-4 text-amber-500"
/>
2026-05-26 04:35:03 +03:00
<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>
2026-05-26 04:35:03 +03:00
<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>
2026-05-26 04:35:03 +03:00
{/* Pricing */}
<div className="bg-gray-50 p-4 rounded-xl">
<h3 className="text-lg font-bold text-gray-900 mb-4">
2026-05-26 04:35:03 +03:00
{formData.purpose === 'rent'
? 'معلومات السعر (إيجار)'
: 'سعر البيع'}
</h3>
2026-05-26 04:35:03 +03:00
{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
2026-05-26 04:35:03 +03:00
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"
/>
2026-05-26 04:35:03 +03:00
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
التأمين
</label>
2026-05-26 04:35:03 +03:00
<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>
2026-05-26 04:35:03 +03:00
</div>
2026-05-26 04:35:03 +03:00
<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);
2026-05-25 21:27:39 +03:00
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;
};
2026-05-25 21:27:39 +03:00
const mappedRent = rentList.map((item) => {
const info = item.propertyInformation || {};
2026-05-26 00:20:20 +03:00
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"
: "";
2026-05-25 21:27:39 +03:00
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,
2026-05-25 21:27:39 +03:00
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"],
2026-05-25 21:27:39 +03:00
createdAt: item.createdAt || new Date().toISOString(),
furnished: details.furnished || false,
2026-05-26 00:20:20 +03:00
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),
2026-05-25 21:27:39 +03:00
rating: item.rating || 0,
currencyId: item.currencyId,
_raw: item,
};
});
const mappedSale = saleList.map((item) => {
const info = item.propertyInformation || {};
2026-05-26 00:20:20 +03:00
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"
: "";
2026-05-25 21:27:39 +03:00
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",
2026-05-25 21:27:39 +03:00
dailyPrice: 0,
monthlyPrice: 0,
salePrice: item.price || 0,
deposit: 0,
location: info.address || "",
2026-05-25 21:27:39 +03:00
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,
2026-05-26 00:20:20 +03:00
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,
};
});
2026-05-25 21:27:39 +03:00
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("تم حذف العقار بنجاح");
}
};
2026-05-26 04:35:03 +03:00
const handleSaveEdit = async (formData) => {
2026-05-25 21:27:39 +03:00
try {
2026-05-26 04:35:03 +03:00
const property = editModal.property;
const raw = property._raw || {};
const rawInfo = raw.propertyInformation || {};
2026-05-25 21:27:39 +03:00
2026-05-26 04:35:03 +03:00
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 = {
2026-05-26 17:00:57 +03:00
description: formData.description || '',
2026-05-26 04:35:03 +03:00
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 };
2026-05-26 02:34:18 +03:00
const payload = {
2026-05-26 04:35:03 +03:00
propertyInformation: propInfo,
deposit: parseFloat(formData.deposit) || 0,
monthlyRent: parseFloat(formData.monthlyPrice) || 0,
dailyRent: parseFloat(formData.dailyPrice) || 0,
2026-05-26 02:34:18 +03:00
rating: 1,
2026-05-26 04:35:03 +03:00
currencyId:
formData.currencyId || property.currencyId || 1,
rentType: rentTypeMap[formData.rentType] ?? 0,
type: formData.furnished ? 0 : 1,
allowedPaymentPeriod: formData.allowedPaymentPeriod || '',
2026-05-25 21:27:39 +03:00
};
2026-05-26 04:35:03 +03: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);
2026-05-25 21:27:39 +03:00
}
2026-05-26 04:35:03 +03:00
const updatedProperty = { ...property, ...formData };
const newProperties = properties.map((p) =>
2026-05-26 04:35:03 +03:00
p.id === property.id ? updatedProperty : p,
2026-05-25 21:27:39 +03:00
);
updatePropertiesInStorage(newProperties);
setEditModal({ isOpen: false, property: null });
2026-05-26 04:35:03 +03:00
toast.success('تم تحديث العقار بنجاح');
2026-05-25 21:27:39 +03:00
} catch (err) {
2026-05-26 04:35:03 +03:00
console.error('[OwnerProperties] Edit failed:', err);
toast.error('فشل تحديث العقار');
throw err;
2026-05-25 21:27:39 +03:00
}
};
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>
<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>
);
}