107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import type footerMessages from "../../../../messages/en/create/footer.json";
|
|
import {
|
|
buildFinalReviewCategoryRowsDetailed,
|
|
type FinalReviewCategoryNames,
|
|
} from "../../../../lib/create/buildFinalReviewCategories";
|
|
import type { TemplateFacetGroupKey } from "../../../../lib/create/templateReviewMapping";
|
|
import type { CreateFlowState, CreateFlowStep } from "../types";
|
|
|
|
type FooterMessages = typeof footerMessages;
|
|
|
|
/**
|
|
* Per-step label override for the default "next-step" primary footer
|
|
* button (the catch-all branch in `CreateFlowLayoutClient`'s footer that
|
|
* fires `goToNextStep` for steps without a bespoke footer). Steps absent
|
|
* from this map fall back to `footer.next`.
|
|
*
|
|
* `final-review` uses Continue (gated by {@link isFinalReviewContinueBlocked}).
|
|
* `edit-rule` is handled separately by the caller because its label also
|
|
* depends on the in-flight publish flag (`publishButtonPublishing` vs
|
|
* `publishCommunityRule`).
|
|
*/
|
|
const DEFAULT_FOOTER_LABEL_BY_STEP: ReadonlyMap<
|
|
CreateFlowStep,
|
|
keyof FooterMessages
|
|
> = new Map<CreateFlowStep, keyof FooterMessages>([
|
|
["confirm-stakeholders", "confirmStakeholders"],
|
|
["community-context", "confirmDescription"],
|
|
["community-structure", "confirmDetails"],
|
|
["community-size", "confirmSize"],
|
|
]);
|
|
|
|
function hasNonEmptyId(ids: readonly string[] | undefined): boolean {
|
|
return (ids ?? []).some((id) => id.length > 0);
|
|
}
|
|
|
|
export function isCommunityNameStepBlocked(
|
|
step: CreateFlowStep | null | undefined,
|
|
title: string | undefined,
|
|
): boolean {
|
|
if (step !== "community-name") return false;
|
|
return typeof title !== "string" || title.trim().length === 0;
|
|
}
|
|
|
|
export function isCommunityStructureStepBlocked(
|
|
step: CreateFlowStep | null | undefined,
|
|
selectedOrganizationTypeIds: readonly string[] | undefined,
|
|
selectedMaturityIds: readonly string[] | undefined,
|
|
): boolean {
|
|
if (step !== "community-structure") return false;
|
|
const mainKind = (selectedOrganizationTypeIds ?? []).find((id) => id.length > 0);
|
|
return !mainKind || !hasNonEmptyId(selectedMaturityIds);
|
|
}
|
|
|
|
export function isCommunitySizeStepBlocked(
|
|
step: CreateFlowStep | null | undefined,
|
|
selectedCommunitySizeIds: readonly string[] | undefined,
|
|
): boolean {
|
|
if (step !== "community-size") return false;
|
|
return !hasNonEmptyId(selectedCommunitySizeIds);
|
|
}
|
|
|
|
const FINAL_REVIEW_BLOCK_NAMES: FinalReviewCategoryNames = {
|
|
values: "values",
|
|
communication: "communication",
|
|
membership: "membership",
|
|
decisions: "decisions",
|
|
conflict: "conflict",
|
|
};
|
|
|
|
const FINAL_REVIEW_REQUIRED_GROUPS: readonly TemplateFacetGroupKey[] = [
|
|
"communication",
|
|
"membership",
|
|
"decisionApproaches",
|
|
"conflictManagement",
|
|
] as const;
|
|
|
|
/**
|
|
* Continue on final review waits for a community name and at least one card
|
|
* on each of the four questions. Skipped values do not block.
|
|
*/
|
|
export function isFinalReviewContinueBlocked(state: CreateFlowState): boolean {
|
|
const title = typeof state.title === "string" ? state.title.trim() : "";
|
|
if (title.length === 0) return true;
|
|
const rows = buildFinalReviewCategoryRowsDetailed(
|
|
state,
|
|
FINAL_REVIEW_BLOCK_NAMES,
|
|
);
|
|
return FINAL_REVIEW_REQUIRED_GROUPS.some((groupKey) => {
|
|
const row = rows.find((candidate) => candidate.groupKey === groupKey);
|
|
return !row || row.entries.length === 0;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Resolve the localized label for the default "next-step" footer button.
|
|
* Returns the per-step override when one is registered, otherwise
|
|
* `footer.next`. Caller still owns the `final-review` / `edit-rule` special case.
|
|
*/
|
|
export function getDefaultFooterLabel(
|
|
step: CreateFlowStep | null | undefined,
|
|
footer: FooterMessages,
|
|
): string {
|
|
if (step == null) return footer.next;
|
|
const key = DEFAULT_FOOTER_LABEL_BY_STEP.get(step);
|
|
return key != null ? footer[key] : footer.next;
|
|
}
|