diff --git a/app/i18n/config.js b/app/i18n/config.js index 928658f..977da54 100644 --- a/app/i18n/config.js +++ b/app/i18n/config.js @@ -60,6 +60,9 @@ const resources = { "termsOfUse": "Terms of Use", "privacyPolicy": "Privacy Policy", "invalidCredentials": "Invalid credentials", + "serverError": "Server error, please try again later", + "apiNotFound": "Service temporarily unavailable", + "tooManyRequests": "Too many requests, please wait", "connectionError": "A connection error occurred", "phoneInvalid": "Invalid phone number", "resendSuccess": "Verification code resent", @@ -1488,6 +1491,16 @@ const resources = { "payments.cashPendingDialogDesc2": "The platform will confirm the payment after receiving the amount.", "payments.platformOfficeFullAddress": "Platform Office: Abu Rumaneh, Al-Malki Street, Damascus", "payments.closeButton": "Close", + "payments.propertyLabel": "Property", + + "payments.method.cash": "Cash Payment", + "payments.method.cashDesc": "Pay now with automatic booking confirmation", + "payments.method.office": "Cash", + "payments.method.officeDesc": "Pay at the platform office. Confirmed later.", + "payments.method.transfer": "Internal Transfer", + "payments.method.transferDesc": "Transfer from internal account then send reference", + "payments.method.electronic": "Electronic Payment", + "payments.method.electronicDesc": "Electronic payment will be activated later", /* ─── Onboarding ─── */ "onboarding.step1.title": "Welcome to SweetHome", @@ -1655,6 +1668,9 @@ const resources = { "termsOfUse": "شروط الاستخدام", "privacyPolicy": "سياسة الخصوصية", "invalidCredentials": "بيانات الدخول غير صحيحة", + "serverError": "خطأ في الخادم، يرجى المحاولة لاحقاً", + "apiNotFound": "الخدمة غير متاحة مؤقتاً", + "tooManyRequests": "طلبات كثيرة جداً، يرجى الانتظار", "connectionError": "حدث خطأ في الاتصال", "phoneInvalid": "رقم الهاتف غير صالح", "resendSuccess": "تم إرسال رمز التحقق مجدداً", @@ -2924,6 +2940,16 @@ const resources = { "payments.cashPendingDialogDesc2": "ستقوم المنصة بتأكيد الدفع بعد استلام المبلع.", "payments.platformOfficeFullAddress": "مكتب المنصة: أبو رمانة، شارع المالكي، دمشق", "payments.closeButton": "إغلاق", + "payments.propertyLabel": "عقار", + + "payments.method.cash": "الدفع النقدي", + "payments.method.cashDesc": "ادفع الآن عبر شام كاش مع تأكيد تلقائي للحجز", + "payments.method.office": "نقداً", + "payments.method.officeDesc": "ادفع في مكتب المنصة. يتم التأكيد لاحقاً", + "payments.method.transfer": "تحويل داخلي", + "payments.method.transferDesc": "حول من حساب داخلي ثم أرسل المرجع", + "payments.method.electronic": "دفع إلكتروني", + "payments.method.electronicDesc": "سيتم تفعيل الدفع الإلكتروني لاحقاً", /* ─── Onboarding ─── */ "onboarding.step1.title": "مرحباً بك في SweetHome", diff --git a/app/login/page.js b/app/login/page.js index 2857520..e3fd8ef 100644 --- a/app/login/page.js +++ b/app/login/page.js @@ -153,8 +153,21 @@ export default function LoginPage() { } setStep("otp"); + } else if (result.status >= 500) { + console.error("[Login] Server error:", result.status, result.data); + toast.error(t("serverError"), { + style: { background: "#fee2e2", color: "#991b1b" }, + }); + } else if (result.status === 404) { + console.error("[Login] API endpoint not found:", result.status); + toast.error(t("apiNotFound"), { + style: { background: "#fee2e2", color: "#991b1b" }, + }); + } else if (result.status === 429) { + toast.error(t("tooManyRequests"), { + style: { background: "#fee2e2", color: "#991b1b" }, + }); } else { - // Other error console.error("[Login] Unexpected status:", result.status, result.data); toast.error( result.data?.message || result.data || t("invalidCredentials"), diff --git a/app/payments/page.js b/app/payments/page.js index d08f231..39cfefa 100644 --- a/app/payments/page.js +++ b/app/payments/page.js @@ -30,47 +30,27 @@ import { payDeposit, getMyTransaction } from '@/app/utils/api'; const STATUS_MAP = ['pending', 'ownerConfirmed', 'depositPaid', 'depositConfirmed', 'completed', 'cancelled']; -const STATUS_CONFIG = { - pending: { label: 'قيد الانتظار', color: 'bg-yellow-100 text-yellow-800 border-yellow-300', icon: Clock }, - ownerConfirmed: { label: 'مؤكد من المالك', color: 'bg-blue-100 text-blue-800 border-blue-300', icon: ShieldCheck }, - depositPaid: { label: 'تم دفع السلفة', color: 'bg-orange-100 text-orange-800 border-orange-300', icon: Wallet }, - depositConfirmed: { label: 'تم تأكيد الدفع', color: 'bg-green-100 text-green-800 border-green-300', icon: Check }, - completed: { label: 'منتهي', color: 'bg-teal-100 text-teal-800 border-teal-300', icon: Check }, - cancelled: { label: 'ملغي', color: 'bg-red-100 text-red-800 border-red-300', icon: X }, -}; +function getStatusConfig(t) { + return { + pending: { label: t('bookingStatus.pending'), color: 'bg-yellow-100 text-yellow-800 border-yellow-300', icon: Clock }, + ownerConfirmed: { label: t('bookingStatus.ownerConfirmed'), color: 'bg-blue-100 text-blue-800 border-blue-300', icon: ShieldCheck }, + depositPaid: { label: t('bookingStatus.depositPaid'), color: 'bg-orange-100 text-orange-800 border-orange-300', icon: Wallet }, + depositConfirmed: { label: t('bookingStatus.depositConfirmed'), color: 'bg-green-100 text-green-800 border-green-300', icon: Check }, + completed: { label: t('bookingStatus.completed'), color: 'bg-teal-100 text-teal-800 border-teal-300', icon: Check }, + cancelled: { label: t('bookingStatus.cancelled'), color: 'bg-red-100 text-red-800 border-red-300', icon: X }, + }; +} -const PAYMENT_METHODS = [ - { - id: 'cash', - label: 'الدفع النقدي', - desc: 'ادفع الآن عبر شام كاش مع تأكيد تلقائي للحجز', - icon: Banknote, - active: true, - }, - { - id: 'office', - label: 'نقداً', - desc: 'ادفع في مكتب المنصة. يتم التأكيد لاحقاً', - icon: Building, - active: true, - }, - { - id: 'transfer', - label: 'تحويل داخلي', - desc: 'حول من حساب داخلي ثم أرسل المرجع', - icon: ArrowLeftRight, - active: false, - }, - { - id: 'electronic', - label: 'دفع إلكتروني', - desc: 'سيتم تفعيل الدفع الإلكتروني والتحويل لاحقاً', - icon: CreditCard, - active: false, - } -]; +function getPaymentMethods(t) { + return [ + { id: 'cash', label: t('payments.method.cash'), desc: t('payments.method.cashDesc'), icon: Banknote, active: true }, + { id: 'office', label: t('payments.method.office'), desc: t('payments.method.officeDesc'), icon: Building, active: true }, + { id: 'transfer', label: t('payments.method.transfer'), desc: t('payments.method.transferDesc'), icon: ArrowLeftRight, active: false }, + { id: 'electronic', label: t('payments.method.electronic'), desc: t('payments.method.electronicDesc'), icon: CreditCard, active: false }, + ]; +} -function formatCurrency(v, sign = 'ل.س') { +function formatCurrency(v, sign = '') { return `${sign} ${Number(v ?? 0).toLocaleString()}`; } @@ -82,7 +62,7 @@ function formatDate(date) { } export default function PaymentsPage() { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const [reservations, setReservations] = useState([]); const [loading, setLoading] = useState(true); const [payingId, setPayingId] = useState(null); @@ -109,10 +89,10 @@ export default function PaymentsPage() { endDate: reservation.endDate, totalPrice: reservation.totalPrice ?? transaction.amount ?? 0, depositAmount: transaction.amount ?? reservation.totalPrice ?? 0, - currencySign: currency.sign || 'ل.س', + currencySign: currency.sign || t('currency.syp'), currencyName: currency.name || '', currencyRate: currency.rate, - propertyName: propertyInfo.name || propertyInfo.address || reservation.propertyName || `عقار #${reservation.id || ''}`, + propertyName: propertyInfo.name || propertyInfo.address || reservation.propertyName || `${t('payments.propertyLabel')} #${reservation.id || ''}`, propertyAddress: propertyInfo.address || reservation.propertyAddress || '', propertyCity: propertyInfo.city || reservation.city || '', _deposit: deposit, @@ -127,7 +107,7 @@ export default function PaymentsPage() { } finally { setLoading(false); } - }, []); + }, [t]); useEffect(() => { if (AuthService.isGuest()) { @@ -156,7 +136,7 @@ export default function PaymentsPage() { if (loading) { return ( -
{t('payments.paymentMethodLabel')}