mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-29 18:13:47 +00:00
fix: remove duplicate back buttons, improve multi-subscription UX
- Remove custom back buttons from Subscription detail and SubscriptionPurchase pages — native Telegram mini-app back button already handles navigation - SubscriptionListCard: distinct trial badge with star icon and amber styling, trial cards get amber border/background for visual differentiation - SubscriptionPurchase: change "Купить тариф" to "Новый тариф" when adding a new tariff in multi-subscription mode - Subscription detail: show tariff name as title in multi-tariff mode
This commit is contained in:
@@ -19,15 +19,28 @@ function formatDate(iso: string | null, locale?: string): string {
|
|||||||
|
|
||||||
function StatusBadge({
|
function StatusBadge({
|
||||||
status,
|
status,
|
||||||
|
isTrial,
|
||||||
t,
|
t,
|
||||||
}: {
|
}: {
|
||||||
status: string;
|
status: string;
|
||||||
|
isTrial: boolean;
|
||||||
t: (key: string, fallback: string) => string;
|
t: (key: string, fallback: string) => string;
|
||||||
}) {
|
}) {
|
||||||
const isActive = status === 'active' || status === 'trial';
|
const isActive = status === 'active' || status === 'trial';
|
||||||
const isLimited = status === 'limited';
|
const isLimited = status === 'limited';
|
||||||
const isExpired = status === 'expired' || status === 'disabled';
|
const isExpired = status === 'expired' || status === 'disabled';
|
||||||
|
|
||||||
|
if (isTrial) {
|
||||||
|
return (
|
||||||
|
<span className="inline-flex items-center gap-1 rounded-full border border-amber-400/25 bg-amber-400/10 px-2 py-0.5 text-[10px] font-semibold text-amber-400">
|
||||||
|
<svg className="h-2.5 w-2.5" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" />
|
||||||
|
</svg>
|
||||||
|
{t('subscription.statusTrial', 'Тестовая')}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const color = isActive
|
const color = isActive
|
||||||
? 'bg-emerald-400/15 text-emerald-400 border-emerald-400/20'
|
? 'bg-emerald-400/15 text-emerald-400 border-emerald-400/20'
|
||||||
: isLimited
|
: isLimited
|
||||||
@@ -35,9 +48,7 @@ function StatusBadge({
|
|||||||
: 'bg-red-400/15 text-red-400 border-red-400/20';
|
: 'bg-red-400/15 text-red-400 border-red-400/20';
|
||||||
|
|
||||||
const label = isActive
|
const label = isActive
|
||||||
? status === 'trial'
|
? t('subscription.statusActive', 'Активна')
|
||||||
? t('subscription.statusTrial', 'Тестовая')
|
|
||||||
: t('subscription.statusActive', 'Активна')
|
|
||||||
: isLimited
|
: isLimited
|
||||||
? t('subscription.statusLimited', 'Ограничена')
|
? t('subscription.statusLimited', 'Ограничена')
|
||||||
: isExpired
|
: isExpired
|
||||||
@@ -70,6 +81,7 @@ export default function SubscriptionListCard({
|
|||||||
onClick();
|
onClick();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isTrial = subscription.is_trial;
|
||||||
const isActive = subscription.status === 'active' || subscription.status === 'trial';
|
const isActive = subscription.status === 'active' || subscription.status === 'trial';
|
||||||
const isExpired = subscription.status === 'expired' || subscription.status === 'disabled';
|
const isExpired = subscription.status === 'expired' || subscription.status === 'disabled';
|
||||||
const trafficLimit = subscription.traffic_limit_gb;
|
const trafficLimit = subscription.traffic_limit_gb;
|
||||||
@@ -83,18 +95,27 @@ export default function SubscriptionListCard({
|
|||||||
const trafficColor =
|
const trafficColor =
|
||||||
trafficPercent >= 90 ? 'bg-red-400' : trafficPercent >= 70 ? 'bg-amber-400' : 'bg-emerald-400';
|
trafficPercent >= 90 ? 'bg-red-400' : trafficPercent >= 70 ? 'bg-amber-400' : 'bg-emerald-400';
|
||||||
|
|
||||||
|
const borderColor = isTrial
|
||||||
|
? 'rgba(251,191,36,0.2)'
|
||||||
|
: isExpired
|
||||||
|
? 'rgba(255,59,92,0.15)'
|
||||||
|
: g.cardBorder;
|
||||||
|
|
||||||
|
const bgColor = isTrial
|
||||||
|
? isDark
|
||||||
|
? 'rgba(251,191,36,0.04)'
|
||||||
|
: 'rgba(251,191,36,0.03)'
|
||||||
|
: isExpired
|
||||||
|
? isDark
|
||||||
|
? 'rgba(255,59,92,0.04)'
|
||||||
|
: 'rgba(255,59,92,0.03)'
|
||||||
|
: g.cardBg;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className="w-full rounded-2xl border p-4 text-left transition-all duration-200 hover:scale-[1.01] active:scale-[0.99]"
|
className="w-full rounded-2xl border p-4 text-left transition-all duration-200 hover:scale-[1.01] active:scale-[0.99]"
|
||||||
style={{
|
style={{ background: bgColor, borderColor }}
|
||||||
background: isExpired
|
|
||||||
? isDark
|
|
||||||
? 'rgba(255,59,92,0.04)'
|
|
||||||
: 'rgba(255,59,92,0.03)'
|
|
||||||
: g.cardBg,
|
|
||||||
borderColor: isExpired ? 'rgba(255,59,92,0.15)' : g.cardBorder,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{/* Header: tariff name + status badge + chevron */}
|
{/* Header: tariff name + status badge + chevron */}
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
@@ -102,7 +123,7 @@ export default function SubscriptionListCard({
|
|||||||
<span className="truncate text-base font-semibold" style={{ color: g.text }}>
|
<span className="truncate text-base font-semibold" style={{ color: g.text }}>
|
||||||
{subscription.tariff_name || t('subscription.defaultName', 'Подписка')}
|
{subscription.tariff_name || t('subscription.defaultName', 'Подписка')}
|
||||||
</span>
|
</span>
|
||||||
<StatusBadge status={subscription.status} t={t} />
|
<StatusBadge status={subscription.status} isTrial={isTrial} t={t} />
|
||||||
</div>
|
</div>
|
||||||
<svg
|
<svg
|
||||||
className="h-4 w-4 shrink-0 opacity-30"
|
className="h-4 w-4 shrink-0 opacity-30"
|
||||||
|
|||||||
@@ -479,34 +479,12 @@ export default function Subscription() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Multi-tariff: back navigation + tariff name */}
|
{/* Page title — native Telegram back button handles navigation */}
|
||||||
{isMultiTariff && subscriptionId ? (
|
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
||||||
<div>
|
{isMultiTariff && subscription?.tariff_name
|
||||||
<button
|
? subscription.tariff_name
|
||||||
onClick={() => navigate('/subscriptions')}
|
: t('subscription.title')}
|
||||||
className="mb-2 flex items-center gap-1.5 text-sm text-dark-50/50 transition-colors hover:text-dark-50/80"
|
</h1>
|
||||||
>
|
|
||||||
<svg
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M15 18l-6-6 6-6" />
|
|
||||||
</svg>
|
|
||||||
{t('subscription.backToList', 'Мои подписки')}
|
|
||||||
</button>
|
|
||||||
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
|
||||||
{subscription?.tariff_name || t('subscription.title')}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">{t('subscription.title')}</h1>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Current Subscription */}
|
{/* Current Subscription */}
|
||||||
{subscription ? (
|
{subscription ? (
|
||||||
|
|||||||
@@ -383,34 +383,7 @@ export default function SubscriptionPurchase() {
|
|||||||
if (optionsError || (!purchaseOptions && !optionsLoading)) {
|
if (optionsError || (!purchaseOptions && !optionsLoading)) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center gap-3">
|
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">{t('subscription.extend')}</h1>
|
||||||
<button
|
|
||||||
onClick={() => navigate('/subscription')}
|
|
||||||
aria-label="Back"
|
|
||||||
className="flex h-9 w-9 items-center justify-center rounded-xl transition-colors"
|
|
||||||
style={{
|
|
||||||
background: g.innerBg,
|
|
||||||
border: `1px solid ${g.innerBorder}`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
width="18"
|
|
||||||
height="18"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="text-dark-50/60"
|
|
||||||
>
|
|
||||||
<path d="M19 12H5M12 19l-7-7 7-7" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
|
||||||
{t('subscription.extend')}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
className="rounded-3xl p-6 text-center"
|
className="rounded-3xl p-6 text-center"
|
||||||
style={{
|
style={{
|
||||||
@@ -434,41 +407,16 @@ export default function SubscriptionPurchase() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Header with back link */}
|
{/* Header — native Telegram back button handles navigation */}
|
||||||
<div className="flex items-center gap-3">
|
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
||||||
<button
|
{isMultiTariff && !subscriptionId
|
||||||
onClick={() => navigate('/subscriptions')}
|
? t('subscription.newTariff', 'Новый тариф')
|
||||||
aria-label="Back"
|
: subscription?.is_daily && !subscription?.is_trial
|
||||||
className="flex h-9 w-9 items-center justify-center rounded-xl transition-colors"
|
? t('subscription.switchTariff.title')
|
||||||
style={{
|
: subscription && !subscription.is_trial
|
||||||
background: g.innerBg,
|
? t('subscription.extend')
|
||||||
border: `1px solid ${g.innerBorder}`,
|
: t('subscription.getSubscription')}
|
||||||
}}
|
</h1>
|
||||||
>
|
|
||||||
<svg
|
|
||||||
width="18"
|
|
||||||
height="18"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
className="text-dark-50/60"
|
|
||||||
>
|
|
||||||
<path d="M19 12H5M12 19l-7-7 7-7" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
|
||||||
{isMultiTariff && !subscriptionId
|
|
||||||
? t('subscription.buyTariff', 'Купить тариф')
|
|
||||||
: subscription?.is_daily && !subscription?.is_trial
|
|
||||||
? t('subscription.switchTariff.title')
|
|
||||||
: subscription && !subscription.is_trial
|
|
||||||
? t('subscription.extend')
|
|
||||||
: t('subscription.getSubscription')}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Tariffs Section */}
|
{/* Tariffs Section */}
|
||||||
{isTariffsMode && tariffs.length > 0 && (
|
{isTariffsMode && tariffs.length > 0 && (
|
||||||
|
|||||||
Reference in New Issue
Block a user