forked from amer2004/SweetHome
Edit payment with haram
This commit is contained in:
@ -1497,6 +1497,12 @@ const resources = {
|
|||||||
"payments.platformOfficeFullAddress": "Platform Office: Abu Rumaneh, Al-Malki Street, Damascus",
|
"payments.platformOfficeFullAddress": "Platform Office: Abu Rumaneh, Al-Malki Street, Damascus",
|
||||||
"payments.closeButton": "Close",
|
"payments.closeButton": "Close",
|
||||||
"payments.propertyLabel": "Property",
|
"payments.propertyLabel": "Property",
|
||||||
|
"payments.uploadReceipt": "Upload Receipt Image",
|
||||||
|
"payments.loadingPaymentMethods": "Loading payment methods...",
|
||||||
|
"payments.noPaymentMethodsAvailable": "No payment methods available.",
|
||||||
|
"payments.paymentMethodName": "Payment Method",
|
||||||
|
"payments.methodActive": "Active",
|
||||||
|
"payments.methodInactive": "Inactive",
|
||||||
|
|
||||||
"payments.method.cash": "Cash Payment",
|
"payments.method.cash": "Cash Payment",
|
||||||
"payments.method.cashDesc": "Pay now with automatic booking confirmation",
|
"payments.method.cashDesc": "Pay now with automatic booking confirmation",
|
||||||
@ -2951,6 +2957,12 @@ const resources = {
|
|||||||
"payments.platformOfficeFullAddress": "مكتب المنصة: أبو رمانة، شارع المالكي، دمشق",
|
"payments.platformOfficeFullAddress": "مكتب المنصة: أبو رمانة، شارع المالكي، دمشق",
|
||||||
"payments.closeButton": "إغلاق",
|
"payments.closeButton": "إغلاق",
|
||||||
"payments.propertyLabel": "عقار",
|
"payments.propertyLabel": "عقار",
|
||||||
|
"payments.uploadReceipt": "صورة الوصل",
|
||||||
|
"payments.loadingPaymentMethods": "جاري تحميل طرق الدفع...",
|
||||||
|
"payments.noPaymentMethodsAvailable": "لا توجد طرق دفع متاحة حالياً.",
|
||||||
|
"payments.paymentMethodName": "طريقة الدفع",
|
||||||
|
"payments.methodActive": "نشط",
|
||||||
|
"payments.methodInactive": "غير نشط",
|
||||||
|
|
||||||
"payments.method.cash": "الدفع النقدي",
|
"payments.method.cash": "الدفع النقدي",
|
||||||
"payments.method.cashDesc": "ادفع الآن عبر شام كاش مع تأكيد تلقائي للحجز",
|
"payments.method.cashDesc": "ادفع الآن عبر شام كاش مع تأكيد تلقائي للحجز",
|
||||||
|
|||||||
@ -65,6 +65,11 @@ function normalizeText(value) {
|
|||||||
return String(value ?? '').trim().toLowerCase();
|
return String(value ?? '').trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isHaramText(value) {
|
||||||
|
const text = normalizeText(value);
|
||||||
|
return text.includes('haram') || text.includes('هرم');
|
||||||
|
}
|
||||||
|
|
||||||
export default function PaymentsPage() {
|
export default function PaymentsPage() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [reservations, setReservations] = useState([]);
|
const [reservations, setReservations] = useState([]);
|
||||||
@ -161,12 +166,11 @@ export default function PaymentsPage() {
|
|||||||
(m) => String(m.id) === String(paymentTypeId) || String(m.name) === String(paymentTypeId),
|
(m) => String(m.id) === String(paymentTypeId) || String(m.name) === String(paymentTypeId),
|
||||||
);
|
);
|
||||||
|
|
||||||
const isHaram = normalizeText(selectedMethod?.name).includes('haram');
|
const isHaram =
|
||||||
|
isHaramText(selectedMethod?.name) ||
|
||||||
if (isHaram && !paymentImageFile) {
|
isHaramText(selectedMethod?.label) ||
|
||||||
toast.error(t('payments.uploadReceiptRequired', { defaultValue: 'يرجى رفع صورة الوصل' }));
|
isHaramText(selectedMethod?.id) ||
|
||||||
return;
|
isHaramText(paymentKey);
|
||||||
}
|
|
||||||
|
|
||||||
setPayingId(reservation.id);
|
setPayingId(reservation.id);
|
||||||
try {
|
try {
|
||||||
@ -335,10 +339,10 @@ function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMeth
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isHaramPayment =
|
const isHaramPayment =
|
||||||
normalizeText(selectedPayment).includes('haram') ||
|
isHaramText(selectedPayment) ||
|
||||||
normalizeText(selectedMethod?.name).includes('haram') ||
|
isHaramText(selectedMethod?.name) ||
|
||||||
normalizeText(selectedMethod?.label).includes('haram') ||
|
isHaramText(selectedMethod?.label) ||
|
||||||
normalizeText(selectedMethod?.id).includes('haram');
|
isHaramText(selectedMethod?.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -407,11 +411,11 @@ function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMeth
|
|||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
{loadingPaymentMethods ? (
|
{loadingPaymentMethods ? (
|
||||||
<div className="col-span-full rounded-2xl border border-dashed border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
<div className="col-span-full rounded-2xl border border-dashed border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
||||||
{t('payments.loadingPaymentMethods', { defaultValue: 'جاري تحميل طرق الدفع...' })}
|
{t('payments.loadingPaymentMethods')}
|
||||||
</div>
|
</div>
|
||||||
) : methods.length === 0 ? (
|
) : methods.length === 0 ? (
|
||||||
<div className="col-span-full rounded-2xl border border-dashed border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
<div className="col-span-full rounded-2xl border border-dashed border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
||||||
{t('payments.noPaymentMethodsAvailable', { defaultValue: 'لا توجد طرق دفع متاحة حالياً.' })}
|
{t('payments.noPaymentMethodsAvailable')}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
methods.map((method, index) => {
|
methods.map((method, index) => {
|
||||||
@ -443,7 +447,7 @@ function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMeth
|
|||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className={`text-sm font-bold ${isSelected ? 'text-amber-900' : 'text-gray-800'}`}>
|
<p className={`text-sm font-bold ${isSelected ? 'text-amber-900' : 'text-gray-800'}`}>
|
||||||
{method.name || method.label || t('paymentMethod', { defaultValue: 'طريقة الدفع' })}
|
{method.name || method.label || t('payments.paymentMethodName')}
|
||||||
</p>
|
</p>
|
||||||
{method.description && (
|
{method.description && (
|
||||||
<p className="text-xs text-gray-500 mt-0.5 leading-relaxed">
|
<p className="text-xs text-gray-500 mt-0.5 leading-relaxed">
|
||||||
@ -455,7 +459,7 @@ function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMeth
|
|||||||
isActive ? 'bg-amber-100 text-amber-700' : 'bg-gray-200 text-gray-500'
|
isActive ? 'bg-amber-100 text-amber-700' : 'bg-gray-200 text-gray-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isActive ? t('active', { defaultValue: 'نشط' }) : t('inactive', { defaultValue: 'غير نشط' })}
|
{isActive ? t('payments.methodActive') : t('payments.methodInactive')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
@ -474,7 +478,7 @@ function PaymentCard({ reservation, payingId, paymentMethods, loadingPaymentMeth
|
|||||||
{isHaramPayment && (
|
{isHaramPayment && (
|
||||||
<div className="px-6 py-5 border-b border-gray-100">
|
<div className="px-6 py-5 border-b border-gray-100">
|
||||||
<label className="block text-sm font-bold text-gray-700 mb-3">
|
<label className="block text-sm font-bold text-gray-700 mb-3">
|
||||||
{t('payments.uploadReceipt', { defaultValue: 'صورة الوصل' })}
|
{t('payments.uploadReceipt')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import AuthService from "../services/AuthService";
|
import AuthService from "../services/AuthService";
|
||||||
const API_BASE =
|
|
||||||
process.env.NEXT_PUBLIC_API_URL || "https://45.93.137.91.nip.io/api";
|
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "https://45.93.137.91.nip.io/api";
|
||||||
const REPORT_API_BASE =
|
const REPORT_API_BASE = process.env.NEXT_PUBLIC_REPORT_API_URL || "http://45.93.137.91/api";
|
||||||
process.env.NEXT_PUBLIC_API_URL || "http://45.93.137.91/api";
|
|
||||||
|
|
||||||
function isFormData(value) {
|
function isFormData(value) {
|
||||||
return typeof FormData !== "undefined" && value instanceof FormData;
|
return typeof FormData !== "undefined" && value instanceof FormData;
|
||||||
@ -65,6 +64,7 @@ async function apiFetch(endpoint, options = {}) {
|
|||||||
|
|
||||||
const url = `${API_BASE}${endpoint}`;
|
const url = `${API_BASE}${endpoint}`;
|
||||||
|
|
||||||
|
try {
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
...options,
|
...options,
|
||||||
headers,
|
headers,
|
||||||
@ -93,6 +93,14 @@ async function apiFetch(endpoint, options = {}) {
|
|||||||
} catch {
|
} catch {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError && error.message === 'Failed to fetch') {
|
||||||
|
throw new Error(
|
||||||
|
`تعذر الاتصال بالخادم. تحقق من اتصالك بالإنترنت أو حاول مرة أخرى لاحقاً. (${API_BASE}${endpoint})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,11 +118,16 @@ async function authFetch(endpoint, body, token = null) {
|
|||||||
headers["Authorization"] = `Bearer ${token}`;
|
headers["Authorization"] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(`${API_BASE}${endpoint}`, {
|
let res;
|
||||||
|
try {
|
||||||
|
res = await fetch(`${API_BASE}${endpoint}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers,
|
||||||
body: bodyIsFormData ? body : JSON.stringify(body),
|
body: bodyIsFormData ? body : JSON.stringify(body),
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
return { status: 0, data: null, ok: false, message: err.message };
|
||||||
|
}
|
||||||
|
|
||||||
assertNotBlocked(res);
|
assertNotBlocked(res);
|
||||||
|
|
||||||
@ -142,13 +155,18 @@ async function authFetch(endpoint, body, token = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function reportFetch(endpoint, body) {
|
async function reportFetch(endpoint, body) {
|
||||||
const res = await fetch(buildApiUrl(REPORT_API_BASE, endpoint), {
|
let res;
|
||||||
|
try {
|
||||||
|
res = await fetch(buildApiUrl(REPORT_API_BASE, endpoint), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
return { status: 0, data: null, ok: false, message: err.message };
|
||||||
|
}
|
||||||
|
|
||||||
assertNotBlocked(res);
|
assertNotBlocked(res);
|
||||||
|
|
||||||
@ -392,13 +410,18 @@ export async function uploadPicture(file) {
|
|||||||
|
|
||||||
const token = AuthService.getToken();
|
const token = AuthService.getToken();
|
||||||
|
|
||||||
const res = await fetch(`${API_BASE}/Files/UploadPicture`, {
|
let res;
|
||||||
|
try {
|
||||||
|
res = await fetch(`${API_BASE}/Files/UploadPicture`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
...(token && { Authorization: `Bearer ${token}` }),
|
...(token && { Authorization: `Bearer ${token}` }),
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`تعذر الاتصال بالخادم: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
assertNotBlocked(res);
|
assertNotBlocked(res);
|
||||||
|
|
||||||
@ -604,7 +627,6 @@ export async function adminConfirmDeposit(
|
|||||||
comment = null,
|
comment = null,
|
||||||
) {
|
) {
|
||||||
const token = AuthService.getToken();
|
const token = AuthService.getToken();
|
||||||
const endpoint = `${API_BASE}/Reservations/AdminConfirmDeposit/admin-confirm-deposit`;
|
|
||||||
const normalizedComment =
|
const normalizedComment =
|
||||||
typeof comment === "string" && comment.trim() ? comment.trim() : null;
|
typeof comment === "string" && comment.trim() ? comment.trim() : null;
|
||||||
const payload = {
|
const payload = {
|
||||||
@ -613,7 +635,7 @@ export async function adminConfirmDeposit(
|
|||||||
comment: normalizedComment,
|
comment: normalizedComment,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(endpoint, {
|
const res = await fetch(buildApiUrl(API_BASE, "/Reservations/AdminConfirmDeposit/admin-confirm-deposit"), {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@ -672,6 +694,9 @@ export async function ownerConfirmReservation(id) {
|
|||||||
|
|
||||||
// ─── Payments ───
|
// ─── Payments ───
|
||||||
|
|
||||||
|
export async function getMyTransaction() {
|
||||||
|
return apiFetch("/Customer/GetMyTransaction");
|
||||||
|
}
|
||||||
|
|
||||||
export async function payDeposit(data) {
|
export async function payDeposit(data) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|||||||
Reference in New Issue
Block a user