'use client'; import { useState, useEffect, useCallback } from 'react'; import { QRCodeSVG } from 'qrcode.react'; import { Button, Spinner } from '@/components/ui'; import { api } from '@/lib/api'; import type { QRResponse } from '@/lib/types'; const QR_TTL_SECONDS = 300; // 5 minutes, matches backend JWT TTL export function QRDisplay() { const [token, setToken] = useState(null); const [secondsLeft, setSecondsLeft] = useState(QR_TTL_SECONDS); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchToken = useCallback(async () => { setLoading(true); setError(null); try { const data = await api.get('/api/v1/me/qr'); setToken(data.token); setSecondsLeft(QR_TTL_SECONDS); } catch (e) { setError(e instanceof Error ? e.message : 'Не удалось получить QR-код'); } finally { setLoading(false); } }, []); useEffect(() => { fetchToken(); }, [fetchToken]); // Countdown tick — stops at 0. useEffect(() => { if (!token || secondsLeft <= 0) return; const id = setInterval(() => setSecondsLeft((s) => s - 1), 1000); return () => clearInterval(id); }, [token, secondsLeft]); const expired = secondsLeft <= 0; const minutes = Math.floor(secondsLeft / 60); const seconds = secondsLeft % 60; const countdownText = `${minutes}:${String(seconds).padStart(2, '0')}`; if (loading) { return (

Генерируем QR-код…

); } if (error) { return (

{error}

); } return (
{/* QR code always has a white bg — required for scanner contrast */}
{token && !expired ? ( ) : (

QR-код истёк

)}
{!expired ? (

Действителен ещё{' '} {countdownText}

) : ( )}
); }