import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Check } from 'lucide-react' import SignaturePad from './SignaturePad.tsx' import PasskeySignButton from './PasskeySignButton.tsx' import type { PasskeySignature, SignatureValue } from '../types/signatures.js' import { isPasskeySignature, getSignaturePayload, getSignatureAttribution } from '../utils/signatures.js' import { formatAppDateTime } from '../utils/dateTimeFormat.js' type SignatureMode = 'passkey' | 'classic' interface SignatureSectionProps { readOnly?: boolean disabled?: boolean isOnline: boolean canSignSkipper: boolean canSignCrew: boolean signSkipper: SignatureValue | '' signCrew: SignatureValue | '' skipperSignatureValid: boolean crewSignatureValid: boolean onSignSkipperChange: (value: SignatureValue | '') => void onSignCrewChange: (value: SignatureValue | '') => void onPasskeySignSkipper: () => Promise onPasskeySignCrew: () => Promise onBeforeSign?: () => Promise } function SignerAttributionBadge({ value }: { value: SignatureValue | '' }) { const { t, i18n } = useTranslation() const attribution = getSignatureAttribution(value) if (!attribution) return null const formattedDate = formatAppDateTime(attribution.signedAt, i18n.language) return (
{t('logs.sign_passkey_signed', { username: attribution.username })} {formattedDate}
) } function padValue(value: SignatureValue | ''): string { return getSignaturePayload(value) } function modeFromValue(value: SignatureValue | '', passkeyAvailable: boolean): SignatureMode { if (isPasskeySignature(value)) return 'passkey' if (getSignaturePayload(value)) return 'classic' return passkeyAvailable ? 'passkey' : 'classic' } interface RoleSignatureBlockProps { roleLabel: string passkeyLabel: string padId: string value: SignatureValue | '' passkeySignature?: PasskeySignature signatureValid: boolean showPasskey: boolean readOnly: boolean disabled: boolean classicHint?: string offlineHint?: string onChange: (value: SignatureValue | '') => void onPasskeySign: () => Promise onBeforeSign?: () => Promise } function RoleSignatureBlock({ roleLabel, passkeyLabel, padId, value, passkeySignature, signatureValid, showPasskey, readOnly, disabled, classicHint, offlineHint, onChange, onPasskeySign, onBeforeSign }: RoleSignatureBlockProps) { const { t } = useTranslation() const [mode, setMode] = useState(() => modeFromValue(value, showPasskey)) useEffect(() => { setMode(modeFromValue(value, showPasskey)) }, [value, showPasskey]) const switchToClassic = () => { setMode('classic') if (isPasskeySignature(value)) onChange('') } const switchToPasskey = () => { setMode('passkey') if (value && !isPasskeySignature(value)) onChange('') } const handlePadChange = (next: string) => { setMode('classic') onChange(next) } if (readOnly) { if (isPasskeySignature(value)) { return (
) } return (
{}} disabled={disabled} readOnly />
) } const showPasskeyPanel = showPasskey && mode === 'passkey' const showClassicPanel = !showPasskey || mode === 'classic' return (
{showPasskey && (
)} {showPasskeyPanel && ( )} {showClassicPanel && ( <> {classicHint && !passkeySignature && (

{classicHint}

)} )} {offlineHint && !showPasskey && (

{offlineHint}

)}
) } export default function SignatureSection({ readOnly = false, disabled = false, isOnline, canSignSkipper, canSignCrew, signSkipper, signCrew, skipperSignatureValid, crewSignatureValid, onSignSkipperChange, onSignCrewChange, onPasskeySignSkipper, onPasskeySignCrew, onBeforeSign }: SignatureSectionProps) { const { t } = useTranslation() const showSkipperPasskey = canSignSkipper && isOnline const showCrewPasskey = canSignCrew && isOnline const hasSignature = !!(signSkipper || signCrew) return (

{t('logs.signatures')}

{!readOnly && (

{hasSignature ? t('logs.sign_lock_active') : t('logs.sign_lock_notice')}

)}
) }