feat: show optional serivce description before payment

This commit is contained in:
3252a8
2026-05-20 21:55:22 +03:00
parent d8a1da1f13
commit 7521f89ffd
51 changed files with 1199 additions and 499 deletions
+4
View File
@@ -279,6 +279,9 @@
$: plans = data?.plans?.length ? data.plans : DEV_MOCK.data.plans;
$: methods = data?.payment_methods?.length ? data.payment_methods : [];
$: appSettings = data?.settings || DEV_MOCK.data.settings;
$: subscriptionPurchaseDescription = String(
appSettings?.subscription_purchase_description || ""
).trim();
$: trafficMode = Boolean(appSettings?.traffic_mode);
$: tariffMode = plans.some((plan) => plan?.tariff_key);
$: tariffCatalog = buildTariffCatalog(plans);
@@ -1321,6 +1324,7 @@
{selectedTariffPlans}
{singleTariffMode}
{subscription}
{subscriptionPurchaseDescription}
{tariffCatalog}
{tariffMode}
closeDeviceDisconnectDialog={devicesStore.closeDeviceDisconnectDialog}
@@ -269,6 +269,14 @@
value={valueFor(field) ?? ""}
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
/>
{:else if field.type === "text"}
<textarea
class="admin-setting-textarea"
rows="4"
placeholder={field.placeholder}
value={valueFor(field) ?? ""}
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
></textarea>
{:else if field.secret}
<input
class="input"
+4
View File
@@ -669,6 +669,10 @@ export async function mockApi(path, options = {}, context = {}) {
}
const language = normalizeLangCode(payload?.language || currentLang);
DEV_MOCK.data.user.language_code = language;
DEV_MOCK.data.settings.subscription_purchase_description =
language === "en"
? "By buying or renewing a subscription, you get access to a VPN/proxy service that helps protect your connection and keep your access stable."
: "Покупая или продлевая подписку, вы получаете доступ к VPN/прокси-сервису, который помогает защищать ваше соединение и поддерживать стабильный доступ к сети.";
return { ok: true, language };
}
if (path === "/account/email/request" && String(options.method || "").toUpperCase() === "POST") {
+2
View File
@@ -222,6 +222,8 @@ export const DEV_MOCK = {
trial_duration_days: 5,
trial_traffic_limit_gb: 10,
trial_traffic_strategy: "NO_RESET",
subscription_purchase_description:
"Покупая или продлевая подписку, вы получаете доступ к VPN/прокси-сервису, который помогает защищать ваше соединение и поддерживать стабильный доступ к сети.",
email_auth_enabled: true,
},
},
+20
View File
@@ -206,6 +206,7 @@
.admin-setting-control .input,
.admin-setting-control .admin-setting-select,
.admin-setting-control .admin-setting-textarea,
.admin-setting-control input[type="text"],
.admin-setting-control input[type="number"] {
flex: 1 1 160px;
@@ -213,6 +214,25 @@
width: 100%;
}
.admin-setting-control .admin-setting-textarea {
min-height: 86px;
resize: vertical;
border-radius: 8px;
border: 1px solid var(--admin-border-strong);
background: color-mix(in srgb, var(--admin-bg) 82%, var(--admin-surface-2));
color: var(--admin-text);
padding: 10px 12px;
font-size: 13px;
line-height: 1.45;
outline: none;
transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.admin-setting-control .admin-setting-textarea:focus {
border-color: var(--admin-ring);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
}
.admin-btn.admin-btn-icon {
width: 30px;
height: 30px;
+18
View File
@@ -795,6 +795,24 @@ a {
line-height: 1.35;
}
.subscription-purchase-description {
display: grid;
gap: 6px;
padding: 11px 12px;
border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--border));
border-radius: var(--radius);
background: color-mix(in srgb, var(--accent) 8%, var(--surface-muted));
box-shadow: inset 0 1px 0 var(--inset-highlight);
}
.subscription-purchase-description p {
margin: 0;
color: var(--text);
font-size: 12px;
line-height: 1.45;
overflow-wrap: anywhere;
}
.skeleton-row,
.skeleton-method,
.skeleton-pay-button {
+18
View File
@@ -64,6 +64,7 @@
export let setPasswordValue = "";
export let singleTariffMode = false;
export let subscription = {};
export let subscriptionPurchaseDescription = "";
export let tariffCatalog = [];
export let tariffMode = false;
export let trafficMode = false;
@@ -111,6 +112,13 @@
return trafficMode ? t("wa_traffic_packages_choose") : t("wa_subscription_choose_period");
}
function showSubscriptionPurchaseDescription() {
if (!subscriptionPurchaseDescription || trafficMode) return false;
if (!tariffMode) return true;
if (paymentStep === "tariff") return false;
return String(selectedTariff?.billing_model || "period").toLowerCase() !== "traffic";
}
export let closeDeviceDisconnectDialog = () => {};
export let closeLinkEmailDialog = () => {};
export let closePaymentModal = () => {};
@@ -184,6 +192,11 @@
</p>
{/if}
{#if selectedTariffPlans.length}
{#if showSubscriptionPurchaseDescription()}
<div class="subscription-purchase-description">
<p>{subscriptionPurchaseDescription}</p>
</div>
{/if}
<div class="period-grid period-grid-two-columns">
{#each selectedTariffPlans as plan}
<button
@@ -233,6 +246,11 @@
branch above, so users on legacy mode saw the period grid, payment
method grid and pay button duplicated.
-->
{#if showSubscriptionPurchaseDescription()}
<div class="subscription-purchase-description">
<p>{subscriptionPurchaseDescription}</p>
</div>
{/if}
<div class="period-grid period-grid-two-columns">
{#each plans as plan}
<button