77 lines
2.0 KiB
TypeScript
77 lines
2.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { createPortal } from 'react-dom';
|
||
import QRCode from 'qrcode';
|
||
|
||
interface SubscriptionQrModalProps {
|
||
link: string | null;
|
||
label?: string;
|
||
imageAlt?: string;
|
||
onClose: () => void;
|
||
}
|
||
|
||
export function SubscriptionQrModal({
|
||
link,
|
||
label = 'Ссылка подписки',
|
||
imageAlt = 'QR-код ссылки подписки',
|
||
onClose,
|
||
}: SubscriptionQrModalProps) {
|
||
const [image, setImage] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
if (!link) return;
|
||
|
||
let active = true;
|
||
void QRCode.toDataURL(link, {
|
||
errorCorrectionLevel: 'M',
|
||
margin: 2,
|
||
width: 280,
|
||
color: { dark: '#1a1610', light: '#faf7f2' },
|
||
})
|
||
.then((dataUrl) => {
|
||
if (active) setImage(dataUrl);
|
||
})
|
||
.catch(() => {
|
||
if (active) setImage(null);
|
||
});
|
||
|
||
const onKey = (event: KeyboardEvent) => {
|
||
if (event.key === 'Escape') onClose();
|
||
};
|
||
document.addEventListener('keydown', onKey);
|
||
document.body.style.overflow = 'hidden';
|
||
return () => {
|
||
active = false;
|
||
document.removeEventListener('keydown', onKey);
|
||
document.body.style.overflow = '';
|
||
};
|
||
}, [link, onClose]);
|
||
|
||
if (!link) return null;
|
||
|
||
return createPortal(
|
||
<div
|
||
className="modal-veil is-open"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label="Откройте на устройстве"
|
||
onClick={(event) => {
|
||
if (event.target === event.currentTarget) onClose();
|
||
}}
|
||
>
|
||
<div className="modal subscription-qr-modal" role="document">
|
||
<div className="modal-kicker">Сканировать</div>
|
||
<h3 className="modal-title" id="subscription-qr-title">
|
||
{label}
|
||
</h3>
|
||
<div className="subscription-qr-image">
|
||
{image ? <img src={image} alt={imageAlt} /> : <span>Генерируем QR-код</span>}
|
||
</div>
|
||
<button type="button" className="btn" onClick={onClose} autoFocus>
|
||
Закрыть
|
||
</button>
|
||
</div>
|
||
</div>,
|
||
document.body,
|
||
);
|
||
}
|