diff --git a/src/locales/en.json b/src/locales/en.json index 3651a40..dfab62d 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -4246,11 +4246,9 @@ "devicesShort": "dev.", "gbShort": "GB", "unlimitedTraffic": "Unlimited", - "shareModalTitle": "Share gift", - "shareModalDesc": "Send this message to the gift recipient", "shareModalActivateVia": "Activate via bot:", "shareModalActivateViaCabinet": "Or via website:", - "shareModalCopyAll": "Copy message", - "shareModalCopied": "Copied!" + "shareToastCopied": "Message copied", + "shareToastTapCopy": "tap to copy again" } } diff --git a/src/locales/ru.json b/src/locales/ru.json index 2abab43..b1bae11 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -4813,11 +4813,9 @@ "devicesShort_many": "устр.", "gbShort": "ГБ", "unlimitedTraffic": "Безлимит", - "shareModalTitle": "Поделиться подарком", - "shareModalDesc": "Отправьте это сообщение получателю подарка", "shareModalActivateVia": "Активировать через бота:", "shareModalActivateViaCabinet": "Или через сайт:", - "shareModalCopyAll": "Скопировать сообщение", - "shareModalCopied": "Скопировано!" + "shareToastCopied": "Сообщение скопировано", + "shareToastTapCopy": "нажмите чтобы скопировать ещё раз" } } diff --git a/src/pages/GiftSubscription.tsx b/src/pages/GiftSubscription.tsx index be3d6fe..ce4cc91 100644 --- a/src/pages/GiftSubscription.tsx +++ b/src/pages/GiftSubscription.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useEffect } from 'react'; +import { useState, useMemo, useEffect, useCallback, useRef } from 'react'; import { useNavigate, useSearchParams, Link } from 'react-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -15,6 +15,7 @@ import type { } from '../api/gift'; import { cn } from '../lib/utils'; +import { copyToClipboard } from '../utils/clipboard'; import { getApiErrorMessage } from '../utils/api-error'; import { formatPrice } from '../utils/format'; @@ -58,23 +59,6 @@ function CheckIcon({ className }: { className?: string }) { ); } -function CopyIcon({ className }: { className?: string }) { - return ( - - - - - ); -} - function ShareIcon({ className }: { className?: string }) { return ( void }) { +function ShareToast({ message, onDismiss }: { message: string; onDismiss: () => void }) { const { t } = useTranslation(); - const [copied, setCopied] = useState(false); + const timerRef = useRef>(undefined); - // Escape key + scroll lock useEffect(() => { - const handler = (e: KeyboardEvent) => { - if (e.key === 'Escape') onClose(); - }; - document.addEventListener('keydown', handler); - document.body.style.overflow = 'hidden'; + timerRef.current = setTimeout(onDismiss, 5000); return () => { - document.removeEventListener('keydown', handler); - document.body.style.overflow = ''; + if (timerRef.current) clearTimeout(timerRef.current); }; - }, [onClose]); + }, [onDismiss]); - const shortCode = gift.token.slice(0, 12); - const botUsername = import.meta.env.VITE_TELEGRAM_BOT_USERNAME as string | undefined; - const botLink = botUsername ? `https://t.me/${botUsername}?start=GIFT_${shortCode}` : null; - const cabinetLink = `${window.location.origin}/gift?tab=activate&code=${shortCode}`; - - const fullMessage = [ - t('gift.shareText'), - '', - botLink ? `${t('gift.shareModalActivateVia')} ${botLink}` : null, - `${t('gift.shareModalActivateViaCabinet')} ${cabinetLink}`, - ] - .filter(Boolean) - .join('\n'); - - const handleCopyAll = async () => { - try { - await navigator.clipboard.writeText(fullMessage); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } catch { - // fallback - } - }; + const handleClick = useCallback(async () => { + await copyToClipboard(message); + if (timerRef.current) clearTimeout(timerRef.current); + timerRef.current = setTimeout(onDismiss, 2000); + }, [message, onDismiss]); return ( - {/* Backdrop */} -
- - {/* Modal content */} - e.stopPropagation()} + +
+ + {t('gift.shareToastCopied')} + {t('gift.shareToastTapCopy')}
- - {/* Message preview */} -
-
-

{t('gift.shareText')}

- - {botLink && ( -
-

- {t('gift.shareModalActivateVia')} -

- - {botLink} - -
- )} - -
-

- {t('gift.shareModalActivateViaCabinet')} -

- - {cabinetLink} - -
-
-
- - {/* Actions */} -
- -
-
+

{message}

+ ); } function SentGiftCard({ gift }: { gift: SentGift }) { const { t } = useTranslation(); - const [showShareModal, setShowShareModal] = useState(false); + const [showToast, setShowToast] = useState(false); - const giftCode = `GIFT-${gift.token.slice(0, 12)}`; + const shortCode = gift.token.slice(0, 12); + const giftCode = `GIFT-${shortCode}`; const isActivated = isGiftActivated(gift); const isAvailable = !isActivated && isGiftAvailable(gift.status); @@ -1146,6 +1009,28 @@ function SentGiftCard({ gift }: { gift: SentGift }) { ? t('gift.statusAvailable') : t(getGiftStatusKey(gift.status)); + const buildShareMessage = useCallback(() => { + const botUsername = import.meta.env.VITE_TELEGRAM_BOT_USERNAME as string | undefined; + const botLink = botUsername ? `https://t.me/${botUsername}?start=GIFT_${shortCode}` : null; + const cabinetLink = `${window.location.origin}/gift?tab=activate&code=${shortCode}`; + return [ + t('gift.shareText'), + '', + botLink ? `${t('gift.shareModalActivateVia')} ${botLink}` : null, + `${t('gift.shareModalActivateViaCabinet')} ${cabinetLink}`, + ] + .filter(Boolean) + .join('\n'); + }, [shortCode, t]); + + const handleShare = useCallback(async () => { + const message = buildShareMessage(); + await copyToClipboard(message); + setShowToast(true); + }, [buildShareMessage]); + + const handleDismissToast = useCallback(() => setShowToast(false), []); + return (
{/* Header: tariff name + status badge */} @@ -1184,10 +1069,10 @@ function SentGiftCard({ gift }: { gift: SentGift }) {

- {/* Share button — opens modal */} + {/* Share button — copies message and shows toast */}
);