Import the remade decks on stable ids and recommend one card per job, so a saved draft still loads after a chip is renamed.

The real-group profiles stay as a test, so a change that moves a pick fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilalloandCursor committed 2026-11-04 14:22:54 -07:00
1 parent 96ca15d8e3
commit bcbc6f30d9
89 files changed
+36555 -2828

No files matched your search

@@ -4,68 +4,80 @@ import { useMemo } from "react";
import { mergeCompactCardIdsWithPinnedSelected } from "../../../../lib/create/methodCardDisplayOrder";
import {
deriveCompactCards,
rankMethodsByScore,
useFacetRecommendations,
groupAnswersForRecommendations,
type RecommendationSection,
} from "./useFacetRecommendations";
import { useCreateFlow } from "../context/CreateFlowContext";
type MethodEntry = { id: string; label: string; supportText: string };
function orderByIds<T extends { id: string }>(
methods: readonly T[],
orderedIds: readonly string[],
): T[] {
const byId = new Map(methods.map((method) => [method.id, method]));
const ordered = orderedIds.flatMap((id) => {
const method = byId.get(id);
return method ? [method] : [];
});
const seen = new Set(ordered.map((method) => method.id));
return [...ordered, ...methods.filter((method) => !seen.has(method.id))];
}
/**
* Applies score ranking and compact-slot rules. Expanded CardStack order stays
* the ranked catalog (selected cards keep their place). Compact slots still
* pin selected ids first so a pick outside the unpinned top-N remains visible
* when the stack is collapsed.
* 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.
*/
export function useMethodCardDeckOrdering(
section: RecommendationSection,
methods: readonly MethodEntry[],
selectedIds: readonly string[],
) {
const { scoresBySlug, hasAnyFacets, isReady } =
useFacetRecommendations(section);
const recommendationsReady = !hasAnyFacets || isReady;
const { state } = useCreateFlow();
const answers = useMemo(
() => groupAnswersForRecommendations(state),
[state],
);
const deck = useMemo(
() => deriveCompactCards(section, answers, 5),
[section, answers],
);
const rankedMethods = useMemo(
() => rankMethodsByScore(methods, scoresBySlug),
[methods, scoresBySlug],
() => orderByIds(methods, deck.orderedIds),
[methods, deck.orderedIds],
);
const selectionShowcaseActive = selectedIds.length > 0;
const displayMethods = rankedMethods;
const { compactCardIds: baseCompactCardIds, recommendedIds } = useMemo(
() =>
deriveCompactCards(
rankedMethods,
scoresBySlug,
hasAnyFacets,
/* limit */ 5,
),
[rankedMethods, scoresBySlug, hasAnyFacets],
);
const { recommendedIds } = deck;
const compactCardIds = useMemo(
() =>
mergeCompactCardIdsWithPinnedSelected(
rankedMethods.map((m) => m.id),
baseCompactCardIds,
rankedMethods.map((method) => method.id),
deck.compactCardIds,
selectedIds,
selectionShowcaseActive,
5,
),
[rankedMethods, baseCompactCardIds, selectedIds, selectionShowcaseActive],
[
rankedMethods,
deck.compactCardIds,
selectedIds,
selectionShowcaseActive,
],
);
const sampleCards = useMemo(
() =>
displayMethods.map((entry) => ({
rankedMethods.map((entry) => ({
id: entry.id,
label: entry.label,
supportText: entry.supportText,
recommended: recommendedIds.has(entry.id),
})),
[displayMethods, recommendedIds],
[rankedMethods, recommendedIds],
);
const methodById = useMemo(
@@ -75,11 +87,11 @@ export function useMethodCardDeckOrdering(
return {
rankedMethods,
displayMethods,
displayMethods: rankedMethods,
compactCardIds,
recommendedIds,
sampleCards,
methodById,
recommendationsReady,
recommendationsReady: true,
};
}