diff --git a/package-lock.json b/package-lock.json index 2359c83..afe3723 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,11 @@ "version": "2.2.0", "license": "MIT", "dependencies": { - "@codesandbox/sandpack-react": "2.14.0", + "@codesandbox/sandpack-react": "2.14.2", "@leanstacks/react-common": "1.0.0", "@react-spring/web": "9.7.3", - "@tanstack/react-query": "5.40.1", - "@tanstack/react-query-devtools": "5.40.1", + "@tanstack/react-query": "5.45.0", + "@tanstack/react-query-devtools": "5.45.0", "@tanstack/react-table": "8.17.3", "axios": "1.7.2", "classnames": "2.5.1", @@ -27,21 +27,21 @@ "react-dom": "18.3.1", "react-i18next": "14.1.2", "react-router-dom": "6.23.1", - "tailwindcss": "3.4.3", - "uuid": "9.0.1", + "tailwindcss": "3.4.4", + "uuid": "10.0.0", "yup": "1.4.0" }, "devDependencies": { "@testing-library/react": "16.0.0", "@testing-library/user-event": "14.5.2", - "@types/lodash": "4.17.4", + "@types/lodash": "4.17.5", "@types/qs": "6.9.15", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "@types/uuid": "9.0.8", - "@typescript-eslint/eslint-plugin": "7.12.0", - "@typescript-eslint/parser": "7.12.0", - "@vitejs/plugin-react": "4.3.0", + "@typescript-eslint/eslint-plugin": "7.13.0", + "@typescript-eslint/parser": "7.13.0", + "@vitejs/plugin-react": "4.3.1", "@vitest/coverage-v8": "1.6.0", "autoprefixer": "10.4.19", "eslint": "8.57.0", @@ -50,10 +50,10 @@ "jsdom": "24.1.0", "msw": "2.3.1", "postcss": "8.4.38", - "prettier": "3.3.0", - "prettier-plugin-tailwindcss": "0.6.1", + "prettier": "3.3.2", + "prettier-plugin-tailwindcss": "0.6.4", "typescript": "5.4.5", - "vite": "5.2.12", + "vite": "5.3.1", "vitest": "1.6.0" } }, @@ -620,9 +620,9 @@ "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==" }, "node_modules/@codesandbox/sandpack-react": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/@codesandbox/sandpack-react/-/sandpack-react-2.14.0.tgz", - "integrity": "sha512-JZvvAnNqmFUFpobS05G1NzYFNQ3TUiT+BU6oBc4VVZp/5A0PR/8OoD/v8sgp1zZV2OY5eDR2nEoyB902yWZBuA==", + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/@codesandbox/sandpack-react/-/sandpack-react-2.14.2.tgz", + "integrity": "sha512-6yuy98zNqtwhQYZR7hg62s7SX5n4UejCtYJXW4TTa8xjfGSxICexx2j4Ub8ebgDLo3gCLl9ZKoMkaf+ZCQ6s3w==", "dependencies": { "@codemirror/autocomplete": "^6.4.0", "@codemirror/commands": "^6.1.3", @@ -679,9 +679,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -695,9 +695,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -711,9 +711,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -727,9 +727,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -743,9 +743,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -759,9 +759,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -775,9 +775,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -791,9 +791,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -807,9 +807,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -823,9 +823,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -839,9 +839,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -855,9 +855,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -871,9 +871,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -887,9 +887,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -903,9 +903,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -919,9 +919,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -935,9 +935,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -951,9 +951,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -967,9 +967,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -983,9 +983,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -999,9 +999,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -1015,9 +1015,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -1031,9 +1031,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -1924,9 +1924,9 @@ "integrity": "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==" }, "node_modules/@tanstack/query-core": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.40.0.tgz", - "integrity": "sha512-eD8K8jsOIq0Z5u/QbvOmfvKKE/XC39jA7yv4hgpl/1SRiU+J8QCIwgM/mEHuunQsL87dcvnHqSVLmf9pD4CiaA==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.45.0.tgz", + "integrity": "sha512-RVfIZQmFUTdjhSAAblvueimfngYyfN6HlwaJUPK71PKd7yi43Vs1S/rdimmZedPWX/WGppcq/U1HOj7O7FwYxw==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -1942,11 +1942,11 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.40.1.tgz", - "integrity": "sha512-gOcmu+gpFd2taHrrgMM9RemLYYEDYfsCqszxCC0xtx+csDa4R8t7Hr7SfWXQP13S2sF+mOxySo/+FNXJFYBqcA==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.45.0.tgz", + "integrity": "sha512-y272cKRJp1BvehrWG4ashOBuqBj1Qm2O6fgYJ9LYSHrLdsCXl74GbSVjUQTReUdHuRIl9cEOoyPa6HYag400lw==", "dependencies": { - "@tanstack/query-core": "5.40.0" + "@tanstack/query-core": "5.45.0" }, "funding": { "type": "github", @@ -1957,9 +1957,9 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.40.1.tgz", - "integrity": "sha512-/AN2UsbuL+28/KSlBkVHq/4chHTEp4l2UWTKWixXbn4pprLQrZGmQTAKN4tYxZDuNwNZY5+Zp67pDfXj+F/UBA==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.45.0.tgz", + "integrity": "sha512-bYHKCBQxRYQgQPPt+OdxJxoGag8SyPYxFxUsTHXERPnhD99I8iUV39XGYePyxKv5b3oME4fM1e8AgQ1aPxTQ6w==", "dependencies": { "@tanstack/query-devtools": "5.37.1" }, @@ -1968,7 +1968,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.40.1", + "@tanstack/react-query": "^5.45.0", "react": "^18 || ^19" } }, @@ -2237,9 +2237,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==", + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", "dev": true }, "node_modules/@types/mute-stream": { @@ -2308,16 +2308,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", - "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", + "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/type-utils": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/type-utils": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2341,15 +2341,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", - "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", + "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4" }, "engines": { @@ -2369,13 +2369,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", - "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2386,13 +2386,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", - "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", + "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/utils": "7.13.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2413,9 +2413,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", - "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2426,13 +2426,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", - "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2454,15 +2454,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", - "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0" + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2476,12 +2476,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", - "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2499,9 +2499,9 @@ "dev": true }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.0.tgz", - "integrity": "sha512-KcEbMsn4Dpk+LIbHMj7gDPRKaTMStxxWRkRmxsg/jVdFdJCZWt1SchZcf0M4t8lIKdwwMsEyzhrcOXRrDPtOBw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", + "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", "dev": true, "dependencies": { "@babel/core": "^7.24.5", @@ -3646,9 +3646,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -3658,29 +3658,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -5762,9 +5762,9 @@ } }, "node_modules/prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", - "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -5777,9 +5777,9 @@ } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.1.tgz", - "integrity": "sha512-AnbeYZu0WGj+QgKciUgdMnRxrqcxltleZPgdwfA5104BHM3siBLONN/HLW1yS2HvzSNkzpQ/JAj+LN0jcJO+0w==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.4.tgz", + "integrity": "sha512-3vhbIvlKyAWPaw9bUr2cw6M1BGx2Oy9CCLJyv+nxEiBGCTcL69WcAz2IFMGqx8IXSzQCInGSo2ujAByg9poHLQ==", "dev": true, "engines": { "node": ">=14.21.3" @@ -6552,9 +6552,9 @@ "dev": true }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -6934,9 +6934,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -6953,12 +6953,12 @@ "peer": true }, "node_modules/vite": { - "version": "5.2.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz", - "integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.20.1", + "esbuild": "^0.21.3", "postcss": "^8.4.38", "rollup": "^4.13.0" }, diff --git a/package.json b/package.json index 41d2c12..601ee4f 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,11 @@ "test:ci": "vitest run --coverage --silent" }, "dependencies": { - "@codesandbox/sandpack-react": "2.14.0", + "@codesandbox/sandpack-react": "2.14.2", "@leanstacks/react-common": "1.0.0", "@react-spring/web": "9.7.3", - "@tanstack/react-query": "5.40.1", - "@tanstack/react-query-devtools": "5.40.1", + "@tanstack/react-query": "5.45.0", + "@tanstack/react-query-devtools": "5.45.0", "@tanstack/react-table": "8.17.3", "axios": "1.7.2", "classnames": "2.5.1", @@ -40,21 +40,21 @@ "react-dom": "18.3.1", "react-i18next": "14.1.2", "react-router-dom": "6.23.1", - "tailwindcss": "3.4.3", - "uuid": "9.0.1", + "tailwindcss": "3.4.4", + "uuid": "10.0.0", "yup": "1.4.0" }, "devDependencies": { "@testing-library/react": "16.0.0", "@testing-library/user-event": "14.5.2", - "@types/lodash": "4.17.4", + "@types/lodash": "4.17.5", "@types/qs": "6.9.15", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "@types/uuid": "9.0.8", - "@typescript-eslint/eslint-plugin": "7.12.0", - "@typescript-eslint/parser": "7.12.0", - "@vitejs/plugin-react": "4.3.0", + "@typescript-eslint/eslint-plugin": "7.13.0", + "@typescript-eslint/parser": "7.13.0", + "@vitejs/plugin-react": "4.3.1", "@vitest/coverage-v8": "1.6.0", "autoprefixer": "10.4.19", "eslint": "8.57.0", @@ -63,10 +63,10 @@ "jsdom": "24.1.0", "msw": "2.3.1", "postcss": "8.4.38", - "prettier": "3.3.0", - "prettier-plugin-tailwindcss": "0.6.1", + "prettier": "3.3.2", + "prettier-plugin-tailwindcss": "0.6.4", "typescript": "5.4.5", - "vite": "5.2.12", + "vite": "5.3.1", "vitest": "1.6.0" } } diff --git a/src/pages/UsersPage/api/__tests__/useUpdateTask.test.ts b/src/pages/UsersPage/api/__tests__/useUpdateTask.test.ts new file mode 100644 index 0000000..9c105ee --- /dev/null +++ b/src/pages/UsersPage/api/__tests__/useUpdateTask.test.ts @@ -0,0 +1,84 @@ +import { describe, expect, it } from 'vitest'; + +import { renderHook, waitFor } from 'test/test-utils'; +import { queryClient } from 'test/query-client'; +import { todosFixture } from '__fixtures__/todos'; +import { QueryKeys } from 'utils/constants'; +import { Task } from '../useGetUserTasks'; + +import { useUpdateTask } from '../useUpdateTask'; + +describe('useUpdateTask', () => { + it('should update task', async () => { + // ARRANGE + const updatedTask = todosFixture[0]; + let isSuccess = false; + const { result } = renderHook(() => useUpdateTask()); + await waitFor(() => expect(result.current).not.toBeNull()); + + // ACT + result.current.mutate( + { task: updatedTask }, + { + onSuccess: () => { + isSuccess = true; + }, + }, + ); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // ASSERT + expect(isSuccess).toBe(true); + }); + + it('should create cached data when none exists', async () => { + // ARRANGE + const updatedTask = todosFixture[0]; + let isSuccess = false; + const { result } = renderHook(() => useUpdateTask()); + await waitFor(() => expect(result.current).not.toBeNull()); + + // ACT + result.current.mutate( + { task: updatedTask }, + { + onSuccess: () => { + isSuccess = true; + }, + }, + ); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // ASSERT + expect(isSuccess).toBe(true); + expect(queryClient.getQueryData([QueryKeys.Tasks, { userId: updatedTask.userId }])).toEqual([ + updatedTask, + ]); + }); + + it('should update cached data when exists', async () => { + // ARRANGE + const updatedTask = todosFixture[0]; + queryClient.setQueryData([QueryKeys.Tasks, { userId: updatedTask.userId }], todosFixture); + let isSuccess = false; + const { result } = renderHook(() => useUpdateTask()); + await waitFor(() => expect(result.current).not.toBeNull()); + + // ACT + result.current.mutate( + { task: updatedTask }, + { + onSuccess: () => { + isSuccess = true; + }, + }, + ); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // ASSERT + expect(isSuccess).toBe(true); + expect( + queryClient.getQueryData([QueryKeys.Tasks, { userId: updatedTask.userId }])?.length, + ).toEqual(todosFixture.length); + }); +}); diff --git a/src/pages/UsersPage/api/useUpdateTask.ts b/src/pages/UsersPage/api/useUpdateTask.ts new file mode 100644 index 0000000..3ff1471 --- /dev/null +++ b/src/pages/UsersPage/api/useUpdateTask.ts @@ -0,0 +1,52 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import reject from 'lodash/reject'; + +import { QueryKeys } from 'utils/constants'; +import { Task } from './useGetUserTasks'; +import { useConfig } from 'hooks/useConfig'; +import { useAxios } from 'hooks/useAxios'; + +/** + * The `useUpdateTask` mutation function variables. + */ +export type UpdateTaskVariables = { + task: Task; +}; + +/** + * An API hook which updates a single `Task`. Returns a `UseMutationResult` + * object whose `mutate` attribute is a function to update as `Task`. + * + * When successful, the hook updates cached `Task` query data. + * @returns Returns a `UseMutationResult`. + */ +export const useUpdateTask = () => { + const queryClient = useQueryClient(); + const config = useConfig(); + const axios = useAxios(); + + /** + * Update a `Task`. + * @param {UpdateTaskVariables} variables - The mutation function variables. + * @returns The updated `Task` object. + */ + const updateTask = async ({ task }: UpdateTaskVariables): Promise => { + const response = await axios.request({ + method: 'put', + url: `${config.VITE_BASE_URL_API}/todos/${task.id}`, + data: task, + }); + return response.data; + }; + + return useMutation({ + mutationFn: updateTask, + onSuccess: (data, variables) => { + // update cached query data + queryClient.setQueryData( + [QueryKeys.Tasks, { userId: variables.task.userId }], + (cachedTasks) => (cachedTasks ? [...reject(cachedTasks, { id: data.id }), data] : [data]), + ); + }, + }); +}; diff --git a/src/pages/UsersPage/components/TaskCompleteToggle.tsx b/src/pages/UsersPage/components/TaskCompleteToggle.tsx new file mode 100644 index 0000000..ce1c5ab --- /dev/null +++ b/src/pages/UsersPage/components/TaskCompleteToggle.tsx @@ -0,0 +1,86 @@ +import { + Button, + ButtonVariant, + PropsWithClassName, + PropsWithTestId, +} from '@leanstacks/react-common'; +import classNames from 'classnames'; +import { useTranslation } from 'react-i18next'; + +import { Task } from '../api/useGetUserTasks'; +import { useUpdateTask } from '../api/useUpdateTask'; +import { useToasts } from 'hooks/useToasts'; +import Icon from 'components/Icon/Icon'; + +/** + * Propeties for the`TaskCompleteToggle` component. + * @param {Task} task - A Task object. + * @see {@link PropsWithClassName} + * @see {@link PropsWithTestId} + */ +interface TaskCompleteToggleProps extends PropsWithClassName, PropsWithTestId { + task: Task; +} + +/** + * The `TaskCompleteToggle` component renders a `Button` which allows a user + * to toggle the value of the Task `complete` attribute. + * @param {TaskCompleteToggleProps} props - Component properties. + * @returns {JSX.Element} JSX + */ +const TaskCompleteToggle = ({ + className, + task, + testId = 'toggle-task-complete', +}: TaskCompleteToggleProps): JSX.Element => { + const { t } = useTranslation(); + const { mutate: updateTask } = useUpdateTask(); + const { createToast } = useToasts(); + + const buttonTitle = task.completed + ? t('task.markIncomplete', { ns: 'users' }) + : t('task.markComplete', { ns: 'users' }); + + /** + * Actions to perform when the task complete toggle button is clicked. + */ + const handleButtonClick = () => { + updateTask( + { + task: { + ...task, + completed: !task.completed, + }, + }, + { + onSuccess: (data) => { + createToast({ + text: data.completed + ? t('task.markedComplete', { ns: 'users' }) + : t('task.markedIncomplete', { ns: 'users' }), + isAutoDismiss: true, + }); + }, + }, + ); + }; + + return ( + + ); +}; + +export default TaskCompleteToggle; diff --git a/src/pages/UsersPage/components/UserTaskListItem.tsx b/src/pages/UsersPage/components/UserTaskListItem.tsx index 6a224ed..2fe8486 100644 --- a/src/pages/UsersPage/components/UserTaskListItem.tsx +++ b/src/pages/UsersPage/components/UserTaskListItem.tsx @@ -1,8 +1,7 @@ import { PropsWithClassName, PropsWithTestId } from '@leanstacks/react-common'; import { Task } from '../api/useGetUserTasks'; -import Icon from 'components/Icon/Icon'; -import classNames from 'classnames'; +import TaskCompleteToggle from './TaskCompleteToggle'; /** * Properties for the `UserTaskListItem` React component. @@ -28,12 +27,7 @@ const UserTaskListItem = ({ return (
- +
{task.title}
diff --git a/src/pages/UsersPage/components/__tests__/TaskCompleteToggle.test.tsx b/src/pages/UsersPage/components/__tests__/TaskCompleteToggle.test.tsx new file mode 100644 index 0000000..27e96ab --- /dev/null +++ b/src/pages/UsersPage/components/__tests__/TaskCompleteToggle.test.tsx @@ -0,0 +1,109 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import userEvent from '@testing-library/user-event'; + +import { render, screen } from 'test/test-utils'; +import { todosFixture } from '__fixtures__/todos'; +import * as UseToasts from 'hooks/useToasts'; + +import TaskCompleteToggle from '../TaskCompleteToggle'; + +describe('TaskCompleteToggle', () => { + const incompleteTask = todosFixture[0]; + const completeTask = todosFixture[1]; + + const useToastsSpy = vi.spyOn(UseToasts, 'useToasts'); + const mockCreateToast = vi.fn(); + + beforeEach(() => { + useToastsSpy.mockReturnValue({ + createToast: mockCreateToast, + removeToast: vi.fn(), + toasts: [], + }); + }); + + it('should render successfully', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + + // ASSERT + expect(screen.getByTestId('toggle-task-complete')).toBeDefined(); + }); + + it('should use custom testId', async () => { + // ARRANGE + render(); + await screen.findByTestId('custom-testId'); + + // ASSERT + expect(screen.getByTestId('custom-testId')).toBeDefined(); + }); + + it('should use custom className', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + + // ASSERT + expect(screen.getByTestId('toggle-task-complete').classList).toContain('custom-className'); + }); + + it('should render incomplete task', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + + // ASSERT + expect(screen.getByTestId('toggle-task-complete')).toBeDefined(); + expect(screen.getByTestId('toggle-task-complete').title).toBe('Mark complete'); + expect(screen.getByTestId('toggle-task-complete-icon').textContent).toBe('circle'); + }); + + it('should render complete task', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + + // ASSERT + expect(screen.getByTestId('toggle-task-complete')).toBeDefined(); + expect(screen.getByTestId('toggle-task-complete').title).toBe('Mark incomplete'); + expect(screen.getByTestId('toggle-task-complete-icon').textContent).toBe('task_alt'); + }); + + it('should toggle task complete when clicked', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + expect(screen.getByTestId('toggle-task-complete').title).toBe('Mark complete'); + expect(screen.getByTestId('toggle-task-complete-icon').textContent).toBe('circle'); + + // ACT + await userEvent.click(screen.getByTestId('toggle-task-complete')); + + // ASSERT + expect(mockCreateToast).toHaveBeenCalledOnce(); + expect(mockCreateToast).toHaveBeenCalledWith({ + text: 'Marked task complete', + isAutoDismiss: true, + }); + }); + + it('should toggle task incomplete when clicked', async () => { + // ARRANGE + render(); + await screen.findByTestId('toggle-task-complete'); + expect(screen.getByTestId('toggle-task-complete').title).toBe('Mark incomplete'); + expect(screen.getByTestId('toggle-task-complete-icon').textContent).toBe('task_alt'); + + // ACT + await userEvent.click(screen.getByTestId('toggle-task-complete')); + + // ASSERT + expect(mockCreateToast).toHaveBeenCalledOnce(); + expect(mockCreateToast).toHaveBeenCalledWith({ + text: 'Marked task incomplete', + isAutoDismiss: true, + }); + }); +}); diff --git a/src/pages/UsersPage/components/__tests__/UserTaskListItem.test.tsx b/src/pages/UsersPage/components/__tests__/UserTaskListItem.test.tsx index c1560ad..09042ff 100644 --- a/src/pages/UsersPage/components/__tests__/UserTaskListItem.test.tsx +++ b/src/pages/UsersPage/components/__tests__/UserTaskListItem.test.tsx @@ -43,6 +43,8 @@ describe('UserTaskListItem', () => { await screen.findByTestId('user-task-list-item'); // ASSERT - expect(screen.getByTestId('user-task-list-item-icon').textContent).toBe('task_alt'); + expect(screen.getByTestId('user-task-list-item-toggle-complete-icon').textContent).toBe( + 'task_alt', + ); }); }); diff --git a/src/test/mocks/handlers.ts b/src/test/mocks/handlers.ts index 3b108b8..029174e 100644 --- a/src/test/mocks/handlers.ts +++ b/src/test/mocks/handlers.ts @@ -7,9 +7,11 @@ import { todosFixture } from '__fixtures__/todos'; export const handlers = [ http.get('https://jsonplaceholder.typicode.com/users', () => { + // get all users return HttpResponse.json(usersFixture); }), http.get('https://jsonplaceholder.typicode.com/users/:userId', ({ params }) => { + // get a user by identifier const { userId } = params; const user = find(usersFixture, { id: Number(userId) }); if (user) { @@ -18,8 +20,20 @@ export const handlers = [ return new HttpResponse(null, { status: 404 }); }), http.get('https://jsonplaceholder.typicode.com/users/:userId/todos', ({ params }) => { + // get all tasks(todos) for a user const { userId } = params; const todos = filter(todosFixture, { userId: Number(userId) }); return HttpResponse.json(todos); }), + http.put('https://jsonplaceholder.typicode.com/todos/:todoId', async ({ params, request }) => { + // update a task + const { todoId } = params; + const todo = find(todosFixture, { id: Number(todoId) }); + if (todo) { + // return the request body as the response + const requestBody = await request.json(); + return HttpResponse.json(requestBody); + } + return new HttpResponse(null, { status: 404 }); + }), ]; diff --git a/src/utils/i18n/locales/en/users.json b/src/utils/i18n/locales/en/users.json index 4910b8c..be73456 100644 --- a/src/utils/i18n/locales/en/users.json +++ b/src/utils/i18n/locales/en/users.json @@ -5,6 +5,10 @@ "errors": { "fetchingList": "A problem occurred fetching your tasks." }, + "markComplete": "Mark complete", + "markIncomplete": "Mark incomplete", + "markedComplete": "Marked task complete", + "markedIncomplete": "Marked task incomplete", "tasks": "tasks", "toComplete": "You have {{val}} tasks to complete." } diff --git a/src/utils/i18n/locales/es/users.json b/src/utils/i18n/locales/es/users.json index 578dbf3..743a290 100644 --- a/src/utils/i18n/locales/es/users.json +++ b/src/utils/i18n/locales/es/users.json @@ -5,6 +5,10 @@ "errors": { "fetchingList": "Ocurrió un problema al recuperar tus tareas." }, + "markComplete": "Márcalo completo", + "markIncomplete": "Márcalo como incompleto", + "markedComplete": "Tarea marcada completada", + "markedIncomplete": "Tarea marcada como incompleta", "tasks": "tareas", "toComplete": "Tienes {{val}} tarea para completar." } diff --git a/src/utils/i18n/locales/fr/users.json b/src/utils/i18n/locales/fr/users.json index 27e0541..0df7345 100644 --- a/src/utils/i18n/locales/fr/users.json +++ b/src/utils/i18n/locales/fr/users.json @@ -5,6 +5,10 @@ "errors": { "fetchingList": "Un problème est survenu lors de la récupération de vos tâches." }, + "markComplete": "Marquez-le comme terminé", + "markIncomplete": "Marquez-le comme incomplet", + "markedComplete": "Tâche marquée terminée", + "markedIncomplete": "Tâche marquée incomplète", "tasks": "tâches", "toComplete": "Vous avez {{val}} tâche à accomplir." }