diff --git a/src/views/CardEntry.tsx b/src/views/CardEntry.tsx index 938f0d0..e3e9419 100644 --- a/src/views/CardEntry.tsx +++ b/src/views/CardEntry.tsx @@ -1,14 +1,31 @@ import { useEffect, useRef, useState } from "react"; import { api, CardRef, Deck, DeckEntry, DECK_STATUSES, isPhysical, libraryKey } from "../api"; -import { CardSearchBox, QtyStepper } from "../components"; +import { CardSearchBox, IconButton, Icons, QtyStepper, useClickPreview } from "../components"; + +interface Added { + card: CardRef; + qty: number; + location: string; + deck: Deck | null; +} + +/** "Just added" lists by library key. Module-level so a list outlives the + * tab switches that unmount this view, but not the app session. */ +const addedLists = new Map(); /** Rapid card entry: fuzzy search-as-you-type, ↑/↓ + Enter (or click) adds one copy. */ export function CardEntry() { const [query, setQuery] = useState(""); const [results, setResults] = useState([]); - const [recent, setRecent] = useState< - { oracleId: string; name: string; qty: number; location: string; deck: string }[] - >([]); + const recentKey = libraryKey("add-recent"); + const [recent, setRecentState] = useState(() => addedLists.get(recentKey) ?? []); + const setRecent = (update: (r: Added[]) => Added[]) => + setRecentState((r) => { + const next = update(r); + addedLists.set(recentKey, next); + return next; + }); + const { open: openPreview } = useClickPreview(); // Persisted so a "box" location sticks while entering a stack of cards. // Each library has its own boxes. const [location, setLocation] = useState(() => localStorage.getItem(libraryKey("add-location")) || ""); @@ -93,9 +110,7 @@ export function CardEntry() { const loc = intoDeck ? "" : location.trim(); if (loc) await api.setLocation(card.oracle_id, loc); if (deck) await sendToDeck(deck, card.oracle_id, entry); - setRecent((r) => - [{ oracleId: card.oracle_id, name: card.name, qty, location: loc, deck: deck?.name ?? "" }, ...r].slice(0, 12), - ); + setRecent((r) => [{ card, qty, location: loc, deck }, ...r].slice(0, 12)); setQuery(""); setResults([]); } @@ -123,7 +138,19 @@ export function CardEntry() { async function adjust(oracleId: string, delta: number) { const qty = await api.addOwned(oracleId, delta); - setRecent((r) => r.map((e) => (e.oracleId === oracleId ? { ...e, qty } : e))); + setRecent((r) => r.map((e) => (e.card.oracle_id === oracleId ? { ...e, qty } : e))); + } + + /** The click preview, where copies' printings are set — and, for a card + * sent to a deck, which printing the deck shows. */ + async function showDetails(added: Added) { + const { card, deck } = added; + const slot = deck ? (await api.deckContents(deck.id)).find((e) => e.oracle_id === card.oracle_id) : undefined; + openPreview(slot ?? { ...card, quantity_owned: added.qty }, { + deckId: slot ? deck!.id : undefined, + // The preview can change how many are owned; keep the row's count in step. + onChanged: () => adjust(card.oracle_id, 0), + }); } return ( @@ -172,14 +199,20 @@ export function CardEntry() {
    {recent.map((r, i) => (
  • - {r.name} - {r.deck && → {r.deck}} + {r.card.name} + {r.deck && → {r.deck.name}} {r.location && {r.location}} + showDetails(r)} + disabled={!r.card.image_uri} + /> adjust(r.oracleId, -1)} - onIncrement={() => adjust(r.oracleId, 1)} + onDecrement={() => adjust(r.card.oracle_id, -1)} + onIncrement={() => adjust(r.card.oracle_id, 1)} />
  • ))}