Keep a guest community logo on review and on the published rule.

Sign-in was clearing the staged file before it uploaded, and review only read the server URL, so a chosen logo disappeared after the upload step.
This commit is contained in:
adilallo committed 2026-11-05 20:02:40 -07:00
1 parent 2348a9e94f
commit 8212423ec3
19 files changed
+780 -61

No files matched your search

@@ -1,19 +1,16 @@
"use client";
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import { useCreateFlow } from "../context/CreateFlowContext";
import {
CreateFlowUploadValidationError,
uploadCreateFlowFile,
} from "../../../../lib/create/uploadToServer";
import {
clearPendingCommunityAvatarFile,
readPendingCommunityAvatarFile,
} from "../../../../lib/create/pendingCommunityAvatarUpload";
import { flushPendingCommunityAvatar } from "../../../../lib/create/flushPendingCommunityAvatar";
/** Background tries after a transient upload failure. The file stays staged. */
const MAX_FLUSH_ATTEMPTS = 4;
/**
* After sign-in, uploads a community avatar staged in IndexedDB (anonymous pick)
* and writes `communityAvatarUrl` on success.
* and writes `communityAvatarUrl` on success. A transient failure retries with
* backoff while this layout stays mounted.
*/
export function CreateFlowPendingAvatarFlush({
sessionUser,
@@ -23,7 +20,8 @@ export function CreateFlowPendingAvatarFlush({
sessionResolved: boolean;
}) {
const { state, updateState } = useCreateFlow();
/** One successful flush per signed-in user id (survives React StrictMode remounts). */
const [attempt, setAttempt] = useState(0);
/** One successful flush per signed-in user id (survives the effect re-running). */
const lastFlushedUserIdRef = useRef<string | null>(null);
const hasServerAvatar =
typeof state.communityAvatarUrl === "string" &&
@@ -33,29 +31,31 @@ export function CreateFlowPendingAvatarFlush({
if (!sessionResolved || !sessionUser) return;
if (lastFlushedUserIdRef.current === sessionUser.id) return;
if (hasServerAvatar) return;
if (attempt >= MAX_FLUSH_ATTEMPTS) return;
let cancelled = false;
let timer: ReturnType<typeof setTimeout> | undefined;
void (async () => {
const file = await readPendingCommunityAvatarFile();
if (cancelled || !file) return;
try {
const { url } = await uploadCreateFlowFile(file, "communityAvatar");
if (cancelled) return;
await clearPendingCommunityAvatarFile();
updateState({ communityAvatarUrl: url });
const result = await flushPendingCommunityAvatar();
if (cancelled) return;
if (result.status === "uploaded") {
updateState({ communityAvatarUrl: result.url });
lastFlushedUserIdRef.current = sessionUser.id;
} catch (err) {
if (err instanceof CreateFlowUploadValidationError) {
await clearPendingCommunityAvatarFile();
}
// Leave a transient (auth / UPLOAD_ROOT) failure in place to retry.
return;
}
if (result.status !== "failed") return;
if (attempt + 1 >= MAX_FLUSH_ATTEMPTS) return;
const delay = Math.min(20_000, 5_000 * 2 ** attempt);
timer = setTimeout(() => {
if (!cancelled) setAttempt((current) => current + 1);
}, delay);
})();
return () => {
cancelled = true;
if (timer) clearTimeout(timer);
};
}, [hasServerAvatar, sessionResolved, sessionUser, updateState]);
}, [attempt, hasServerAvatar, sessionResolved, sessionUser, updateState]);
return null;
}