diff --git a/packages/contracts/src/Inventory.sol b/packages/contracts/src/Inventory.sol index 464df773..39d9c190 100644 --- a/packages/contracts/src/Inventory.sol +++ b/packages/contracts/src/Inventory.sol @@ -343,15 +343,10 @@ contract Inventory is Ownable { // --------------------------------------------------------------------------------------------- // Returns the list of cards in the given deck of the given player. - function getDeck(address player, uint8 deckID) - external - view - exists(player, deckID) - returns (Deck memory) - { + function getDeck(address player, uint8 deckID) external view exists(player, deckID) returns (Deck memory) { return decks[player][deckID]; } - + // --------------------------------------------------------------------------------------------- // Returns the decks of a given player. diff --git a/packages/webapp/src/actions/getDeck.ts b/packages/webapp/src/actions/getDeck.ts index c17f5168..74df826a 100644 --- a/packages/webapp/src/actions/getDeck.ts +++ b/packages/webapp/src/actions/getDeck.ts @@ -1,158 +1,158 @@ -import { defaultErrorHandling } from "src/actions/errors" -import { contractWriteThrowing } from "src/actions/libContractWrite" -import { Address } from "src/chain" -import { deployment } from "src/deployment" -import { inventoryABI } from "src/generated" - -// ================================================================================================= - -export type GetDeckArgs = { - playerAddress: Address - onSuccess: () => void -} - -export type GetDeckAtArgs = { - playerAddress: Address - onSuccess: () => void - index: number -} - -// ------------------------------------------------------------------------------------------------- - -/** - * Fetches all decks of the given player by sending the `getAllDecks` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function getAllDecks(args: GetDeckArgs): Promise { - try { - return await getAllDecksImpl(args) - } catch (err) { - defaultErrorHandling("getAllDecks", err) - return false - } -} - -/** - * Fetches the deck of the given player of a given ID by sending the `getDeck` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function getDeck(args: GetDeckAtArgs): Promise { - try { - return await getDeckImpl(args) - } catch (err) { - defaultErrorHandling("getDeck", err) - return false - } -} - -// ------------------------------------------------------------------------------------------------- - -/** - * Fetches deck count of the given player by sending the `getNumDecks` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function getNumDecks(args: GetDeckArgs): Promise { - try { - return await getNumDecksImpl(args) - } catch (err) { - defaultErrorHandling("getNumDecks", err) - return false - } -} - -// ------------------------------------------------------------------------------------------------- - -/** - * Fetches deck count of the given player by sending the `getNumDecks` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function getDeckNames(args: GetDeckArgs): Promise { - try { - return await getDeckNamesImpl(args) - } catch (err) { - defaultErrorHandling("getDeckNames", err) - return false - } -} - -// ------------------------------------------------------------------------------------------------- - -async function getAllDecksImpl(args: GetDeckArgs): Promise { - try { - const result = await contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "getAllDecks", - args: [args.playerAddress], - }) - - args.onSuccess() - return result - } catch (error) { - console.error("Error fetching decks:", error) - return null - } - } - -// ------------------------------------------------------------------------------------------------- - -async function getDeckImpl(args: GetDeckAtArgs): Promise { - try { - const result = await contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "getDeck", - args: [args.playerAddress, args.index], - }) - - args.onSuccess() - return result - } catch (error) { - console.error("Error fetching deck:", error) - return null - } -} - -// ------------------------------------------------------------------------------------------------- - -async function getNumDecksImpl(args: GetDeckArgs): Promise { - try { - const result = await contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "getNumDecks", - args: [args.playerAddress], - }) - - args.onSuccess() - return result - } catch (error) { - console.error("Error fetching decks:", error) - return null - } -} - -// ------------------------------------------------------------------------------------------------- - -async function getDeckNamesImpl(args: GetDeckArgs): Promise { - try { - const result = await contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "getDeckNames", - args: [args.playerAddress], - }) - - args.onSuccess() - return result - } catch (error) { - console.error("Error fetching decks:", error) - return null - } -} - -// ================================================================================================= \ No newline at end of file +import { defaultErrorHandling } from "src/actions/errors" +import { contractWriteThrowing } from "src/actions/libContractWrite" +import { Address } from "src/chain" +import { deployment } from "src/deployment" +import { inventoryABI } from "src/generated" + +// ================================================================================================= + +export type GetDeckArgs = { + playerAddress: Address + onSuccess: () => void +} + +export type GetDeckAtArgs = { + playerAddress: Address + onSuccess: () => void + index: number +} + +// ------------------------------------------------------------------------------------------------- + +/** + * Fetches all decks of the given player by sending the `getAllDecks` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function getAllDecks(args: GetDeckArgs): Promise { + try { + return await getAllDecksImpl(args) + } catch (err) { + defaultErrorHandling("getAllDecks", err) + return false + } +} + +/** + * Fetches the deck of the given player of a given ID by sending the `getDeck` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function getDeck(args: GetDeckAtArgs): Promise { + try { + return await getDeckImpl(args) + } catch (err) { + defaultErrorHandling("getDeck", err) + return false + } +} + +// ------------------------------------------------------------------------------------------------- + +/** + * Fetches deck count of the given player by sending the `getNumDecks` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function getNumDecks(args: GetDeckArgs): Promise { + try { + return await getNumDecksImpl(args) + } catch (err) { + defaultErrorHandling("getNumDecks", err) + return false + } +} + +// ------------------------------------------------------------------------------------------------- + +/** + * Fetches deck count of the given player by sending the `getNumDecks` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function getDeckNames(args: GetDeckArgs): Promise { + try { + return await getDeckNamesImpl(args) + } catch (err) { + defaultErrorHandling("getDeckNames", err) + return false + } +} + +// ------------------------------------------------------------------------------------------------- + +async function getAllDecksImpl(args: GetDeckArgs): Promise { + try { + const result = await contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "getAllDecks", + args: [args.playerAddress], + }) + + args.onSuccess() + return result + } catch (error) { + console.error("Error fetching decks:", error) + return null + } +} + +// ------------------------------------------------------------------------------------------------- + +async function getDeckImpl(args: GetDeckAtArgs): Promise { + try { + const result = await contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "getDeck", + args: [args.playerAddress, args.index], + }) + + args.onSuccess() + return result + } catch (error) { + console.error("Error fetching deck:", error) + return null + } +} + +// ------------------------------------------------------------------------------------------------- + +async function getNumDecksImpl(args: GetDeckArgs): Promise { + try { + const result = await contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "getNumDecks", + args: [args.playerAddress], + }) + + args.onSuccess() + return result + } catch (error) { + console.error("Error fetching decks:", error) + return null + } +} + +// ------------------------------------------------------------------------------------------------- + +async function getDeckNamesImpl(args: GetDeckArgs): Promise { + try { + const result = await contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "getDeckNames", + args: [args.playerAddress], + }) + + args.onSuccess() + return result + } catch (error) { + console.error("Error fetching decks:", error) + return null + } +} + +// ================================================================================================= diff --git a/packages/webapp/src/actions/setDeck.ts b/packages/webapp/src/actions/setDeck.ts index 01f8ffdb..c114aeae 100644 --- a/packages/webapp/src/actions/setDeck.ts +++ b/packages/webapp/src/actions/setDeck.ts @@ -1,92 +1,90 @@ -import { defaultErrorHandling } from "src/actions/errors" -import { contractWriteThrowing } from "src/actions/libContractWrite" -import { Address } from "src/chain" -import { deployment } from "src/deployment" -import { inventoryABI } from "src/generated" -import { checkFresh, freshWrap } from "src/store/checkFresh" -import { Deck } from "src/store/types" - -// ================================================================================================= - -export type SaveArgs = { - deck: Deck - playerAddress: Address - onSuccess: () => void -} - -export type ModifyArgs = { - deck: Deck - playerAddress: Address - index: number - onSuccess: () => void -} - - -// ------------------------------------------------------------------------------------------------- - -/** - * Saves a deck created by the player by sending the `saveDeck` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function save(args: SaveArgs): Promise { - try { - return await saveImpl(args) - } catch (err) { - return defaultErrorHandling("save", err) - } -} - -/** - * Modifies a deck owned by the player by sending the `modifyDeck` transaction. - * - * Returns `true` iff the transaction is successful. - */ -export async function modify(args: ModifyArgs): Promise { - try { - return await modifyImpl(args) - } catch (err) { - return defaultErrorHandling("modify", err) - } -} - -// ------------------------------------------------------------------------------------------------- - -async function saveImpl(args: SaveArgs): Promise { - const cardBigInts = args.deck.cards.map(card => card.id) - - checkFresh(await freshWrap( - contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "addDeck", - args: [ - args.playerAddress, - { name: args.deck.name, cards: cardBigInts } - ], - }))) - - args.onSuccess() - return true -} - -async function modifyImpl(args: ModifyArgs): Promise { - const cardBigInts = args.deck.cards.map(card => card.id) - console.log("INDEX: " + args.index) - checkFresh(await freshWrap( - contractWriteThrowing({ - contract: deployment.Inventory, - abi: inventoryABI, - functionName: "replaceDeck", - args: [ - args.playerAddress, - args.index, - { name: args.deck.name, cards: cardBigInts } - ], - }))) - - args.onSuccess() - return true -} - -// ================================================================================================= \ No newline at end of file +import { defaultErrorHandling } from "src/actions/errors" +import { contractWriteThrowing } from "src/actions/libContractWrite" +import { Address } from "src/chain" +import { deployment } from "src/deployment" +import { inventoryABI } from "src/generated" +import { checkFresh, freshWrap } from "src/store/checkFresh" +import { Deck } from "src/store/types" + +// ================================================================================================= + +export type SaveArgs = { + deck: Deck + playerAddress: Address + onSuccess: () => void +} + +export type ModifyArgs = { + deck: Deck + playerAddress: Address + index: number + onSuccess: () => void +} + +// ------------------------------------------------------------------------------------------------- + +/** + * Saves a deck created by the player by sending the `saveDeck` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function save(args: SaveArgs): Promise { + try { + return await saveImpl(args) + } catch (err) { + return defaultErrorHandling("save", err) + } +} + +/** + * Modifies a deck owned by the player by sending the `modifyDeck` transaction. + * + * Returns `true` iff the transaction is successful. + */ +export async function modify(args: ModifyArgs): Promise { + try { + return await modifyImpl(args) + } catch (err) { + return defaultErrorHandling("modify", err) + } +} + +// ------------------------------------------------------------------------------------------------- + +async function saveImpl(args: SaveArgs): Promise { + const cardBigInts = args.deck.cards.map((card) => card.id) + + checkFresh( + await freshWrap( + contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "addDeck", + args: [args.playerAddress, { name: args.deck.name, cards: cardBigInts }], + }) + ) + ) + + args.onSuccess() + return true +} + +async function modifyImpl(args: ModifyArgs): Promise { + const cardBigInts = args.deck.cards.map((card) => card.id) + console.log("INDEX: " + args.index) + checkFresh( + await freshWrap( + contractWriteThrowing({ + contract: deployment.Inventory, + abi: inventoryABI, + functionName: "replaceDeck", + args: [args.playerAddress, args.index, { name: args.deck.name, cards: cardBigInts }], + }) + ) + ) + + args.onSuccess() + return true +} + +// ================================================================================================= diff --git a/packages/webapp/src/components/cards/handCard.tsx b/packages/webapp/src/components/cards/handCard.tsx index 5feb8f39..7057952d 100644 --- a/packages/webapp/src/components/cards/handCard.tsx +++ b/packages/webapp/src/components/cards/handCard.tsx @@ -39,7 +39,7 @@ const HandCard = forwardRef(({ id, isDragging, ha showingDetails ? "max-w-[320px] select-none overflow-hidden text-clip text-left font-serif text-2xl font-bold text-slate-200" : handHovered - ? "select-none truncate text-left font-serif text-[14px] font-bold text-slate-200" + ? "font-serif text-[14px] font-bold text-slate-200 text-left truncate select-none" : "hidden" } > diff --git a/packages/webapp/src/components/collection/deckList.tsx b/packages/webapp/src/components/collection/deckList.tsx index f3a2f493..f84610ed 100644 --- a/packages/webapp/src/components/collection/deckList.tsx +++ b/packages/webapp/src/components/collection/deckList.tsx @@ -1,85 +1,77 @@ -import React, { useEffect, useState, useCallback } from "react" -import Link from "src/components/link" -import { Deck } from 'src/store/types' -import { Button } from "src/components/ui/button" -import { getAllDecks, getNumDecks, getDeckNames } from "src/actions/getDeck" -import * as store from "src/store/hooks" -import { Deck } from "src/store/types" - -interface DeckCollectionDisplayProps { - decks: Deck[] - setDecks: React.Dispatch> - onDeckSelect: (deckID: number) => void -} - -const DeckCollectionDisplay: React.FC = ({ decks, setDecks, onDeckSelect }) => { - const playerAddress = store.usePlayerAddress() - const [ deckNames, setDeckNames] = useState([]) - const [ isLoadingDecks, setIsLoadingDecks ] = useState(false) - - function deckCount(): Promise { - return new Promise((resolve) => { - getNumDecks({ - playerAddress: playerAddress!, - onSuccess: () => { } - }) - }) - } - - const loadDeckNames = useCallback(() => { - if (playerAddress) { - setIsLoadingDecks(true) - getDeckNames({ - playerAddress: playerAddress, - onSuccess: () => { - }, - }).then(response => { - if(!response.simulatedResult) return - const receivedDecks = response.simulatedResult as string[] - setDeckNames(receivedDecks) - setIsLoadingDecks(false) - }).catch(error => { - console.error("Error fetching decks:", error) - }) - } - }, [playerAddress]) - - - useEffect(() => { - loadDeckNames() - }, [loadDeckNames]) - - return ( -
- {/* New Deck Button */} - - - {/* Loading Button */} - {isLoadingDecks && ( - - )} - - {/* Deck Buttons */} - {deckNames.map((deckname, deckID) => ( - - ))} -
- ) -} - -export default DeckCollectionDisplay +import React, { useEffect, useState, useCallback } from "react" +import Link from "src/components/link" +import { Button } from "src/components/ui/button" +import { getDeckNames } from "src/actions/getDeck" +import * as store from "src/store/hooks" + +interface DeckCollectionDisplayProps { + onDeckSelect: (deckID: number) => void +} + +const DeckCollectionDisplay: React.FC = ({ onDeckSelect }) => { + const playerAddress = store.usePlayerAddress() + const [deckNames, setDeckNames] = useState([]) + const [isLoadingDecks, setIsLoadingDecks] = useState(false) + + const loadDeckNames = useCallback(() => { + if (playerAddress) { + setIsLoadingDecks(true) + getDeckNames({ + playerAddress: playerAddress, + onSuccess: () => {}, + }) + .then((response) => { + if (!response.simulatedResult) return + const receivedDecks = response.simulatedResult as string[] + setDeckNames(receivedDecks) + setIsLoadingDecks(false) + }) + .catch((error) => { + console.error("Error fetching decks:", error) + }) + } + }, [playerAddress]) + + useEffect(() => { + loadDeckNames() + }, [loadDeckNames]) + + return ( +
+ {/* New Deck Button */} + + + {/* Loading Button */} + {isLoadingDecks && ( + + )} + + {/* Deck Buttons */} + {deckNames.map((deckname, deckID) => ( + + ))} +
+ ) +} + +export default DeckCollectionDisplay diff --git a/packages/webapp/src/components/collection/deckPanel.tsx b/packages/webapp/src/components/collection/deckPanel.tsx index 46c23f45..f5ce2bbf 100644 --- a/packages/webapp/src/components/collection/deckPanel.tsx +++ b/packages/webapp/src/components/collection/deckPanel.tsx @@ -62,14 +62,15 @@ const DeckConstructionPanel: React.FC = ({ {/* Counter Row */}
-
-
+
+
-
- {selectedCards.length}/{MAX_CARDS} + {selectedCards.length}/{MAX_CARDS}
diff --git a/packages/webapp/src/pages/collection.tsx b/packages/webapp/src/pages/collection.tsx index 9de55726..df52c273 100644 --- a/packages/webapp/src/pages/collection.tsx +++ b/packages/webapp/src/pages/collection.tsx @@ -1,10 +1,8 @@ +import debounce from "lodash/debounce" import React, { useEffect, useMemo, useState } from "react" import Head from "next/head" import { useRouter } from "next/router" - -import React, { useState, useMemo, useEffect, useCallback } from "react" import { useAccount } from "wagmi" - import { Address } from "src/chain" import CardCollectionDisplay from "src/components/collection/cardCollectionDisplay" import DeckList from "src/components/collection/deckList" @@ -15,13 +13,8 @@ import { Navbar } from "src/components/navbar" import { deployment } from "src/deployment" import { useInventoryCardsCollectionGetCollection } from "src/generated" import { FablePage } from "src/pages/_app" -import { useRouter } from "next/router" import { navigate } from "utils/navigate" import { getDeck } from "src/actions/getDeck" -import FilterPanel from 'src/components/collection/filterPanel' -import CardCollectionDisplay from 'src/components/collection/cardCollectionDisplay' -import DeckList from 'src/components/collection/deckList' -import DeckPanel from 'src/components/collection/deckPanel' import { save, modify } from "src/actions/setDeck" import * as store from "src/store/hooks" import { LoadingModal } from "src/components/modals/loadingModal" @@ -53,9 +46,8 @@ const Collection: FablePage = ({ isHydrated }) => { const [isEditing, setIsEditing] = useState(false) // Deck Collection Display - const [ editingDeckIndex, setEditingDeckIndex ] = useState(null) - const [decks, setDecks] = useState([]) - const [ isLoadingDeck, setIsLoadingDeck ] = useState(false) + const [editingDeckIndex, setEditingDeckIndex] = useState(null) + const [isLoadingDeck, setIsLoadingDeck] = useState(false) const activeEffects = Object.keys(effectMap).filter((key) => effectMap[key]) const activeTypes = Object.keys(typeMap).filter((key) => typeMap[key]) @@ -81,66 +73,70 @@ const Collection: FablePage = ({ isHydrated }) => { ) }) - const handleInputChangeBouncy = (event: React.ChangeEvent) => { - setSearchInput(event.target.value) - } - const handleInputChange = useMemo(() => debounce(handleInputChangeBouncy, 300), []) + const handleInputChangeBouncy = (event: React.ChangeEvent) => { + setSearchInput(event.target.value) + } + const handleInputChange = useMemo(() => debounce(handleInputChangeBouncy, 300), []) - const handleEffectClick = (effectIndex: number) => { - const effect = effects[effectIndex] - setEffectMap({...effectMap, [effect]: !effectMap[effect]}) - } + const handleEffectClick = (effectIndex: number) => { + const effect = effects[effectIndex] + setEffectMap({ ...effectMap, [effect]: !effectMap[effect] }) + } - const handleTypeClick = (typeIndex: number) => { - const type = types[typeIndex] - setTypeMap({...typeMap, [type]: !typeMap[type]}) - } + const handleTypeClick = (typeIndex: number) => { + const type = types[typeIndex] + setTypeMap({ ...typeMap, [type]: !typeMap[type] }) + } - const handleSaveDeck = async (updatedDeck: Deck) => { - setIsSaving(true) + const handleSaveDeck = async (updatedDeck: Deck) => { + setIsSaving(true) - if (editingDeckIndex !== null) { - // Update existing deck - await modifyOnchain(updatedDeck, editingDeckIndex) - } else { - // Add the new deck to the list - await saveOnchain(updatedDeck) + if (editingDeckIndex !== null) { + // Update existing deck + await modifyOnchain(updatedDeck, editingDeckIndex) + } else { + // Add the new deck to the list + await saveOnchain(updatedDeck) + } + + setIsSaving(false) + + setIsEditing(false) + setSelectedCards([]) + void navigate(router, "/collection") } - - setIsSaving(false) - setIsEditing(false) - setSelectedCards([]) - void navigate(router, '/collection') - } + function saveOnchain(deck: Deck): Promise { + return new Promise((resolve) => { + save({ + deck, + playerAddress: playerAddress!, + onSuccess: () => { + resolve() + }, + }) + }) + } - function saveOnchain(deck: Deck): Promise { - return new Promise((resolve) => { - save({ - deck, - playerAddress: playerAddress!, - onSuccess: () => { resolve() } - }) - }) - } + function modifyOnchain(deck: Deck, editingDeckIndex: number): Promise { + return new Promise((resolve) => { + modify({ + deck, + playerAddress: playerAddress!, + index: BigInt(editingDeckIndex), + onSuccess: () => { + resolve() + }, + }) + }) + } - function modifyOnchain(deck: Deck, editingDeckIndex: number): Promise { - return new Promise((resolve) => { - modify({ - deck, - playerAddress: playerAddress!, - index: BigInt(editingDeckIndex), - onSuccess: () => { resolve() } - }) - }) - } + const handleCancelEditing = () => { + setIsEditing(false) + setSelectedCards([]) + void navigate(router, "/collection") + } - const handleCancelEditing = () => { - setIsEditing(false) - setSelectedCards([]) - void navigate(router, '/collection') - } - const addToDeck = (card: Card) => { setSelectedCards((prevSelectedCards) => { // Add or remove card from the selectedCards @@ -166,40 +162,42 @@ const Collection: FablePage = ({ isHydrated }) => { } const handleDeckSelect = (deckID: number) => { - if (isLoadingDeck) return; - if (playerAddress) { - setIsLoadingDeck(true) - getDeck({ - playerAddress: playerAddress, - index: deckID, - onSuccess: () => { - }, - }).then(response => { - if(!response.simulatedResult) return; - - - const cardsReceived = response.simulatedResult.cards; - const cardObjects: Card[] = [] - cardsReceived.forEach(card => { - const cID = Number(card) - const co = cards.find(c => Number(c.id) === cID) - if(co) { cardObjects.push(co) } - }) + if (isLoadingDeck) return + if (playerAddress) { + setIsLoadingDeck(true) + getDeck({ + playerAddress: playerAddress, + index: deckID, + onSuccess: () => {}, + }) + .then((response) => { + if (!response.simulatedResult) return - setSelectedCards(cardObjects); - - const deckName = response.simulatedResult.name; - setCurrentDeck({ name: deckName, cards: cardObjects }) - setEditingDeckIndex(deckID) - setIsEditing(true) - - }).catch(error => { - console.error("Error fetching deck:", error); - }).finally(_ => { - setIsLoadingDeck(false) - }) - } - } + const cardsReceived = response.simulatedResult.cards + const cardObjects: Card[] = [] + cardsReceived.forEach((card) => { + const cID = Number(card) + const co = cards.find((c) => Number(c.id) === cID) + if (co) { + cardObjects.push(co) + } + }) + + setSelectedCards(cardObjects) + + const deckName = response.simulatedResult.name + setCurrentDeck({ name: deckName, cards: cardObjects }) + setEditingDeckIndex(deckID) + setIsEditing(true) + }) + .catch((error) => { + console.error("Error fetching deck:", error) + }) + .finally((_) => { + setIsLoadingDeck(false) + }) + } + } // Sets up an event listener for route changes when deck editor is rendered. useEffect(() => { @@ -220,65 +218,63 @@ const Collection: FablePage = ({ isHydrated }) => { }, [router.events, router.query.newDeck]) return ( - <> - - 0xFable: My Collection - - {jotaiDebug()} - {isLoadingDeck ? ( - - ) : ( -
- -
- {/* Left Panel - Search and Filters */} -
- -
- {/* Middle Panel - Card Collection Display */} -
- -
- {/* Right Panel - Deck List */} - {isSaving ? ( - - ) : ( -
- {isEditing && currentDeck ? ( - - ) : ( - - )} -
- )} -
-
- )} - - )} + <> + + 0xFable: My Collection + + {jotaiDebug()} + {isLoadingDeck ? ( + + ) : ( +
+ +
+ {/* Left Panel - Search and Filters */} +
+ +
+ {/* Middle Panel - Card Collection Display */} +
+ +
+ {/* Right Panel - Deck List */} + {isSaving ? ( + + ) : ( +
+ {isEditing && currentDeck ? ( + + ) : ( + + )} +
+ )} +
+
+ )} + + ) +} export default Collection