"use client"; import { useCallback, useEffect, useRef, useState, type ChangeEvent, } from "react"; import Upload from "../../../../components/controls/Upload"; import { useMessages, useTranslation } from "../../../../contexts/MessagesContext"; import { useCreateFlow } from "../../context/CreateFlowContext"; import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup"; import { CreateFlowStepShell } from "../../components/CreateFlowStepShell"; import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens"; import { fetchAuthSession } from "../../../../../lib/create/api"; import { ASSETS, getAssetPath } from "../../../../../lib/assetUtils"; import { createFlowUploadFailureMessageKey, uploadCreateFlowFile, } from "../../../../../lib/create/uploadToServer"; import { COMMUNITY_AVATAR_ACCEPT, messageKeyForCreateFlowUploadReason, validateCreateFlowUploadFile, } from "../../../../../lib/create/createFlowUploadValidation"; import { clearPendingCommunityAvatarFile, readPendingCommunityAvatarFile, storePendingCommunityAvatarFile, } from "../../../../../lib/create/pendingCommunityAvatarUpload"; function hasCommunityAvatarUrl(url: string | undefined): boolean { return typeof url === "string" && url.trim().length > 0; } /** Create Community — Figma Flow — Upload `20094:41524`. */ export function CommunityUploadScreen() { const m = useMessages(); const u = m.create.community.communityUpload; const { markCreateFlowInteraction, state, updateState } = useCreateFlow(); const tUpload = useTranslation("create.upload"); const fileInputRef = useRef(null); const [signedIn, setSignedIn] = useState(null); const [localPreviewUrl, setLocalPreviewUrl] = useState(null); const [busy, setBusy] = useState(false); const [errorMessage, setErrorMessage] = useState(null); useEffect(() => { let cancelled = false; void fetchAuthSession().then(({ user }) => { if (!cancelled) setSignedIn(Boolean(user)); }); return () => { cancelled = true; }; }, []); useEffect( () => () => { if (localPreviewUrl) URL.revokeObjectURL(localPreviewUrl); }, [localPreviewUrl], ); const serverAvatarUrl = hasCommunityAvatarUrl(state.communityAvatarUrl) ? state.communityAvatarUrl!.trim() : null; const serverAvatarUrlRef = useRef(serverAvatarUrl); serverAvatarUrlRef.current = serverAvatarUrl; useEffect(() => { if (serverAvatarUrl) { setLocalPreviewUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return null; }); } }, [serverAvatarUrl]); useEffect(() => { let cancelled = false; void (async () => { try { const file = await readPendingCommunityAvatarFile(); if (cancelled || !file) return; const validated = await validateCreateFlowUploadFile( file, "communityAvatar", ); if (validated.ok === false) { await clearPendingCommunityAvatarFile(); return; } if (cancelled) return; if (serverAvatarUrlRef.current) return; const objectUrl = URL.createObjectURL(file); if (cancelled) { URL.revokeObjectURL(objectUrl); return; } setLocalPreviewUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return objectUrl; }); } catch { // Missing IndexedDB / quota: leave the picker empty. } })(); return () => { cancelled = true; }; }, []); const resolveUploadError = useCallback( (err: unknown) => tUpload(createFlowUploadFailureMessageKey(err)), [tUpload], ); const handleFileChange = useCallback( async (e: ChangeEvent) => { const file = e.target.files?.[0]; e.target.value = ""; if (!file) return; markCreateFlowInteraction(); setErrorMessage(null); if (signedIn) { setBusy(true); try { const { url } = await uploadCreateFlowFile(file, "communityAvatar"); setLocalPreviewUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return null; }); updateState({ communityAvatarUrl: url }); } catch (err) { setErrorMessage(resolveUploadError(err)); } finally { setBusy(false); } return; } if (signedIn === false) { const validated = await validateCreateFlowUploadFile( file, "communityAvatar", ); if (validated.ok === false) { setErrorMessage( tUpload(messageKeyForCreateFlowUploadReason(validated.reason)), ); return; } try { await storePendingCommunityAvatarFile(file); setLocalPreviewUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return URL.createObjectURL(file); }); } catch { setErrorMessage(tUpload("errors.generic")); } } }, [ markCreateFlowInteraction, resolveUploadError, signedIn, tUpload, updateState, ], ); const handleClearPendingUpload = useCallback(() => { markCreateFlowInteraction(); setErrorMessage(null); setLocalPreviewUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return null; }); if (hasCommunityAvatarUrl(state.communityAvatarUrl)) { updateState({ communityAvatarUrl: undefined }); } void clearPendingCommunityAvatarFile(); if (fileInputRef.current) { fileInputRef.current.value = ""; } }, [markCreateFlowInteraction, state.communityAvatarUrl, updateState]); const displaySrc = serverAvatarUrl ?? localPreviewUrl; const hasPreview = typeof displaySrc === "string" && displaySrc.length > 0; return (
{hasPreview ? (
{/* eslint-disable-next-line @next/next/no-img-element -- user/device file or same-origin upload URL */} {u.previewAlt}
) : ( { if (!busy) fileInputRef.current?.click(); }} /> )} {signedIn === false ? (

{u.signInToUploadNote}

) : null} {errorMessage ? (

{errorMessage}

) : null}
); }