Added confirm button for admin
All checks were successful
Build frontend / build (push) Successful in 46s
All checks were successful
Build frontend / build (push) Successful in 46s
This commit is contained in:
@ -23,7 +23,8 @@ import {
|
|||||||
Download,
|
Download,
|
||||||
Printer,
|
Printer,
|
||||||
History,
|
History,
|
||||||
Loader2
|
Loader2,
|
||||||
|
CreditCard
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import jsPDF from 'jspdf';
|
import jsPDF from 'jspdf';
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
@ -356,11 +357,11 @@ const PDFExportButton = ({ request, onExportComplete }) => {
|
|||||||
<span class="pdf-label">الحالة:</span>
|
<span class="pdf-label">الحالة:</span>
|
||||||
<span class="pdf-value">
|
<span class="pdf-value">
|
||||||
<span class="pdf-status pdf-status-${request.status}">
|
<span class="pdf-status pdf-status-${request.status}">
|
||||||
${request.status === 'pending' ? '⏳ قيد الانتظار' :
|
${request.status === 'pending' ? 'قيد الانتظار' :
|
||||||
request.status === 'owner_approved' ? '✓ موافقة المالك' :
|
request.status === 'owner_approved' ? 'موافقة المالك' :
|
||||||
request.status === 'admin_approved' ? '✓ موافقة الإدارة' :
|
request.status === 'admin_approved' ? 'موافقة الإدارة' :
|
||||||
request.status === 'active' ? '🏠 إيجار نشط' :
|
request.status === 'active' ? 'إيجار نشط' :
|
||||||
request.status === 'completed' ? '✔️ منتهي' : '❌ مرفوض'}
|
request.status === 'completed' ? 'منتهي' : 'مرفوض'}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -585,7 +586,7 @@ const RequestDetailsDialog = ({ request, isOpen, onClose }) => {
|
|||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-gray-500">نوع الهوية</label>
|
<label className="text-xs text-gray-500">نوع الهوية</label>
|
||||||
<div className="font-medium">
|
<div className="font-medium">
|
||||||
{request.userType === 'syrian' ? '🇸🇾 هوية سورية' : '🛂 جواز سفر'}
|
{request.userType === 'syrian' ? '🇸🇾 هوية سورية' : 'جواز سفر'}
|
||||||
<span className="text-xs text-gray-500 mr-2">{request.identityNumber}</span>
|
<span className="text-xs text-gray-500 mr-2">{request.identityNumber}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -658,6 +659,16 @@ const RequestDetailsDialog = ({ request, isOpen, onClose }) => {
|
|||||||
<label className="text-xs text-gray-500">سلفة الضمان</label>
|
<label className="text-xs text-gray-500">سلفة الضمان</label>
|
||||||
<div className="font-medium text-blue-600">{formatCurrency(request.securityDeposit)}</div>
|
<div className="font-medium text-blue-600">{formatCurrency(request.securityDeposit)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-gray-500">حالة الرعبون</label>
|
||||||
|
<div className={`font-medium px-3 py-1 rounded-full text-sm inline-block ${
|
||||||
|
request.securityDepositPaid
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-yellow-100 text-yellow-800'
|
||||||
|
}`}>
|
||||||
|
{request.securityDepositPaid ? '✓ تم الدفع' : '⏳ في انتظار الدفع'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-gray-500">نسبة العمولة</label>
|
<label className="text-xs text-gray-500">نسبة العمولة</label>
|
||||||
<div className="font-medium">{request.commissionRate}%</div>
|
<div className="font-medium">{request.commissionRate}%</div>
|
||||||
@ -821,18 +832,24 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
exit={{ height: 0, opacity: 0 }}
|
exit={{ height: 0, opacity: 0 }}
|
||||||
className="border-t bg-white p-4"
|
className="border-t bg-white p-4"
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3 mb-4">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4">
|
||||||
<div className="bg-blue-50 p-2 rounded-lg">
|
<div className="bg-blue-50 p-2 rounded-lg">
|
||||||
<div className="text-xs text-gray-500">سلفة ضمان</div>
|
<div className="text-xs text-gray-500">سلفة ضمان</div>
|
||||||
<div className="font-bold text-blue-600">{formatCurrency(request.securityDeposit)}</div>
|
<div className="font-bold text-blue-600">{formatCurrency(request.securityDeposit)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`p-2 rounded-lg ${request.securityDepositPaid ? 'bg-green-50' : 'bg-yellow-50'}`}>
|
||||||
|
<div className="text-xs text-gray-500">حالة الرعبون</div>
|
||||||
|
<div className={`font-bold text-xs ${request.securityDepositPaid ? 'text-green-600' : 'text-yellow-600'}`}>
|
||||||
|
{request.securityDepositPaid ? 'تم الدفع' : ' بانتظار'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="bg-amber-50 p-2 rounded-lg">
|
<div className="bg-amber-50 p-2 rounded-lg">
|
||||||
<div className="text-xs text-gray-500">العمولة</div>
|
<div className="text-xs text-gray-500">العمولة</div>
|
||||||
<div className="font-bold text-amber-600">{request.commissionRate}% ({request.commissionType})</div>
|
<div className="font-bold text-amber-600">{request.commissionRate}% ({request.commissionType})</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-purple-50 p-2 rounded-lg">
|
<div className="bg-purple-50 p-2 rounded-lg">
|
||||||
<div className="text-xs text-gray-500">مدة الإيجار</div>
|
<div className="text-xs text-gray-500">مدة الإيجار</div>
|
||||||
<div className="font-bold text-purple-600">{request.startDate} إلى {request.endDate}</div>
|
<div className="font-bold text-purple-600 text-xs">{request.startDate} إلى {request.endDate}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -908,7 +925,20 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
|
|
||||||
{request.status === 'admin_approved' && (
|
{request.status === 'admin_approved' && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-3 gap-3">
|
||||||
|
<button
|
||||||
|
onClick={() => onAction('confirm_deposit', { id: request.id })}
|
||||||
|
disabled={request.securityDepositPaid}
|
||||||
|
className={`py-3 rounded-xl font-medium flex items-center justify-center gap-2 transition-all ${
|
||||||
|
request.securityDepositPaid
|
||||||
|
? 'bg-purple-100 text-purple-800 cursor-default'
|
||||||
|
: 'bg-purple-600 text-white hover:bg-purple-700 transform hover:scale-105'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<CreditCard className="w-5 h-5" />
|
||||||
|
<span className="hidden md:inline">{request.securityDepositPaid ? 'تم دفع الرعبون' : 'تأكيد الرعبون'}</span>
|
||||||
|
<span className="md:hidden">{request.securityDepositPaid ? '✓' : 'رعبون'}</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => onAction('deliver_key', { id: request.id, type: 'owner' })}
|
onClick={() => onAction('deliver_key', { id: request.id, type: 'owner' })}
|
||||||
disabled={request.ownerDelivered}
|
disabled={request.ownerDelivered}
|
||||||
@ -919,7 +949,8 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Key className="w-5 h-5" />
|
<Key className="w-5 h-5" />
|
||||||
{request.ownerDelivered ? '✓ تم تسليم المفتاح' : 'تسليم المفتاح'}
|
<span className="hidden md:inline">{request.ownerDelivered ? 'تم تسليم المفتاح' : 'تسليم المفتاح'}</span>
|
||||||
|
<span className="md:hidden">{request.ownerDelivered ? '✓' : 'مفتاح'}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => onAction('receive_property', { id: request.id, type: 'tenant' })}
|
onClick={() => onAction('receive_property', { id: request.id, type: 'tenant' })}
|
||||||
@ -931,7 +962,8 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<DoorOpen className="w-5 h-5" />
|
<DoorOpen className="w-5 h-5" />
|
||||||
{request.tenantReceived ? '✓ تم الاستلام' : 'استلام العقار'}
|
<span className="hidden md:inline">{request.tenantReceived ? 'تم الاستلام' : 'استلام العقار'}</span>
|
||||||
|
<span className="md:hidden">{request.tenantReceived ? '✓' : 'استلام'}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -950,7 +982,7 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<DoorOpen className="w-5 h-5" />
|
<DoorOpen className="w-5 h-5" />
|
||||||
{request.tenantLeft ? '✓ تم المغادرة' : 'مغادرة العقار'}
|
{request.tenantLeft ? 'تم المغادرة' : 'مغادرة العقار'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => onAction('owner_receive', { id: request.id, type: 'owner' })}
|
onClick={() => onAction('owner_receive', { id: request.id, type: 'owner' })}
|
||||||
@ -962,7 +994,7 @@ const RequestCard = ({ request, onAction, onViewDetails }) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Key className="w-5 h-5" />
|
<Key className="w-5 h-5" />
|
||||||
{request.ownerReceived ? '✓ تم الاستلام' : 'استلام العقار'}
|
{request.ownerReceived ? 'تم الاستلام' : 'استلام العقار'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1018,6 +1050,7 @@ export default function BookingRequests() {
|
|||||||
tenantReceived: false,
|
tenantReceived: false,
|
||||||
tenantLeft: false,
|
tenantLeft: false,
|
||||||
ownerReceived: false,
|
ownerReceived: false,
|
||||||
|
securityDepositPaid: false,
|
||||||
securityDepositReturned: null,
|
securityDepositReturned: null,
|
||||||
contractSigned: false,
|
contractSigned: false,
|
||||||
notes: '',
|
notes: '',
|
||||||
@ -1050,6 +1083,7 @@ export default function BookingRequests() {
|
|||||||
tenantReceived: false,
|
tenantReceived: false,
|
||||||
tenantLeft: false,
|
tenantLeft: false,
|
||||||
ownerReceived: false,
|
ownerReceived: false,
|
||||||
|
securityDepositPaid: false,
|
||||||
securityDepositReturned: null,
|
securityDepositReturned: null,
|
||||||
contractSigned: false,
|
contractSigned: false,
|
||||||
notes: '',
|
notes: '',
|
||||||
@ -1082,6 +1116,7 @@ export default function BookingRequests() {
|
|||||||
tenantReceived: true,
|
tenantReceived: true,
|
||||||
tenantLeft: false,
|
tenantLeft: false,
|
||||||
ownerReceived: false,
|
ownerReceived: false,
|
||||||
|
securityDepositPaid: true,
|
||||||
securityDepositReturned: null,
|
securityDepositReturned: null,
|
||||||
contractSigned: true,
|
contractSigned: true,
|
||||||
notes: 'عقد موقع إلكترونياً',
|
notes: 'عقد موقع إلكترونياً',
|
||||||
@ -1108,6 +1143,9 @@ export default function BookingRequests() {
|
|||||||
case 'admin_reject':
|
case 'admin_reject':
|
||||||
setReasonDialog({ isOpen: true, requestId: data, type: 'admin' });
|
setReasonDialog({ isOpen: true, requestId: data, type: 'admin' });
|
||||||
break;
|
break;
|
||||||
|
case 'confirm_deposit':
|
||||||
|
handleDepositConfirmation(data.id);
|
||||||
|
break;
|
||||||
case 'deliver_key':
|
case 'deliver_key':
|
||||||
handleKeyDelivery(data.id, data.type);
|
handleKeyDelivery(data.id, data.type);
|
||||||
break;
|
break;
|
||||||
@ -1178,6 +1216,17 @@ export default function BookingRequests() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const handleDepositConfirmation = (requestId) => {
|
||||||
|
setRequests(prev =>
|
||||||
|
prev.map(req => {
|
||||||
|
if (req.id === requestId) {
|
||||||
|
toast.success('✓ تم تأكيد دفع الرعبون بنجاح!', { id: requestId });
|
||||||
|
return { ...req, securityDepositPaid: true };
|
||||||
|
}
|
||||||
|
return req;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyDelivery = (requestId, userType) => {
|
const handleKeyDelivery = (requestId, userType) => {
|
||||||
setRequests(prev =>
|
setRequests(prev =>
|
||||||
@ -1266,7 +1315,6 @@ export default function BookingRequests() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<Toaster position="top-center" reverseOrder={false} />
|
<Toaster position="top-center" reverseOrder={false} />
|
||||||
|
|
||||||
{/* إحصائيات سريعة */}
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
<div className="grid grid-cols-4 gap-4">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
|||||||
@ -370,3 +370,19 @@ export async function removeFavoriteProperty(favePropId) {
|
|||||||
export async function getUserNotifications() {
|
export async function getUserNotifications() {
|
||||||
return apiFetch('/Notifications/GetUserNotifications');
|
return apiFetch('/Notifications/GetUserNotifications');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Booking/Reservation Management ───
|
||||||
|
|
||||||
|
export async function confirmDepositPayment(bookingId) {
|
||||||
|
return apiFetch('/Reservations/ConfirmDepositPayment', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ bookingId }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateBookingStatus(bookingId, status) {
|
||||||
|
return apiFetch('/Reservations/UpdateStatus', {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ bookingId, status }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user