feat: lock traffic topup when under 80% of traffic used

This commit is contained in:
3252a8
2026-05-12 21:27:37 +03:00
parent af66103111
commit 6afbb72a34
4 changed files with 55 additions and 19 deletions
+27 -7
View File
@@ -35,6 +35,9 @@
import { normalizedEmail, telegramName } from "./lib/webapp/formatters.js";
import { activeTariffName, buildTariffCatalog } from "./lib/webapp/tariffs.js";
import { premiumTrafficPercent, trafficPercent } from "./lib/webapp/traffic.js";
/** Used-traffic percent from which top-up modals and CTAs unlock in the web app home screen */
const TRAFFIC_TOPUP_UNLOCK_PERCENT = 80;
import { buildGravatarUrl } from "./lib/webapp/gravatar.js";
import { createBillingActions } from "./lib/webapp/billingActions.js";
import { invalidateWebappTariffOptionCaches } from "./lib/webapp/billingOptionCache.js";
@@ -215,10 +218,26 @@
(subscription?.can_topup_premium_traffic ?? subscription?.can_topup_traffic) &&
Number(subscription?.premium_limit_bytes || 0) > 0,
);
$: canOpenTopupModal = Boolean(canOpenRegularTopupModal || canOpenPremiumTopupModal);
$: canShowTopupButton = Boolean(
canOpenTopupModal &&
(trafficPercent(subscription) >= 85 || premiumTrafficPercent(subscription) >= 85),
$: activeTariffCatalogEntry =
tariffCatalog.find((entry) => entry.key === String(subscription?.tariff_key || "").trim()) || null;
$: subscriptionIsTrafficTariff = Boolean(
String(subscription?.billing_model || activeTariffCatalogEntry?.billing_model || "")
.toLowerCase() === "traffic",
);
$: regularTrafficTopupUnlocked = Boolean(
canOpenRegularTopupModal && trafficPercent(subscription) >= TRAFFIC_TOPUP_UNLOCK_PERCENT,
);
$: premiumTrafficTopupUnlocked = Boolean(
canOpenPremiumTopupModal && premiumTrafficPercent(subscription) >= TRAFFIC_TOPUP_UNLOCK_PERCENT,
);
/** Progress-bar card opens top-up immediately on traffic-only tariffs; period tariffs still need 80% usage */
$: regularTrafficTopupBarClickable = Boolean(
canOpenRegularTopupModal &&
(subscriptionIsTrafficTariff || trafficPercent(subscription) >= TRAFFIC_TOPUP_UNLOCK_PERCENT),
);
$: premiumTrafficTopupBarClickable = Boolean(
canOpenPremiumTopupModal &&
(subscriptionIsTrafficTariff || premiumTrafficPercent(subscription) >= TRAFFIC_TOPUP_UNLOCK_PERCENT),
);
$: user = data?.user || {};
$: isAdmin = Boolean(user?.is_admin);
@@ -877,12 +896,13 @@
{brandEmoji}
{brandTitle}
{canChangeTariff}
{canOpenPremiumTopupModal}
{canOpenRegularTopupModal}
{canShowTopupButton}
{currentTariffName}
{hasActiveTariffSubscription}
{hasMultipleTariffs}
{premiumTrafficTopupBarClickable}
{premiumTrafficTopupUnlocked}
{regularTrafficTopupBarClickable}
{regularTrafficTopupUnlocked}
{subscription}
{termUnitLabel}
{trafficMode}
@@ -23,9 +23,10 @@
export let brandEmoji = "";
export let brandTitle = "";
export let canChangeTariff = false;
export let canOpenPremiumTopupModal = false;
export let canOpenRegularTopupModal = false;
export let canShowTopupButton = false;
export let premiumTrafficTopupBarClickable = false;
export let premiumTrafficTopupUnlocked = false;
export let regularTrafficTopupBarClickable = false;
export let regularTrafficTopupUnlocked = false;
export let currentTariffName = "";
export let hasActiveTariffSubscription = false;
export let hasMultipleTariffs = false;
@@ -86,9 +87,9 @@
</Card>
{#if subscription.active}
<Card class={canOpenRegularTopupModal ? "traffic-card-clickable" : ""}>
{#if canOpenRegularTopupModal}
<button class="card-click-target" type="button" onclick={openRegularTopupModal} aria-label={t("wa_topup_traffic")}></button>
<Card class={regularTrafficTopupBarClickable ? "traffic-card-clickable" : ""}>
{#if regularTrafficTopupBarClickable}
<button class="card-click-target" type="button" onclick={openRegularTopupModal} aria-label={t("wa_add_traffic")}></button>
{/if}
<div class="traffic-top">
<span>{t("wa_home_traffic_used")}</span>
@@ -128,9 +129,14 @@
</div>
</Card>
{:else if Number(subscription?.premium_limit_bytes || 0) > 0}
<Card class={`${canOpenPremiumTopupModal ? "traffic-card-clickable " : ""}premium-traffic-card${subscription?.premium_is_limited ? " premium-traffic-card-limited" : ""}`}>
{#if canOpenPremiumTopupModal}
<button class="card-click-target" type="button" onclick={openPremiumTopupModal} aria-label={premiumTitle(subscription)}></button>
<Card class={`${premiumTrafficTopupBarClickable ? "traffic-card-clickable " : ""}premium-traffic-card${subscription?.premium_is_limited ? " premium-traffic-card-limited" : ""}`}>
{#if premiumTrafficTopupBarClickable}
<button
class="card-click-target"
type="button"
onclick={openPremiumTopupModal}
aria-label={t("wa_add_traffic_premium", { target: premiumTitle(subscription) })}
></button>
{/if}
<div class="traffic-top">
<span>{premiumTitle(subscription)}</span>
@@ -199,10 +205,16 @@
{t("wa_change_tariff")}
</Button>
{/if}
{#if canShowTopupButton}
<Button class="wide" variant="secondary" onclick={canOpenRegularTopupModal ? openRegularTopupModal : openPremiumTopupModal}>
{#if regularTrafficTopupUnlocked}
<Button class="wide" variant="secondary" onclick={openRegularTopupModal}>
<Database size={18} />
{t("wa_topup_traffic")}
{t("wa_add_traffic")}
</Button>
{/if}
{#if premiumTrafficTopupUnlocked}
<Button class="wide" variant="secondary" onclick={openPremiumTopupModal}>
<Database size={18} />
{t("wa_add_traffic_premium", { target: premiumTitle(subscription) })}
</Button>
{/if}
</div>
+2
View File
@@ -701,6 +701,8 @@
"wa_tariff_no_description": "Tariff description is not configured",
"wa_change_tariff": "Change tariff",
"wa_topup_traffic": "Buy traffic",
"wa_add_traffic": "Add traffic",
"wa_add_traffic_premium": "Add traffic on {target}",
"wa_current_tariff": "Current tariff: {tariff}",
"wa_tariff_options_loading": "Loading options",
"wa_tariff_options_failed": "Failed to load tariff options",
+2
View File
@@ -701,6 +701,8 @@
"wa_tariff_no_description": "Описание тарифа не задано",
"wa_change_tariff": "Сменить тариф",
"wa_topup_traffic": "Докупить трафик",
"wa_add_traffic": "Добавить трафик",
"wa_add_traffic_premium": "Добавить трафик на {target}",
"wa_current_tariff": "Текущий тариф: {tariff}",
"wa_tariff_options_loading": "Загружаем варианты",
"wa_tariff_options_failed": "Не удалось загрузить варианты тарифов",