feat: add telegram guardrails for trials and referrals
This commit is contained in:
@@ -125,9 +125,9 @@
|
||||
function showHwidRenewalUnavailableNote() {
|
||||
return Boolean(
|
||||
subscription?.active &&
|
||||
Number(subscription?.extra_hwid_devices || 0) > 0 &&
|
||||
isSubscriptionPlan(selectedPlan) &&
|
||||
!showHwidRenewalBlock()
|
||||
Number(subscription?.extra_hwid_devices || 0) > 0 &&
|
||||
isSubscriptionPlan(selectedPlan) &&
|
||||
!showHwidRenewalBlock()
|
||||
);
|
||||
}
|
||||
function hwidRenewalCount(plan = selectedPlan) {
|
||||
@@ -146,7 +146,7 @@
|
||||
function showHwidDesyncNotice() {
|
||||
return Boolean(
|
||||
subscription?.device_topup_renewal_available &&
|
||||
subscription?.extra_hwid_devices_valid_until_text
|
||||
subscription?.extra_hwid_devices_valid_until_text
|
||||
);
|
||||
}
|
||||
function planKey(plan) {
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
Download,
|
||||
Gift,
|
||||
Repeat2,
|
||||
Send,
|
||||
} from "$components/ui/icons.js";
|
||||
|
||||
import BrandMark from "$lib/webapp/BrandMark.svelte";
|
||||
import { AttentionDot } from "$components/ui/index.js";
|
||||
import Button from "$components/ui/button.svelte";
|
||||
import Card from "$components/ui/card.svelte";
|
||||
import TelegramNotificationsBanner from "../TelegramNotificationsBanner.svelte";
|
||||
@@ -39,10 +41,12 @@
|
||||
export let premiumTrafficTopupUnlocked = false;
|
||||
export let regularTrafficTopupBarClickable = false;
|
||||
export let regularTrafficTopupUnlocked = false;
|
||||
export let referral = {};
|
||||
export let currentTariffName = "";
|
||||
export let hasActiveTariffSubscription = false;
|
||||
export let hasMultipleTariffs = false;
|
||||
export let subscription = {};
|
||||
export let linkTelegramBusy = false;
|
||||
export let telegramNotificationsNeedPrompt = false;
|
||||
export let telegramNotificationsStartLink = "";
|
||||
export let telegramNotificationsStatus = "unknown";
|
||||
@@ -142,6 +146,14 @@
|
||||
$: trialOfferAvailable = Boolean(
|
||||
!subscription?.active && appSettings?.trial_enabled && appSettings?.trial_available
|
||||
);
|
||||
$: trialRequiresTelegram = Boolean(
|
||||
!subscription?.active && appSettings?.trial_enabled && appSettings?.trial_requires_telegram
|
||||
);
|
||||
$: referralWelcomeRequiresTelegram = Boolean(
|
||||
!subscription?.active &&
|
||||
referral?.welcome_bonus_requires_telegram &&
|
||||
Number(referral?.welcome_bonus_days || 0) > 0
|
||||
);
|
||||
$: subscriptionEndMs = subscription?.active ? parseSubscriptionEndMs(subscription) : null;
|
||||
$: subscriptionRemainingMs = Math.max(0, Number(subscriptionEndMs || 0) - nowMs);
|
||||
$: subscriptionExpiryWarning = Boolean(
|
||||
@@ -186,6 +198,8 @@
|
||||
});
|
||||
|
||||
export let activateTrial = () => {};
|
||||
export let linkTelegramAndActivateTrial = () => {};
|
||||
export let linkTelegramAndClaimReferralWelcome = () => {};
|
||||
export let openConnectLink = () => {};
|
||||
export let openPaymentModal = () => {};
|
||||
export let openTelegramNotificationsBot = () => {};
|
||||
@@ -374,37 +388,113 @@
|
||||
/>
|
||||
</Card>
|
||||
{/if}
|
||||
{:else if trialOfferAvailable}
|
||||
<Card class="trial-card trial-offer-card">
|
||||
<div class="trial-card-head">
|
||||
<Gift size={22} />
|
||||
<span>
|
||||
<strong>{t("wa_trial_offer_title", {}, "Можно начать с льготного периода")}</strong>
|
||||
<small>{t("wa_trial_title")}</small>
|
||||
</span>
|
||||
</div>
|
||||
<p class="trial-card-description">
|
||||
{t(
|
||||
"wa_trial_offer_description",
|
||||
{ duration: trialDurationLabel(), traffic: trialTrafficLabel() },
|
||||
"Активируйте триал: {duration} доступа и {traffic} для скачивания без оплаты."
|
||||
)}
|
||||
</p>
|
||||
<div class="trial-card-facts">
|
||||
<span>
|
||||
<small>{t("wa_trial_duration_label", {}, "Срок")}</small>
|
||||
<strong>{trialDurationLabel()}</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t("wa_trial_download_traffic_label", {}, "Доступно для скачивания")}</small>
|
||||
<strong>{trialTrafficLabel()}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<Button class="wide trial-card-action" onclick={activateTrial} disabled={trialBusy}>
|
||||
<Gift size={18} />
|
||||
{t("wa_trial_try_free", {}, "Попробовать бесплатно")}
|
||||
</Button>
|
||||
</Card>
|
||||
{:else}
|
||||
{#if referralWelcomeRequiresTelegram}
|
||||
<Card class="trial-card trial-offer-card">
|
||||
<div class="trial-card-head">
|
||||
<Gift size={22} />
|
||||
<span>
|
||||
<strong>
|
||||
{t(
|
||||
"wa_referral_welcome_telegram_required_title",
|
||||
{},
|
||||
"Бонус ждёт привязки Telegram"
|
||||
)}
|
||||
</strong>
|
||||
<small>{t("wa_referral_program_title", {}, "Реферальная программа")}</small>
|
||||
</span>
|
||||
</div>
|
||||
<p class="trial-card-description">
|
||||
{t(
|
||||
"wa_referral_welcome_telegram_required_description",
|
||||
{ days: Number(referral?.welcome_bonus_days || 0) },
|
||||
"Привяжите Telegram, чтобы получить {days} бонусных дней за регистрацию по приглашению."
|
||||
)}
|
||||
</p>
|
||||
<Button
|
||||
class="wide trial-card-action settings-telegram-link-btn attention-wrap"
|
||||
variant="telegram"
|
||||
onclick={linkTelegramAndClaimReferralWelcome}
|
||||
disabled={linkTelegramBusy}
|
||||
>
|
||||
<AttentionDot />
|
||||
<Send size={18} />
|
||||
{t("wa_referral_link_telegram_and_claim", {}, "Привязать и получить бонус")}
|
||||
</Button>
|
||||
</Card>
|
||||
{/if}
|
||||
|
||||
{#if trialOfferAvailable}
|
||||
<Card class="trial-card trial-offer-card">
|
||||
<div class="trial-card-head">
|
||||
<Gift size={22} />
|
||||
<span>
|
||||
<strong>{t("wa_trial_offer_title", {}, "Можно начать с льготного периода")}</strong>
|
||||
<small>{t("wa_trial_title")}</small>
|
||||
</span>
|
||||
</div>
|
||||
<p class="trial-card-description">
|
||||
{t(
|
||||
"wa_trial_offer_description",
|
||||
{ duration: trialDurationLabel(), traffic: trialTrafficLabel() },
|
||||
"Активируйте триал: {duration} доступа и {traffic} для скачивания без оплаты."
|
||||
)}
|
||||
</p>
|
||||
<div class="trial-card-facts">
|
||||
<span>
|
||||
<small>{t("wa_trial_duration_label", {}, "Срок")}</small>
|
||||
<strong>{trialDurationLabel()}</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t("wa_trial_download_traffic_label", {}, "Доступно для скачивания")}</small>
|
||||
<strong>{trialTrafficLabel()}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<Button class="wide trial-card-action" onclick={activateTrial} disabled={trialBusy}>
|
||||
<Gift size={18} />
|
||||
{t("wa_trial_try_free", {}, "Попробовать бесплатно")}
|
||||
</Button>
|
||||
</Card>
|
||||
{:else if trialRequiresTelegram}
|
||||
<Card class="trial-card trial-offer-card">
|
||||
<div class="trial-card-head">
|
||||
<Gift size={22} />
|
||||
<span>
|
||||
<strong>
|
||||
{t("wa_trial_telegram_required_title", {}, "Привяжите Telegram для триала")}
|
||||
</strong>
|
||||
<small>{t("wa_trial_title")}</small>
|
||||
</span>
|
||||
</div>
|
||||
<p class="trial-card-description">
|
||||
{t(
|
||||
"wa_trial_telegram_required_description",
|
||||
{ duration: trialDurationLabel(), traffic: trialTrafficLabel() },
|
||||
"Чтобы активировать триал на {duration} с лимитом {traffic}, сначала привяжите Telegram."
|
||||
)}
|
||||
</p>
|
||||
<div class="trial-card-facts">
|
||||
<span>
|
||||
<small>{t("wa_trial_duration_label", {}, "Срок")}</small>
|
||||
<strong>{trialDurationLabel()}</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t("wa_trial_download_traffic_label", {}, "Доступно для скачивания")}</small>
|
||||
<strong>{trialTrafficLabel()}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
class="wide trial-card-action settings-telegram-link-btn attention-wrap"
|
||||
variant="telegram"
|
||||
onclick={linkTelegramAndActivateTrial}
|
||||
disabled={linkTelegramBusy || trialBusy}
|
||||
>
|
||||
<AttentionDot />
|
||||
<Send size={18} />
|
||||
{t("wa_trial_link_telegram_and_activate", {}, "Привязать и активировать")}
|
||||
</Button>
|
||||
</Card>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<div class="action-stack">
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
Download,
|
||||
Gift,
|
||||
RefreshCw,
|
||||
Send,
|
||||
} from "$components/ui/icons.js";
|
||||
|
||||
import BrandMark from "$lib/webapp/BrandMark.svelte";
|
||||
import { AttentionDot } from "$components/ui/index.js";
|
||||
import Button from "$components/ui/button.svelte";
|
||||
import Card from "$components/ui/card.svelte";
|
||||
import { formatTrafficGb } from "../../lib/webapp/formatters.js";
|
||||
@@ -19,9 +21,11 @@
|
||||
export let brandTitle = "";
|
||||
export let subscription = {};
|
||||
export let trialBusy = false;
|
||||
export let linkTelegramBusy = false;
|
||||
export let trialResult = null;
|
||||
export let trialError = "";
|
||||
export let activateTrial = () => {};
|
||||
export let linkTelegramAndActivateTrial = () => {};
|
||||
export let openInstallOrConnect = () => {};
|
||||
export let goHome = () => {};
|
||||
export let t = (key, _params = {}, fallback = "") => fallback || key;
|
||||
@@ -30,6 +34,9 @@
|
||||
|
||||
$: trialEnabled = Boolean(appSettings?.trial_enabled);
|
||||
$: trialAvailable = Boolean(appSettings?.trial_available);
|
||||
$: trialRequiresTelegram = Boolean(
|
||||
trialEnabled && appSettings?.trial_requires_telegram && !subscription?.active
|
||||
);
|
||||
$: canRequestTrial = Boolean(trialEnabled && trialAvailable && !subscription?.active);
|
||||
$: isTrialStatus =
|
||||
Boolean(trialResult?.activated) ||
|
||||
@@ -78,6 +85,8 @@
|
||||
<RefreshCw size={27} />
|
||||
{:else if hasActiveAccess}
|
||||
<CheckCircle2 size={30} />
|
||||
{:else if trialRequiresTelegram}
|
||||
<Gift size={30} />
|
||||
{:else if trialError || !canRequestTrial}
|
||||
<CircleX size={30} />
|
||||
{:else}
|
||||
@@ -116,6 +125,31 @@
|
||||
<dd>{trafficLabel}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
{:else if trialRequiresTelegram}
|
||||
<h2>{t("wa_trial_telegram_required_title", {}, "Привяжите Telegram для триала")}</h2>
|
||||
<p>
|
||||
{t(
|
||||
"wa_trial_telegram_required_description",
|
||||
{
|
||||
duration:
|
||||
daysLeft > 0 ? t("wa_trial_days_left", { days: daysLeft }, "{days} days") : "",
|
||||
traffic: trafficLabel,
|
||||
},
|
||||
"Чтобы активировать пробный период, сначала привяжите Telegram."
|
||||
)}
|
||||
</p>
|
||||
<dl class="trial-activation-facts">
|
||||
{#if daysLeft > 0}
|
||||
<div>
|
||||
<dt>{t("wa_trial_duration_label", {}, "Срок")}</dt>
|
||||
<dd>{t("wa_trial_days_left", { days: daysLeft }, "{days} days")}</dd>
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
<dt>{t("wa_trial_traffic_label", {}, "Traffic")}</dt>
|
||||
<dd>{trafficLabel}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
{:else if trialError}
|
||||
<h2>{t("wa_trial_activation_failed")}</h2>
|
||||
<p>{trialError}</p>
|
||||
@@ -138,6 +172,17 @@
|
||||
<Download size={18} />
|
||||
{t("wa_install_and_configure")}
|
||||
</Button>
|
||||
{:else if trialRequiresTelegram}
|
||||
<Button
|
||||
class="wide settings-telegram-link-btn attention-wrap"
|
||||
variant="telegram"
|
||||
onclick={linkTelegramAndActivateTrial}
|
||||
disabled={linkTelegramBusy || trialBusy}
|
||||
>
|
||||
<AttentionDot />
|
||||
<Send size={18} />
|
||||
{t("wa_trial_link_telegram_and_activate", {}, "Привязать и активировать")}
|
||||
</Button>
|
||||
{:else if trialError && canRequestTrial}
|
||||
<Button class="wide" onclick={activateTrial} disabled={trialBusy}>
|
||||
<RefreshCw size={18} />
|
||||
|
||||
Reference in New Issue
Block a user