diff --git a/app/property/[id]/PropertyDetail.js b/app/property/[id]/PropertyDetail.js
index e1c5027..5ead963 100644
--- a/app/property/[id]/PropertyDetail.js
+++ b/app/property/[id]/PropertyDetail.js
@@ -187,7 +187,7 @@ function mapApiDetail(item) {
const rawImages = Array.isArray(info.images) ? info.images : [];
const photosFallback = Array.isArray(details.photos) ? details.photos : [];
const allRaw = rawImages.length > 0 ? rawImages : photosFallback;
- const images = allRaw.length > 0 ? allRaw.map(buildImageUrl) : [];
+ const images = allRaw.length > 0 ? allRaw.map(buildImageUrl).filter(Boolean) : [];
// Normalize services: Flutter sends list of strings or object with boolean values
const rawServices = details.services || {};
diff --git a/app/reservations/page.js b/app/reservations/page.js
index 6887749..9265475 100644
--- a/app/reservations/page.js
+++ b/app/reservations/page.js
@@ -425,7 +425,7 @@ import {
} from 'lucide-react';
import toast, { Toaster } from 'react-hot-toast';
import AuthService from '../services/AuthService';
-import { getRentProperties, getUserReservations, payDeposit } from '../utils/api';
+import { getPaymentTypes, getRentProperties, getUserReservations, payDeposit } from '../utils/api';
import { addPropertyRating } from '../utils/ratings';
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'https://45.93.137.91.nip.io/api';
@@ -441,37 +441,6 @@ const STATUS_UI = {
cancelled: { color: 'bg-gray-100 text-gray-800', icon: XCircle },
};
-const PAYMENT_METHODS = [
- {
- id: 'cash',
- labelKey: 'payment.cash',
- descKey: 'payment.cashDesc',
- icon: Banknote,
- active: true,
- },
- {
- id: 'office',
- labelKey: 'payment.office',
- descKey: 'payment.officeDesc',
- icon: Building,
- active: true,
- },
- {
- id: 'transfer',
- labelKey: 'payment.transfer',
- descKey: 'payment.transferDesc',
- icon: ArrowLeftRight,
- active: false,
- },
- {
- id: 'electronic',
- labelKey: 'payment.electronic',
- descKey: 'payment.electronicDesc',
- icon: CreditCard,
- active: false,
- },
-];
-
function statusColor(code) { return STATUS_UI[STATUS_MAP[code]]?.color ?? 'bg-gray-100 text-gray-700'; }
function statusIcon(code) { return STATUS_UI[STATUS_MAP[code]]?.icon ?? Clock; }
@@ -667,6 +636,8 @@ function PaymentDialog({
onSelectPayment,
onConfirmPay,
payingId,
+ paymentMethods,
+ loadingPaymentMethods,
}) {
const { t } = useTranslation();
const [showCashDialog, setShowCashDialog] = useState(false);
@@ -745,52 +716,66 @@ function PaymentDialog({
{t('paymentMethod')}
-
- {PAYMENT_METHODS.map((method) => {
- const isSelected = selectedPayment === method.id;
- const Icon = method.icon;
+ {loadingPaymentMethods ? (
+
+ {t('loadingPaymentMethods', { defaultValue: 'جاري تحميل طرق الدفع...' })}
+
+ ) : (!Array.isArray(paymentMethods) || paymentMethods.length === 0) ? (
+
+ {t('noPaymentMethodsAvailable', { defaultValue: 'لا توجد طرق دفع متاحة حالياً.' })}
+
+ ) : (
+
+ {paymentMethods.map((method, index) => {
+ const isActive = method?.isActive === true || method?.active === true;
+ const optionId = method?.id ?? method?.name ?? `payment-method-${index}`;
+ const label = method?.name || t('paymentMethod', { defaultValue: 'طريقة الدفع' });
+ const isSelected = selectedPayment === optionId;
- return (
-
+ );
+ })}
+
+ )}
@@ -1176,8 +1161,8 @@ export default function UserReservationsPage() {
const [reportingId, setReportingId] = useState(null);
const [selectedPayment, setSelectedPayment] = useState('cash');
const [paymentDialog, setPaymentDialog] = useState({ open: false, reservation: null });
-
- useEffect(() => { if (!AuthService.getUser()) { router.push('/login'); return; } loadReservations(); }, [router]);
+ const [paymentMethods, setPaymentMethods] = useState([]);
+ const [loadingPaymentMethods, setLoadingPaymentMethods] = useState(false);
const loadReservations = useCallback(async () => {
try {
@@ -1207,8 +1192,27 @@ export default function UserReservationsPage() {
setFiltered([]);
}
setLoading(false);
+ }, [t]);
+
+ useEffect(() => { if (!AuthService.getUser()) { router.push('/login'); return; } loadReservations(); }, [router, loadReservations]);
+
+ const loadPaymentMethods = useCallback(async () => {
+ setLoadingPaymentMethods(true);
+ try {
+ const data = await getPaymentTypes();
+ setPaymentMethods(Array.isArray(data) ? data : []);
+ } catch (err) {
+ console.error(err);
+ setPaymentMethods([]);
+ } finally {
+ setLoadingPaymentMethods(false);
+ }
}, []);
+ useEffect(() => {
+ loadPaymentMethods();
+ }, [loadPaymentMethods]);
+
useEffect(() => {
let r = reservations;
if (filterStatus !== 'all') r = r.filter(x => STATUS_MAP[x.status] === filterStatus);
@@ -1301,6 +1305,8 @@ export default function UserReservationsPage() {
onSelectPayment={setSelectedPayment}
onConfirmPay={handleConfirmPay}
payingId={payingId}
+ paymentMethods={paymentMethods}
+ loadingPaymentMethods={loadingPaymentMethods}
/>
diff --git a/app/utils/api.js b/app/utils/api.js
index 53c0327..1f0ee27 100644
--- a/app/utils/api.js
+++ b/app/utils/api.js
@@ -355,6 +355,10 @@ export async function getCurrencies() {
return apiFetch("/Currency/GetAll");
}
+export async function getPaymentTypes() {
+ return apiFetch("/PaymentType/GetAll");
+}
+
// ─── Files ───
export async function uploadPicture(file) {