|
|
@@ -8,7 +8,7 @@ import { RollAnimation } from "@/components/dice/roll-animation";
|
|
|
import { RollAnnouncer } from "@/components/dice/roll-announcer";
|
|
|
import { GenreRollModal, type GenreRollPayload } from "@/components/dice/genre-roll-modal";
|
|
|
import { HomeRollTeaserCard } from "@/components/home/home-roll-teaser-card";
|
|
|
-import { filterByGenresAndEmotions } from "@/lib/dice/genre-filter";
|
|
|
+import { filterByGenresAndEmotionsStructured } from "@/lib/dice/genre-filter";
|
|
|
import type { Movie } from "@/types/movie";
|
|
|
|
|
|
/**
|
|
|
@@ -17,11 +17,10 @@ import type { Movie } from "@/types/movie";
|
|
|
* The home-page roll renders IN PLACE — no `router.push()` on the roll path
|
|
|
* (PROJECT_SCOPE.md:222-223). User stays on `/home`.
|
|
|
*
|
|
|
- * Genre roll filter: uses the legacy string-tokenizer `filterByGenresAndEmotions`
|
|
|
- * (Option A from the PHASE4 plan). Mood keys resolve via EMOTION_TO_GENRE_MAP;
|
|
|
- * bare numeric genre IDs pass through the tokenizer without matching, so a
|
|
|
- * genre-only selection currently degrades to a full-pool roll. U8 owns the
|
|
|
- * structured replacement in a parallel branch we must not touch.
|
|
|
+ * Genre roll filter: uses `filterByGenresAndEmotionsStructured` so genre IDs
|
|
|
+ * and mood keys from `<GenreRollModal>` are matched against both numeric TMDB
|
|
|
+ * IDs and the name strings stored in `movies.genres`. A genre-only selection
|
|
|
+ * now filters correctly instead of falling through to an unfiltered pool.
|
|
|
*/
|
|
|
|
|
|
export function RollSection() {
|
|
|
@@ -62,12 +61,11 @@ export function RollSection() {
|
|
|
setGenreModalOpen(false);
|
|
|
if (!hasPool) return;
|
|
|
|
|
|
- const tokens = [...payload.genreIds.map(String), ...payload.moodKeys].join(" ");
|
|
|
- const { movies: filtered, noMatches } = filterByGenresAndEmotions(tokens, fullPool);
|
|
|
+ const { movies: filtered, noMatches } = filterByGenresAndEmotionsStructured(
|
|
|
+ { genreIds: payload.genreIds, moodKeys: payload.moodKeys },
|
|
|
+ fullPool,
|
|
|
+ );
|
|
|
|
|
|
- // On no-match, filterByGenresAndEmotions already returns the full pool,
|
|
|
- // but we roll explicitly on `fullPool` so future contract changes can't
|
|
|
- // silently break the fallback.
|
|
|
const rollPool = noMatches ? fullPool : filtered;
|
|
|
setNoMatchesBanner(noMatches);
|
|
|
setActivePool(rollPool);
|