From eed077b0197f215c8f74f70a2bf0b73fd41d4628 Mon Sep 17 00:00:00 2001
From: Fringg
Date: Sat, 7 Mar 2026 20:33:55 +0300
Subject: [PATCH] feat: add gift purchase UI states for telegram recipients
- Add recipient_in_bot and bot_link fields to PurchaseStatus API type
- Show bot link instruction when gift recipient is not in bot
- Show "gift sent via Telegram" message when recipient is in bot
- Fix duplicate text rendering in GiftPendingActivationState
- Handle recipientInBot=null edge case safely
- Add gift notification translations for ru, en, zh, fa locales
---
src/api/landings.ts | 2 ++
src/locales/en.json | 5 +++
src/locales/fa.json | 5 +++
src/locales/ru.json | 5 +++
src/locales/zh.json | 5 +++
src/pages/PurchaseSuccess.tsx | 62 +++++++++++++++++++++++++++++++++--
6 files changed, 81 insertions(+), 3 deletions(-)
diff --git a/src/api/landings.ts b/src/api/landings.ts
index 18b5b1d..f557de0 100644
--- a/src/api/landings.ts
+++ b/src/api/landings.ts
@@ -126,6 +126,8 @@ export interface PurchaseStatus {
cabinet_email: string | null;
cabinet_password: string | null;
auto_login_token: string | null;
+ recipient_in_bot: boolean | null;
+ bot_link: string | null;
}
// ============================================================
diff --git a/src/locales/en.json b/src/locales/en.json
index 83e5890..130143d 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -4060,6 +4060,11 @@
"giftSentSuccess": "Gift sent!",
"giftSentDesc": "Recipient will be notified by email",
"giftPendingActivationDesc": "The recipient already has an active subscription. They will receive a link to activate the gift.",
+ "giftTelegramSent": "Gift notification sent to recipient via Telegram",
+ "giftTelegramNotInBot": "Recipient hasn't started the bot yet. Send them this link:",
+ "giftTelegramPendingSent": "Activation request sent to recipient via Telegram",
+ "giftTelegramPendingNotInBot": "Recipient hasn't started the bot yet. Send them the bot link so they can activate the gift:",
+ "openBot": "Open bot",
"autoLoginFailed": "Auto-login failed",
"autoLoginProcessing": "Signing in...",
"discount": {
diff --git a/src/locales/fa.json b/src/locales/fa.json
index f6c21df..89df8b6 100644
--- a/src/locales/fa.json
+++ b/src/locales/fa.json
@@ -3552,6 +3552,11 @@
"giftSentSuccess": "هدیه ارسال شد!",
"giftSentDesc": "گیرنده از طریق ایمیل مطلع خواهد شد",
"giftPendingActivationDesc": "گیرنده در حال حاضر اشتراک فعال دارد. لینک فعالسازی هدیه برای او ارسال خواهد شد.",
+ "giftTelegramSent": "اطلاعیه هدیه از طریق تلگرام به گیرنده ارسال شد",
+ "giftTelegramNotInBot": "گیرنده هنوز ربات را شروع نکرده است. این لینک را برای او ارسال کنید:",
+ "giftTelegramPendingSent": "درخواست فعالسازی از طریق تلگرام به گیرنده ارسال شد",
+ "giftTelegramPendingNotInBot": "گیرنده هنوز در ربات نیست. لینک ربات را برایش ارسال کنید تا بتواند هدیه را فعال کند:",
+ "openBot": "باز کردن ربات",
"autoLoginFailed": "ورود خودکار ناموفق بود",
"autoLoginProcessing": "در حال ورود...",
"periodLabels": {
diff --git a/src/locales/ru.json b/src/locales/ru.json
index 9fde123..4f5022e 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -4620,6 +4620,11 @@
"giftSentSuccess": "Подарок отправлен!",
"giftSentDesc": "Получатель получит уведомление на email",
"giftPendingActivationDesc": "У получателя уже есть активная подписка. Ему будет отправлена ссылка для активации подарка.",
+ "giftTelegramSent": "Мы отправили получателю уведомление о подарке в Telegram",
+ "giftTelegramNotInBot": "Получатель пока не пользуется ботом. Отправьте ему эту ссылку, чтобы он мог забрать подарок:",
+ "giftTelegramPendingSent": "Мы отправили получателю предложение активировать подарок в Telegram",
+ "giftTelegramPendingNotInBot": "Получатель пока не пользуется ботом. Отправьте ему ссылку, чтобы он мог активировать подарок:",
+ "openBot": "Ссылка на бота",
"autoLoginFailed": "Не удалось выполнить автоматический вход",
"autoLoginProcessing": "Выполняется вход...",
"discount": {
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 1213972..23640a2 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -3551,6 +3551,11 @@
"giftSentSuccess": "礼物已发送!",
"giftSentDesc": "收件人将通过邮件收到通知",
"giftPendingActivationDesc": "收件人已有活跃订阅。他们将收到激活礼物的链接。",
+ "giftTelegramSent": "已通过 Telegram 向收件人发送通知",
+ "giftTelegramNotInBot": "收件人尚未启动机器人。请将此链接发送给他们:",
+ "giftTelegramPendingSent": "已通过 Telegram 向收件人发送激活请求",
+ "giftTelegramPendingNotInBot": "收件人尚未启动机器人。请将机器人链接发送给他们以激活礼物:",
+ "openBot": "打开机器人",
"autoLoginFailed": "自动登录失败",
"autoLoginProcessing": "正在登录...",
"periodLabels": {
diff --git a/src/pages/PurchaseSuccess.tsx b/src/pages/PurchaseSuccess.tsx
index a4e9575..94ac3f5 100644
--- a/src/pages/PurchaseSuccess.tsx
+++ b/src/pages/PurchaseSuccess.tsx
@@ -218,6 +218,9 @@ function SuccessState({
periodDays,
isGift,
giftMessage,
+ recipientInBot,
+ botLink,
+ contactType,
}: {
subscriptionUrl: string | null;
cryptoLink: string | null;
@@ -227,6 +230,9 @@ function SuccessState({
periodDays: number | null;
isGift: boolean;
giftMessage: string | null;
+ recipientInBot: boolean | null;
+ botLink: string | null;
+ contactType: string | null;
}) {
const { t } = useTranslation();
const [copied, setCopied] = useState(false);
@@ -299,7 +305,13 @@ function SuccessState({
{tariffName} — {periodDays} {t('landing.daysAccess')}
)}
- {displayContact && (
+ {isGift && contactType === 'telegram' && recipientInBot === true && (
+ {t('landing.giftTelegramSent')}
+ )}
+ {isGift && contactType === 'telegram' && recipientInBot !== true && (
+ {t('landing.giftTelegramNotInBot')}
+ )}
+ {!(isGift && contactType === 'telegram') && displayContact && (
{isGift
? t('landing.giftSentTo', { contact: displayContact })
@@ -313,6 +325,18 @@ function SuccessState({
)}
+ {/* Bot link for telegram gifts where recipient is not in bot */}
+ {isGift && contactType === 'telegram' && recipientInBot !== true && botLink && (
+
+ {t('landing.openBot')}
+
+ )}
+
{/* QR Code */}
{displayUrl && (
@@ -507,11 +531,17 @@ function GiftPendingActivationState({
periodDays,
recipientContactValue,
giftMessage,
+ recipientInBot,
+ botLink,
+ contactType,
}: {
tariffName: string | null;
periodDays: number | null;
recipientContactValue: string | null;
giftMessage: string | null;
+ recipientInBot: boolean | null;
+ botLink: string | null;
+ contactType: string | null;
}) {
const { t } = useTranslation();
@@ -556,18 +586,38 @@ function GiftPendingActivationState({
{tariffName} — {periodDays} {t('landing.daysAccess')}
)}
- {recipientContactValue && (
+ {contactType === 'telegram' && recipientInBot === true && (
+
{t('landing.giftTelegramPendingSent')}
+ )}
+ {contactType === 'telegram' && recipientInBot !== true && (
+
{t('landing.giftTelegramPendingNotInBot')}
+ )}
+ {contactType !== 'telegram' && (
+
{t('landing.giftPendingActivationDesc')}
+ )}
+ {contactType !== 'telegram' && recipientContactValue && (
{t('landing.giftSentTo', { contact: recipientContactValue })}
)}
-
{t('landing.giftPendingActivationDesc')}
{giftMessage && (
{t('landing.giftMessage')}: {giftMessage}
)}
+
+ {/* Bot link for telegram gifts where recipient is not in bot */}
+ {contactType === 'telegram' && recipientInBot !== true && botLink && (
+
+ {t('landing.openBot')}
+
+ )}
);
}
@@ -756,6 +806,9 @@ export default function PurchaseSuccess() {
periodDays={purchaseStatus.period_days}
isGift={purchaseStatus.is_gift}
giftMessage={purchaseStatus.gift_message}
+ recipientInBot={purchaseStatus.recipient_in_bot}
+ botLink={purchaseStatus.bot_link}
+ contactType={purchaseStatus.contact_type}
/>
) : isGiftPendingActivation ? (
) : isPendingActivation ? (