Files
dyolink/frontend/src/components/ui/lab/LabCaseShareQrDialog.tsx

102 lines
3.4 KiB
TypeScript

'use client';
import { useCallback, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Copy } from 'lucide-react';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import {
ResponsiveDialogOverlay,
ResponsiveDialogPanel,
} from '@/components/ui/shared/ResponsiveDialog';
import { Button } from '@/components/ui/shared/Button';
import { useToast } from '@/lib/hooks/useToast';
import { LabCaseShareQrCode } from '@/components/ui/lab/LabCaseShareQrCode';
interface LabCaseShareQrDialogProps {
open: boolean;
onClose: () => void;
shareUrl: string;
}
export function LabCaseShareQrDialog({ open, onClose, shareUrl }: LabCaseShareQrDialogProps) {
const t = useTranslations('cases');
const { showSuccess } = useToast();
const [copying, setCopying] = useState(false);
const handleCopy = useCallback(async () => {
setCopying(true);
try {
await navigator.clipboard.writeText(shareUrl);
showSuccess(t('shareLinkCopied'));
} catch {
// ignore clipboard failures
} finally {
setCopying(false);
}
}, [shareUrl, showSuccess, t]);
if (!open) return null;
return (
<ResponsiveDialogOverlay onBackdropClick={onClose}>
<ResponsiveDialogPanel
maxWidthClass="sm:max-w-3xl"
role="dialog"
aria-modal="true"
aria-labelledby="case-share-qr-title"
className="space-y-4"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0 flex-1">
<h2 id="case-share-qr-title" className="text-lg font-semibold text-text-primary">
{t('shareQrDialogTitle')}
</h2>
<p className="text-sm text-text-muted mt-1">{t('shareQrDialogSubtitle')}</p>
</div>
<DialogCloseButton onClick={onClose} />
</div>
<div className="flex flex-col items-center gap-4 min-w-0">
<div className="w-full max-w-[17rem] sm:max-w-[16rem] rounded-md border border-border bg-white p-3 sm:p-4">
<LabCaseShareQrCode value={shareUrl} size={256} className="h-auto w-full" />
</div>
<p className="w-full min-w-0 break-all text-center text-sm text-text-secondary px-2">
{shareUrl}
</p>
<Button
type="button"
variant="outline"
disabled={copying}
className="w-full sm:w-auto"
onClick={() => handleCopy()}
>
<Copy className="h-4 w-4 me-1.5" />
{t('copyShareLink')}
</Button>
</div>
</ResponsiveDialogPanel>
</ResponsiveDialogOverlay>
);
}
interface LabCaseShareQrThumbProps {
shareUrl: string;
onClick: () => void;
}
export function LabCaseShareQrThumb({ shareUrl, onClick }: LabCaseShareQrThumbProps) {
const t = useTranslations('cases');
return (
<button
type="button"
onClick={onClick}
className="aspect-square w-24 sm:w-32 cursor-pointer rounded-[var(--radius-md)] border border-border/60 overflow-hidden bg-white p-2 transition-colors hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary flex items-center justify-center"
title={t('viewShareQr')}
aria-label={t('viewShareQr')}
>
<LabCaseShareQrCode value={shareUrl} size={96} className="h-full w-full max-h-full max-w-full" />
</button>
);
}