From 8d0ce534f89c2c7f7fa46d14fa42caec8e213442 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Wed, 26 Nov 2025 13:51:26 +0100 Subject: [PATCH] add commander color identity validation and improve deck validation logic --- dev-dist/sw.js | 2 +- src/components/DeckEditor.tsx | 1 + src/components/DeckManager.tsx | 25 +----------------- src/utils/deckValidation.ts | 48 ++++++++++++++++++++++++++++------ 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/dev-dist/sw.js b/dev-dist/sw.js index d262385..bb5975d 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-ca84f546'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.bbuf8ja4298" + "revision": "0.ufhads5pjvs" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/src/components/DeckEditor.tsx b/src/components/DeckEditor.tsx index f476ca0..de301a1 100644 --- a/src/components/DeckEditor.tsx +++ b/src/components/DeckEditor.tsx @@ -42,6 +42,7 @@ export default function DeckEditor({ deckId, onClose }: DeckEditorProps) { const cards = cardEntities.map(entity => ({ card: scryfallCards.find(c => c.id === entity.card_id) as Card, quantity: entity.quantity, + is_commander: entity.is_commander, })); setDeck({ diff --git a/src/components/DeckManager.tsx b/src/components/DeckManager.tsx index 98ad72f..7bd0c22 100644 --- a/src/components/DeckManager.tsx +++ b/src/components/DeckManager.tsx @@ -442,11 +442,8 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) { const validation = validateDeck(currentDeck); - // Commander color identity validation + // Commander color identity validation (for land suggestions) const commanderColors = deckFormat === 'commander' ? getCommanderColors(commander) : []; - const invalidCards = deckFormat === 'commander' && commander - ? selectedCards.filter(({ card }) => !isCardValidForCommander(card, commanderColors)) - : []; const deckSize = selectedCards.reduce((acc, curr) => acc + curr.quantity, 0); const { @@ -829,26 +826,6 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) { )} - {/* Commander Color Identity Warning */} - {deckFormat === 'commander' && commander && invalidCards.length > 0 && ( -
-
- -
-

Commander Color Identity Warning

-

- The following cards don't match your commander's color identity: -

-
    - {invalidCards.map(({ card }) => ( -
  • {card.name}
  • - ))} -
-
-
-
- )} -

diff --git a/src/utils/deckValidation.ts b/src/utils/deckValidation.ts index 465a47c..fd7fcd9 100644 --- a/src/utils/deckValidation.ts +++ b/src/utils/deckValidation.ts @@ -1,10 +1,23 @@ -import { Deck } from '../types'; +import { Card, Deck } from '../types'; interface DeckValidation { isValid: boolean; errors: string[]; } +// Helper function to get commander color identity +function getCommanderColors(commander: Card | null): string[] { + if (!commander) return []; + return commander.colors || []; +} + +// Helper function to check if a card's colors are valid for the commander +function isCardValidForCommander(card: Card, commanderColors: string[]): boolean { + if (commanderColors.length === 0) return true; + const cardColors = card.colors || []; + return cardColors.every(color => commanderColors.includes(color)); +} + const FORMAT_RULES = { standard: { minCards: 60, @@ -42,20 +55,20 @@ const FORMAT_RULES = { export function validateDeck(deck: Deck): DeckValidation { const rules = FORMAT_RULES[deck.format as keyof typeof FORMAT_RULES]; const errors: string[] = []; - + // Count total cards const totalCards = deck.cards.reduce((acc, curr) => acc + curr.quantity, 0); - + // Check minimum cards if (totalCards < rules.minCards) { errors.push(`Deck must contain at least ${rules.minCards} cards`); } - + // Check maximum cards if (rules.maxCards && totalCards > rules.maxCards) { errors.push(`Deck must not contain more than ${rules.maxCards} cards`); } - + // Check card copies const cardCounts = new Map(); for (const element of deck.cards) { @@ -64,7 +77,7 @@ export function validateDeck(deck: Deck): DeckValidation { const currentCount = cardCounts.get(card.id) || 0; cardCounts.set(card.id, currentCount + quantity); } - + cardCounts.forEach((count, cardName) => { const card = deck.cards.find(c => c.card.id === cardName)?.card; const isBasicLand = card?.name === 'Plains' || card?.name === 'Island' || card?.name === 'Swamp' || card?.name === 'Mountain' || card?.name === 'Forest'; @@ -73,9 +86,28 @@ export function validateDeck(deck: Deck): DeckValidation { errors.push(`${cardName} has too many copies (max ${rules.maxCopies})`); } }); - + + // Commander-specific validations + if (deck.format === 'commander') { + const commander = deck.cards.find(card => card.is_commander)?.card; + + if (!commander) { + errors.push('Commander deck must have a commander'); + } else { + // Check commander color identity + const commanderColors = getCommanderColors(commander); + const invalidCards = deck.cards.filter(({ card, is_commander }) => + !is_commander && !isCardValidForCommander(card, commanderColors) + ); + + if (invalidCards.length > 0) { + errors.push(`Some cards don't match commander's color identity`); + } + } + } + return { isValid: errors.length === 0, errors, }; -} +}