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

@@ -0,0 +1,65 @@
"use client";
import { useEffect, useState } from "react";
import { readPendingCommunityAvatarFile } from "../../../../lib/create/pendingCommunityAvatarUpload";
function trimmedAvatarUrl(url: string | null): string | null {
if (typeof url !== "string") return null;
const trimmed = url.trim();
return trimmed.length > 0 ? trimmed : null;
}
/**
* Logo src for review cards. Uses the uploaded URL when the draft has one,
* otherwise the guest file staged in IndexedDB.
*
* @param serverUrl `communityAvatarUrl` from create-flow state, if any.
* @returns A URL the Rule card can render, or `null` when there is no logo.
*
* @example
* const logoUrl = useCommunityAvatarDisplayUrl(state.communityAvatarUrl ?? null);
*/
export function useCommunityAvatarDisplayUrl(
serverUrl: string | null | undefined,
): string | null {
const resolvedServerUrl = trimmedAvatarUrl(serverUrl ?? null);
const [objectUrl, setObjectUrl] = useState<string | null>(null);
useEffect(() => {
if (resolvedServerUrl) {
setObjectUrl((prev) => {
if (prev) URL.revokeObjectURL(prev);
return null;
});
return;
}
let cancelled = false;
let created: string | null = null;
void (async () => {
try {
const file = await readPendingCommunityAvatarFile();
if (cancelled || !file) return;
created = URL.createObjectURL(file);
if (cancelled) {
URL.revokeObjectURL(created);
created = null;
return;
}
setObjectUrl((prev) => {
if (prev && prev !== created) URL.revokeObjectURL(prev);
return created;
});
} catch {
// IndexedDB missing or blocked: the card keeps the placeholder.
}
})();
return () => {
cancelled = true;
if (created) URL.revokeObjectURL(created);
};
}, [resolvedServerUrl]);
return resolvedServerUrl ?? objectUrl;
}
+11 -4
View File
@@ -3,6 +3,7 @@
import { useCallback } from "react";
import type { CreateFlowState, CreateFlowStep } from "../types";
import { buildPublishPayload } from "../../../../lib/create/buildPublishPayload";
import { stateWithPendingCommunityAvatar } from "../../../../lib/create/flushPendingCommunityAvatar";
import { saveDraftToServer, updatePublishedRule } from "../../../../lib/create/api";
import { writeLastPublishedRule } from "../../../../lib/create/lastPublishedRule";
import { isBackendSyncEnabled } from "../../../../lib/create/backendSyncEnabled";
@@ -47,12 +48,18 @@ export function useCreateFlowExit({
}
if (saveDraft && isBackendSyncEnabled()) {
const prepared = await stateWithPendingCommunityAvatar(state);
if (prepared.ok === false) {
setDraftSaveBannerMessage?.(messages.create.upload.errors.generic);
return;
}
const draftState = prepared.state;
const editingId =
typeof state.editingPublishedRuleId === "string"
? state.editingPublishedRuleId.trim()
typeof draftState.editingPublishedRuleId === "string"
? draftState.editingPublishedRuleId.trim()
: "";
if (editingId.length > 0) {
const payloadResult = buildPublishPayload(state);
const payloadResult = buildPublishPayload(draftState);
if (payloadResult.ok === false) {
setDraftSaveBannerMessage?.(
payloadResult.error === "missingCommunityName"
@@ -82,7 +89,7 @@ export function useCreateFlowExit({
}
} else {
const payload: CreateFlowState = {
...state,
...draftState,
...(currentStep ? { currentStep } : {}),
};
const result = await saveDraftToServer(payload);
@@ -2,6 +2,7 @@
import { useCallback, useState } from "react";
import { buildPublishPayload } from "../../../../lib/create/buildPublishPayload";
import { stateWithPendingCommunityAvatar } from "../../../../lib/create/flushPendingCommunityAvatar";
import { publishRule, updatePublishedRule } from "../../../../lib/create/api";
import { writeLastPublishedRule } from "../../../../lib/create/lastPublishedRule";
import { writePendingKeepRuleLogin } from "../../../../lib/create/pendingKeepRuleLogin";
@@ -63,8 +64,19 @@ export function useCreateFlowFinalize({
if (sessionUser === undefined) return;
setPublishBannerMessage(null);
const payloadResult = buildPublishPayload(state);
setIsPublishing(true);
const prepared = await stateWithPendingCommunityAvatar(state);
if (prepared.ok === false) {
setIsPublishing(false);
setPublishBannerMessage(messages.create.upload.errors.generic);
return;
}
if (prepared.state.communityAvatarUrl !== state.communityAvatarUrl) {
updateState({ communityAvatarUrl: prepared.state.communityAvatarUrl });
}
const payloadResult = buildPublishPayload(prepared.state);
if (payloadResult.ok === false) {
setIsPublishing(false);
setPublishBannerMessage(
payloadResult.error === "missingCommunityName"
? messages.create.reviewAndComplete.publish.missingCommunityName
@@ -73,7 +85,6 @@ export function useCreateFlowFinalize({
return;
}
const { title, summary, document: ruleDocument } = payloadResult;
setIsPublishing(true);
const editingId =
typeof state.editingPublishedRuleId === "string"