Final review edit modals created

This commit is contained in:
adilallo
2026-04-20 17:57:17 -06:00
parent c08cd62872
commit a22d53e860
27 changed files with 2410 additions and 620 deletions
+129 -8
View File
@@ -1,5 +1,19 @@
import type { CoreValueDetailEntry, CreateFlowState } from "../../app/(app)/create/types";
import type {
CommunicationMethodDetailEntry,
ConflictManagementDetailEntry,
CoreValueDetailEntry,
CreateFlowState,
DecisionApproachDetailEntry,
MembershipMethodDetailEntry,
} from "../../app/(app)/create/types";
import type { CommunityRuleDocumentSection } from "../../app/components/sections/CommunityRuleDocument/CommunityRuleDocument.types";
import {
communicationPresetFor,
conflictManagementPresetFor,
decisionApproachPresetFor,
membershipPresetFor,
methodLabelFor,
} from "./finalReviewChipPresets";
function isDocumentEntry(x: unknown): x is { title: string; body: string } {
if (!x || typeof x !== "object") return false;
@@ -52,6 +66,36 @@ export function buildCoreValuesForDocument(state: CreateFlowState): Array<{
});
}
/**
* Structured per-group method selections emitted into `document.methodSelections`
* at publish time. Each entry carries the preset id (stable key), display
* label, and the fully-resolved section payload (override on top of preset).
* Empty groups are omitted so downstream readers can iterate just the set
* the author actually picked.
*/
export type PublishedMethodSelections = {
communication?: Array<{
id: string;
label: string;
sections: CommunicationMethodDetailEntry;
}>;
membership?: Array<{
id: string;
label: string;
sections: MembershipMethodDetailEntry;
}>;
decisionApproaches?: Array<{
id: string;
label: string;
sections: DecisionApproachDetailEntry;
}>;
conflictManagement?: Array<{
id: string;
label: string;
sections: ConflictManagementDetailEntry;
}>;
};
export type BuildPublishPayloadResult =
| {
ok: true;
@@ -97,16 +141,93 @@ export function buildPublishPayload(
}
const coreValues = buildCoreValuesForDocument(state);
const methodSelections = buildMethodSelectionsForDocument(state);
const document: Record<string, unknown> = { sections, coreValues };
if (hasAnyMethodSelection(methodSelections)) {
document.methodSelections = methodSelections;
}
if (summary !== undefined) {
return {
ok: true,
title,
summary,
document: { sections, coreValues },
};
return { ok: true, title, summary, document };
}
return { ok: true, title, document: { sections, coreValues } };
return { ok: true, title, document };
}
function hasAnyMethodSelection(m: PublishedMethodSelections): boolean {
return Boolean(
m.communication?.length ||
m.membership?.length ||
m.decisionApproaches?.length ||
m.conflictManagement?.length,
);
}
/**
* Merge `selected*MethodIds` with any saved `{group}MethodDetailsById`
* overrides authored on the final-review screen. Preset defaults from the
* shipped `messages/en/create/customRule/*.json` seed any sub-fields the
* user didn't edit so consumers of `document.methodSelections` always see
* a complete payload per method.
*/
export function buildMethodSelectionsForDocument(
state: CreateFlowState,
): PublishedMethodSelections {
const out: PublishedMethodSelections = {};
const commIds = state.selectedCommunicationMethodIds ?? [];
if (commIds.length > 0) {
out.communication = commIds.map((id) => {
const preset = communicationPresetFor(id);
const override = state.communicationMethodDetailsById?.[id];
return {
id,
label: methodLabelFor("communication", id),
sections: override ? { ...preset, ...override } : preset,
};
});
}
const memIds = state.selectedMembershipMethodIds ?? [];
if (memIds.length > 0) {
out.membership = memIds.map((id) => {
const preset = membershipPresetFor(id);
const override = state.membershipMethodDetailsById?.[id];
return {
id,
label: methodLabelFor("membership", id),
sections: override ? { ...preset, ...override } : preset,
};
});
}
const daIds = state.selectedDecisionApproachIds ?? [];
if (daIds.length > 0) {
out.decisionApproaches = daIds.map((id) => {
const preset = decisionApproachPresetFor(id);
const override = state.decisionApproachDetailsById?.[id];
return {
id,
label: methodLabelFor("decisionApproaches", id),
sections: override ? { ...preset, ...override } : preset,
};
});
}
const cmIds = state.selectedConflictManagementIds ?? [];
if (cmIds.length > 0) {
out.conflictManagement = cmIds.map((id) => {
const preset = conflictManagementPresetFor(id);
const override = state.conflictManagementDetailsById?.[id];
return {
id,
label: methodLabelFor("conflictManagement", id),
sections: override ? { ...preset, ...override } : preset,
};
});
}
return out;
}
/** Read `document.sections` from a stored published payload for display. */