Added Active or DeActive for owner with API
All checks were successful
Build frontend / build (push) Successful in 1m10s
All checks were successful
Build frontend / build (push) Successful in 1m10s
This commit is contained in:
@ -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"
|
||||
|
||||
@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user