mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
fix: mobile layout and period label translations for quick purchase landing
- Add i18n period labels (ru/en/zh/fa) instead of backend English-only labels - Period tabs wrap on mobile instead of horizontal scroll - Prevent horizontal overflow shifting the layout
This commit is contained in:
@@ -3995,6 +3995,24 @@
|
|||||||
"giftSentSuccess": "Gift sent!",
|
"giftSentSuccess": "Gift sent!",
|
||||||
"giftSentDesc": "Recipient will be notified by email",
|
"giftSentDesc": "Recipient will be notified by email",
|
||||||
"autoLoginFailed": "Auto-login failed",
|
"autoLoginFailed": "Auto-login failed",
|
||||||
"autoLoginProcessing": "Signing in..."
|
"autoLoginProcessing": "Signing in...",
|
||||||
|
"periodLabels": {
|
||||||
|
"d1": "1 day",
|
||||||
|
"d2": "2 days",
|
||||||
|
"d3": "3 days",
|
||||||
|
"d5": "5 days",
|
||||||
|
"d7": "1 week",
|
||||||
|
"d14": "2 weeks",
|
||||||
|
"d30": "1 month",
|
||||||
|
"d60": "2 months",
|
||||||
|
"d90": "3 months",
|
||||||
|
"d180": "6 months",
|
||||||
|
"d365": "1 year",
|
||||||
|
"d456": "1 year + 3 mo.",
|
||||||
|
"nDays_one": "{{count}} day",
|
||||||
|
"nDays_other": "{{count}} days",
|
||||||
|
"nMonths_one": "{{count}} month",
|
||||||
|
"nMonths_other": "{{count}} months"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3546,6 +3546,22 @@
|
|||||||
"giftSentSuccess": "هدیه ارسال شد!",
|
"giftSentSuccess": "هدیه ارسال شد!",
|
||||||
"giftSentDesc": "گیرنده از طریق ایمیل مطلع خواهد شد",
|
"giftSentDesc": "گیرنده از طریق ایمیل مطلع خواهد شد",
|
||||||
"autoLoginFailed": "ورود خودکار ناموفق بود",
|
"autoLoginFailed": "ورود خودکار ناموفق بود",
|
||||||
"autoLoginProcessing": "در حال ورود..."
|
"autoLoginProcessing": "در حال ورود...",
|
||||||
|
"periodLabels": {
|
||||||
|
"d1": "۱ روز",
|
||||||
|
"d2": "۲ روز",
|
||||||
|
"d3": "۳ روز",
|
||||||
|
"d5": "۵ روز",
|
||||||
|
"d7": "۱ هفته",
|
||||||
|
"d14": "۲ هفته",
|
||||||
|
"d30": "۱ ماه",
|
||||||
|
"d60": "۲ ماه",
|
||||||
|
"d90": "۳ ماه",
|
||||||
|
"d180": "۶ ماه",
|
||||||
|
"d365": "۱ سال",
|
||||||
|
"d456": "۱ سال و ۳ ماه",
|
||||||
|
"nDays": "{{count}} روز",
|
||||||
|
"nMonths": "{{count}} ماه"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4554,6 +4554,26 @@
|
|||||||
"giftSentSuccess": "Подарок отправлен!",
|
"giftSentSuccess": "Подарок отправлен!",
|
||||||
"giftSentDesc": "Получатель получит уведомление на email",
|
"giftSentDesc": "Получатель получит уведомление на email",
|
||||||
"autoLoginFailed": "Не удалось выполнить автоматический вход",
|
"autoLoginFailed": "Не удалось выполнить автоматический вход",
|
||||||
"autoLoginProcessing": "Выполняется вход..."
|
"autoLoginProcessing": "Выполняется вход...",
|
||||||
|
"periodLabels": {
|
||||||
|
"d1": "1 день",
|
||||||
|
"d2": "2 дня",
|
||||||
|
"d3": "3 дня",
|
||||||
|
"d5": "5 дней",
|
||||||
|
"d7": "1 неделя",
|
||||||
|
"d14": "2 недели",
|
||||||
|
"d30": "1 месяц",
|
||||||
|
"d60": "2 месяца",
|
||||||
|
"d90": "3 месяца",
|
||||||
|
"d180": "6 месяцев",
|
||||||
|
"d365": "1 год",
|
||||||
|
"d456": "1 год + 3 мес.",
|
||||||
|
"nDays_one": "{{count}} день",
|
||||||
|
"nDays_few": "{{count}} дня",
|
||||||
|
"nDays_many": "{{count}} дней",
|
||||||
|
"nMonths_one": "{{count}} месяц",
|
||||||
|
"nMonths_few": "{{count}} месяца",
|
||||||
|
"nMonths_many": "{{count}} месяцев"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3545,6 +3545,22 @@
|
|||||||
"giftSentSuccess": "礼物已发送!",
|
"giftSentSuccess": "礼物已发送!",
|
||||||
"giftSentDesc": "收件人将通过邮件收到通知",
|
"giftSentDesc": "收件人将通过邮件收到通知",
|
||||||
"autoLoginFailed": "自动登录失败",
|
"autoLoginFailed": "自动登录失败",
|
||||||
"autoLoginProcessing": "正在登录..."
|
"autoLoginProcessing": "正在登录...",
|
||||||
|
"periodLabels": {
|
||||||
|
"d1": "1天",
|
||||||
|
"d2": "2天",
|
||||||
|
"d3": "3天",
|
||||||
|
"d5": "5天",
|
||||||
|
"d7": "1周",
|
||||||
|
"d14": "2周",
|
||||||
|
"d30": "1个月",
|
||||||
|
"d60": "2个月",
|
||||||
|
"d90": "3个月",
|
||||||
|
"d180": "6个月",
|
||||||
|
"d365": "1年",
|
||||||
|
"d456": "1年3个月",
|
||||||
|
"nDays": "{{count}}天",
|
||||||
|
"nMonths": "{{count}}个月"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,22 @@ function isValidContact(value: string): boolean {
|
|||||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed);
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatPeriodLabel(
|
||||||
|
days: number,
|
||||||
|
t: (key: string, options?: Record<string, unknown>) => string,
|
||||||
|
): string {
|
||||||
|
const key = `landing.periodLabels.d${days}`;
|
||||||
|
const result = t(key);
|
||||||
|
if (result !== key) return result;
|
||||||
|
|
||||||
|
const months = Math.floor(days / 30);
|
||||||
|
const remainder = days % 30;
|
||||||
|
if (months > 0 && remainder === 0) {
|
||||||
|
return t('landing.periodLabels.nMonths', { count: months });
|
||||||
|
}
|
||||||
|
return t('landing.periodLabels.nDays', { count: days });
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Sub-components
|
// Sub-components
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -82,21 +98,23 @@ function PeriodTabs({
|
|||||||
selectedDays: number;
|
selectedDays: number;
|
||||||
onSelect: (days: number) => void;
|
onSelect: (days: number) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="scrollbar-none flex gap-2 overflow-x-auto pb-1">
|
<div className="flex flex-wrap gap-2">
|
||||||
{periods.map((period) => (
|
{periods.map((period) => (
|
||||||
<button
|
<button
|
||||||
key={period.days}
|
key={period.days}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onSelect(period.days)}
|
onClick={() => onSelect(period.days)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'whitespace-nowrap rounded-full px-5 py-2.5 text-sm font-medium transition-all duration-200',
|
'whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium transition-all duration-200',
|
||||||
selectedDays === period.days
|
selectedDays === period.days
|
||||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25'
|
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25'
|
||||||
: 'bg-dark-800/50 text-dark-300 hover:bg-dark-700/50 hover:text-dark-100',
|
: 'bg-dark-800/50 text-dark-300 hover:bg-dark-700/50 hover:text-dark-100',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{period.label}
|
{formatPeriodLabel(period.days, t)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -469,7 +487,9 @@ function SummaryCard({
|
|||||||
<p className="text-xs font-medium uppercase tracking-wider text-dark-500">
|
<p className="text-xs font-medium uppercase tracking-wider text-dark-500">
|
||||||
{t('landing.period', 'Period')}
|
{t('landing.period', 'Period')}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm text-dark-200">{selectedPeriod.label}</p>
|
<p className="mt-1 text-sm text-dark-200">
|
||||||
|
{formatPeriodLabel(selectedPeriod.days, t)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="border-t border-dark-800/50 pt-4">
|
<div className="border-t border-dark-800/50 pt-4">
|
||||||
@@ -788,7 +808,7 @@ export default function QuickPurchase() {
|
|||||||
const showTariffCards = visibleTariffs.length > 1;
|
const showTariffCards = visibleTariffs.length > 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-dvh bg-dark-950">
|
<div className="min-h-dvh overflow-x-hidden bg-dark-950">
|
||||||
<div className="mx-auto max-w-5xl px-4 py-8 sm:px-6 lg:px-8">
|
<div className="mx-auto max-w-5xl px-4 py-8 sm:px-6 lg:px-8">
|
||||||
{/* Language switcher */}
|
{/* Language switcher */}
|
||||||
<div className="mb-4 flex justify-end">
|
<div className="mb-4 flex justify-end">
|
||||||
|
|||||||
Reference in New Issue
Block a user