diff --git a/package-lock.json b/package-lock.json index 776a16f..7e623fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,10 +34,13 @@ "globals": "^16.5.0", "jsdom": "^29.0.1", "msw": "^2.12.14", + "enhanced-resolve": "^5.20.1", + "tapable": "^3.2.2", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1", - "vitest": "^4.1.1" + "vitest": "^4.1.1", + "esrecurse": "^4.3.0" } }, "node_modules/@adobe/css-tools": { @@ -1145,32 +1148,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, "node_modules/@eslint/object-schema": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", @@ -1776,6 +1753,19 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.60.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", @@ -1852,7 +1842,7 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT", - "optional": true, + "optional": true }, "node_modules/@sinclair/typebox": { "version": "0.34.49", @@ -1879,8 +1869,11 @@ }, "node_modules/@types/react-dom": { "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2180,15 +2173,6 @@ } } }, - "node_modules/@vitejs/plugin-react": { - "version": "5.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, "node_modules/@types/babel__traverse": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", @@ -2280,11 +2264,12 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=0.4.0" } }, "node_modules/acorn-jsx": { @@ -2292,14 +2277,27 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, "node_modules/ajv": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, "node_modules/@types/node": { "version": "24.12.0", @@ -2316,11 +2314,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } + "license": "Python-2.0" }, "node_modules/@types/react-copy-to-clipboard": { "version": "5.0.7", @@ -2332,26 +2326,12 @@ "@types/react": "*" } }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } + "license": "MIT" }, "node_modules/@types/statuses": { "version": "2.0.6", @@ -2624,6 +2604,8 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, @@ -2777,12 +2759,15 @@ }, "node_modules/dom-accessibility-api": { "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.302", + "version": "1.5.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz", + "integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==", "dev": true, "license": "ISC" }, @@ -2794,16 +2779,16 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.19.0", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.2", - "@vitest/utils": "4.1.2", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=10.13.0" } }, "node_modules/@vitest/spy": { @@ -2831,47 +2816,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2898,13 +2842,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -2925,13 +2862,6 @@ "node": ">=12" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, "node_modules/baseline-browser-mapping": { "version": "2.10.12", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", @@ -2967,13 +2897,13 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3050,9 +2980,17 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { @@ -3070,22 +3008,16 @@ }, "node_modules/esquery": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } }, "node_modules/chai": { "version": "6.2.2", @@ -3102,16 +3034,32 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tapable": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-3.2.2.tgz", + "integrity": "sha512-/Z5S0go9dnB6ZCTXrNPi3yA5FI0rLmnOkwJ9cY8kBceftH9EeIv4X7p2U2KAOLmZIOf6JfU69peAaUz7Kq7Nyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" } }, "node_modules/ci-info": { @@ -3200,13 +3148,6 @@ "dev": true, "license": "MIT" }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -3337,44 +3278,10 @@ "node": ">=8" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.328", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz", - "integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -3542,8 +3449,8 @@ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" + "engines": { + "node": ">= 4" } }, "node_modules/import-fresh": { @@ -3551,73 +3458,16 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=6" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/estraverse": { @@ -3678,20 +3528,6 @@ "node": ">=12.0.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -3803,6 +3639,8 @@ }, "node_modules/jiti": { "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -3810,6 +3648,8 @@ }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-yaml": { @@ -3923,33 +3763,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4208,47 +4021,16 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node": "*" } }, "node_modules/jsdom": { @@ -4322,13 +4104,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -4512,11 +4287,7 @@ "callsites": "^3.0.0" }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=6" } }, "node_modules/lightningcss-linux-arm64-musl": { @@ -4561,16 +4332,22 @@ }, "node_modules/path-to-regexp": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT" }, "node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { @@ -4579,11 +4356,10 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/lightningcss-win32-arm64-msvc": { @@ -4642,13 +4418,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4716,19 +4485,6 @@ "node": ">=4" } }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4901,19 +4657,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -4947,38 +4690,6 @@ "node": ">=8" } }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", @@ -5106,12 +4817,6 @@ "react": "^19.2.4" } }, - "node_modules/react-is": { - "version": "17.0.2", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -5191,16 +4896,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", diff --git a/package.json b/package.json index e605da3..157b831 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,13 @@ "globals": "^16.5.0", "jsdom": "^29.0.1", "msw": "^2.12.14", + "enhanced-resolve": "^5.20.1", + "tapable": "^3.2.2", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1", - "vitest": "^4.1.1" + "vitest": "^4.1.1", + "esrecurse": "^4.3.0" }, "msw": { "workerDirectory": [ diff --git a/src/components/ui/__tests__/__snapshots__/TimelineEntry.test.tsx.snap b/src/components/ui/__tests__/__snapshots__/TimelineEntry.test.tsx.snap deleted file mode 100644 index d6359ea..0000000 --- a/src/components/ui/__tests__/__snapshots__/TimelineEntry.test.tsx.snap +++ /dev/null @@ -1,388 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`TimelineEntry > handles missing optional fields gracefully 1`] = ` -
-
  • -
    -
    -

    - Basic entry -

    -
    -
    - -
    -
  • -
    -`; - -exports[`TimelineEntry > renders SDK-driven entry with transaction link 1`] = ` -
    -
  • -
    -
    - - Escrow Created - - -
    - -
    - - Escrow Funded - - -
    -
    -
    -
    - - John Doe - - - ( - adopter - ) - -
    -

    - Escrow created -

    -

    - Funds deposited successfully -

    -
    - -
    -
    -
    - -
    -
  • -
    -`; - -exports[`TimelineEntry > renders admin override entry correctly 1`] = ` -
    -
  • -
    -
    - - Escrow Funded - - -
    - -
    - - Funds Released - - -
    -
    -
    -
    - - Admin User - - - ( - administrator - ) - -
    -

    - Escrow created -

    -

    - Manual release due to completed custody -

    -
    - - Admin override - -
    -
    -
    - -
    -
  • -
    -`; - -exports[`TimelineEntry > renders regular entry correctly 1`] = ` -
    -
  • -
    -
    - - Escrow Created - - -
    -
    -
    -
    - - John Doe - - - ( - adopter - ) - -
    -

    - Escrow created -

    -

    - Initial escrow setup -

    -
    -
    - -
    -
  • -
    -`; diff --git a/src/main.tsx b/src/main.tsx index dbfee2f..e4fb881 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,7 +10,7 @@ async function bootstrap() { if (import.meta.env.VITE_MSW === 'true') { const { worker } = await import('./mocks/browser') await worker.start({ onUnhandledRequest: 'warn' }) - } + } createRoot(document.getElementById('root')!).render( diff --git a/src/mocks/handlers/dispute.ts b/src/mocks/handlers/dispute.ts index 8d239b8..aaabded 100644 --- a/src/mocks/handlers/dispute.ts +++ b/src/mocks/handlers/dispute.ts @@ -5,221 +5,229 @@ import type { Dispute, DisputeListResponse } from "../../types/dispute"; // ─── Seed data ──────────────────────────────────────────────────────────────── const MOCK_DISPUTES: Dispute[] = [ - { - id: "dispute-001", - adoptionId: "adoption-002", - raisedBy: "user-buyer-2", - reason: "misrepresentation", - description: "Pet's health condition was not accurately described in the listing.", - status: "open", - isOverdue: true, - pet: { id: "pet-1", name: "Max" }, - adopter: { id: "user-buyer-2", name: "Alice Smith" }, - shelter: { id: "user-shelter-1", name: "Happy Paws Shelter" }, - evidence: [ - { - id: "ev-001", - type: "document", - url: "/mock-files/vet-report-ev001.pdf", - submittedBy: "user-buyer-2", - submittedAt: "2026-03-23T11:00:00.000Z", - }, - ], - timeline: [ - { - event: "Dispute raised", - actor: "user-buyer-2", - timestamp: "2026-03-23T10:45:00.000Z", - }, - ], - resolution: null, - createdAt: "2026-03-23T10:45:00.000Z", - updatedAt: "2026-03-23T11:00:00.000Z", - }, - { - id: "dispute-002", - adoptionId: "adoption-004", - raisedBy: "user-buyer-6", - reason: "delayed_handover", - description: "Shelter did not physically hand over the pet at the agreed time.", - status: "under_review", - isOverdue: false, - pet: { id: "pet-2", name: "Bella" }, - adopter: { id: "user-buyer-6", name: "Bob Johnson" }, - shelter: { id: "user-shelter-2", name: "Rescue Dogs" }, - evidence: [], - timeline: [], - resolution: null, - createdAt: "2026-03-26T10:45:00.000Z", - updatedAt: "2026-03-26T10:45:00.000Z", - }, - { - id: "dispute-003", - adoptionId: "adoption-005", - raisedBy: "user-buyer-1", - reason: "other", - description: "Unspecified issues during escrow period.", - status: "resolved", - isOverdue: false, - pet: { id: "pet-3", name: "Charlie" }, - adopter: { id: "user-buyer-1", name: "Eve Williams" }, - shelter: { id: "user-shelter-3", name: "Safe Haven" }, - evidence: [], - timeline: [], - resolution: "Refunded to buyer", - createdAt: "2026-03-15T09:00:00.000Z", - updatedAt: "2026-03-20T10:00:00.000Z", - }, - { - id: "dispute-004", - adoptionId: "adoption-006", - raisedBy: "user-buyer-2", - reason: "misleading_photos", - description: "Not the same animal as shown.", - status: "open", - isOverdue: true, - pet: { id: "pet-4", name: "Luna" }, - adopter: { id: "user-buyer-2", name: "Alice Smith" }, - shelter: { id: "user-shelter-3", name: "Safe Haven" }, - evidence: [], - timeline: [], - resolution: null, - createdAt: "2026-03-20T10:45:00.000Z", - updatedAt: "2026-03-20T10:45:00.000Z", - }, + { + id: "dispute-001", + adoptionId: "adoption-002", + raisedBy: "user-buyer-2", + reason: "misrepresentation", + description: + "Pet's health condition was not accurately described in the listing.", + status: "open", + isOverdue: true, + pet: { id: "pet-1", name: "Max" }, + adopter: { id: "user-buyer-2", name: "Alice Smith" }, + shelter: { id: "user-shelter-1", name: "Happy Paws Shelter" }, + evidence: [ + { + id: "ev-001", + type: "document", + url: "/mock-files/vet-report-ev001.pdf", + submittedBy: "user-buyer-2", + submittedAt: "2026-03-23T11:00:00.000Z", + }, + ], + timeline: [ + { + event: "Dispute raised", + actor: "user-buyer-2", + timestamp: "2026-03-23T10:45:00.000Z", + }, + ], + resolution: null, + createdAt: "2026-03-23T10:45:00.000Z", + updatedAt: "2026-03-23T11:00:00.000Z", + }, + { + id: "dispute-002", + adoptionId: "adoption-004", + raisedBy: "user-buyer-6", + reason: "delayed_handover", + description: + "Shelter did not physically hand over the pet at the agreed time.", + status: "under_review", + isOverdue: false, + pet: { id: "pet-2", name: "Bella" }, + adopter: { id: "user-buyer-6", name: "Bob Johnson" }, + shelter: { id: "user-shelter-2", name: "Rescue Dogs" }, + evidence: [], + timeline: [], + resolution: null, + createdAt: "2026-03-26T10:45:00.000Z", + updatedAt: "2026-03-26T10:45:00.000Z", + }, + { + id: "dispute-003", + adoptionId: "adoption-005", + raisedBy: "user-buyer-1", + reason: "other", + description: "Unspecified issues during escrow period.", + status: "resolved", + isOverdue: false, + pet: { id: "pet-3", name: "Charlie" }, + adopter: { id: "user-buyer-1", name: "Eve Williams" }, + shelter: { id: "user-shelter-3", name: "Safe Haven" }, + evidence: [], + timeline: [], + resolution: "Refunded to buyer", + createdAt: "2026-03-15T09:00:00.000Z", + updatedAt: "2026-03-20T10:00:00.000Z", + }, + { + id: "dispute-004", + adoptionId: "adoption-006", + raisedBy: "user-buyer-2", + reason: "misleading_photos", + description: "Not the same animal as shown.", + status: "open", + isOverdue: true, + pet: { id: "pet-4", name: "Luna" }, + adopter: { id: "user-buyer-2", name: "Alice Smith" }, + shelter: { id: "user-shelter-3", name: "Safe Haven" }, + evidence: [], + timeline: [], + resolution: null, + createdAt: "2026-03-20T10:45:00.000Z", + updatedAt: "2026-03-20T10:45:00.000Z", + }, ]; // ─── Helpers ────────────────────────────────────────────────────────────────── function getDelay(request: Request): number { - return Number(new URL(request.url).searchParams.get("delay") ?? 0); + return Number(new URL(request.url).searchParams.get("delay") ?? 0); } // ─── Handlers ───────────────────────────────────────────────────────────────── export const disputeHandlers = [ - // GET /api/disputes — list all disputes with optional filters and pagination - http.get("/api/disputes", async ({ request }) => { - await delay(getDelay(request)); - const url = new URL(request.url); - - const statusParam = url.searchParams.get("status"); - const overdueParam = url.searchParams.get("overdue"); - const cursorParam = url.searchParams.get("cursor"); - - let results = MOCK_DISPUTES; - - // 1) Filter status - if (statusParam && statusParam !== "all") { - results = results.filter(d => d.status === statusParam); - } - - // 2) Filter overdue - if (overdueParam === "true") { - results = results.filter(d => d.isOverdue === true); - } - - // 3) Pagination (using ID as cursor for simplicity) - // Assume page size is 2 to make testing pagination easy - const pageSize = 2; - let startIndex = 0; - if (cursorParam) { - const index = results.findIndex(d => d.id === cursorParam); - if (index !== -1) { - startIndex = index + 1; // start after the cursor - } - } - - const data = results.slice(startIndex, startIndex + pageSize); - const lastItem = data[data.length - 1]; - - // Determine if there's more data - const nextCursor = (startIndex + pageSize < results.length && lastItem) ? lastItem.id : undefined; - - return HttpResponse.json({ - data, - nextCursor - }); - }), - - // GET /api/disputes/:id — get a single dispute with evidence and timeline - http.get("/api/disputes/:id", async ({ request, params }) => { - await delay(getDelay(request)); - const found = MOCK_DISPUTES.find((d) => d.id === params.id); - if (!found) { - return HttpResponse.json( - { message: `Dispute '${params.id}' not found` }, - { status: 404 }, - ); - } - return HttpResponse.json(found); - }), - - // POST /api/disputes — raise a new dispute - http.post("/api/disputes", async ({ request }) => { - await delay(getDelay(request)); - const body = (await request.json()) as { - adoptionId: string; - raisedBy: string; - reason: string; - description: string; - }; - const created: Dispute = { - id: `dispute-${Date.now()}`, - adoptionId: body.adoptionId, - raisedBy: body.raisedBy, - reason: body.reason, - description: body.description, - status: "open", - isOverdue: false, - pet: { id: "pet-new", name: "Unknown" }, - adopter: { id: "adopter-new", name: "Unknown" }, - shelter: { id: "shelter-new", name: "Unknown" }, - evidence: [], - timeline: [ - { - event: "Dispute raised", - actor: body.raisedBy, - timestamp: new Date().toISOString(), - }, - ], - resolution: null, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }; - MOCK_DISPUTES.push(created); - return HttpResponse.json(created, { status: 201 }); - }), - - // PATCH /api/disputes/:id/resolve — mark a dispute as resolved - http.patch("/api/disputes/:id/resolve", async ({ request, params }) => { - await delay(getDelay(request)); - const body = (await request.json()) as { resolution: string; resolvedBy: string }; - const index = MOCK_DISPUTES.findIndex((d) => d.id === params.id); - - if (index === -1) { - return HttpResponse.json({ message: "Not found" }, { status: 404 }); - } - - const base = MOCK_DISPUTES[index]; - const updated: Dispute = { - ...base, - id: params.id as string, - status: "resolved", - resolution: body.resolution, - timeline: [ - ...base.timeline, - { - event: `Resolved: ${body.resolution}`, - actor: body.resolvedBy, - timestamp: new Date().toISOString(), - }, - ], - updatedAt: new Date().toISOString(), - }; - - MOCK_DISPUTES[index] = updated; - - return HttpResponse.json(updated); - }), + // GET /api/disputes — list all disputes with optional filters and pagination + http.get("/api/disputes", async ({ request }) => { + await delay(getDelay(request)); + const url = new URL(request.url); + + const statusParam = url.searchParams.get("status"); + const overdueParam = url.searchParams.get("overdue"); + const cursorParam = url.searchParams.get("cursor"); + + let results = MOCK_DISPUTES; + + // 1) Filter status + if (statusParam && statusParam !== "all") { + results = results.filter((d) => d.status === statusParam); + } + + // 2) Filter overdue + if (overdueParam === "true") { + results = results.filter((d) => d.isOverdue === true); + } + + // 3) Pagination (using ID as cursor for simplicity) + // Assume page size is 2 to make testing pagination easy + const pageSize = 2; + let startIndex = 0; + if (cursorParam) { + const index = results.findIndex((d) => d.id === cursorParam); + if (index !== -1) { + startIndex = index + 1; // start after the cursor + } + } + + const data = results.slice(startIndex, startIndex + pageSize); + const lastItem = data[data.length - 1]; + + // Determine if there's more data + const nextCursor = + startIndex + pageSize < results.length && lastItem + ? lastItem.id + : undefined; + + return HttpResponse.json({ + data, + nextCursor, + }); + }), + + // GET /api/disputes/:id — get a single dispute with evidence and timeline + http.get("/api/disputes/:id", async ({ request, params }) => { + await delay(getDelay(request)); + const found = MOCK_DISPUTES.find((d) => d.id === params.id); + if (!found) { + return HttpResponse.json( + { message: `Dispute '${params.id}' not found` }, + { status: 404 }, + ); + } + return HttpResponse.json(found); + }), + + // POST /api/disputes — raise a new dispute + http.post("/api/disputes", async ({ request }) => { + await delay(getDelay(request)); + const body = (await request.json()) as { + adoptionId: string; + raisedBy: string; + reason: string; + description: string; + }; + const created: Dispute = { + id: `dispute-${Date.now()}`, + adoptionId: body.adoptionId, + raisedBy: body.raisedBy, + reason: body.reason, + description: body.description, + status: "open", + isOverdue: false, + pet: { id: "pet-new", name: "Unknown" }, + adopter: { id: "adopter-new", name: "Unknown" }, + shelter: { id: "shelter-new", name: "Unknown" }, + evidence: [], + timeline: [ + { + event: "Dispute raise", + actor: body.raisedBy, + timestamp: new Date().toISOString(), + }, + ], + resolution: null, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; + MOCK_DISPUTES.push(created); + return HttpResponse.json(created, { status: 201 }); + }), + + // PATCH /api/disputes/:id/resolve — mark a dispute as resolved + http.patch("/api/disputes/:id/resolve", async ({ request, params }) => { + await delay(getDelay(request)); + const body = (await request.json()) as { + resolution: string; + resolvedBy: string; + }; + const index = MOCK_DISPUTES.findIndex((d) => d.id === params.id); + + if (index === -1) { + return HttpResponse.json({ message: "Not found" }, { status: 404 }); + } + + const base = MOCK_DISPUTES[index]; + const updated: Dispute = { + ...base, + id: params.id as string, + status: "resolved", + resolution: body.resolution, + timeline: [ + ...base.timeline, + { + event: `Resolved: ${body.resolution}`, + actor: body.resolvedBy, + timestamp: new Date().toISOString(), + }, + ], + updatedAt: new Date().toISOString(), + }; + + MOCK_DISPUTES[index] = updated; + + return HttpResponse.json(updated); + }), ];