Added Active or DeActive for owner with API
All checks were successful
Build frontend / build (push) Successful in 1m10s

This commit is contained in:
Rahaf
2026-06-09 18:21:52 +03:00
parent 471332b59f
commit ce6caf08eb
2 changed files with 190 additions and 11 deletions

View File

@ -59,6 +59,8 @@ import {
getMySaleListings,
editRentProperty,
editSaleProperty,
updateRentPropertyStatus,
updateSalePropertyStatus,
} from "../../utils/api";
const DeleteConfirmationModal = ({
@ -117,6 +119,86 @@ const DeleteConfirmationModal = ({
);
};
const DeactivateConfirmationModal = ({
isOpen,
onClose,
onConfirm,
propertyTitle,
isActivating,
}) => {
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-amber-100 rounded-full flex items-center justify-center mx-auto mb-3">
<AlertCircle className="w-8 h-8 text-amber-600" />
</div>
<h3 className="text-xl font-bold text-gray-900">
{isActivating ? "تأكيد التنشيط" : "تأكيد إلغاء التنشيط"}
</h3>
<p className="text-sm text-gray-500 mt-2">
العقار:{" "}
<span className="font-bold text-gray-700">"{propertyTitle}"</span>
</p>
{!isActivating ? (
<div className="mt-4 p-4 bg-red-50 border border-red-200 rounded-xl">
<p className="text-sm text-red-700 font-medium">
تحذير
</p>
<p className="text-sm text-red-600 mt-1">
إذا قمت بإلغاء التنشيط، سيصبح هذا العقار غير متاح للحجز أو الشراء.
لا يمكن للعملاء رؤيته أو حجزه حتى تقوم بتنشيطه مرة أخرى.
</p>
</div>
) : (
<div className="mt-4 p-4 bg-green-50 border border-green-200 rounded-xl">
<p className="text-sm text-green-700 font-medium">
تنشيط العقار
</p>
<p className="text-sm text-green-600 mt-1">
سيصبح العقار متاحاً مرة أخرى للحجز أو الشراء.
</p>
</div>
)}
</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 py-3 rounded-xl font-medium transition-colors ${
isActivating
? "bg-green-600 text-white hover:bg-green-700"
: "bg-red-600 text-white hover:bg-red-700"
}`}
>
{isActivating ? "نعم، فعّل" : "نعم، ألغي التنشيط"}
</button>
</div>
</motion.div>
</motion.div>
);
};
const serviceLabels = {
Electricity: "كهرباء",
Internet: "إنترنت",
@ -1074,6 +1156,11 @@ export default function OwnerPropertiesPage() {
});
const [viewModal, setViewModal] = useState({ isOpen: false, property: null });
const [editModal, setEditModal] = useState({ isOpen: false, property: null });
const [deactivateModal, setDeactivateModal] = useState({
isOpen: false,
property: null,
isActivating: false,
});
const filteredProperties = properties.filter((p) => p.purpose === activeTab);
const rentCount = properties.filter((p) => p.purpose === "rent").length;
@ -1511,11 +1598,44 @@ export default function OwnerPropertiesPage() {
toast.success('تم تحديث العقار بنجاح');
} catch (err) {
console.error('[OwnerProperties] Edit failed:', err);
toast.error('فشل تحديث العقار');
toast.error("فشل تحديث العقار");
throw err;
}
};
const handleToggleActivation = async () => {
const prop = deactivateModal.property;
if (!prop) return;
const willActivate = deactivateModal.isActivating;
const newStatus = willActivate ? "available" : "notAvailable";
const statusCode = willActivate ? 0 : 1;
setDeactivateModal({ isOpen: false, property: null, isActivating: false });
try {
if (prop.purpose === "rent") {
await updateRentPropertyStatus(prop.id, statusCode);
} else {
await updateSalePropertyStatus(prop.id, statusCode);
}
const newProperties = properties.map((p) =>
p.id === prop.id ? { ...p, status: newStatus } : p,
);
setProperties(newProperties);
localStorage.setItem("ownerProperties", JSON.stringify(newProperties));
toast.success(
willActivate
? "تم تنشيط العقار بنجاح"
: "تم إلغاء تنشيط العقار بنجاح",
);
} catch (err) {
console.error("[OwnerProperties] Toggle status failed:", err);
toast.error("فشل تحديث حالة العقار");
}
};
const fadeInUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
@ -1557,6 +1677,16 @@ export default function OwnerPropertiesPage() {
onSave={handleSaveEdit}
/>
<DeactivateConfirmationModal
isOpen={deactivateModal.isOpen}
onClose={() =>
setDeactivateModal({ isOpen: false, property: null, isActivating: false })
}
onConfirm={handleToggleActivation}
propertyTitle={deactivateModal.property?.title}
isActivating={deactivateModal.isActivating}
/>
<div className="container mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: -20 }}
@ -1709,16 +1839,22 @@ export default function OwnerPropertiesPage() {
<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>
<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"
: property.status === "notAvailable"
? "bg-red-50/90 text-red-700"
: "bg-white/90 text-yellow-700"
}`}
>
{property.status === "notAvailable"
? "غير متاح"
: property.status === "available"
? "متاح"
: "مؤجل"}
</span>
{property.purpose === "rent" &&
property.furnished !== undefined && (
<span
@ -1862,6 +1998,35 @@ export default function OwnerPropertiesPage() {
</div>
<div className="flex gap-1">
{property.status === "notAvailable" ? (
<button
onClick={() =>
setDeactivateModal({
isOpen: true,
property,
isActivating: true,
})
}
className="p-1.5 hover:bg-green-50 rounded-lg transition-colors group"
title="تنشيط العقار"
>
<CheckCircle className="w-3.5 h-3.5 text-gray-400 group-hover:text-green-600" />
</button>
) : (
<button
onClick={() =>
setDeactivateModal({
isOpen: true,
property,
isActivating: false,
})
}
className="p-1.5 hover:bg-red-50 rounded-lg transition-colors group"
title="إلغاء تنشيط العقار"
>
<XCircle className="w-3.5 h-3.5 text-gray-400 group-hover:text-red-600" />
</button>
)}
<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"

View File

@ -685,6 +685,20 @@ export async function getSalePropertyById(id) {
return apiFetch(`/SaleProperties/${id}`);
}
export async function updateRentPropertyStatus(id, status) {
return apiFetch(`/RentProperties/UpdateStatus/${id}`, {
method: 'PUT',
body: { status },
});
}
export async function updateSalePropertyStatus(id, status) {
return apiFetch(`/SaleProperties/UpdateStatus/${id}`, {
method: 'PUT',
body: { status },
});
}
// ─── Currencies ───
export async function getCurrencies() {