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:
1 parent
2348a9e94f
commit
8212423ec3
19 files changed
+780
-61
No files matched your search
@@ -0,0 +1,97 @@
|
||||
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<FlushPendingCommunityAvatarResult> | null = null;
|
||||
|
||||
export function forgetFlushedCommunityAvatarUrl(): void {
|
||||
lastUploadedUrl = null;
|
||||
}
|
||||
|
||||
async function runFlush(): Promise<FlushPendingCommunityAvatarResult> {
|
||||
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<FlushPendingCommunityAvatarResult> {
|
||||
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 };
|
||||
}
|
||||
@@ -28,8 +28,8 @@ function reasonFromUnknown(value: unknown): CreateFlowUploadValidationReason | n
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticated multipart upload to `POST /api/uploads`.
|
||||
* Caller must have a session cookie (same-origin fetch).
|
||||
* Multipart upload to `POST /api/uploads`.
|
||||
* `communityAvatar` is accepted for a guest; other purposes need a session.
|
||||
*/
|
||||
export async function uploadCreateFlowFile(
|
||||
file: File,
|
||||
|
||||
Reference in new issue
Block a user