import type { CreateFlowState } from "../../app/(app)/create/types"; import { CreateFlowUploadValidationError } from "./createFlowUploadValidation"; import { clearPendingCommunityAvatarFile, readPendingCommunityAvatarFile, } from "./pendingCommunityAvatarUpload"; import { uploadCreateFlowFile } from "./uploadToServer"; export type FlushPendingCommunityAvatarResult = | { status: "none" } | { status: "uploaded"; url: string } | { status: "invalid" } | { status: "failed" }; /** * URL from the last successful flush. The IndexedDB file is removed on * success, so a second caller (publish, sign-in transfer) can still apply * the same URL if React state has not caught up yet. * Cleared when anonymous draft storage is wiped. */ let lastUploadedUrl: string | null = null; let inFlight: Promise | null = null; export function forgetFlushedCommunityAvatarUrl(): void { lastUploadedUrl = null; } async function runFlush(): Promise { let file: File | null; try { file = await readPendingCommunityAvatarFile(); } catch { return lastUploadedUrl ? { status: "uploaded", url: lastUploadedUrl } : { status: "none" }; } if (!file) { return lastUploadedUrl ? { status: "uploaded", url: lastUploadedUrl } : { status: "none" }; } try { const { url } = await uploadCreateFlowFile(file, "communityAvatar"); lastUploadedUrl = url; await clearPendingCommunityAvatarFile(); return { status: "uploaded", url }; } catch (err) { if (err instanceof CreateFlowUploadValidationError) { await clearPendingCommunityAvatarFile(); return { status: "invalid" }; } return { status: "failed" }; } } /** * Upload the staged community logo, once, even if review and sign-in both ask. * A validation failure drops the file. A transient failure leaves it in place. */ export function flushPendingCommunityAvatar(): Promise { if (!inFlight) { inFlight = runFlush().finally(() => { inFlight = null; }); } return inFlight; } /** * Copy a staged logo onto `state` as `communityAvatarUrl` when upload works. * `upload_failed` means the file is still staged and must not be published over. */ export async function stateWithPendingCommunityAvatar( state: CreateFlowState, ): Promise< | { ok: true; state: CreateFlowState } | { ok: false; reason: "upload_failed" } > { const existing = typeof state.communityAvatarUrl === "string" ? state.communityAvatarUrl.trim() : ""; if (existing.length > 0) return { ok: true, state }; const flushed = await flushPendingCommunityAvatar(); if (flushed.status === "uploaded") { return { ok: true, state: { ...state, communityAvatarUrl: flushed.url }, }; } if (flushed.status === "failed") { return { ok: false, reason: "upload_failed" }; } return { ok: true, state }; }