import { useQueries } from "@tanstack/react-query"; import { useMemo } from "react"; import { groupCards, sortCards, sortGroupNames } from "@/lib/deck-grouping"; import type { DeckCard, GroupBy, Section, SortBy } from "@/lib/deck-types"; import type { Violation } from "@/lib/deck-validation"; import { combineCardQueries, getCardByIdQueryOptions } from "@/lib/queries"; import type { OracleId, ScryfallId } from "@/lib/scryfall-types"; import { DraggableCard } from "./DraggableCard"; import { DroppableSection } from "./DroppableSection"; import { DroppableSectionHeader } from "./DroppableSectionHeader"; import { DroppableTagGroup } from "./DroppableTagGroup"; interface DeckSectionProps { section: Section; cards: DeckCard[]; groupBy: GroupBy; sortBy: SortBy; onCardHover?: (cardId: ScryfallId | null) => void; onCardClick?: (card: DeckCard) => void; isDragging: boolean; readOnly?: boolean; highlightedCards?: Set; violationsByCard?: Map; } export function DeckSection({ section, cards, groupBy, sortBy, onCardHover, onCardClick, isDragging, readOnly = false, highlightedCards, violationsByCard, }: DeckSectionProps) { const sectionNames: Record = { commander: "Commander", mainboard: "Mainboard", sideboard: "Sideboard", maybeboard: "Maybeboard", }; const totalQuantity = cards.reduce((sum, card) => sum + card.quantity, 0); // Fetch all card data individually (populates cache for DeckCardRow) const cardMap = useQueries({ queries: cards.map((card) => getCardByIdQueryOptions(card.scryfallId)), combine: combineCardQueries, }); // Group and sort cards with memoization const groupedCards = useMemo(() => { if (!cardMap) return new Map([["all", { cards, forTag: false }]]); const lookup = (card: DeckCard) => cardMap.get(card.scryfallId); return groupCards(cards, lookup, groupBy); }, [cards, cardMap, groupBy]); const sortedGroupNames = useMemo( () => sortGroupNames(groupedCards, groupBy), [groupedCards, groupBy], ); // Sort cards within each group const sortedGroups = useMemo(() => { if (!cardMap) return new Map( Array.from(groupedCards.entries(), ([k, v]) => [k, v.cards]), ); const lookup = (card: DeckCard) => cardMap.get(card.scryfallId); return new Map( sortedGroupNames.map((groupName) => { const groupCards = groupedCards.get(groupName) ?? { cards: [], forTag: false, }; return [groupName, sortCards(groupCards.cards, lookup, sortBy)]; }), ); }, [sortedGroupNames, groupedCards, cardMap, sortBy]); return (

{sectionNames[section]}

{totalQuantity} {totalQuantity === 1 ? "card" : "cards"}
{cards.length === 0 ? (

No cards in {sectionNames[section].toLowerCase()}

) : groupBy === "none" ? (
{cardMap ? sortCards( cards, (card) => cardMap.get(card.scryfallId), sortBy, ).map((card, index) => { const uniqueId = `${card.scryfallId}-${section}-none-${index}`; return (
); }) : cards.map((card, index) => { const uniqueId = `${card.scryfallId}-${section}-none-${index}`; return (
); })}
) : (
{sortedGroupNames.map((groupName) => { const groupCards = sortedGroups.get(groupName) ?? []; const groupQuantity = groupCards.reduce( (sum, card) => sum + card.quantity, 0, ); return (
{groupName} ({groupQuantity})
{groupCards.map((card, index) => { const uniqueId = `${card.scryfallId}-${section}-${groupName}-${index}`; return ( ); })}
); })}
)}
); }