diff --git a/Makefile b/Makefile index 779bcda0..9767ddcf 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ check: # Performs code formatting for the webapp files and contracts in their respective directories. format: cd packages/webapp && make format - cd packages/contract && make format + cd packages/contracts && make format .PHONY: format # ================================================================================================== diff --git a/packages/webapp/.eslintrc.cjs b/packages/webapp/.eslintrc.cjs index 3d4bad6d..39739480 100644 --- a/packages/webapp/.eslintrc.cjs +++ b/packages/webapp/.eslintrc.cjs @@ -1,32 +1,65 @@ /** @type {import("eslint").Linter.Config} */ const config = { - extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended", "prettier"], - parser: "@typescript-eslint/parser", - parserOptions: { - project: "./tsconfig.json", - }, - plugins: ["@typescript-eslint"], - root: true, - ignorePatterns: ["node_modules", "src/hooks/useScrollBox.ts"], - rules: { - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "react/no-unescaped-entities": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/ban-ts-comment": "off", + extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended", "prettier"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "./tsconfig.json", + sourceType: "module", + ecmaVersion: "latest", + }, + plugins: ["@typescript-eslint", "simple-import-sort"], + root: true, + ignorePatterns: ["node_modules", "src/generated.ts"], + rules: { + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "react/no-unescaped-entities": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-comment": "off", + "no-restricted-imports": "off", + "@typescript-eslint/no-restricted-imports": [ + "error", + { + patterns: ["./*", "../*"], + }, + ], - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - // ignore unused args that start with underscore - argsIgnorePattern: "^_", - varsIgnorePattern: "^_", - caughtErrorsIgnorePattern: "^_", - }, - ], - }, + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + // ignore unused args that start with underscore + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "import/first": "error", + "import/newline-after-import": "error", + "import/no-duplicates": "error", + "simple-import-sort/imports": [ + "error", + { + groups: [ + // Packages. `react` related packages come first. + ["^react", "^next"], + // External packages. + ["^@?\\w"], + // Custom group for src/ prefixed imports + ["^src/"], + // Parent imports. Put `..` last. + ["^\\.\\.(?!/?$)", "^\\.\\./?$"], + // Other relative imports. Put same-folder imports and `.` last. + ["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"], + // Style imports. + ["^.+\\.s?css$"], + // Side effect imports. + ["^\\u0000"], + ], + }, + ], + }, } module.exports = config diff --git a/packages/webapp/.prettierrc.json b/packages/webapp/.prettierrc.json index da298910..1367ec9a 100644 --- a/packages/webapp/.prettierrc.json +++ b/packages/webapp/.prettierrc.json @@ -4,5 +4,6 @@ "singleQuote": false, "tabWidth": 4, "useTabs": false, - "printWidth": 120 + "printWidth": 120, + "plugins": ["prettier-plugin-tailwindcss"] } diff --git a/packages/webapp/.vscode/settings.json b/packages/webapp/.vscode/settings.json index f288ef4a..2f0fcb6b 100644 --- a/packages/webapp/.vscode/settings.json +++ b/packages/webapp/.vscode/settings.json @@ -1,4 +1,8 @@ { "javascript.validate.enable": false, - "typescript.validate.enable": false + "typescript.validate.enable": false, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"] } diff --git a/packages/webapp/Makefile b/packages/webapp/Makefile index ddc8b88e..e045b510 100644 --- a/packages/webapp/Makefile +++ b/packages/webapp/Makefile @@ -26,11 +26,12 @@ lint: # Runs code quality checks. check: - pnpm eslint . + make lint pnpm prettier --check "src/**/*.{js,jsx,ts,tsx,json,css}" .PHONY: check # Runs prettier formatting across webapp files with specified file extensions. format: - pnpm prettier --write "**/*.{js,jsx,ts,tsx,json,css}" + pnpm eslint . --fix + pnpm prettier --write "**/*.{js,jsx,ts,tsx,json,css,cjs,mjs}" .PHONY: format \ No newline at end of file diff --git a/packages/webapp/next.config.mjs b/packages/webapp/next.config.mjs index 1dd012c4..b6b92755 100644 --- a/packages/webapp/next.config.mjs +++ b/packages/webapp/next.config.mjs @@ -9,57 +9,57 @@ const require = createRequire(import.meta.url) /** @type {import("next").NextConfig} */ const nextConfig = { - reactStrictMode: true, + reactStrictMode: true, - /** - * If you have the "experimental: { appDir: true }" setting enabled, then you - * must comment the below `i18n` config out. - * - * @see https://github.com/vercel/next.js/issues/41980 - */ - i18n: { - locales: ["en"], - defaultLocale: "en", - }, - eslint: { - // Warning: This allows production builds to successfully complete even if - // your project has ESLint errors. - ignoreDuringBuilds: true, - }, - experimental: { - // Currently broken in Next 13.3.0: https://github.com/pmndrs/swc-jotai/issues/6 - // Unlike what is suggested, also broken when I downgrade to Next 13.2.3 and Next 13.1.6. - swcPlugins: [ - // ['@swc-jotai/react-refresh', {}], - // ["@swc-jotai/debug-label", {}] - ] - }, - webpack(config, { dev, isServer }) { - // prevent node-gyp from failing because "can't resolve fs" - config.resolve.fallback = { - ...config.resolve.fallback, - fs: false, - net: false, - tls: false, - readline: false - } + /** + * If you have the "experimental: { appDir: true }" setting enabled, then you + * must comment the below `i18n` config out. + * + * @see https://github.com/vercel/next.js/issues/41980 + */ + i18n: { + locales: ["en"], + defaultLocale: "en", + }, + eslint: { + // Warning: This allows production builds to successfully complete even if + // your project has ESLint errors. + ignoreDuringBuilds: true, + }, + experimental: { + // Currently broken in Next 13.3.0: https://github.com/pmndrs/swc-jotai/issues/6 + // Unlike what is suggested, also broken when I downgrade to Next 13.2.3 and Next 13.1.6. + swcPlugins: [ + // ['@swc-jotai/react-refresh', {}], + // ["@swc-jotai/debug-label", {}] + ], + }, + webpack(config, { dev, isServer }) { + // prevent node-gyp from failing because "can't resolve fs" + config.resolve.fallback = { + ...config.resolve.fallback, + fs: false, + net: false, + tls: false, + readline: false, + } - config.experiments = { - ...config.experiments, - topLevelAwait: true // enable await at top-level in modules - } + config.experiments = { + ...config.experiments, + topLevelAwait: true, // enable await at top-level in modules + } - // This would be great, but is sadly disallowed by Next, because they hate freedom. - // https://nextjs.org/docs/messages/improper-devtool - // Having this would enable parsing hook names in the React DevTools. - // config.devtool = "cheap-module-source-map" - return config - }, - // This hack makes it possible to use the Jotai devtools - // Sources: - // https://github.com/jotaijs/jotai-devtools/issues/47 - // https://github.com/martpie/next-transpile-modules/releases/tag/the-end - transpilePackages: ['jotai-devtools'] + // This would be great, but is sadly disallowed by Next, because they hate freedom. + // https://nextjs.org/docs/messages/improper-devtool + // Having this would enable parsing hook names in the React DevTools. + // config.devtool = "cheap-module-source-map" + return config + }, + // This hack makes it possible to use the Jotai devtools + // Sources: + // https://github.com/jotaijs/jotai-devtools/issues/47 + // https://github.com/martpie/next-transpile-modules/releases/tag/the-end + transpilePackages: ["jotai-devtools"], } // // This hack makes it possible to use the Jotai devtools @@ -68,4 +68,4 @@ const nextConfig = { // "jotai-devtools", // ]) // export default withTranspileModules(nextConfig) -export default nextConfig \ No newline at end of file +export default nextConfig diff --git a/packages/webapp/package.json b/packages/webapp/package.json index e373bebe..a56c5857 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -19,7 +19,6 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "connectkit": "^1.5.3", - "eslint-config-prettier": "^9.1.0", "jotai": "^2.4.3", "jotai-devtools": "^0.7.0", "lodash": "^4.17.21", @@ -27,6 +26,7 @@ "next": "^13.5.6", "next-themes": "^0.2.1", "next-transpile-modules": "^10.0.1", + "prettier": "^3.2.5", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.11.0", @@ -52,8 +52,11 @@ "autoprefixer": "^10.4.16", "eslint": "^8.52.0", "eslint-config-next": "^13.5.6", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-simple-import-sort": "^12.0.0", "postcss": "^8.4.31", - "prettier": "2.8.8", + "prettier-plugin-tailwindcss": "^0.5.11", "tailwindcss": "^3.3.3", "typescript": "^5.2.2" } diff --git a/packages/webapp/postcss.config.cjs b/packages/webapp/postcss.config.cjs index 5080cb5e..a27c49b1 100644 --- a/packages/webapp/postcss.config.cjs +++ b/packages/webapp/postcss.config.cjs @@ -1,8 +1,8 @@ const config = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, } -module.exports = config \ No newline at end of file +module.exports = config diff --git a/packages/webapp/postcss.config.mjs b/packages/webapp/postcss.config.mjs index 2e7af2b7..d41ad635 100644 --- a/packages/webapp/postcss.config.mjs +++ b/packages/webapp/postcss.config.mjs @@ -1,6 +1,6 @@ export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, } diff --git a/packages/webapp/src/actions/concede.ts b/packages/webapp/src/actions/concede.ts index e15ac381..55d9805f 100644 --- a/packages/webapp/src/actions/concede.ts +++ b/packages/webapp/src/actions/concede.ts @@ -1,9 +1,9 @@ import { defaultErrorHandling } from "src/actions/errors" -import { checkFresh, freshWrap } from "src/store/checkFresh" import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address } from "src/chain" import { deployment } from "src/deployment" import { gameABI } from "src/generated" +import { checkFresh, freshWrap } from "src/store/checkFresh" // ================================================================================================= diff --git a/packages/webapp/src/actions/defend.ts b/packages/webapp/src/actions/defend.ts index 48d465a6..6bc9630a 100644 --- a/packages/webapp/src/actions/defend.ts +++ b/packages/webapp/src/actions/defend.ts @@ -1,9 +1,9 @@ import { defaultErrorHandling } from "src/actions/errors" -import { checkFresh, freshWrap } from "src/store/checkFresh" import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address } from "src/chain" import { deployment } from "src/deployment" import { gameABI } from "src/generated" +import { checkFresh, freshWrap } from "src/store/checkFresh" // ================================================================================================= diff --git a/packages/webapp/src/actions/drawCard.ts b/packages/webapp/src/actions/drawCard.ts index e21bcbae..46e40e88 100644 --- a/packages/webapp/src/actions/drawCard.ts +++ b/packages/webapp/src/actions/drawCard.ts @@ -8,10 +8,12 @@ import { defaultErrorHandling } from "src/actions/errors" import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address, type HexString } from "src/chain" +import { CancellationHandler } from "src/components/modals/loadingModal" +import { DRAW_CARD_PROOF_TIMEOUT } from "src/constants" import { deployment } from "src/deployment" import { packCards } from "src/game/fableProofs" import { gameABI } from "src/generated" -import { getOrInitPrivateInfo, setPrivateInfo } from "src/store/write" +import { checkFresh, freshWrap } from "src/store/checkFresh" import { getCards, getCurrentPlayerAddress, @@ -21,12 +23,10 @@ import { getPlayerAddress, } from "src/store/read" import { GameStep, PrivateInfo } from "src/store/types" -import { FAKE_PROOF, proveInWorker, SHOULD_GENERATE_PROOFS } from "src/utils/zkproofs" -import { bigintToHexString } from "src/utils/js-utils" +import { getOrInitPrivateInfo, setPrivateInfo } from "src/store/write" import { mimcHash } from "src/utils/hashing" -import { DRAW_CARD_PROOF_TIMEOUT } from "src/constants" -import { CancellationHandler } from "src/components/modals/loadingModal" -import { checkFresh, freshWrap } from "src/store/checkFresh" +import { bigintToHexString } from "src/utils/js-utils" +import { FAKE_PROOF, proveInWorker, SHOULD_GENERATE_PROOFS } from "src/utils/zkproofs" // ================================================================================================= diff --git a/packages/webapp/src/actions/endTurn.ts b/packages/webapp/src/actions/endTurn.ts index 14e3a24d..6d6829e8 100644 --- a/packages/webapp/src/actions/endTurn.ts +++ b/packages/webapp/src/actions/endTurn.ts @@ -10,9 +10,9 @@ import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address } from "src/chain" import { deployment } from "src/deployment" import { gameABI } from "src/generated" +import { checkFresh, freshWrap } from "src/store/checkFresh" import { getCurrentPlayerAddress, getGameData, getGameID, getPlayerAddress } from "src/store/read" import { GameStep } from "src/store/types" -import { checkFresh, freshWrap } from "src/store/checkFresh" // ================================================================================================= diff --git a/packages/webapp/src/actions/errors.ts b/packages/webapp/src/actions/errors.ts index fe8fca64..9dd4a0e8 100644 --- a/packages/webapp/src/actions/errors.ts +++ b/packages/webapp/src/actions/errors.ts @@ -12,9 +12,8 @@ import { ContractFunctionRevertedError, UserRejectedRequestError } from "viem" import { ContractWriteError } from "src/actions/libContractWrite" import { GIT_ISSUES } from "src/constants" -import { setError } from "src/store/write" - import { StaleError } from "src/store/checkFresh" +import { setError } from "src/store/write" import { TimeoutError } from "src/utils/errors" import { ProofCancelled, ProofError, ProofTimeoutError } from "src/utils/zkproofs/proofs" diff --git a/packages/webapp/src/actions/joinGame.ts b/packages/webapp/src/actions/joinGame.ts index c4a3c235..e6485c14 100644 --- a/packages/webapp/src/actions/joinGame.ts +++ b/packages/webapp/src/actions/joinGame.ts @@ -10,11 +10,15 @@ import { decodeEventLog } from "viem" import { defaultErrorHandling, FableRequestTimeout, InconsistentGameStateError } from "src/actions/errors" import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address } from "src/chain" +import { CancellationHandler } from "src/components/modals/loadingModal" +import { DRAW_HAND_PROOF_TIMEOUT } from "src/constants" import { deployment } from "src/deployment" +import { NUM_CARDS_FOR_PROOF } from "src/game/constants" import { drawInitialHand } from "src/game/drawInitialHand" +import { packCards } from "src/game/fableProofs" import { gameABI } from "src/generated" -import { waitForUpdate } from "src/store/update" -import { getOrInitPrivateInfo, setGameID, setPrivateInfo } from "src/store/write" +import { checkFresh, freshWrap } from "src/store/checkFresh" +import { getPlayerHand } from "src/store/derive" import { getCards, getDeck, @@ -26,13 +30,9 @@ import { isGameReadyToStart, } from "src/store/read" import { FetchedGameData, GameStatus, PlayerData, PrivateInfo } from "src/store/types" -import { SHOULD_GENERATE_PROOFS, FAKE_PROOF, ProofOutput, proveInWorker } from "src/utils/zkproofs" -import { NUM_CARDS_FOR_PROOF } from "src/game/constants" -import { packCards } from "src/game/fableProofs" -import { DRAW_HAND_PROOF_TIMEOUT } from "src/constants" -import { CancellationHandler } from "src/components/modals/loadingModal" -import { checkFresh, freshWrap } from "src/store/checkFresh" -import { getPlayerHand } from "src/store/derive" +import { waitForUpdate } from "src/store/update" +import { getOrInitPrivateInfo, setGameID, setPrivateInfo } from "src/store/write" +import { FAKE_PROOF, ProofOutput, proveInWorker, SHOULD_GENERATE_PROOFS } from "src/utils/zkproofs" // ================================================================================================= @@ -85,7 +85,8 @@ async function joinGameImpl(args: JoinGameArgs): Promise { if (gameStatus < GameStatus.JOINED) { // we can skip the join step if already performed const promise = doJoinGameTransaction(args, privateInfo.saltHash) - if (gameID === null) await promise // gameID starts null and the call will set it + if (gameID === null) + await promise // gameID starts null and the call will set it else checkFresh(await freshWrap(promise)) } diff --git a/packages/webapp/src/actions/libContractWrite.ts b/packages/webapp/src/actions/libContractWrite.ts index 883352b2..a2f48362 100644 --- a/packages/webapp/src/actions/libContractWrite.ts +++ b/packages/webapp/src/actions/libContractWrite.ts @@ -13,7 +13,6 @@ import { TransactionExecutionError, TransactionReceipt, } from "viem" - import { prepareWriteContract, waitForTransaction, writeContract } from "wagmi/actions" import type { Address, Hash } from "src/chain" diff --git a/packages/webapp/src/actions/playCard.ts b/packages/webapp/src/actions/playCard.ts index da37e81e..91f7a128 100644 --- a/packages/webapp/src/actions/playCard.ts +++ b/packages/webapp/src/actions/playCard.ts @@ -8,18 +8,18 @@ import { defaultErrorHandling } from "src/actions/errors" import { contractWriteThrowing } from "src/actions/libContractWrite" import { Address, type HexString } from "src/chain" +import { CancellationHandler } from "src/components/modals/loadingModal" +import { PLAY_CARD_PROOF_TIMEOUT } from "src/constants" import { deployment } from "src/deployment" import { packCards } from "src/game/fableProofs" import { gameABI } from "src/generated" -import { getOrInitPrivateInfo, setPrivateInfo } from "src/store/write" +import { checkFresh, freshWrap } from "src/store/checkFresh" import { getCards, getCurrentPlayerAddress, getGameData, getGameID, getPlayerAddress } from "src/store/read" import { GameStep, PrivateInfo } from "src/store/types" -import { FAKE_PROOF, proveInWorker, SHOULD_GENERATE_PROOFS } from "src/utils/zkproofs" -import { bigintToHexString } from "src/utils/js-utils" +import { getOrInitPrivateInfo, setPrivateInfo } from "src/store/write" import { mimcHash } from "src/utils/hashing" -import { PLAY_CARD_PROOF_TIMEOUT } from "src/constants" -import { CancellationHandler } from "src/components/modals/loadingModal" -import { checkFresh, freshWrap } from "src/store/checkFresh" +import { bigintToHexString } from "src/utils/js-utils" +import { FAKE_PROOF, proveInWorker, SHOULD_GENERATE_PROOFS } from "src/utils/zkproofs" // ================================================================================================= diff --git a/packages/webapp/src/components/cards/boardCard.tsx b/packages/webapp/src/components/cards/boardCard.tsx index 3c672e86..ff7cdfb1 100644 --- a/packages/webapp/src/components/cards/boardCard.tsx +++ b/packages/webapp/src/components/cards/boardCard.tsx @@ -1,6 +1,6 @@ -import { forwardRef, useState } from "react" +import React, { forwardRef, useState } from "react" import Image from "next/image" -import React from "react" + import { testCards } from "src/utils/card-list" interface BoardCardProps { @@ -12,14 +12,14 @@ const BoardCard = forwardRef(({ id }, ref) => { return (
setShowCardName(true)} onMouseLeave={() => setShowCardName(false)} > {`${id}`}(({ id }, ref) => { /> {showCardName && ( <> -
-
+
+
{`${testCards[id]?.attack}`}
-
+
{`${testCards[id]?.defense}`}
{`${testCards[id]?.name}`} diff --git a/packages/webapp/src/components/cards/cardContainer.tsx b/packages/webapp/src/components/cards/cardContainer.tsx index 6267b9ca..369c91cb 100644 --- a/packages/webapp/src/components/cards/cardContainer.tsx +++ b/packages/webapp/src/components/cards/cardContainer.tsx @@ -1,10 +1,12 @@ import React from "react" -import { CardPlacement } from "src/store/types" + import { useSortable } from "@dnd-kit/sortable" -import DraggedCard from "./draggedCard" -import BoardCard from "./boardCard" -import HandCard from "./handCard" import { CSS } from "@dnd-kit/utilities" + +import BoardCard from "src/components/cards/boardCard" +import DraggedCard from "src/components/cards/draggedCard" +import HandCard from "src/components/cards/handCard" +import { CardPlacement } from "src/store/types" import { convertStringToSafeNumber } from "src/utils/js-utils" interface BaseCardProps { @@ -49,7 +51,7 @@ const CardContainer: React.FC = ({ id, handHovered, placement, ca } return (
(({ id }, ref) <> {`${id}`}(({ id, isDragging, ha return (
(({ id, isDragging, ha {testCards[id]?.name} @@ -49,17 +50,17 @@ const HandCard = forwardRef(({ id, isDragging, ha src={testCards[id]?.image} width={showingDetails ? 375 : 200} height={showingDetails ? 375 : 200} - className="pointer-events-none rounded-xl border select-none" + className="pointer-events-none select-none rounded-xl border" style={{ boxShadow: (cardHover && !isDetailsVisible) || cardGlow ? "0 0 10px 2px gold" : "none", // Adds golden glow when hovered }} /> {showingDetails && ( <> -

+

{testCards[id]?.description}

-
+

⚔️ {testCards[id]?.attack}

🛡 {testCards[id]?.defense}

diff --git a/packages/webapp/src/components/collection/cardCollectionDisplay.tsx b/packages/webapp/src/components/collection/cardCollectionDisplay.tsx index 0a2faadc..ffec6b8c 100644 --- a/packages/webapp/src/components/collection/cardCollectionDisplay.tsx +++ b/packages/webapp/src/components/collection/cardCollectionDisplay.tsx @@ -1,7 +1,8 @@ import React from "react" import Image from "next/image" -import { Card } from "src/store/types" + import { MintDeckModal } from "src/components/modals/mintDeckModal" +import { Card } from "src/store/types" import { testCards } from "src/utils/card-list" interface CardCollectionDisplayProps { @@ -23,9 +24,9 @@ const CardCollectionDisplay: React.FC = ({ }) => { return ( <> -
+
{isHydrated && cards.length === 0 && ( -
+
)} @@ -39,7 +40,7 @@ const CardCollectionDisplay: React.FC = ({ selectedCards.some((c) => c.id === card.id) ? "shadow-highlight shadow-orange-300" : "" - } hover:bg-slate-800 rounded-lg p-4 border-4 border-slate-900 grow w-[220px] max-w-[330px]`} + } w-[220px] max-w-[330px] grow rounded-lg border-4 border-slate-900 p-4 hover:bg-slate-800`} onMouseEnter={() => setSelectedCard(card)} onClick={() => { if (isEditing) { @@ -55,11 +56,11 @@ const CardCollectionDisplay: React.FC = ({ height={256} />
{card.lore.name}
-
-
+
+
{card.stats.attack}
-
+
{card.stats.defense}
diff --git a/packages/webapp/src/components/collection/deckList.tsx b/packages/webapp/src/components/collection/deckList.tsx index 0d6c312a..89abdaa3 100644 --- a/packages/webapp/src/components/collection/deckList.tsx +++ b/packages/webapp/src/components/collection/deckList.tsx @@ -1,7 +1,8 @@ import React from "react" + import Link from "src/components/link" -import { Deck } from "src/store/types" import { Button } from "src/components/ui/button" +import { Deck } from "src/store/types" interface DeckCollectionDisplayProps { decks: Deck[] @@ -10,12 +11,12 @@ interface DeckCollectionDisplayProps { const DeckCollectionDisplay: React.FC = ({ decks, onDeckSelect }) => { return ( -
+
{/* New Deck Button */}
@@ -26,7 +27,7 @@ const DeckCollectionDisplay: React.FC = ({ decks, on
{/* Types */} -

Types

+

Types

{types.map((type, index) => (
diff --git a/packages/webapp/src/components/hand.tsx b/packages/webapp/src/components/hand.tsx index f2724475..7b8b100f 100644 --- a/packages/webapp/src/components/hand.tsx +++ b/packages/webapp/src/components/hand.tsx @@ -1,11 +1,13 @@ import { useEffect, useRef, useState } from "react" import { AiOutlineLeft, AiOutlineRight } from "react-icons/ai" -import useScrollBox from "../hooks/useScrollBox" -import { SortableContext, horizontalListSortingStrategy, useSortable } from "@dnd-kit/sortable" + +import { horizontalListSortingStrategy, SortableContext, useSortable } from "@dnd-kit/sortable" + +import CardContainer from "src/components/cards/cardContainer" +import { CancellationHandler } from "src/components/modals/loadingModal" +import useScrollBox from "src/hooks/useScrollBox" import { CardPlacement } from "src/store/types" -import CardContainer from "./cards/cardContainer" import { convertBigIntArrayToStringArray } from "src/utils/js-utils" -import { CancellationHandler } from "src/components/modals/loadingModal" const Hand = ({ cards, @@ -44,7 +46,7 @@ const Hand = ({
{ setIsFocused(true) @@ -55,14 +57,14 @@ const Hand = ({ > {showLeftArrow && isFocused && (
- +
)}
-
+
@@ -82,10 +84,10 @@ const Hand = ({
{showRightArrow && isFocused && (
- +
)}
diff --git a/packages/webapp/src/components/lib/modal.tsx b/packages/webapp/src/components/lib/modal.tsx index cf118bae..f2b91fd0 100644 --- a/packages/webapp/src/components/lib/modal.tsx +++ b/packages/webapp/src/components/lib/modal.tsx @@ -1,8 +1,8 @@ import React, { ReactNode, RefObject, useRef, useState } from "react" +import { createPortal } from "react-dom" import { useIsMounted } from "src/hooks/useIsMounted" import { useErrorConfig } from "src/store/hooks" -import { createPortal } from "react-dom" // ================================================================================================= @@ -103,7 +103,7 @@ const ModalInner = ({ ctrl, children }: { ctrl: ModalController; children: React onClick={state.surroundCloseable ? ctrl.close : undefined} style={{ display: displayed ? "flex" : "none" }} > -
+
{state.closeable && ( diff --git a/packages/webapp/src/components/link.tsx b/packages/webapp/src/components/link.tsx index 9cdc831b..581121f2 100644 --- a/packages/webapp/src/components/link.tsx +++ b/packages/webapp/src/components/link.tsx @@ -1,6 +1,6 @@ import React from "react" -import { useRouter } from "next/router" import Link from "next/link" +import { useRouter } from "next/router" interface QueryParamLinkProps { children: React.ReactNode diff --git a/packages/webapp/src/components/modals/createGameModal.tsx b/packages/webapp/src/components/modals/createGameModal.tsx index da174081..df528c74 100644 --- a/packages/webapp/src/components/modals/createGameModal.tsx +++ b/packages/webapp/src/components/modals/createGameModal.tsx @@ -1,20 +1,21 @@ -import { useRouter } from "next/router" import { useCallback, useEffect, useState } from "react" +import { useRouter } from "next/router" + import { decodeEventLog } from "viem" -import { LoadingModalContent } from "src/components/modals/loadingModal" +import { joinGame, reportInconsistentGameState } from "src/actions" +import { concede } from "src/actions/concede" import { Spinner } from "src/components/lib/modalElements" import { InGameMenuModalContent } from "src/components/modals/inGameMenuModalContent" +import { LoadingModalContent } from "src/components/modals/loadingModal" +import { Button } from "src/components/ui/button" +import { Dialog, DialogContent, DialogDescription, DialogTitle, DialogTrigger } from "src/components/ui/dialog" import { gameABI } from "src/generated" +import { useCancellationHandler } from "src/hooks/useCancellationHandler" import { useGameWrite } from "src/hooks/useFableWrite" import * as store from "src/store/hooks" -import { joinGame, reportInconsistentGameState } from "src/actions" import { GameStatus } from "src/store/types" import { navigate } from "src/utils/navigate" -import { useCancellationHandler } from "src/hooks/useCancellationHandler" -import { concede } from "src/actions/concede" -import { Dialog, DialogContent, DialogDescription, DialogTitle, DialogTrigger } from "src/components/ui/dialog" -import { Button } from "src/components/ui/button" interface CreateGameModalContentProps { loading: string | null @@ -42,7 +43,7 @@ export const CreateGameModal = () => { @@ -189,7 +190,7 @@ const CreateGameModalContent: React.FC = ({ loading
)} {joined && ( -
+
{!allPlayersJoined && ( @@ -151,7 +151,7 @@ const JoinGameModalContent: React.FC = ({ loading, se placeholder="Game ID" min={0} onChange={handleInputChange} - className="mr-2 w-full max-w-xs text-white placeholder-gray-500 font-mono" + className="mr-2 w-full max-w-xs font-mono text-white placeholder-gray-500" /> diff --git a/packages/webapp/src/components/navbar.tsx b/packages/webapp/src/components/navbar.tsx index 2006f88c..2da1e766 100644 --- a/packages/webapp/src/components/navbar.tsx +++ b/packages/webapp/src/components/navbar.tsx @@ -1,7 +1,9 @@ import Link from "next/link" + import { ConnectKitButton } from "connectkit" -import { Button } from "./ui/button" -import { NavigationMenu, NavigationMenuList, NavigationMenuItem } from "src/components/ui/navigation-menu" + +import { Button } from "src/components/ui/button" +import { NavigationMenu, NavigationMenuItem, NavigationMenuList } from "src/components/ui/navigation-menu" export const Navbar = () => { return ( @@ -9,8 +11,8 @@ export const Navbar = () => { - @@ -20,7 +22,7 @@ export const Navbar = () => { - diff --git a/packages/webapp/src/components/playerBoard.tsx b/packages/webapp/src/components/playerBoard.tsx index 500985e9..adfa1e6c 100644 --- a/packages/webapp/src/components/playerBoard.tsx +++ b/packages/webapp/src/components/playerBoard.tsx @@ -1,8 +1,9 @@ -import * as store from "src/store/hooks" -import { convertBigIntArrayToStringArray, shortenAddress } from "src/utils/js-utils" import { horizontalListSortingStrategy, SortableContext, useSortable } from "@dnd-kit/sortable" + +import CardContainer from "src/components/cards/cardContainer" +import * as store from "src/store/hooks" import { CardPlacement } from "src/store/types" -import CardContainer from "./cards/cardContainer" +import { convertBigIntArrayToStringArray, shortenAddress } from "src/utils/js-utils" interface PlayerBoardProps { playerAddress: `0x${string}` | undefined | null @@ -19,9 +20,9 @@ const PlayerBoard: React.FC = ({ playerAddress, playedCards }) const convertedCards = convertBigIntArrayToStringArray(playedCards) return (
= ({ playerAddress, playedCards }) }} >
-
-

+

+

{`🛡 ${shortenAddress(playerAddress)}`}

-

♥️ 100

+

♥️ 100

diff --git a/packages/webapp/src/components/ui/button.tsx b/packages/webapp/src/components/ui/button.tsx index 0648de01..83864f3d 100644 --- a/packages/webapp/src/components/ui/button.tsx +++ b/packages/webapp/src/components/ui/button.tsx @@ -1,4 +1,5 @@ import * as React from "react" + import { Slot } from "@radix-ui/react-slot" import { cva, type VariantProps } from "class-variance-authority" diff --git a/packages/webapp/src/components/ui/dialog.tsx b/packages/webapp/src/components/ui/dialog.tsx index dcdc5d8e..bdf9c265 100644 --- a/packages/webapp/src/components/ui/dialog.tsx +++ b/packages/webapp/src/components/ui/dialog.tsx @@ -1,4 +1,5 @@ import * as React from "react" + import * as DialogPrimitive from "@radix-ui/react-dialog" import { X } from "lucide-react" diff --git a/packages/webapp/src/components/ui/navigation-menu.tsx b/packages/webapp/src/components/ui/navigation-menu.tsx index 08458a2e..2eb48144 100644 --- a/packages/webapp/src/components/ui/navigation-menu.tsx +++ b/packages/webapp/src/components/ui/navigation-menu.tsx @@ -1,4 +1,5 @@ import * as React from "react" + import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" import { cva } from "class-variance-authority" import { ChevronDown } from "lucide-react" diff --git a/packages/webapp/src/components/ui/sonner.tsx b/packages/webapp/src/components/ui/sonner.tsx index bb08b5c0..3edc70b7 100644 --- a/packages/webapp/src/components/ui/sonner.tsx +++ b/packages/webapp/src/components/ui/sonner.tsx @@ -1,4 +1,5 @@ import { useTheme } from "next-themes" + import { Toaster as Sonner } from "sonner" type ToasterProps = React.ComponentProps diff --git a/packages/webapp/src/deployment.ts b/packages/webapp/src/deployment.ts index e97311e1..a47e0173 100644 --- a/packages/webapp/src/deployment.ts +++ b/packages/webapp/src/deployment.ts @@ -5,8 +5,8 @@ * @module deployment */ -import type { Address } from "wagmi" import * as deployment_ from "contracts/out/deployment.json" assert { type: "json" } +import type { Address } from "wagmi" export interface Deployment { CardsCollection: Address diff --git a/packages/webapp/src/game/drawInitialHand.ts b/packages/webapp/src/game/drawInitialHand.ts index 2e9601d7..681ec155 100644 --- a/packages/webapp/src/game/drawInitialHand.ts +++ b/packages/webapp/src/game/drawInitialHand.ts @@ -5,9 +5,9 @@ */ import { Hash } from "src/chain" -import { mimcHash } from "src/utils/hashing" -import { PrivateInfo } from "src/store/types" import { FELT_SIZE, INITIAL_HAND_SIZE, MAX_DECK_SIZE, MAX_HAND_SIZE } from "src/game/constants" +import { PrivateInfo } from "src/store/types" +import { mimcHash } from "src/utils/hashing" import { bigintToHexString, parseBigInt } from "src/utils/js-utils" // ================================================================================================= diff --git a/packages/webapp/src/game/fableProofs.ts b/packages/webapp/src/game/fableProofs.ts index 68a77948..2b75cfee 100644 --- a/packages/webapp/src/game/fableProofs.ts +++ b/packages/webapp/src/game/fableProofs.ts @@ -6,8 +6,8 @@ * @module game/fableProofs */ -import { packBytes } from "src/utils/zkproofs/proofs" import { FELT_SIZE, NUM_FELTS_FOR_CARDS } from "src/game/constants" +import { packBytes } from "src/utils/zkproofs/proofs" // ================================================================================================= diff --git a/packages/webapp/src/game/misc.ts b/packages/webapp/src/game/misc.ts index e6ce7af7..6f80f403 100644 --- a/packages/webapp/src/game/misc.ts +++ b/packages/webapp/src/game/misc.ts @@ -1,8 +1,8 @@ /** * Misc game logic helpers. */ -import { FetchedGameData, GameStep } from "src/store/types" import { Address } from "src/chain" +import { FetchedGameData, GameStep } from "src/store/types" // ================================================================================================= diff --git a/packages/webapp/src/hooks/useCancellationHandler.ts b/packages/webapp/src/hooks/useCancellationHandler.ts index da193ef5..fcce13fd 100644 --- a/packages/webapp/src/hooks/useCancellationHandler.ts +++ b/packages/webapp/src/hooks/useCancellationHandler.ts @@ -4,9 +4,10 @@ * @module hooks/useCancellationHandler */ -import { CancellationHandler } from "src/components/modals/loadingModal" import { useEffect, useRef } from "react" +import { CancellationHandler } from "src/components/modals/loadingModal" + // ================================================================================================= /** diff --git a/packages/webapp/src/hooks/useChainWrite.ts b/packages/webapp/src/hooks/useChainWrite.ts index 2e24a8bc..8dd65125 100644 --- a/packages/webapp/src/hooks/useChainWrite.ts +++ b/packages/webapp/src/hooks/useChainWrite.ts @@ -1,5 +1,6 @@ -import { useContractWrite, usePrepareContractWrite, useWaitForTransaction } from "wagmi" import { type TransactionReceipt } from "viem" +import { useContractWrite, usePrepareContractWrite, useWaitForTransaction } from "wagmi" + import { Address, Hash } from "src/chain" // ================================================================================================= diff --git a/packages/webapp/src/hooks/useDebug.ts b/packages/webapp/src/hooks/useDebug.ts index 1abb1621..41e940a5 100644 --- a/packages/webapp/src/hooks/useDebug.ts +++ b/packages/webapp/src/hooks/useDebug.ts @@ -1,4 +1,5 @@ import { useDebugValue, useState } from "react" + import { toString } from "src/utils/js-utils" // ------------------------------------------------------------------------------------------------- diff --git a/packages/webapp/src/hooks/useDragEvents.ts b/packages/webapp/src/hooks/useDragEvents.ts index f5ded6c7..436fb18b 100644 --- a/packages/webapp/src/hooks/useDragEvents.ts +++ b/packages/webapp/src/hooks/useDragEvents.ts @@ -1,10 +1,12 @@ -import { DragStartEvent, DragEndEvent, UniqueIdentifier } from "@dnd-kit/core" +import { useCallback } from "react" + +import { DragEndEvent, DragStartEvent, UniqueIdentifier } from "@dnd-kit/core" + +import { playCard } from "src/actions/playCard" +import { CancellationHandler } from "src/components/modals/loadingModal" import * as store from "src/store/hooks" import { CardPlacement } from "src/store/types" -import { useCallback } from "react" import { extractCardID } from "src/utils/js-utils" -import { CancellationHandler } from "src/components/modals/loadingModal" -import { playCard } from "src/actions/playCard" function useDragEvents( setActiveId: (id: UniqueIdentifier | null) => void, diff --git a/packages/webapp/src/hooks/useFableWrite.ts b/packages/webapp/src/hooks/useFableWrite.ts index 13441ed7..8101496c 100644 --- a/packages/webapp/src/hooks/useFableWrite.ts +++ b/packages/webapp/src/hooks/useFableWrite.ts @@ -1,11 +1,10 @@ import { type TransactionReceipt } from "viem" +import { Hash } from "src/chain" import { deployment } from "src/deployment" import { cardsCollectionABI, deckAirdropABI, gameABI, inventoryABI } from "src/generated" import { useChainWrite, UseWriteResult } from "src/hooks/useChainWrite" -import { Hash } from "src/chain" - // ================================================================================================= // useWrite: just `useWrite` with the contract address and ABI already set. diff --git a/packages/webapp/src/hooks/useScrollBox.ts b/packages/webapp/src/hooks/useScrollBox.ts index 3b4597cf..0d53bbab 100644 --- a/packages/webapp/src/hooks/useScrollBox.ts +++ b/packages/webapp/src/hooks/useScrollBox.ts @@ -1,4 +1,5 @@ -import { useState, useEffect, useCallback, RefObject } from "react" +import { RefObject, useCallback, useEffect, useState } from "react" + import throttle from "lodash/throttle" import { toast } from "sonner" @@ -21,37 +22,40 @@ function useScrollBox(scrollRef: RefObject, cards: readonly bigi const duration = 300 /** Checks and updates the arrow visibility states based on the scroll position. */ - const checkArrowsVisibility = () => { + const checkArrowsVisibility = useCallback(() => { if (!scrollRef.current) return const { scrollLeft, scrollWidth, clientWidth } = scrollRef.current setShowLeftArrow(scrollLeft > 0) setShowRightArrow(scrollLeft < scrollWidth - clientWidth) - } + }, [scrollRef]) /** Performs a smooth scrolling animation to a specified target position. * Accepts a target scroll position and an optional callback to execute after completion. */ - const smoothScroll = useCallback((target: number, callback?: () => void) => { - if (!scrollRef.current) return + const smoothScroll = useCallback( + (target: number, callback?: () => void) => { + if (!scrollRef.current) return - const start = scrollRef.current.scrollLeft - const startTime = Date.now() + const start = scrollRef.current.scrollLeft + const startTime = Date.now() - const animateScroll = () => { - const now = Date.now() - const time = Math.min(1, (now - startTime) / duration) + const animateScroll = () => { + const now = Date.now() + const time = Math.min(1, (now - startTime) / duration) - scrollRef.current!.scrollLeft = start + time * (target - start) + scrollRef.current!.scrollLeft = start + time * (target - start) - if (time < 1) { - requestAnimationFrame(animateScroll) - } else { - checkArrowsVisibility() - if (callback) callback() // Execute callback after the scroll animation completes + if (time < 1) { + requestAnimationFrame(animateScroll) + } else { + checkArrowsVisibility() + if (callback) callback() // Execute callback after the scroll animation completes + } } - } - requestAnimationFrame(animateScroll) - }, []) + requestAnimationFrame(animateScroll) + }, + [checkArrowsVisibility, scrollRef] + ) /** Scrolls the container a fixed distance to the left or right with animation. */ const scrollLeft = () => { @@ -68,6 +72,7 @@ function useScrollBox(scrollRef: RefObject, cards: readonly bigi } /** Throttled function to update the last horizontal scroll position, minimizing performance impact. */ + // eslint-disable-next-line react-hooks/exhaustive-deps const handleLastScrollX = useCallback( throttle((screenX) => { setLastScrollX(screenX) @@ -76,12 +81,15 @@ function useScrollBox(scrollRef: RefObject, cards: readonly bigi ) /** Handles the wheel event to adjust the scrollLeft property, enabling horizontal scrolling. */ - const handleScroll = (e: WheelEvent) => { - if (scrollRef.current) { - // Adjust the scrollLeft property based on the deltaY value - scrollRef.current.scrollLeft += e.deltaY - } - } + const handleScroll = useCallback( + (e: WheelEvent) => { + if (scrollRef.current) { + // Adjust the scrollLeft property based on the deltaY value + scrollRef.current.scrollLeft += e.deltaY + } + }, + [scrollRef] + ) /** Responds to window resize events to update arrow visibility states. */ const handleResize = () => { @@ -99,6 +107,7 @@ function useScrollBox(scrollRef: RefObject, cards: readonly bigi smoothScroll(targetRight, () => { triggerLastCardGlow() }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [scrollRef]) const triggerLastCardGlow = useCallback(() => { @@ -133,7 +142,7 @@ function useScrollBox(scrollRef: RefObject, cards: readonly bigi } } } - }, [scrollWrapperCurrent, handleLastScrollX, lastScrollX]) + }, [scrollWrapperCurrent, handleLastScrollX, lastScrollX, scrollRef, checkArrowsVisibility, handleScroll]) // Detects changes in the `cards` array to trigger the pop-up effect and initiate smooth scrolling to highlight new content. useEffect(() => { diff --git a/packages/webapp/src/pages/_app.tsx b/packages/webapp/src/pages/_app.tsx index 6d8425c9..45ebf983 100644 --- a/packages/webapp/src/pages/_app.tsx +++ b/packages/webapp/src/pages/_app.tsx @@ -1,23 +1,26 @@ // ================================================================================================= // Must come first, so that can we can hook global members before they're used by imports. -import "src/setup" -import "src/store/setup" -import { ConnectKitProvider } from "connectkit" +import { ComponentType, useEffect } from "react" import { NextPage } from "next" import type { AppType } from "next/app" import Head from "next/head" +import { useRouter } from "next/router" + +import { ConnectKitProvider } from "connectkit" import { useAccount, WagmiConfig } from "wagmi" + import { ensureLocalAccountIndex, wagmiConfig } from "src/chain" import jotaiDebug from "src/components/lib/jotaiDebug" import { GlobalErrorModal } from "src/components/modals/globalErrorModal" +import { Toaster } from "src/components/ui/sonner" import { useIsHydrated } from "src/hooks/useIsHydrated" import { useErrorConfig } from "src/store/hooks" + import "src/styles/globals.css" -import { useRouter } from "next/router" -import { ComponentType, useEffect } from "react" -import { Toaster } from "src/components/ui/sonner" -import useOfflineCheck from "src/hooks/useOfflineCheck" + +import "src/setup" +import "src/store/setup" // ================================================================================================= @@ -29,11 +32,8 @@ export type FablePage = NextPage<{ isHydrated: boolean }> // ================================================================================================= - const MyApp: AppType = ({ Component, pageProps }) => { - - useOfflineCheck() - + useOfflineCheck() return ( <> @@ -96,4 +96,4 @@ const ComponentWrapper = ({ Component, pageProps }: { Component: ComponentType; ) } -// ================================================================================================= +// ================================================================================================= \ No newline at end of file diff --git a/packages/webapp/src/pages/collection.tsx b/packages/webapp/src/pages/collection.tsx index 4cc00f70..0cbeb5ec 100644 --- a/packages/webapp/src/pages/collection.tsx +++ b/packages/webapp/src/pages/collection.tsx @@ -1,23 +1,22 @@ -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 } from "react" +import debounce from "lodash/debounce" +import { navigate } from "utils/navigate" import { useAccount } from "wagmi" +import { Address } from "src/chain" +import CardCollectionDisplay from "src/components/collection/cardCollectionDisplay" +import DeckList from "src/components/collection/deckList" +import DeckPanel from "src/components/collection/deckPanel" +import FilterPanel from "src/components/collection/filterPanel" import jotaiDebug from "src/components/lib/jotaiDebug" import { Navbar } from "src/components/navbar" import { deployment } from "src/deployment" import { useInventoryCardsCollectionGetCollection } from "src/generated" -import { Deck, Card } from "src/store/types" -import { Address } from "src/chain" import { FablePage } from "src/pages/_app" -import { useRouter } from "next/router" -import { navigate } from "utils/navigate" - -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 { Card, Deck } from "src/store/types" // NOTE(norswap & geniusgarlic): Just an example, when the game actually has effects & types, // fetch those from the chain instead of hardcoding them here. @@ -165,9 +164,9 @@ const Collection: FablePage = ({ isHydrated }) => { {jotaiDebug()}
-
+
{/* Left Panel - Search and Filters */} -
+
{
{/* Middle Panel - Card Collection Display */} -
+
{
{/* Right Panel - Deck List */} -
+
{isEditing && currentDeck ? ( { const { address } = useAccount() @@ -38,7 +38,7 @@ const Home: FablePage = ({ isHydrated }) => { const isWrongNetwork = !notConnected && !chainSupported return ( -
+

0xFABLE @@ -48,7 +48,7 @@ const Home: FablePage = ({ isHydrated }) => {
diff --git a/packages/webapp/src/pages/play.tsx b/packages/webapp/src/pages/play.tsx index f8866e8c..d54fa94c 100644 --- a/packages/webapp/src/pages/play.tsx +++ b/packages/webapp/src/pages/play.tsx @@ -1,44 +1,45 @@ import { useCallback, useEffect, useState } from "react" - -import Hand from "src/components/hand" -import { LoadingModal } from "src/components/modals/loadingModal" -import { GameEndedModal } from "src/components/modals/gameEndedModal" -import { Navbar } from "src/components/navbar" -import * as store from "src/store/hooks" -import { CardPlacement, GameStatus, GameStep } from "src/store/types" -import { FablePage } from "src/pages/_app" -import { Address } from "viem" -import { readContract } from "wagmi/actions" -import { deployment } from "src/deployment" -import { gameABI } from "src/generated" +import { createPortal } from "react-dom" import { useRouter } from "next/router" -import { setError } from "src/store/write" -import { DISMISS_BUTTON } from "src/actions/errors" -import { navigate } from "src/utils/navigate" -import { concede } from "src/actions/concede" -import { drawCard } from "src/actions/drawCard" -import { endTurn } from "src/actions/endTurn" -import { currentPlayer, isEndingTurn } from "src/game/misc" -import { useCancellationHandler } from "src/hooks/useCancellationHandler" -import { usePlayerHand } from "src/store/hooks" + import { + closestCenter, + defaultDropAnimationSideEffects, DndContext, DragOverlay, DropAnimation, MeasuringStrategy, MouseSensor, UniqueIdentifier, - closestCenter, - defaultDropAnimationSideEffects, useSensor, useSensors, } from "@dnd-kit/core" -import PlayerBoard from "src/components/playerBoard" -import { createPortal } from "react-dom" -import useDragEvents from "src/hooks/useDragEvents" +import { toast } from "sonner" +import { Address } from "viem" +import { readContract } from "wagmi/actions" + +import { concede } from "src/actions/concede" +import { drawCard } from "src/actions/drawCard" +import { endTurn } from "src/actions/endTurn" +import { DISMISS_BUTTON } from "src/actions/errors" import CardContainer from "src/components/cards/cardContainer" +import Hand from "src/components/hand" +import { GameEndedModal } from "src/components/modals/gameEndedModal" +import { LoadingModal } from "src/components/modals/loadingModal" +import { Navbar } from "src/components/navbar" +import PlayerBoard from "src/components/playerBoard" import { Button } from "src/components/ui/button" -import { toast } from "sonner" +import { deployment } from "src/deployment" +import { currentPlayer, isEndingTurn } from "src/game/misc" +import { gameABI } from "src/generated" +import { useCancellationHandler } from "src/hooks/useCancellationHandler" +import useDragEvents from "src/hooks/useDragEvents" +import { FablePage } from "src/pages/_app" +import * as store from "src/store/hooks" +import { usePlayerHand } from "src/store/hooks" +import { CardPlacement, GameStatus, GameStep } from "src/store/types" +import { setError } from "src/store/write" +import { navigate } from "src/utils/navigate" const Play: FablePage = ({ isHydrated }) => { const [gameID, setGameID] = store.useGameID() @@ -229,7 +230,7 @@ const Play: FablePage = ({ isHydrated }) => { cards={playerHand as readonly bigint[]} setLoading={setLoading} cancellationHandler={cancellationHandler} - className={`absolute left-0 right-0 mx-auto z-[100] translate-y-1/2 transition-all duration-500 rounded-xl ease-in-out hover:translate-y-0`} + className={`absolute left-0 right-0 z-[100] mx-auto translate-y-1/2 rounded-xl transition-all duration-500 ease-in-out hover:translate-y-0`} />
@@ -239,7 +240,7 @@ const Play: FablePage = ({ isHydrated }) => { {showDrawButton && (