'use client'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { useI18n } from '@/lib/i18n'; import { Copy, Loader2 } from 'lucide-react'; import * as React from 'react'; export type ShareDialogValues = { accessCode: string; expiresInMinutes: number | null; }; type ShareDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; isCreating: boolean; shareUrl: string | null; error: string | null; onCreate: (values: ShareDialogValues) => void; }; const expiryOptions = [ { value: 'none', minutes: null, labelKey: 'share.expiryNone' }, { value: '60', minutes: 60, labelKey: 'share.expiryOneHour' }, { value: '1440', minutes: 1440, labelKey: 'share.expiryOneDay' }, { value: '10080', minutes: 10080, labelKey: 'share.expirySevenDays' } ] as const; export const DEFAULT_SHARE_EXPIRY_VALUE = '1440'; const MIN_ACCESS_CODE_LENGTH = 8; function getDefaultShareExpiryMinutes(): number | null { const defaultOption = expiryOptions.find((option) => option.value === DEFAULT_SHARE_EXPIRY_VALUE); if (!defaultOption) { throw new Error('Default share expiry option is not configured.'); } return defaultOption.minutes; } export function getShareExpiryMinutes(value: string): number | null { const option = expiryOptions.find((candidate) => candidate.value === value); return option === undefined ? getDefaultShareExpiryMinutes() : option.minutes; } export function ShareExpiryField(props: { expiry: string; onExpiryChange: (value: string) => void }) { const { t } = useI18n(); return (
); } export function ShareDialogFooterActions(props: { isCreating: boolean; accessCodeError: string | null; onClose: () => void; onCreate: () => void; }) { const { t } = useI18n(); return ( ); } export function ShareLinkField(props: { shareUrl: string; copyStatus: { url: string; result: 'copied' | 'error' } | null; onCopy: () => void; }) { const { t } = useI18n(); const copyResult = props.copyStatus?.url === props.shareUrl ? props.copyStatus.result : null; return (
{copyResult === 'copied' ? (

{t('common.copied')}

) : null} {copyResult === 'error' ? (

{t('share.copyFailed')}

) : null}
); } export function ShareDialog({ open, onOpenChange, isCreating, shareUrl, error, onCreate }: ShareDialogProps) { const { t } = useI18n(); const [accessCode, setAccessCode] = React.useState(''); const [expiry, setExpiry] = React.useState(DEFAULT_SHARE_EXPIRY_VALUE); const [copyStatus, setCopyStatus] = React.useState<{ url: string; result: 'copied' | 'error' } | null>(null); const trimmedAccessCode = accessCode.trim(); const accessCodeError = trimmedAccessCode && trimmedAccessCode.length < MIN_ACCESS_CODE_LENGTH ? t('share.accessCodeTooShort') : null; const handleOpenChange = (nextOpen: boolean) => { if (!nextOpen) { setCopyStatus(null); } onOpenChange(nextOpen); }; return ( {t('share.dialogTitle')} {t('share.dialogDescription')}
setAccessCode(event.target.value)} placeholder={t('share.accessCodeOptional')} type='password' autoComplete='new-password' spellCheck={false} />

{t('share.publicRiskHint')}

{accessCodeError ?

{accessCodeError}

: null} {error ? (

{error}

) : null} {shareUrl ? ( { void (async () => { setCopyStatus(null); try { if (!navigator.clipboard?.writeText) { throw new Error(t('share.copyFailed')); } await navigator.clipboard.writeText(shareUrl); setCopyStatus({ url: shareUrl, result: 'copied' }); } catch { setCopyStatus({ url: shareUrl, result: 'error' }); } })(); }} /> ) : null}
handleOpenChange(false)} onCreate={() => onCreate({ accessCode: trimmedAccessCode, expiresInMinutes: getShareExpiryMinutes(expiry) }) } />
); }