From 7610053893f230920da67a074e28cd6ec708c500 Mon Sep 17 00:00:00 2001 From: KillT Date: Thu, 14 May 2026 14:55:20 +0700 Subject: [PATCH] fix(unstake): prevent double execution of unstake button by disabling button while submitting --- package-lock.json | 81 ++++++++++--------- package.json | 6 +- .../unstake/unstake_bundle_form.tsx | 11 ++- src/version.json | 2 +- tsconfig.json | 18 ++++- 5 files changed, 69 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index b919b483..579782f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,8 +55,8 @@ "@typechain/ethers-v5": "^11.1.2", "@types/canvas-confetti": "^1.9.0", "@types/jest": "^29.5.14", - "@types/node": "^22", - "@types/react": "^18.3.12", + "@types/node": "22.19.19", + "@types/react": "18.3.28", "@types/react-blockies": "^1.4.4", "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "^7.16.0", @@ -66,7 +66,7 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "typechain": "^8.3.2", - "typescript": "^5.7.2" + "typescript": "5.9.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -4479,12 +4479,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/parse-json": { @@ -4504,12 +4505,13 @@ "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-blockies": { @@ -7052,9 +7054,10 @@ "dev": true }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -14936,10 +14939,11 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15000,10 +15004,11 @@ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" }, "node_modules/unenv": { "version": "1.10.0", @@ -18673,12 +18678,12 @@ "dev": true }, "@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, "requires": { - "undici-types": "~6.20.0" + "undici-types": "~6.21.0" } }, "@types/parse-json": { @@ -18698,12 +18703,12 @@ "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" }, "@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "requires": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "@types/react-blockies": { @@ -20626,9 +20631,9 @@ } }, "csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, "damerau-levenshtein": { "version": "1.0.8", @@ -26297,9 +26302,9 @@ } }, "typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true }, "typical": { @@ -26344,9 +26349,9 @@ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" }, "undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true }, "unenv": { diff --git a/package.json b/package.json index b6ed8c55..04855ccf 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,8 @@ "@typechain/ethers-v5": "^11.1.2", "@types/canvas-confetti": "^1.9.0", "@types/jest": "^29.5.14", - "@types/node": "^22", - "@types/react": "^18.3.12", + "@types/node": "22.19.19", + "@types/react": "18.3.28", "@types/react-blockies": "^1.4.4", "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "^7.16.0", @@ -73,6 +73,6 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "typechain": "^8.3.2", - "typescript": "^5.7.2" + "typescript": "5.9.3" } } diff --git a/src/components/unstake/unstake_bundle_form.tsx b/src/components/unstake/unstake_bundle_form.tsx index 79a45efd..1662b7d7 100644 --- a/src/components/unstake/unstake_bundle_form.tsx +++ b/src/components/unstake/unstake_bundle_form.tsx @@ -2,7 +2,7 @@ import { Alert, Button, Checkbox, FormControlLabel, Grid, InputAdornment, TextFi import { BigNumber } from "ethers"; import { parseEther } from "ethers/lib/utils"; import { useTranslation } from "next-i18next"; -import { useEffect, useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Controller, SubmitHandler, useForm } from "react-hook-form"; import { useDispatch, useSelector } from "react-redux"; import { BundleInfo } from "../../backend/bundle_info"; @@ -99,14 +99,19 @@ export default function UnstakeBundleForm(props: UnstakeBundleFormProps) { dispatch(setStep(1)); } + const [isSubmitting, setIsSubmitting] = useState(false); + const onSubmit: SubmitHandler = async data => { + if (isSubmitting) return; + setIsSubmitting(true); const values = getValues(); if ((values.unstakedAmount && errors.unstakedAmount === undefined) || values.unstakeMaxAmount) { const unstakedAmount = parseEther(values.unstakedAmount); const unstakeMaxAmount = values.unstakeMaxAmount; - props.unstake(unstakedAmount, selectedNft!.nftId, unstakeMaxAmount, props.bundle) + await props.unstake(unstakedAmount, selectedNft!.nftId, unstakeMaxAmount, props.bundle) } + setIsSubmitting(false); } return (<> @@ -177,7 +182,7 @@ export default function UnstakeBundleForm(props: UnstakeBundleFormProps) { type="submit" variant="contained" color="primary" - disabled={! canSubmit} + disabled={! canSubmit || isSubmitting} > {t('action.unstake')} diff --git a/src/version.json b/src/version.json index 43b8efee..5cf914cd 100644 --- a/src/version.json +++ b/src/version.json @@ -1 +1 @@ -{ "name": "staking-ui", "version": "dev", "date": "202T-0D-A1" } \ No newline at end of file +{"name": "staking-ui", "version": "1.1.19", "date": "2026-05-14" } diff --git a/tsconfig.json b/tsconfig.json index 99710e85..c55ec971 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -9,12 +13,18 @@ "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] }