forked from amer2004/SweetHome
payment with haram
This commit is contained in:
@ -61,6 +61,10 @@ function formatDate(date) {
|
|||||||
return d.toLocaleDateString('en-GB');
|
return d.toLocaleDateString('en-GB');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeText(value) {
|
||||||
|
return String(value ?? '').trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
export default function PaymentsPage() {
|
export default function PaymentsPage() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [reservations, setReservations] = useState([]);
|
const [reservations, setReservations] = useState([]);
|
||||||
@ -69,7 +73,7 @@ export default function PaymentsPage() {
|
|||||||
const [isGuest, setIsGuest] = useState(null);
|
const [isGuest, setIsGuest] = useState(null);
|
||||||
const [paymentMethods, setPaymentMethods] = useState([]);
|
const [paymentMethods, setPaymentMethods] = useState([]);
|
||||||
const [loadingPaymentMethods, setLoadingPaymentMethods] = useState(true);
|
const [loadingPaymentMethods, setLoadingPaymentMethods] = useState(true);
|
||||||
const [selectedPayment, setSelectedPayment] = useState('cash');
|
const [selectedPayment, setSelectedPayment] = useState(null);
|
||||||
|
|
||||||
const loadReservations = useCallback(async () => {
|
const loadReservations = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -117,9 +121,10 @@ export default function PaymentsPage() {
|
|||||||
const data = await getPaymentTypes();
|
const data = await getPaymentTypes();
|
||||||
const methods = Array.isArray(data) ? data : [];
|
const methods = Array.isArray(data) ? data : [];
|
||||||
setPaymentMethods(methods);
|
setPaymentMethods(methods);
|
||||||
|
|
||||||
const firstActive = methods.find((method) => method?.isActive === true || method?.active === true);
|
const firstActive = methods.find((method) => method?.isActive === true || method?.active === true);
|
||||||
if (firstActive) {
|
if (firstActive) {
|
||||||
setSelectedPayment(firstActive.id ?? firstActive.name ?? selectedPayment);
|
setSelectedPayment(firstActive.name ?? firstActive.id ?? null);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Payments] failed to load payment methods', err);
|
console.error('[Payments] failed to load payment methods', err);
|
||||||
@ -127,7 +132,7 @@ export default function PaymentsPage() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoadingPaymentMethods(false);
|
setLoadingPaymentMethods(false);
|
||||||
}
|
}
|
||||||
}, [selectedPayment]);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (AuthService.isGuest()) {
|
if (AuthService.isGuest()) {
|
||||||
@ -150,13 +155,25 @@ export default function PaymentsPage() {
|
|||||||
return method?.id ?? paymentKey;
|
return method?.id ?? paymentKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePayDeposit = async (reservation, paymentKey) => {
|
const handlePayDeposit = async (reservation, paymentKey, paymentImageFile) => {
|
||||||
setPayingId(reservation.id);
|
|
||||||
const paymentTypeId = resolvePaymentTypeId(paymentKey);
|
const paymentTypeId = resolvePaymentTypeId(paymentKey);
|
||||||
|
const selectedMethod = paymentMethods.find(
|
||||||
|
(m) => String(m.id) === String(paymentTypeId) || String(m.name) === String(paymentTypeId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const isHaram = normalizeText(selectedMethod?.name).includes('haram');
|
||||||
|
|
||||||
|
if (isHaram && !paymentImageFile) {
|
||||||
|
toast.error(t('payments.uploadReceiptRequired', { defaultValue: 'يرجى رفع صورة الوصل' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPayingId(reservation.id);
|
||||||
try {
|
try {
|
||||||
await payDeposit({
|
await payDeposit({
|
||||||
reservationId: reservation.id,
|
reservationId: reservation.id,
|
||||||
paymentTypeId,
|
paymentTypeId,
|
||||||
|
paymentImage: paymentImageFile,
|
||||||
});
|
});
|
||||||
toast.success(t('payments.depositPaidSuccess'));
|
toast.success(t('payments.depositPaidSuccess'));
|
||||||
loadReservations();
|
loadReservations();
|
||||||
@ -282,36 +299,54 @@ export default function PaymentsPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{reservations.length === 0 && (
|
{reservations.length === 0 && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
className="bg-white rounded-2xl p-12 text-center border-2 border-dashed border-gray-300"
|
className="bg-white rounded-2xl p-12 text-center border-2 border-dashed border-gray-300"
|
||||||
>
|
>
|
||||||
<CreditCard className="w-16 h-16 text-gray-300 mx-auto mb-4" />
|
<CreditCard className="w-16 h-16 text-gray-300 mx-auto mb-4" />
|
||||||
<h3 className="text-xl font-bold text-gray-700 mb-2">{t('payments.noTransactions')}</h3>
|
<h3 className="text-xl font-bold text-gray-700 mb-2">{t('payments.noTransactions')}</h3>
|
||||||
<p className="text-gray-500">{t('payments.noTransactionsDesc')}</p>
|
<p className="text-gray-500">{t('payments.noTransactionsDesc')}</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line react/prop-types
|
// eslint-disable-next-line react/prop-types
|
||||||
function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMethods, selectedPayment, onSelectPayment, onPay }) {
|
function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMethods, selectedPayment, onSelectPayment, onPay }) {
|
||||||
const r = reservation;
|
const { t } = useTranslation();
|
||||||
const amount = r.depositAmount || r.totalPrice || 0;
|
const r = reservation;
|
||||||
const [showCashDialog, setShowCashDialog] = useState(false);
|
const amount = r.depositAmount || r.totalPrice || 0;
|
||||||
const methods = paymentMethods.length > 0 ? paymentMethods : getPaymentMethods(t);
|
const [showCashDialog, setShowCashDialog] = useState(false);
|
||||||
|
const [localPaymentImage, setLocalPaymentImage] = useState(null);
|
||||||
|
|
||||||
return (
|
const methods = paymentMethods.length > 0 ? paymentMethods : getPaymentMethods(t);
|
||||||
<>
|
|
||||||
<motion.div
|
const selectedMethod = methods.find((m) => {
|
||||||
initial={{ opacity: 0, y: 20 }}
|
const methodName = normalizeText(m?.name);
|
||||||
animate={{ opacity: 1, y: 0 }}
|
const methodLabel = normalizeText(m?.label);
|
||||||
className="bg-white rounded-3xl shadow-md border border-gray-200 overflow-hidden"
|
const methodId = normalizeText(m?.id);
|
||||||
>
|
const paymentKey = normalizeText(selectedPayment);
|
||||||
|
|
||||||
|
return methodName === paymentKey || methodLabel === paymentKey || methodId === paymentKey;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isHaramPayment =
|
||||||
|
normalizeText(selectedPayment).includes('haram') ||
|
||||||
|
normalizeText(selectedMethod?.name).includes('haram') ||
|
||||||
|
normalizeText(selectedMethod?.label).includes('haram') ||
|
||||||
|
normalizeText(selectedMethod?.id).includes('haram');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="bg-white rounded-3xl shadow-md border border-gray-200 overflow-hidden"
|
||||||
|
>
|
||||||
{/* Property details */}
|
{/* Property details */}
|
||||||
<div className="p-6 border-b border-gray-100">
|
<div className="p-6 border-b border-gray-100">
|
||||||
<div className="flex items-start gap-4 mb-4">
|
<div className="flex items-start gap-4 mb-4">
|
||||||
@ -380,7 +415,7 @@ export default function PaymentsPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
methods.map((method, index) => {
|
methods.map((method, index) => {
|
||||||
const optionId = method.id ?? method.name ?? `payment-method-${index}`;
|
const optionId = method.name ?? method.id ?? `payment-method-${index}`;
|
||||||
const isActive = method?.isActive === true || method?.active === true;
|
const isActive = method?.isActive === true || method?.active === true;
|
||||||
const isSelected = String(selectedPayment) === String(optionId);
|
const isSelected = String(selectedPayment) === String(optionId);
|
||||||
const Icon = method.icon || CreditCard;
|
const Icon = method.icon || CreditCard;
|
||||||
@ -399,9 +434,11 @@ export default function PaymentsPage() {
|
|||||||
: 'border-gray-200 bg-white hover:border-amber-300 cursor-pointer'
|
: 'border-gray-200 bg-white hover:border-amber-300 cursor-pointer'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className={`w-10 h-10 rounded-xl flex items-center justify-center shrink-0 ${
|
<div
|
||||||
isSelected ? 'bg-amber-500 text-white' : 'bg-gray-100 text-gray-500'
|
className={`w-10 h-10 rounded-xl flex items-center justify-center shrink-0 ${
|
||||||
}`}>
|
isSelected ? 'bg-amber-500 text-white' : 'bg-gray-100 text-gray-500'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<Icon className="w-5 h-5" />
|
<Icon className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
@ -413,9 +450,11 @@ export default function PaymentsPage() {
|
|||||||
{method.description}
|
{method.description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<span className={`inline-block mt-1 text-[10px] font-medium px-2 py-0.5 rounded-full ${
|
<span
|
||||||
isActive ? 'bg-amber-100 text-amber-700' : 'bg-gray-200 text-gray-500'
|
className={`inline-block mt-1 text-[10px] font-medium px-2 py-0.5 rounded-full ${
|
||||||
}`}>
|
isActive ? 'bg-amber-100 text-amber-700' : 'bg-gray-200 text-gray-500'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{isActive ? t('active', { defaultValue: 'نشط' }) : t('inactive', { defaultValue: 'غير نشط' })}
|
{isActive ? t('active', { defaultValue: 'نشط' }) : t('inactive', { defaultValue: 'غير نشط' })}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -431,103 +470,118 @@ export default function PaymentsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Pay button */}
|
{/* Upload receipt only for Haram */}
|
||||||
<div className="px-6 py-5 border-b border-gray-100">
|
{isHaramPayment && (
|
||||||
<motion.button
|
<div className="px-6 py-5 border-b border-gray-100">
|
||||||
type="button"
|
<label className="block text-sm font-bold text-gray-700 mb-3">
|
||||||
onClick={() => onPay(r, selectedPayment)}
|
{t('payments.uploadReceipt', { defaultValue: 'صورة الوصل' })}
|
||||||
disabled={payingId === r.id}
|
</label>
|
||||||
whileHover={{ scale: 1.01 }}
|
<input
|
||||||
whileTap={{ scale: 0.99 }}
|
type="file"
|
||||||
className="w-full bg-amber-500 hover:bg-amber-600 disabled:bg-amber-300 text-white font-bold py-4 px-6 rounded-2xl text-lg transition-all shadow-lg hover:shadow-xl flex items-center justify-center gap-3"
|
accept="image/*"
|
||||||
>
|
onChange={(e) => setLocalPaymentImage(e.target.files?.[0] || null)}
|
||||||
{payingId === r.id ? (
|
className="block w-full rounded-2xl border border-gray-300 bg-white px-4 py-3 text-sm text-gray-700 file:mr-4 file:rounded-xl file:border-0 file:bg-amber-500 file:px-4 file:py-2 file:text-white hover:file:bg-amber-600"
|
||||||
<>
|
/>
|
||||||
<Loader2 className="w-5 h-5 animate-spin" />
|
</div>
|
||||||
{t('payments.processingPayment')}
|
)}
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Banknote className="w-5 h-5" />
|
|
||||||
{t('payments.payButton', { amount: formatCurrency(amount, r.currencySign) })}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</motion.button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Cash pay button */}
|
{/* Pay button */}
|
||||||
<div className="px-6 py-4 border-b border-gray-100">
|
<div className="px-6 py-5 border-b border-gray-100">
|
||||||
<button
|
<motion.button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowCashDialog(true)}
|
onClick={() => onPay(r, selectedPayment, localPaymentImage)}
|
||||||
className="w-full bg-white border-2 border-amber-200 hover:border-amber-400 text-amber-700 font-bold py-3 px-6 rounded-2xl text-base transition-all flex items-center justify-center gap-2"
|
disabled={payingId === r.id}
|
||||||
>
|
whileHover={{ scale: 1.01 }}
|
||||||
<Building className="w-5 h-5" />
|
whileTap={{ scale: 0.99 }}
|
||||||
{t('payments.payCashButton')}
|
className="w-full bg-amber-500 hover:bg-amber-600 disabled:bg-amber-300 text-white font-bold py-4 px-6 rounded-2xl text-lg transition-all shadow-lg hover:shadow-xl flex items-center justify-center gap-3"
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Cash payment dialog */}
|
|
||||||
{showCashDialog && (
|
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 px-4 py-8">
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, scale: 0.95 }}
|
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
|
||||||
className="w-full max-w-md rounded-3xl bg-white p-8 shadow-2xl border border-gray-200 text-center"
|
|
||||||
>
|
>
|
||||||
<div className="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-5">
|
{payingId === r.id ? (
|
||||||
<Clock className="w-8 h-8 text-amber-600" />
|
<>
|
||||||
</div>
|
<Loader2 className="w-5 h-5 animate-spin" />
|
||||||
<h3 className="text-xl font-bold text-gray-900 mb-3">{t('payments.cashPendingDialogTitle')}</h3>
|
{t('payments.processingPayment')}
|
||||||
<p className="text-gray-600 leading-relaxed mb-6">
|
</>
|
||||||
{t('payments.cashPendingDialogDesc1')}
|
) : (
|
||||||
<br />
|
<>
|
||||||
{t('payments.cashPendingDialogDesc2')}
|
<Banknote className="w-5 h-5" />
|
||||||
</p>
|
{t('payments.payButton', { amount: formatCurrency(amount, r.currencySign) })}
|
||||||
<div className="bg-gray-50 rounded-2xl p-4 mb-6 text-right">
|
</>
|
||||||
<p className="text-sm font-bold text-gray-800 mb-1">{t('payments.platformOfficeLabel')}</p>
|
)}
|
||||||
<p className="text-sm text-gray-600">{t('payments.platformOfficeFullAddress')}</p>
|
</motion.button>
|
||||||
<p className="text-sm text-gray-600 flex items-center gap-1 mt-1" dir="ltr">
|
</div>
|
||||||
|
|
||||||
|
{/* Cash pay button */}
|
||||||
|
<div className="px-6 py-4 border-b border-gray-100">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowCashDialog(true)}
|
||||||
|
className="w-full bg-white border-2 border-amber-200 hover:border-amber-400 text-amber-700 font-bold py-3 px-6 rounded-2xl text-base transition-all flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<Building className="w-5 h-5" />
|
||||||
|
{t('payments.payCashButton')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Cash payment dialog */}
|
||||||
|
{showCashDialog && (
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 px-4 py-8">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
className="w-full max-w-md rounded-3xl bg-white p-8 shadow-2xl border border-gray-200 text-center"
|
||||||
|
>
|
||||||
|
<div className="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-5">
|
||||||
|
<Clock className="w-8 h-8 text-amber-600" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-bold text-gray-900 mb-3">{t('payments.cashPendingDialogTitle')}</h3>
|
||||||
|
<p className="text-gray-600 leading-relaxed mb-6">
|
||||||
|
{t('payments.cashPendingDialogDesc1')}
|
||||||
|
<br />
|
||||||
|
{t('payments.cashPendingDialogDesc2')}
|
||||||
|
</p>
|
||||||
|
<div className="bg-gray-50 rounded-2xl p-4 mb-6 text-right">
|
||||||
|
<p className="text-sm font-bold text-gray-800 mb-1">{t('payments.platformOfficeLabel')}</p>
|
||||||
|
<p className="text-sm text-gray-600">{t('payments.platformOfficeFullAddress')}</p>
|
||||||
|
<p className="text-sm text-gray-600 flex items-center gap-1 mt-1" dir="ltr">
|
||||||
|
<Phone className="w-3.5 h-3.5" />
|
||||||
|
+963567823411
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-3 sm:flex-row">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowCashDialog(false)}
|
||||||
|
className="w-full px-5 py-3 rounded-xl border border-gray-300 text-gray-700 hover:bg-gray-100 transition-colors font-medium"
|
||||||
|
>
|
||||||
|
{t('payments.closeButton')}
|
||||||
|
</button>
|
||||||
|
<Link
|
||||||
|
href="/reservations"
|
||||||
|
className="w-full px-5 py-3 rounded-xl bg-amber-500 text-white font-semibold text-center hover:bg-amber-600 transition-colors"
|
||||||
|
>
|
||||||
|
{t('payments.myReservationsLink')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Platform location */}
|
||||||
|
<div className="px-6 py-5 bg-gray-50">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Landmark className="w-5 h-5 text-amber-600 shrink-0 mt-0.5" />
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-bold text-gray-800 mb-1">{t('payments.cashPaymentLocationLabel')}</p>
|
||||||
|
<p className="text-sm text-gray-600 leading-relaxed">
|
||||||
|
{t('payments.platformOfficeFullAddress')}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-gray-600 flex items-center gap-1 mt-1">
|
||||||
<Phone className="w-3.5 h-3.5" />
|
<Phone className="w-3.5 h-3.5" />
|
||||||
+963567823411
|
<span dir="ltr">+963567823411</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-3 sm:flex-row">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setShowCashDialog(false)}
|
|
||||||
className="w-full px-5 py-3 rounded-xl border border-gray-300 text-gray-700 hover:bg-gray-100 transition-colors font-medium"
|
|
||||||
>
|
|
||||||
{t('payments.closeButton')}
|
|
||||||
</button>
|
|
||||||
<Link
|
|
||||||
href="/reservations"
|
|
||||||
className="w-full px-5 py-3 rounded-xl bg-amber-500 text-white font-semibold text-center hover:bg-amber-600 transition-colors"
|
|
||||||
>
|
|
||||||
{t('payments.myReservationsLink')}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Platform location */}
|
|
||||||
<div className="px-6 py-5 bg-gray-50">
|
|
||||||
<div className="flex items-start gap-3">
|
|
||||||
<Landmark className="w-5 h-5 text-amber-600 shrink-0 mt-0.5" />
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-bold text-gray-800 mb-1">{t('payments.cashPaymentLocationLabel')}</p>
|
|
||||||
<p className="text-sm text-gray-600 leading-relaxed">
|
|
||||||
{t('payments.platformOfficeFullAddress')}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-gray-600 flex items-center gap-1 mt-1">
|
|
||||||
<Phone className="w-3.5 h-3.5" />
|
|
||||||
<span dir="ltr">+963567823411</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</motion.div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -672,17 +672,38 @@ export async function ownerConfirmReservation(id) {
|
|||||||
|
|
||||||
// ─── Payments ───
|
// ─── Payments ───
|
||||||
|
|
||||||
|
|
||||||
export async function payDeposit(data) {
|
export async function payDeposit(data) {
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
formData.append(
|
||||||
|
"ReservationId",
|
||||||
|
String(data.reservationId ?? data.ReservationId ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
|
formData.append(
|
||||||
|
"PaymentTypeId",
|
||||||
|
String(data.paymentTypeId ?? data.PaymentTypeId ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.comment) {
|
||||||
|
formData.append("Comment", data.comment);
|
||||||
|
} else {
|
||||||
|
formData.append("Comment", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// صورة الوصل لطريقة الدفع Haram
|
||||||
|
if (data.paymentImage) {
|
||||||
|
formData.append("TransactionType", data.paymentImage);
|
||||||
|
formData.append("paymentImage", data.paymentImage);
|
||||||
|
}
|
||||||
|
|
||||||
return apiFetch("/Reservations/PayDeposit/pay-deposit", {
|
return apiFetch("/Reservations/PayDeposit/pay-deposit", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: data,
|
body: formData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMyTransaction() {
|
|
||||||
return apiFetch("/Customer/GetMyTransaction");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Owner Contact & Stats ───
|
// ─── Owner Contact & Stats ───
|
||||||
|
|
||||||
export async function getOwnerContactInformation(propertyInformationId) {
|
export async function getOwnerContactInformation(propertyInformationId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user