Show seven cards on the four method decks and open each as a routing overlay of its parts, so groups write from empty fields with Generate draft, search the full deck, and see unselected scope chips with enough contrast.
This commit is contained in:
1 parent
dea7dd7fbd
commit
46656f52d3
28 files changed
+1349
-318
No files matched your search
@@ -14,7 +14,10 @@ import {
|
||||
deckData,
|
||||
recommendDeck,
|
||||
} from "../../../../lib/create/deckRecommend";
|
||||
import type { GroupAnswers } from "../../../../lib/create/deckTypes";
|
||||
import type {
|
||||
GroupAnswers,
|
||||
RecommendedCard,
|
||||
} from "../../../../lib/create/deckTypes";
|
||||
|
||||
/**
|
||||
* Card-deck section ids served by `/api/create-flow/methods` (CR-88 §9.2).
|
||||
@@ -143,8 +146,13 @@ export function deriveCompactCards(
|
||||
compactCardIds: string[];
|
||||
recommendedIds: Set<string>;
|
||||
orderedIds: string[];
|
||||
fallback: boolean;
|
||||
recommendedById: Map<string, RecommendedCard>;
|
||||
} {
|
||||
const recommendation = recommendDeck(deckData(section), answers, { limit });
|
||||
const recommendedById = new Map(
|
||||
recommendation.recommended.map((card) => [card.id, card]),
|
||||
);
|
||||
const orderedIds = recommendation.fallback
|
||||
? recommendation.seeAll
|
||||
: [
|
||||
@@ -156,6 +164,8 @@ export function deriveCompactCards(
|
||||
compactCardIds: orderedIds.slice(0, limit),
|
||||
recommendedIds: new Set<string>(),
|
||||
orderedIds,
|
||||
fallback: true,
|
||||
recommendedById,
|
||||
};
|
||||
}
|
||||
return {
|
||||
@@ -166,6 +176,8 @@ export function deriveCompactCards(
|
||||
.map((card) => card.id),
|
||||
),
|
||||
orderedIds,
|
||||
fallback: false,
|
||||
recommendedById,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
import { useMemo } from "react";
|
||||
import { mergeCompactCardIdsWithPinnedSelected } from "../../../../lib/create/methodCardDisplayOrder";
|
||||
import { formatRecommendationWhyLine } from "../../../../lib/create/formatRecommendationWhyLine";
|
||||
import {
|
||||
deriveCompactCards,
|
||||
groupAnswersForRecommendations,
|
||||
type RecommendationSection,
|
||||
} from "./useFacetRecommendations";
|
||||
import { deckData } from "../../../../lib/create/deckRecommend";
|
||||
import { useCreateFlow } from "../context/CreateFlowContext";
|
||||
import { useMessages } from "../../../contexts/MessagesContext";
|
||||
|
||||
type MethodEntry = { id: string; label: string; supportText: string };
|
||||
|
||||
@@ -25,9 +28,8 @@ function orderByIds<T extends { id: string }>(
|
||||
}
|
||||
|
||||
/**
|
||||
* Deck order and the compact stack come from the job rule. Current screens
|
||||
* show five cards; a deck screen passes seven. Selected cards still pin
|
||||
* into the compact stack.
|
||||
* Deck order and the compact stack come from the job rule. Compact shows
|
||||
* at most seven recommended cards. Selected cards still pin into the stack.
|
||||
*/
|
||||
export function useMethodCardDeckOrdering(
|
||||
section: RecommendationSection,
|
||||
@@ -35,13 +37,15 @@ export function useMethodCardDeckOrdering(
|
||||
selectedIds: readonly string[],
|
||||
) {
|
||||
const { state } = useCreateFlow();
|
||||
const copy = useMessages().create.customRule.recommendations;
|
||||
const compactLimit = deckData(section).config.displayLimit;
|
||||
const answers = useMemo(
|
||||
() => groupAnswersForRecommendations(state),
|
||||
[state],
|
||||
);
|
||||
const deck = useMemo(
|
||||
() => deriveCompactCards(section, answers, 5),
|
||||
[section, answers],
|
||||
() => deriveCompactCards(section, answers, compactLimit),
|
||||
[section, answers, compactLimit],
|
||||
);
|
||||
|
||||
const rankedMethods = useMemo(
|
||||
@@ -59,25 +63,57 @@ export function useMethodCardDeckOrdering(
|
||||
deck.compactCardIds,
|
||||
selectedIds,
|
||||
selectionShowcaseActive,
|
||||
5,
|
||||
compactLimit,
|
||||
),
|
||||
[
|
||||
rankedMethods,
|
||||
deck.compactCardIds,
|
||||
selectedIds,
|
||||
selectionShowcaseActive,
|
||||
compactLimit,
|
||||
],
|
||||
);
|
||||
|
||||
const compactIdSet = useMemo(
|
||||
() => new Set(compactCardIds),
|
||||
[compactCardIds],
|
||||
);
|
||||
|
||||
const sampleCards = useMemo(
|
||||
() =>
|
||||
rankedMethods.map((entry) => ({
|
||||
id: entry.id,
|
||||
label: entry.label,
|
||||
supportText: entry.supportText,
|
||||
recommended: recommendedIds.has(entry.id),
|
||||
})),
|
||||
[rankedMethods, recommendedIds],
|
||||
rankedMethods.map((entry) => {
|
||||
const recommendation = deck.recommendedById.get(entry.id);
|
||||
const whyLine =
|
||||
recommendation && recommendation.tag !== "everyRuleHas"
|
||||
? formatRecommendationWhyLine(recommendation.reason, answers, copy)
|
||||
: "";
|
||||
const alternativeId = recommendation?.alternative;
|
||||
const alternativeMethod = alternativeId
|
||||
? rankedMethods.find((method) => method.id === alternativeId) ??
|
||||
methods.find((method) => method.id === alternativeId)
|
||||
: undefined;
|
||||
return {
|
||||
id: entry.id,
|
||||
label: entry.label,
|
||||
supportText: entry.supportText,
|
||||
compactSupportText:
|
||||
whyLine && compactIdSet.has(entry.id) ? whyLine : undefined,
|
||||
recommended: recommendedIds.has(entry.id),
|
||||
alternative:
|
||||
alternativeMethod && compactIdSet.has(entry.id)
|
||||
? { id: alternativeMethod.id, label: alternativeMethod.label }
|
||||
: undefined,
|
||||
};
|
||||
}),
|
||||
[
|
||||
answers,
|
||||
compactIdSet,
|
||||
copy,
|
||||
deck.recommendedById,
|
||||
methods,
|
||||
rankedMethods,
|
||||
recommendedIds,
|
||||
],
|
||||
);
|
||||
|
||||
const methodById = useMemo(
|
||||
@@ -92,6 +128,8 @@ export function useMethodCardDeckOrdering(
|
||||
recommendedIds,
|
||||
sampleCards,
|
||||
methodById,
|
||||
showDeckLine: !deck.fallback,
|
||||
compactLimit,
|
||||
recommendationsReady: true,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user