112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback } from "react";
|
|
import type { CreateFlowState, CreateFlowStep } from "../types";
|
|
import { buildPublishPayload } from "../../../../lib/create/buildPublishPayload";
|
|
import { saveDraftToServer, updatePublishedRule } from "../../../../lib/create/api";
|
|
import { writeLastPublishedRule } from "../../../../lib/create/lastPublishedRule";
|
|
import { isBackendSyncEnabled } from "../../../../lib/create/backendSyncEnabled";
|
|
import messages from "../../../../messages/en/index";
|
|
|
|
export type CreateFlowExitClearState = () => void;
|
|
|
|
type AppRouterLike = { push: (_href: string) => void };
|
|
|
|
/**
|
|
* Leave the create flow for a **signed-in** user. Caller must not invoke for anonymous users.
|
|
*/
|
|
export function useCreateFlowExit({
|
|
state,
|
|
currentStep,
|
|
clearState,
|
|
router,
|
|
user,
|
|
setDraftSaveBannerMessage,
|
|
confirmLeave,
|
|
}: {
|
|
state: CreateFlowState;
|
|
currentStep: CreateFlowStep | null;
|
|
clearState: CreateFlowExitClearState;
|
|
router: AppRouterLike;
|
|
user: { id: string; email: string } | null;
|
|
/** When save fails, surface the server message in the create shell banner (no leave confirm). */
|
|
setDraftSaveBannerMessage?: (_message: string | null) => void;
|
|
/** When exit would discard unsaved work, return true to proceed. Defaults to denying leave. */
|
|
confirmLeave?: () => Promise<boolean>;
|
|
}): (_options?: { saveDraft?: boolean }) => Promise<void> {
|
|
return useCallback(
|
|
async (options?: { saveDraft?: boolean }) => {
|
|
if (!user) return;
|
|
|
|
const saveDraft = options?.saveDraft ?? false;
|
|
|
|
if (!saveDraft) {
|
|
const confirmFn = confirmLeave ?? (async () => false);
|
|
const confirmed = await confirmFn();
|
|
if (!confirmed) return;
|
|
}
|
|
|
|
if (saveDraft && isBackendSyncEnabled()) {
|
|
const editingId =
|
|
typeof state.editingPublishedRuleId === "string"
|
|
? state.editingPublishedRuleId.trim()
|
|
: "";
|
|
if (editingId.length > 0) {
|
|
const payloadResult = buildPublishPayload(state);
|
|
if (payloadResult.ok === false) {
|
|
setDraftSaveBannerMessage?.(
|
|
payloadResult.error === "missingCommunityName"
|
|
? messages.create.reviewAndComplete.publish
|
|
.missingCommunityName
|
|
: payloadResult.error,
|
|
);
|
|
return;
|
|
}
|
|
const { title, summary, document } = payloadResult;
|
|
const updateResult = await updatePublishedRule(editingId, {
|
|
title,
|
|
summary: summary ?? null,
|
|
document,
|
|
});
|
|
if (updateResult.ok === true) {
|
|
writeLastPublishedRule({
|
|
id: editingId,
|
|
title,
|
|
summary: summary ?? null,
|
|
document,
|
|
});
|
|
setDraftSaveBannerMessage?.(null);
|
|
} else {
|
|
setDraftSaveBannerMessage?.(updateResult.error);
|
|
return;
|
|
}
|
|
} else {
|
|
const payload: CreateFlowState = {
|
|
...state,
|
|
...(currentStep ? { currentStep } : {}),
|
|
};
|
|
const result = await saveDraftToServer(payload);
|
|
if (result.ok === true) {
|
|
setDraftSaveBannerMessage?.(null);
|
|
} else {
|
|
setDraftSaveBannerMessage?.(result.message);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
clearState();
|
|
router.push("/");
|
|
},
|
|
[
|
|
state,
|
|
currentStep,
|
|
clearState,
|
|
router,
|
|
user,
|
|
setDraftSaveBannerMessage,
|
|
confirmLeave,
|
|
],
|
|
);
|
|
}
|