Deck status (Idea/Building/Built/Retired) and pulled-card tracking
Only building and built decks now claim owned copies, so several idea decks can share one copy without an over-assignment warning. Deck cards track how many copies are physically pulled: physical decks list cards to pull with their source (a storage box, or another deck to take a copy from), and idea decks split cards into available / in other decks / not owned. The deck list shows status chips with to-pull counts, filters by status, and collapses retired decks. Status and pulled counts sync, which bumps the library document to version 4. Existing decks migrate as ideas. Closes #25 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
53
src/api.ts
53
src/api.ts
@@ -25,7 +25,12 @@ export interface CardRef {
|
||||
export interface LibraryCard extends CardRef {
|
||||
quantity_owned: number;
|
||||
decks: string[];
|
||||
/** The subset of `decks` that physically exist (building or built). */
|
||||
physical_decks: string[];
|
||||
/** Copies claimed by building/built decks (idea/retired decks claim none). */
|
||||
quantity_assigned: number;
|
||||
/** Copies physically pulled into decks; the rest are at `location`. */
|
||||
quantity_in_decks: number;
|
||||
location: string;
|
||||
}
|
||||
|
||||
@@ -46,8 +51,41 @@ export interface DeckEntry extends CardRef {
|
||||
/** The printing whose art this slot shows; `image_uri` already reflects it. */
|
||||
preferred_scryfall_id: string | null;
|
||||
partner: Partner | null;
|
||||
/** Copies physically in this deck; meaningful for building/built decks. */
|
||||
quantity_pulled: number;
|
||||
/** Owned copies not claimed by any *other* building/built deck. */
|
||||
quantity_spare: number;
|
||||
/** Owned copies not pulled into any deck — still in their box. */
|
||||
quantity_in_box: number;
|
||||
/** The *other* building/built decks claiming copies; those with copies
|
||||
* pulled are where to take one from when the box is empty. */
|
||||
claimed_by: DeckHolding[];
|
||||
/** Where the card's library copies are stored ("" if unset). */
|
||||
location: string;
|
||||
}
|
||||
|
||||
export interface DeckHolding {
|
||||
deck_id: number;
|
||||
name: string;
|
||||
/** Copies the deck's main board lists. */
|
||||
quantity: number;
|
||||
/** Of those, copies physically in the deck. */
|
||||
pulled: number;
|
||||
}
|
||||
|
||||
/** Where a deck stands physically. Building and built decks hold cards and
|
||||
* claim owned copies; ideas and retired decks are just lists. */
|
||||
export type DeckStatus = "idea" | "building" | "built" | "retired";
|
||||
|
||||
export const DECK_STATUSES: { value: DeckStatus; label: string }[] = [
|
||||
{ value: "idea", label: "Idea" },
|
||||
{ value: "building", label: "Building" },
|
||||
{ value: "built", label: "Built" },
|
||||
{ value: "retired", label: "Retired" },
|
||||
];
|
||||
|
||||
export const isPhysical = (s: DeckStatus) => s === "building" || s === "built";
|
||||
|
||||
/** One printing of a card, for the printing picker and copy labels. */
|
||||
export interface PrintingRef {
|
||||
scryfall_id: string;
|
||||
@@ -82,6 +120,9 @@ export interface LibraryCopy {
|
||||
export type PreviewCard = CardRef & {
|
||||
quantity_owned?: number;
|
||||
decks?: string[];
|
||||
physical_decks?: string[];
|
||||
quantity_in_decks?: number;
|
||||
location?: string;
|
||||
preferred_scryfall_id?: string | null;
|
||||
};
|
||||
|
||||
@@ -107,6 +148,7 @@ export interface Deck {
|
||||
notes: string;
|
||||
/** The card chosen to headline the deck in the deck list; null = automatic. */
|
||||
cover_oracle_id: string | null;
|
||||
status: DeckStatus;
|
||||
}
|
||||
|
||||
export interface DeckImportResult {
|
||||
@@ -497,6 +539,17 @@ export const api = {
|
||||
invoke<Deck>("duplicate_deck", { deckId, newName }),
|
||||
setDeckFormat: (deckId: number, format: string) =>
|
||||
invoke<void>("set_deck_format", { deckId, format }),
|
||||
/** Change a deck's status. Leaving building/built returns pulled copies to
|
||||
* their boxes; entering it with `assembled` marks the copies in the box as
|
||||
* already in the deck. */
|
||||
setDeckStatus: (deckId: number, status: DeckStatus, assembled = false) =>
|
||||
invoke<void>("set_deck_status", { deckId, status, assembled }),
|
||||
/** Record copies physically in a deck; returns the (clamped) count stored. */
|
||||
setDeckCardPulled: (deckId: number, oracleId: string, pulled: number) =>
|
||||
invoke<number>("set_deck_card_pulled", { deckId, oracleId, pulled }),
|
||||
/** Move one pulled copy between decks; false if there was nothing to move. */
|
||||
takeDeckCardCopy: (fromDeckId: number, toDeckId: number, oracleId: string) =>
|
||||
invoke<boolean>("take_deck_card_copy", { fromDeckId, toDeckId, oracleId }),
|
||||
/** Choose the card headlining the deck in the deck list; null = automatic. */
|
||||
setDeckCover: (deckId: number, oracleId: string | null) =>
|
||||
invoke<void>("set_deck_cover", { deckId, oracleId }),
|
||||
|
||||
Reference in New Issue
Block a user