fix: activation broken — token uppercased + wrong env var for bot username

- Remove .toUpperCase() from activation code input — tokens are case-sensitive base64
- Fix VITE_BOT_USERNAME → VITE_TELEGRAM_BOT_USERNAME (correct env var name)
- Add Escape key handler, scroll lock, role="dialog" to ShareModal
This commit is contained in:
Fringg
2026-03-10 06:13:50 +03:00
parent 1bafcca1ef
commit d852bfe969
2 changed files with 25 additions and 7 deletions

View File

@@ -57,7 +57,7 @@ function CodeOnlySuccessState({
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const giftCode = formatGiftCode(purchaseToken); const giftCode = formatGiftCode(purchaseToken);
const botUsername = import.meta.env.VITE_BOT_USERNAME as string | undefined; const botUsername = import.meta.env.VITE_TELEGRAM_BOT_USERNAME as string | undefined;
const botLink = botUsername const botLink = botUsername
? `https://t.me/${botUsername}?start=GIFTCODE_${purchaseToken}` ? `https://t.me/${botUsername}?start=GIFTCODE_${purchaseToken}`
: null; : null;

View File

@@ -853,11 +853,11 @@ function BuyTabContent({
function ActivateTabContent({ initialCode }: { initialCode?: string | null }) { function ActivateTabContent({ initialCode }: { initialCode?: string | null }) {
const { t } = useTranslation(); const { t } = useTranslation();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [code, setCode] = useState(initialCode?.toUpperCase() ?? ''); const [code, setCode] = useState(initialCode ?? '');
// Sync when initialCode changes (e.g. URL param update while tab is active) // Sync when initialCode changes (e.g. URL param update while tab is active)
useEffect(() => { useEffect(() => {
if (initialCode) setCode(initialCode.toUpperCase()); if (initialCode) setCode(initialCode);
}, [initialCode]); }, [initialCode]);
const [activateError, setActivateError] = useState<string | null>(null); const [activateError, setActivateError] = useState<string | null>(null);
@@ -916,11 +916,11 @@ function ActivateTabContent({ initialCode }: { initialCode?: string | null }) {
type="text" type="text"
value={code} value={code}
onChange={(e) => { onChange={(e) => {
setCode(e.target.value.toUpperCase()); setCode(e.target.value);
setActivateError(null); setActivateError(null);
}} }}
placeholder={t('gift.activateCodePlaceholder')} placeholder={t('gift.activateCodePlaceholder')}
className="w-full rounded-2xl border border-dark-700/50 bg-dark-800/50 px-6 py-4 text-center font-mono text-lg uppercase tracking-widest text-dark-50 placeholder-dark-500 outline-none transition-colors focus:border-accent-500/50 focus:ring-1 focus:ring-accent-500/25" className="w-full rounded-2xl border border-dark-700/50 bg-dark-800/50 px-6 py-4 text-center font-mono text-sm text-dark-50 placeholder-dark-500 outline-none transition-colors focus:border-accent-500/50 focus:ring-1 focus:ring-accent-500/25"
aria-label={t('gift.activateTitle')} aria-label={t('gift.activateTitle')}
/> />
</div> </div>
@@ -969,7 +969,20 @@ function ShareModal({ gift, onClose }: { gift: SentGift; onClose: () => void })
const { t } = useTranslation(); const { t } = useTranslation();
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const botUsername = import.meta.env.VITE_BOT_USERNAME as string | undefined; // Escape key + scroll lock
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handler);
document.body.style.overflow = 'hidden';
return () => {
document.removeEventListener('keydown', handler);
document.body.style.overflow = '';
};
}, [onClose]);
const botUsername = import.meta.env.VITE_TELEGRAM_BOT_USERNAME as string | undefined;
const botLink = botUsername ? `https://t.me/${botUsername}?start=GIFTCODE_${gift.token}` : null; const botLink = botUsername ? `https://t.me/${botUsername}?start=GIFTCODE_${gift.token}` : null;
const cabinetLink = `${window.location.origin}/gift?tab=activate&code=${gift.token}`; const cabinetLink = `${window.location.origin}/gift?tab=activate&code=${gift.token}`;
@@ -1006,6 +1019,9 @@ function ShareModal({ gift, onClose }: { gift: SentGift; onClose: () => void })
{/* Modal content */} {/* Modal content */}
<motion.div <motion.div
role="dialog"
aria-modal="true"
aria-labelledby="share-modal-title"
initial={{ opacity: 0, y: 40, scale: 0.95 }} initial={{ opacity: 0, y: 40, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }} animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 40, scale: 0.95 }} exit={{ opacity: 0, y: 40, scale: 0.95 }}
@@ -1020,7 +1036,9 @@ function ShareModal({ gift, onClose }: { gift: SentGift; onClose: () => void })
<ShareIcon className="h-4.5 w-4.5 text-accent-400" /> <ShareIcon className="h-4.5 w-4.5 text-accent-400" />
</div> </div>
<div> <div>
<h3 className="text-base font-bold text-dark-50">{t('gift.shareModalTitle')}</h3> <h3 id="share-modal-title" className="text-base font-bold text-dark-50">
{t('gift.shareModalTitle')}
</h3>
<p className="text-xs text-dark-400">{t('gift.shareModalDesc')}</p> <p className="text-xs text-dark-400">{t('gift.shareModalDesc')}</p>
</div> </div>
</div> </div>