import { useState } from 'react' import { uploadNip95Media } from '@/lib/nip95' import { t } from '@/lib/i18n' import Image from 'next/image' import { UnlockAccountModal } from './UnlockAccountModal' interface ImageUploadFieldProps { id: string label?: string | undefined value?: string | undefined onChange: (url: string) => void helpText?: string | undefined } function ImagePreview({ value }: { value: string }): React.ReactElement { return (
{t('presentation.field.picture')}
) } function UploadButtonLabel({ uploading, value }: { uploading: boolean; value: string | undefined }): React.ReactElement { if (uploading) { return {t('presentation.field.picture.uploading')} } return {value ? t('presentation.field.picture.change') : t('presentation.field.picture.upload')} } function RemoveButton({ value, onChange }: { value: string | undefined; onChange: (url: string) => void }): React.ReactElement | null { if (!value) { return null } return ( ) } function ImageUploadControls({ id, uploading, value, onChange, onFileSelect, }: { id: string uploading: boolean value: string | undefined onChange: (url: string) => void onFileSelect: (e: React.ChangeEvent) => Promise }): React.ReactElement { return (
{ void onFileSelect(e) }} disabled={uploading} />
) } async function processFileUpload(file: File, onChange: (url: string) => void, setError: (error: string | null) => void): Promise { const media = await uploadNip95Media(file) if (media.type === 'image') { onChange(media.url) } else { setError(t('presentation.field.picture.error.imagesOnly')) } } function useImageUpload(onChange: (url: string) => void): { uploading: boolean error: string | null handleFileSelect: (e: React.ChangeEvent) => Promise showUnlockModal: boolean setShowUnlockModal: (show: boolean) => void handleUnlockSuccess: () => Promise } { const [uploading, setUploading] = useState(false) const [error, setError] = useState(null) const [showUnlockModal, setShowUnlockModal] = useState(false) const [pendingFile, setPendingFile] = useState(null) const handleFileSelect = async (event: React.ChangeEvent): Promise => { const file = event.target.files?.[0] if (!file) { return } setError(null) setUploading(true) try { await processFileUpload(file, onChange, setError) } catch (uploadError) { const uploadErr = uploadError instanceof Error ? uploadError : new Error(String(uploadError)) // Check if unlock is required if (uploadErr.message === 'UNLOCK_REQUIRED' || ('unlockRequired' in uploadErr && (uploadErr as { unlockRequired?: boolean }).unlockRequired)) { setPendingFile(file) setShowUnlockModal(true) setError(null) // Don't show error, show unlock modal instead } else { setError(uploadErr.message ?? t('presentation.field.picture.error.uploadFailed')) } } finally { setUploading(false) } } const handleUnlockSuccess = async (): Promise => { setShowUnlockModal(false) if (pendingFile) { // Retry upload after unlock setUploading(true) setError(null) try { await processFileUpload(pendingFile, onChange, setError) setPendingFile(null) } catch (retryError) { setError(retryError instanceof Error ? retryError.message : t('presentation.field.picture.error.uploadFailed')) } finally { setUploading(false) } } } return { uploading, error, handleFileSelect, showUnlockModal, setShowUnlockModal, handleUnlockSuccess } } export function ImageUploadField({ id, label, value, onChange, helpText }: ImageUploadFieldProps): React.ReactElement { const { uploading, error, handleFileSelect, showUnlockModal, setShowUnlockModal, handleUnlockSuccess } = useImageUpload(onChange) const displayLabel = label ?? t('presentation.field.picture') const displayHelpText = helpText ?? t('presentation.field.picture.help') return ( <>
{value && } {error &&

{error}

} {displayHelpText &&

{displayHelpText}

}
{showUnlockModal && ( { void handleUnlockSuccess() }} onClose={() => { setShowUnlockModal(false) }} /> )} ) }