Custom add and create flow polish

This commit is contained in:
adilallo
2026-05-08 20:32:24 -06:00
parent 26bcd61ea3
commit 026a1e6d71
68 changed files with 6208 additions and 527 deletions
+80 -9
View File
@@ -4,8 +4,56 @@ import type {
CommunityRuleSection,
} from "../../app/components/type/CommunityRule/CommunityRule.types";
import type { PublishedMethodSelections } from "./buildPublishPayload";
import type { CustomMethodCardFieldBlock } from "./customMethodCardFieldBlocks";
import { templateCategoryToGroupKey } from "./templateReviewMapping";
/**
* Serialize wizard-authored field blocks into Community Rule labeled rows for
* read-only surfaces (completed step, exported views). Matches how those blocks
* are edited in-app; `placeholderText` holds the author's answer for text blocks.
*/
export function labeledBlocksFromCustomMethodCardFieldBlocks(
blocks: CustomMethodCardFieldBlock[],
): CommunityRuleLabeledBlock[] {
const out: CommunityRuleLabeledBlock[] = [];
for (const b of blocks) {
switch (b.kind) {
case "text": {
const body = nonEmptyTrimmed(b.placeholderText);
if (body) out.push({ label: b.blockTitle, body });
break;
}
case "badges": {
const opts = b.options.filter((x) => typeof x === "string" && x.trim().length > 0);
if (opts.length === 0) break;
out.push({ label: b.blockTitle, body: opts.join(", ") });
break;
}
case "upload": {
const name = nonEmptyTrimmed(b.fileName);
const url = nonEmptyTrimmed(b.assetUrl);
const body = name ?? url;
if (body) out.push({ label: b.blockTitle, body });
break;
}
case "proportion":
out.push({
label: b.blockTitle,
body: `${b.defaultPercent}%`,
});
break;
default:
break;
}
}
return out;
}
export type CommunityRuleEntryFromChipOptions = {
consensusLevelKey?: string;
customFieldBlocks?: CustomMethodCardFieldBlock[];
};
/** Canonical `categoryName` strings for method groups in published documents. */
export const RULE_SECTION_CATEGORY = {
values: "Values",
@@ -107,21 +155,35 @@ export function communityRuleEntryFromMethodChip(
title: string,
sections: Record<string, unknown>,
labelByKey: Record<string, string>,
options?: { consensusLevelKey?: string },
options?: CommunityRuleEntryFromChipOptions,
): CommunityRuleEntry | null {
const blocks = blocksFromKeyedRecord(sections, labelByKey, options);
const presetBlocks = blocksFromKeyedRecord(
sections,
labelByKey,
options?.consensusLevelKey
? { consensusLevelKey: options.consensusLevelKey }
: undefined,
);
const wizardBlocks =
options?.customFieldBlocks && options.customFieldBlocks.length > 0
? labeledBlocksFromCustomMethodCardFieldBlocks(options.customFieldBlocks)
: [];
const blocks = [...presetBlocks, ...wizardBlocks];
if (blocks.length === 0) return null;
return { title, body: "", blocks };
}
export function sectionFromCommunication(
ms: NonNullable<PublishedMethodSelections["communication"]>,
customFieldBlocksById?: Record<string, CustomMethodCardFieldBlock[]>,
): CommunityRuleSection | null {
if (ms.length === 0) return null;
const entries: CommunityRuleEntry[] = [];
for (const m of ms) {
const sec = m.sections as unknown as Record<string, unknown>;
const e = communityRuleEntryFromMethodChip(m.label, sec, COMM_LABELS);
const e = communityRuleEntryFromMethodChip(m.label, sec, COMM_LABELS, {
customFieldBlocks: customFieldBlocksById?.[m.id],
});
if (e) entries.push(e);
}
return entries.length > 0
@@ -131,12 +193,15 @@ export function sectionFromCommunication(
export function sectionFromMembership(
ms: NonNullable<PublishedMethodSelections["membership"]>,
customFieldBlocksById?: Record<string, CustomMethodCardFieldBlock[]>,
): CommunityRuleSection | null {
if (ms.length === 0) return null;
const entries: CommunityRuleEntry[] = [];
for (const m of ms) {
const sec = m.sections as unknown as Record<string, unknown>;
const e = communityRuleEntryFromMethodChip(m.label, sec, MEM_LABELS);
const e = communityRuleEntryFromMethodChip(m.label, sec, MEM_LABELS, {
customFieldBlocks: customFieldBlocksById?.[m.id],
});
if (e) entries.push(e);
}
return entries.length > 0
@@ -146,6 +211,7 @@ export function sectionFromMembership(
export function sectionFromDecision(
ms: NonNullable<PublishedMethodSelections["decisionApproaches"]>,
customFieldBlocksById?: Record<string, CustomMethodCardFieldBlock[]>,
): CommunityRuleSection | null {
if (ms.length === 0) return null;
const entries: CommunityRuleEntry[] = [];
@@ -159,6 +225,7 @@ export function sectionFromDecision(
delete merged.selectedApplicableScope;
const e = communityRuleEntryFromMethodChip(m.label, merged, DEC_LABELS, {
consensusLevelKey: "consensusLevel",
customFieldBlocks: customFieldBlocksById?.[m.id],
});
if (e) entries.push(e);
}
@@ -169,6 +236,7 @@ export function sectionFromDecision(
export function sectionFromConflict(
ms: NonNullable<PublishedMethodSelections["conflictManagement"]>,
customFieldBlocksById?: Record<string, CustomMethodCardFieldBlock[]>,
): CommunityRuleSection | null {
if (ms.length === 0) return null;
const entries: CommunityRuleEntry[] = [];
@@ -180,7 +248,9 @@ export function sectionFromConflict(
formatScopePayload(sec.applicableScope);
if (scope) merged.applicableScope = scope;
delete merged.selectedApplicableScope;
const e = communityRuleEntryFromMethodChip(m.label, merged, CM_LABELS);
const e = communityRuleEntryFromMethodChip(m.label, merged, CM_LABELS, {
customFieldBlocks: customFieldBlocksById?.[m.id],
});
if (e) entries.push(e);
}
return entries.length > 0
@@ -195,20 +265,21 @@ export function sectionFromConflict(
export function replaceMethodSectionsWithMethodSelections(
sections: CommunityRuleSection[],
ms: PublishedMethodSelections,
customFieldBlocksById?: Record<string, CustomMethodCardFieldBlock[]>,
): CommunityRuleSection[] {
return sections.map((s) => {
const gk = templateCategoryToGroupKey(s.categoryName);
if (gk === "communication" && ms.communication?.length) {
return sectionFromCommunication(ms.communication) ?? s;
return sectionFromCommunication(ms.communication, customFieldBlocksById) ?? s;
}
if (gk === "membership" && ms.membership?.length) {
return sectionFromMembership(ms.membership) ?? s;
return sectionFromMembership(ms.membership, customFieldBlocksById) ?? s;
}
if (gk === "decisionApproaches" && ms.decisionApproaches?.length) {
return sectionFromDecision(ms.decisionApproaches) ?? s;
return sectionFromDecision(ms.decisionApproaches, customFieldBlocksById) ?? s;
}
if (gk === "conflictManagement" && ms.conflictManagement?.length) {
return sectionFromConflict(ms.conflictManagement) ?? s;
return sectionFromConflict(ms.conflictManagement, customFieldBlocksById) ?? s;
}
return s;
});