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 ? (