Compare commits

...

4 Commits

Author SHA1 Message Date
Elisiário Couto
81d7d16301 fix(frontend): Add index signature to PieDataPoint interface.
Resolves TypeScript error where PieDataPoint[] was not assignable to
ChartDataInput[] by adding the required string index signature.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-16 18:30:36 +01:00
Elisiário Couto
84e609a774 refactor(frontend): Replace LoadingSpinner with shadcn skeleton components.
- Created AccountsSkeleton.tsx and NotificationsSkeleton.tsx components
- Updated AccountsOverview.tsx and Notifications.tsx to use skeletons
- Removed unused LoadingSpinner.tsx component
- Improved loading state UX by showing content structure

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-16 18:30:36 +01:00
copilot-swe-agent[bot]
fb310a5953 fix(frontend): Resolve linting issue in skeleton component
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
2025-09-16 18:30:36 +01:00
copilot-swe-agent[bot]
c83386b1d5 feat(frontend): Complete shadcn migration of skeleton and styling components
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
2025-09-16 18:30:36 +01:00
19 changed files with 763 additions and 373 deletions

View File

@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-select": "^2.2.6", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
@@ -29,6 +30,7 @@
"react-day-picker": "^9.10.0", "react-day-picker": "^9.10.0",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"recharts": "^3.2.0", "recharts": "^3.2.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"
@@ -1637,6 +1639,30 @@
} }
} }
}, },
"node_modules/@radix-ui/react-progress": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz",
"integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-primitive": "2.1.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-select": { "node_modules/@radix-ui/react-select": {
"version": "2.2.6", "version": "2.2.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
@@ -1897,9 +1923,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz",
"integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1911,9 +1937,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz",
"integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1925,9 +1951,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz",
"integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1939,9 +1965,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz",
"integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1953,9 +1979,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz",
"integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1967,9 +1993,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz",
"integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1981,9 +2007,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz",
"integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1995,9 +2021,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz",
"integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2009,9 +2035,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz",
"integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2023,9 +2049,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz",
"integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2036,10 +2062,10 @@
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz",
"integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -2051,9 +2077,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-ppc64-gnu": { "node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz",
"integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -2065,9 +2091,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz",
"integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -2079,9 +2105,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz",
"integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -2093,9 +2119,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz",
"integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -2107,9 +2133,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz",
"integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2121,9 +2147,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz",
"integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2135,9 +2161,9 @@
] ]
}, },
"node_modules/@rollup/rollup-openharmony-arm64": { "node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz",
"integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2149,9 +2175,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz",
"integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2163,9 +2189,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz",
"integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -2177,9 +2203,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz",
"integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2228,9 +2254,9 @@
} }
}, },
"node_modules/@tanstack/query-core": { "node_modules/@tanstack/query-core": {
"version": "5.87.4", "version": "5.89.0",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.87.4.tgz", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz",
"integrity": "sha512-uNsg6zMxraEPDVO2Bn+F3/ctHi+Zsk+MMpcN8h6P7ozqD088F6mFY5TfGM7zuyIrL7HKpDyu6QHfLWiDxh3cuw==", "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",
@@ -2238,12 +2264,12 @@
} }
}, },
"node_modules/@tanstack/react-query": { "node_modules/@tanstack/react-query": {
"version": "5.87.4", "version": "5.89.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.87.4.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz",
"integrity": "sha512-T5GT/1ZaNsUXf5I3RhcYuT17I4CPlbZgyLxc/ZGv7ciS6esytlbjb3DgUFO6c8JWYMDpdjSWInyGZUErgzqhcA==", "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/query-core": "5.87.4" "@tanstack/query-core": "5.89.0"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
@@ -2254,14 +2280,14 @@
} }
}, },
"node_modules/@tanstack/react-router": { "node_modules/@tanstack/react-router": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.44.tgz",
"integrity": "sha512-QEbTYpAosiD8e4qEZRr9aJipGSb8pQc+pfZwK6NCD2Tcxwu2oF6MVtwv0bIDLRpZP0VJMBpxXlTRISUDNMNqIA==", "integrity": "sha512-LREJfrl8lSedXHCRAAt0HvnHFP9ikAQWnVhYRM++B26w4ZYQBbLvgCT1BCDZVY7MR6rslcd4OfgpZMOyVhNzFg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/history": "1.131.2", "@tanstack/history": "1.131.2",
"@tanstack/react-store": "^0.7.0", "@tanstack/react-store": "^0.7.0",
"@tanstack/router-core": "1.131.41", "@tanstack/router-core": "1.131.44",
"isbot": "^5.1.22", "isbot": "^5.1.22",
"tiny-invariant": "^1.3.3", "tiny-invariant": "^1.3.3",
"tiny-warning": "^1.0.3" "tiny-warning": "^1.0.3"
@@ -2317,12 +2343,12 @@
} }
}, },
"node_modules/@tanstack/router-cli": { "node_modules/@tanstack/router-cli": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/router-cli/-/router-cli-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/router-cli/-/router-cli-1.131.44.tgz",
"integrity": "sha512-EpLnnCwwCd94HRCWHoa1GZGtIWIffx4rPBb6gbWm4cvyEIGV2Gq+27vL2OEw819/elxyBQmG2RrPB8+7dfVACw==", "integrity": "sha512-fKt2Whxbi3mvLXxVphSqlvVQyKe6BjdmOj5n+9LOgXQnFGyRwxrFR5cnNF+N4gUGp9iwnJpguZHXH4rNF5Xc+A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/router-generator": "1.131.41", "@tanstack/router-generator": "1.131.44",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
@@ -2338,9 +2364,9 @@
} }
}, },
"node_modules/@tanstack/router-core": { "node_modules/@tanstack/router-core": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.44.tgz",
"integrity": "sha512-VoLly00DWM0abKuVPRm8wiwGtRBHOKs6K896fy48Q/KYoDVLs8kRCRjFGS7rGnYC2FIkmmvHqYRqNg7jgCx2yg==", "integrity": "sha512-Npi9xB3GSYZhRW8+gPhP6bEbyx0vNc8ZNwsi0JapdiFpIiszgRJ57pesy/rklruv46gYQjLVA5KDOsuaCT/urA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/history": "1.131.2", "@tanstack/history": "1.131.2",
@@ -2360,12 +2386,12 @@
} }
}, },
"node_modules/@tanstack/router-generator": { "node_modules/@tanstack/router-generator": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.44.tgz",
"integrity": "sha512-HsDkBU1u/KvHrzn76v/9oeyMFuxvVlE3dfIu4fldZbPy/i903DWBwODIDGe6fVUsYtzPPrRvNtbjV18HVz5GCA==", "integrity": "sha512-CnrlRkGatdQXdvTteflOTMANupb1z59CO3DSV+UzBkTG+g+vfWgJeKQ0EkfwZ2QuS6Su2v5r5EMHs/AookeZZw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/router-core": "1.131.41", "@tanstack/router-core": "1.131.44",
"@tanstack/router-utils": "1.131.2", "@tanstack/router-utils": "1.131.2",
"@tanstack/virtual-file-routes": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2",
"prettier": "^3.5.0", "prettier": "^3.5.0",
@@ -2383,9 +2409,9 @@
} }
}, },
"node_modules/@tanstack/router-plugin": { "node_modules/@tanstack/router-plugin": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.44.tgz",
"integrity": "sha512-MENVYQwvhKFIPZ/YO/CGCwbh3Ba3TRvUYZ2y2KiU6aa1CWao4KHDRsungzv34AbbUBSmzbc8mKVeqd+G+E9cDQ==", "integrity": "sha512-CvheUPlB8vxXf23RSDz6q97l1EI5H3f+1qJ/LEBvy7bhls8vYouJ3xyTeu4faz8bEEieLUoVQrCcr+xFY0lkuw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2395,8 +2421,8 @@
"@babel/template": "^7.27.2", "@babel/template": "^7.27.2",
"@babel/traverse": "^7.27.7", "@babel/traverse": "^7.27.7",
"@babel/types": "^7.27.7", "@babel/types": "^7.27.7",
"@tanstack/router-core": "1.131.41", "@tanstack/router-core": "1.131.44",
"@tanstack/router-generator": "1.131.41", "@tanstack/router-generator": "1.131.44",
"@tanstack/router-utils": "1.131.2", "@tanstack/router-utils": "1.131.2",
"@tanstack/virtual-file-routes": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2",
"babel-dead-code-elimination": "^1.0.10", "babel-dead-code-elimination": "^1.0.10",
@@ -2413,7 +2439,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@rsbuild/core": ">=1.0.2", "@rsbuild/core": ">=1.0.2",
"@tanstack/react-router": "^1.131.41", "@tanstack/react-router": "^1.131.44",
"vite": ">=5.0.0 || >=6.0.0", "vite": ">=5.0.0 || >=6.0.0",
"vite-plugin-solid": "^2.11.2", "vite-plugin-solid": "^2.11.2",
"webpack": ">=5.92.0" "webpack": ">=5.92.0"
@@ -2458,13 +2484,13 @@
} }
}, },
"node_modules/@tanstack/router-vite-plugin": { "node_modules/@tanstack/router-vite-plugin": {
"version": "1.131.41", "version": "1.131.44",
"resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.131.41.tgz", "resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.131.44.tgz",
"integrity": "sha512-UNMLW5BsueJX77lAWwddWGKTDElXS23XfpvaEnxpAPS8rnu+7HEpV4bWciN5VruuTZZM5plP6bXAGec+Bi51Hw==", "integrity": "sha512-5q87hJuT/ybQ3K77Qd649L2curIIh50TIx4OkPCInaqqBeBx101G/6FWubOm2UTl7dVOfDsPPJHcmSbgwvowcA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/router-plugin": "1.131.41" "@tanstack/router-plugin": "1.131.44"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=12"
@@ -2556,9 +2582,9 @@
} }
}, },
"node_modules/@types/d3-array": { "node_modules/@types/d3-array": {
"version": "3.2.1", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
"integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/d3-color": { "node_modules/@types/d3-color": {
@@ -2633,9 +2659,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.1.12", "version": "19.1.13",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
"integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2659,17 +2685,17 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz",
"integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==", "integrity": "sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/scope-manager": "8.44.0",
"@typescript-eslint/type-utils": "8.43.0", "@typescript-eslint/type-utils": "8.44.0",
"@typescript-eslint/utils": "8.43.0", "@typescript-eslint/utils": "8.44.0",
"@typescript-eslint/visitor-keys": "8.43.0", "@typescript-eslint/visitor-keys": "8.44.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@@ -2683,7 +2709,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.43.0", "@typescript-eslint/parser": "^8.44.0",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
@@ -2699,16 +2725,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.0.tgz",
"integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", "integrity": "sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/scope-manager": "8.44.0",
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/typescript-estree": "8.44.0",
"@typescript-eslint/visitor-keys": "8.43.0", "@typescript-eslint/visitor-keys": "8.44.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2724,14 +2750,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.0.tgz",
"integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==", "integrity": "sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.43.0", "@typescript-eslint/tsconfig-utils": "^8.44.0",
"@typescript-eslint/types": "^8.43.0", "@typescript-eslint/types": "^8.44.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2746,14 +2772,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.0.tgz",
"integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==", "integrity": "sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"@typescript-eslint/visitor-keys": "8.43.0" "@typescript-eslint/visitor-keys": "8.44.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2764,9 +2790,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.0.tgz",
"integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==", "integrity": "sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2781,15 +2807,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.0.tgz",
"integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==", "integrity": "sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/typescript-estree": "8.44.0",
"@typescript-eslint/utils": "8.43.0", "@typescript-eslint/utils": "8.44.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@@ -2806,9 +2832,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.0.tgz",
"integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", "integrity": "sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2820,16 +2846,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.0.tgz",
"integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==", "integrity": "sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.43.0", "@typescript-eslint/project-service": "8.44.0",
"@typescript-eslint/tsconfig-utils": "8.43.0", "@typescript-eslint/tsconfig-utils": "8.44.0",
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"@typescript-eslint/visitor-keys": "8.43.0", "@typescript-eslint/visitor-keys": "8.44.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -2888,16 +2914,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.0.tgz",
"integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==", "integrity": "sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/scope-manager": "8.44.0",
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"@typescript-eslint/typescript-estree": "8.43.0" "@typescript-eslint/typescript-estree": "8.44.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2912,13 +2938,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.0.tgz",
"integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==", "integrity": "sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.43.0", "@typescript-eslint/types": "8.44.0",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
@@ -3126,9 +3152,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.12.1", "version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.6",
@@ -3156,9 +3182,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/baseline-browser-mapping": { "node_modules/baseline-browser-mapping": {
"version": "2.8.2", "version": "2.8.4",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.2.tgz", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
"integrity": "sha512-NvcIedLxrs9llVpX7wI+Jz4Hn9vJQkCPKrTaHIE0sW/Rj1iq6Fzby4NbyTZjQJNoypBXNaG7tEHkTgONZpwgxQ==", "integrity": "sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"baseline-browser-mapping": "dist/cli.js" "baseline-browser-mapping": "dist/cli.js"
@@ -3200,9 +3226,9 @@
} }
}, },
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.26.0", "version": "4.26.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.0.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
"integrity": "sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==", "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -3219,7 +3245,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.2", "baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001741", "caniuse-lite": "^1.0.30001741",
"electron-to-chromium": "^1.5.218", "electron-to-chromium": "^1.5.218",
"node-releases": "^2.0.21", "node-releases": "^2.0.21",
@@ -3265,9 +3291,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001741", "version": "1.0.30001743",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
"integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -3663,9 +3689,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.1", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -5171,9 +5197,19 @@
} }
}, },
"node_modules/postcss-js": { "node_modules/postcss-js": {
"version": "4.0.1", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"camelcase-css": "^2.0.1" "camelcase-css": "^2.0.1"
@@ -5181,10 +5217,6 @@
"engines": { "engines": {
"node": "^12 || ^14 || >= 16" "node": "^12 || ^14 || >= 16"
}, },
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
"peerDependencies": { "peerDependencies": {
"postcss": "^8.4.21" "postcss": "^8.4.21"
} }
@@ -5527,9 +5559,9 @@
} }
}, },
"node_modules/recharts": { "node_modules/recharts": {
"version": "3.2.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.2.0.tgz", "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.2.1.tgz",
"integrity": "sha512-fX0xCgNXo6mag9wz3oLuANR+dUQM4uIlTYBGTGq9CBRgW/8TZPzqPGYs5NTt8aENCf+i1CI8vqxT1py8L/5J2w==", "integrity": "sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "1.x.x || 2.x.x", "@reduxjs/toolkit": "1.x.x || 2.x.x",
@@ -5633,9 +5665,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.50.1", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz",
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -5649,27 +5681,27 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.50.1", "@rollup/rollup-android-arm-eabi": "4.50.2",
"@rollup/rollup-android-arm64": "4.50.1", "@rollup/rollup-android-arm64": "4.50.2",
"@rollup/rollup-darwin-arm64": "4.50.1", "@rollup/rollup-darwin-arm64": "4.50.2",
"@rollup/rollup-darwin-x64": "4.50.1", "@rollup/rollup-darwin-x64": "4.50.2",
"@rollup/rollup-freebsd-arm64": "4.50.1", "@rollup/rollup-freebsd-arm64": "4.50.2",
"@rollup/rollup-freebsd-x64": "4.50.1", "@rollup/rollup-freebsd-x64": "4.50.2",
"@rollup/rollup-linux-arm-gnueabihf": "4.50.1", "@rollup/rollup-linux-arm-gnueabihf": "4.50.2",
"@rollup/rollup-linux-arm-musleabihf": "4.50.1", "@rollup/rollup-linux-arm-musleabihf": "4.50.2",
"@rollup/rollup-linux-arm64-gnu": "4.50.1", "@rollup/rollup-linux-arm64-gnu": "4.50.2",
"@rollup/rollup-linux-arm64-musl": "4.50.1", "@rollup/rollup-linux-arm64-musl": "4.50.2",
"@rollup/rollup-linux-loongarch64-gnu": "4.50.1", "@rollup/rollup-linux-loong64-gnu": "4.50.2",
"@rollup/rollup-linux-ppc64-gnu": "4.50.1", "@rollup/rollup-linux-ppc64-gnu": "4.50.2",
"@rollup/rollup-linux-riscv64-gnu": "4.50.1", "@rollup/rollup-linux-riscv64-gnu": "4.50.2",
"@rollup/rollup-linux-riscv64-musl": "4.50.1", "@rollup/rollup-linux-riscv64-musl": "4.50.2",
"@rollup/rollup-linux-s390x-gnu": "4.50.1", "@rollup/rollup-linux-s390x-gnu": "4.50.2",
"@rollup/rollup-linux-x64-gnu": "4.50.1", "@rollup/rollup-linux-x64-gnu": "4.50.2",
"@rollup/rollup-linux-x64-musl": "4.50.1", "@rollup/rollup-linux-x64-musl": "4.50.2",
"@rollup/rollup-openharmony-arm64": "4.50.1", "@rollup/rollup-openharmony-arm64": "4.50.2",
"@rollup/rollup-win32-arm64-msvc": "4.50.1", "@rollup/rollup-win32-arm64-msvc": "4.50.2",
"@rollup/rollup-win32-ia32-msvc": "4.50.1", "@rollup/rollup-win32-ia32-msvc": "4.50.2",
"@rollup/rollup-win32-x64-msvc": "4.50.1", "@rollup/rollup-win32-x64-msvc": "4.50.2",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@@ -5765,6 +5797,16 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/sonner": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
"integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
"license": "MIT",
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.7.6", "version": "0.7.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
@@ -6172,16 +6214,16 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.43.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.43.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.0.tgz",
"integrity": "sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==", "integrity": "sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.43.0", "@typescript-eslint/eslint-plugin": "8.44.0",
"@typescript-eslint/parser": "8.43.0", "@typescript-eslint/parser": "8.44.0",
"@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/typescript-estree": "8.44.0",
"@typescript-eslint/utils": "8.43.0" "@typescript-eslint/utils": "8.44.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View File

@@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-select": "^2.2.6", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
@@ -31,6 +32,7 @@
"react-day-picker": "^9.10.0", "react-day-picker": "^9.10.0",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"recharts": "^3.2.0", "recharts": "^3.2.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"

View File

@@ -22,7 +22,7 @@ import {
} from "./ui/card"; } from "./ui/card";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { Alert, AlertDescription, AlertTitle } from "./ui/alert"; import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import LoadingSpinner from "./LoadingSpinner"; import AccountsSkeleton from "./AccountsSkeleton";
import type { Account, Balance } from "../types/api"; import type { Account, Balance } from "../types/api";
// Helper function to get status indicator color and styles // Helper function to get status indicator color and styles
@@ -37,23 +37,23 @@ const getStatusIndicator = (status: string) => {
}; };
case "pending": case "pending":
return { return {
color: "bg-yellow-500", color: "bg-amber-500",
tooltip: "Pending", tooltip: "Pending",
}; };
case "error": case "error":
case "failed": case "failed":
return { return {
color: "bg-red-500", color: "bg-destructive",
tooltip: "Error", tooltip: "Error",
}; };
case "inactive": case "inactive":
return { return {
color: "bg-gray-500", color: "bg-muted-foreground",
tooltip: "Inactive", tooltip: "Inactive",
}; };
default: default:
return { return {
color: "bg-blue-500", color: "bg-primary",
tooltip: status, tooltip: status,
}; };
} }
@@ -114,11 +114,7 @@ export default function AccountsOverview() {
}; };
if (accountsLoading) { if (accountsLoading) {
return ( return <AccountsSkeleton />;
<Card>
<LoadingSpinner message="Loading accounts..." />
</Card>
);
} }
if (accountsError) { if (accountsError) {
@@ -201,8 +197,8 @@ export default function AccountsOverview() {
{uniqueBanks} {uniqueBanks}
</p> </p>
</div> </div>
<div className="p-3 bg-purple-100 dark:bg-purple-900/20 rounded-full"> <div className="p-3 bg-muted rounded-full">
<Building2 className="h-6 w-6 text-purple-600" /> <Building2 className="h-6 w-6 text-muted-foreground" />
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -304,7 +300,9 @@ export default function AccountsOverview() {
<div> <div>
<div className="flex items-center space-x-2 min-w-0"> <div className="flex items-center space-x-2 min-w-0">
<h4 className="text-base sm:text-lg font-medium text-foreground truncate"> <h4 className="text-base sm:text-lg font-medium text-foreground truncate">
{account.display_name || account.name || "Unnamed Account"} {account.display_name ||
account.name ||
"Unnamed Account"}
</h4> </h4>
<button <button
onClick={() => handleEditStart(account)} onClick={() => handleEditStart(account)}

View File

@@ -0,0 +1,61 @@
import { Skeleton } from "./ui/skeleton";
import { Card, CardContent, CardHeader } from "./ui/card";
export default function AccountsSkeleton() {
return (
<div className="space-y-6">
{/* Summary Cards Skeleton */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{Array.from({ length: 3 }).map((_, i) => (
<Card key={i}>
<CardContent className="p-6">
<div className="flex items-center justify-between">
<div className="space-y-2">
<Skeleton className="h-4 w-20" />
<Skeleton className="h-8 w-24" />
</div>
<Skeleton className="h-12 w-12 rounded-full" />
</div>
</CardContent>
</Card>
))}
</div>
{/* Accounts List Skeleton */}
<Card>
<CardHeader>
<Skeleton className="h-6 w-32" />
<Skeleton className="h-4 w-48" />
</CardHeader>
<CardContent className="p-0">
<div className="divide-y divide-border">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="p-4 sm:p-6">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
<div className="flex items-start sm:items-center space-x-3 sm:space-x-4 min-w-0 flex-1">
<Skeleton className="h-10 w-10 sm:h-12 sm:w-12 rounded-full flex-shrink-0" />
<div className="flex-1 space-y-2">
<Skeleton className="h-5 w-48" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-3 w-40" />
</div>
</div>
<div className="flex items-center justify-between sm:flex-col sm:items-end sm:text-right flex-shrink-0">
<div className="flex items-center space-x-2 order-1 sm:order-2">
<Skeleton className="h-3 w-3 rounded-full" />
<Skeleton className="h-4 w-20" />
</div>
<div className="flex items-center space-x-2 order-2 sm:order-1">
<Skeleton className="h-4 w-4" />
<Skeleton className="h-5 w-24" />
</div>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,6 +1,9 @@
import { Component } from "react"; import { Component } from "react";
import type { ErrorInfo, ReactNode } from "react"; import type { ErrorInfo, ReactNode } from "react";
import { AlertTriangle, RefreshCw } from "lucide-react"; import { AlertTriangle, RefreshCw } from "lucide-react";
import { Card, CardContent } from "./ui/card";
import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import { Button } from "./ui/button";
interface Props { interface Props {
children: ReactNode; children: ReactNode;
@@ -39,46 +42,49 @@ class ErrorBoundary extends Component<Props, State> {
} }
return ( return (
<div className="bg-white rounded-lg shadow p-6"> <Card>
<CardContent className="p-6">
<div className="flex items-center justify-center text-center"> <div className="flex items-center justify-center text-center">
<div> <div>
<AlertTriangle className="h-12 w-12 text-red-400 mx-auto mb-4" /> <AlertTriangle className="h-12 w-12 text-destructive mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2"> <h3 className="text-lg font-medium text-foreground mb-2">
Something went wrong Something went wrong
</h3> </h3>
<p className="text-gray-600 mb-4"> <p className="text-muted-foreground mb-4">
An error occurred while rendering this component. Please try An error occurred while rendering this component. Please try
refreshing or check the console for more details. refreshing or check the console for more details.
</p> </p>
{this.state.error && ( {this.state.error && (
<div className="bg-red-50 border border-red-200 rounded-md p-3 mb-4 text-left"> <Alert variant="destructive" className="mb-4 text-left">
<p className="text-sm font-mono text-red-800"> <AlertTriangle className="h-4 w-4" />
<AlertTitle>Error Details</AlertTitle>
<AlertDescription className="space-y-2">
<p className="text-sm font-mono">
<strong>Error:</strong> {this.state.error.message} <strong>Error:</strong> {this.state.error.message}
</p> </p>
{this.state.error.stack && ( {this.state.error.stack && (
<details className="mt-2"> <details className="mt-2">
<summary className="text-sm text-red-600 cursor-pointer"> <summary className="text-sm cursor-pointer">
Stack trace Stack trace
</summary> </summary>
<pre className="text-xs text-red-700 mt-1 whitespace-pre-wrap"> <pre className="text-xs mt-1 whitespace-pre-wrap">
{this.state.error.stack} {this.state.error.stack}
</pre> </pre>
</details> </details>
)} )}
</div> </AlertDescription>
</Alert>
)} )}
<button <Button onClick={this.handleReset}>
onClick={this.handleReset}
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
>
<RefreshCw className="h-4 w-4 mr-2" /> <RefreshCw className="h-4 w-4 mr-2" />
Try Again Try Again
</button> </Button>
</div>
</div> </div>
</div> </div>
</CardContent>
</Card>
); );
} }

View File

@@ -1,29 +1,32 @@
import { Skeleton } from "./ui/skeleton";
import { Card, CardContent } from "./ui/card";
export default function FiltersSkeleton() { export default function FiltersSkeleton() {
return ( return (
<div className="bg-white rounded-lg shadow animate-pulse"> <Card>
<div className="px-6 py-4 border-b border-gray-200"> <div className="px-6 py-4 border-b border-border">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="h-6 bg-gray-200 rounded w-32"></div> <Skeleton className="h-6 w-32" />
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<div className="h-8 bg-gray-200 rounded w-24"></div> <Skeleton className="h-8 w-24" />
<div className="h-8 bg-gray-200 rounded w-20"></div> <Skeleton className="h-8 w-20" />
</div> </div>
</div> </div>
</div> </div>
<div className="px-6 py-4 border-b border-gray-200 bg-gray-50"> <CardContent className="px-6 py-4 border-b border-border bg-muted/30">
{/* Quick Date Filters Skeleton */} {/* Quick Date Filters Skeleton */}
<div className="mb-6"> <div className="mb-6">
<div className="h-4 bg-gray-200 rounded w-32 mb-3"></div> <Skeleton className="h-4 w-32 mb-3" />
<div className="space-y-2"> <div className="space-y-2">
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
<div className="h-10 bg-gray-200 rounded-lg w-24"></div> <Skeleton className="h-10 w-24 rounded-lg" />
<div className="h-10 bg-gray-200 rounded-lg w-20"></div> <Skeleton className="h-10 w-20 rounded-lg" />
<div className="h-10 bg-gray-200 rounded-lg w-28"></div> <Skeleton className="h-10 w-28 rounded-lg" />
</div> </div>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
<div className="h-10 bg-gray-200 rounded-lg w-24"></div> <Skeleton className="h-10 w-24 rounded-lg" />
<div className="h-10 bg-gray-200 rounded-lg w-20"></div> <Skeleton className="h-10 w-20 rounded-lg" />
</div> </div>
</div> </div>
</div> </div>
@@ -31,40 +34,40 @@ export default function FiltersSkeleton() {
{/* Filter Fields Skeleton */} {/* Filter Fields Skeleton */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="sm:col-span-2 lg:col-span-1"> <div className="sm:col-span-2 lg:col-span-1">
<div className="h-4 bg-gray-200 rounded w-16 mb-1"></div> <Skeleton className="h-4 w-16 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div> </div>
<div> <div>
<div className="h-4 bg-gray-200 rounded w-16 mb-1"></div> <Skeleton className="h-4 w-16 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div> </div>
<div> <div>
<div className="h-4 bg-gray-200 rounded w-20 mb-1"></div> <Skeleton className="h-4 w-20 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div> </div>
<div> <div>
<div className="h-4 bg-gray-200 rounded w-16 mb-1"></div> <Skeleton className="h-4 w-16 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div> </div>
</div> </div>
{/* Amount Range Filters Skeleton */} {/* Amount Range Filters Skeleton */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4">
<div> <div>
<div className="h-4 bg-gray-200 rounded w-20 mb-1"></div> <Skeleton className="h-4 w-20 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div> </div>
<div> <div>
<div className="h-4 bg-gray-200 rounded w-20 mb-1"></div> <Skeleton className="h-4 w-20 mb-1" />
<div className="h-10 bg-gray-200 rounded"></div> <Skeleton className="h-10 w-full" />
</div>
</div> </div>
</div> </div>
</CardContent>
{/* Results Summary Skeleton */} {/* Results Summary Skeleton */}
<div className="px-6 py-3 bg-gray-50 border-b border-gray-200"> <CardContent className="px-6 py-3 bg-muted/30 border-b border-border">
<div className="h-4 bg-gray-200 rounded w-48"></div> <Skeleton className="h-4 w-48" />
</div> </CardContent>
</div> </Card>
); );
} }

View File

@@ -49,15 +49,15 @@ export default function Header({ setSidebarOpen }: HeaderProps) {
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{healthLoading ? ( {healthLoading ? (
<> <>
<Activity className="h-4 w-4 text-yellow-500 animate-pulse" /> <Activity className="h-4 w-4 text-muted-foreground animate-pulse" />
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
Checking... Checking...
</span> </span>
</> </>
) : healthError || healthStatus?.status !== "healthy" ? ( ) : healthError || healthStatus?.status !== "healthy" ? (
<> <>
<WifiOff className="h-4 w-4 text-red-500" /> <WifiOff className="h-4 w-4 text-destructive" />
<span className="text-sm text-red-500">Disconnected</span> <span className="text-sm text-destructive">Disconnected</span>
</> </>
) : ( ) : (
<> <>

View File

@@ -1,18 +0,0 @@
import { RefreshCw } from "lucide-react";
interface LoadingSpinnerProps {
message?: string;
}
export default function LoadingSpinner({
message = "Loading...",
}: LoadingSpinnerProps) {
return (
<div className="flex items-center justify-center p-8">
<div className="text-center">
<RefreshCw className="h-8 w-8 animate-spin text-blue-600 mx-auto mb-2" />
<p className="text-gray-600 text-sm">{message}</p>
</div>
</div>
);
}

View File

@@ -12,7 +12,7 @@ import {
TestTube, TestTube,
} from "lucide-react"; } from "lucide-react";
import { apiClient } from "../lib/api"; import { apiClient } from "../lib/api";
import LoadingSpinner from "./LoadingSpinner"; import NotificationsSkeleton from "./NotificationsSkeleton";
import { import {
Card, Card,
CardContent, CardContent,
@@ -24,6 +24,7 @@ import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { Input } from "./ui/input"; import { Input } from "./ui/input";
import { Label } from "./ui/label"; import { Label } from "./ui/label";
import { Badge } from "./ui/badge";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -80,11 +81,7 @@ export default function Notifications() {
}); });
if (settingsLoading || servicesLoading) { if (settingsLoading || servicesLoading) {
return ( return <NotificationsSkeleton />;
<Card>
<LoadingSpinner message="Loading notifications..." />
</Card>
);
} }
if (settingsError || servicesError) { if (settingsError || servicesError) {
@@ -233,12 +230,10 @@ export default function Notifications() {
{service.name} {service.name}
</h4> </h4>
<div className="flex items-center space-x-2 mt-1"> <div className="flex items-center space-x-2 mt-1">
<span <Badge
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${ variant={
service.enabled service.enabled ? "default" : "destructive"
? "bg-green-100 text-green-800" }
: "bg-red-100 text-red-800"
}`}
> >
{service.enabled ? ( {service.enabled ? (
<CheckCircle className="h-3 w-3 mr-1" /> <CheckCircle className="h-3 w-3 mr-1" />
@@ -246,18 +241,16 @@ export default function Notifications() {
<AlertCircle className="h-3 w-3 mr-1" /> <AlertCircle className="h-3 w-3 mr-1" />
)} )}
{service.enabled ? "Enabled" : "Disabled"} {service.enabled ? "Enabled" : "Disabled"}
</span> </Badge>
<span <Badge
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${ variant={
service.configured service.configured ? "secondary" : "outline"
? "bg-blue-100 text-blue-800" }
: "bg-yellow-100 text-yellow-800"
}`}
> >
{service.configured {service.configured
? "Configured" ? "Configured"
: "Not Configured"} : "Not Configured"}
</span> </Badge>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,95 @@
import { Skeleton } from "./ui/skeleton";
import { Card, CardContent, CardHeader } from "./ui/card";
export default function NotificationsSkeleton() {
return (
<div className="space-y-6">
{/* Test Notification Section Skeleton */}
<Card>
<CardHeader>
<div className="flex items-center space-x-2">
<Skeleton className="h-5 w-5" />
<Skeleton className="h-6 w-36" />
</div>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Skeleton className="h-4 w-16" />
<Skeleton className="h-10 w-full" />
</div>
<div className="space-y-2">
<Skeleton className="h-4 w-16" />
<Skeleton className="h-10 w-full" />
</div>
</div>
<div className="mt-4">
<Skeleton className="h-10 w-48" />
</div>
</CardContent>
</Card>
{/* Notification Services Skeleton */}
<Card>
<CardHeader>
<div className="flex items-center space-x-2">
<Skeleton className="h-5 w-5" />
<Skeleton className="h-6 w-40" />
</div>
<Skeleton className="h-4 w-56" />
</CardHeader>
<CardContent className="p-0">
<div className="divide-y divide-border">
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className="p-6">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Skeleton className="h-12 w-12 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-5 w-24" />
<div className="flex items-center space-x-2">
<Skeleton className="h-5 w-16" />
<Skeleton className="h-5 w-20" />
</div>
</div>
</div>
<Skeleton className="h-8 w-8" />
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Notification Settings Skeleton */}
<Card>
<CardHeader>
<div className="flex items-center space-x-2">
<Skeleton className="h-5 w-5" />
<Skeleton className="h-6 w-40" />
</div>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="space-y-2">
<Skeleton className="h-4 w-16" />
<div className="bg-muted rounded-md p-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="space-y-2">
<Skeleton className="h-3 w-32" />
<Skeleton className="h-4 w-24" />
</div>
<div className="space-y-2">
<Skeleton className="h-3 w-28" />
<Skeleton className="h-4 w-20" />
</div>
</div>
</div>
</div>
<Skeleton className="h-12 w-full" />
</div>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,3 +1,6 @@
import { Skeleton } from "./ui/skeleton";
import { Card } from "./ui/card";
interface TransactionSkeletonProps { interface TransactionSkeletonProps {
rows?: number; rows?: number;
view?: "table" | "mobile"; view?: "table" | "mobile";
@@ -11,93 +14,89 @@ export default function TransactionSkeleton({
if (view === "mobile") { if (view === "mobile") {
return ( return (
<div className="bg-white rounded-lg shadow divide-y divide-gray-200"> <Card className="divide-y divide-border">
{skeletonRows.map((_, index) => ( {skeletonRows.map((_, index) => (
<div key={index} className="p-4 animate-pulse"> <div key={index} className="p-4">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex-1"> <div className="flex-1">
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<div className="p-2 rounded-full bg-gray-200 flex-shrink-0"> <Skeleton className="h-10 w-10 rounded-full flex-shrink-0" />
<div className="h-4 w-4 bg-gray-300 rounded"></div>
</div>
<div className="flex-1 min-w-0 space-y-2"> <div className="flex-1 min-w-0 space-y-2">
<div className="h-4 bg-gray-200 rounded w-3/4"></div> <Skeleton className="h-4 w-3/4" />
<div className="space-y-1"> <div className="space-y-1">
<div className="h-3 bg-gray-200 rounded w-1/2"></div> <Skeleton className="h-3 w-1/2" />
<div className="h-3 bg-gray-200 rounded w-2/3"></div> <Skeleton className="h-3 w-2/3" />
<div className="h-3 bg-gray-200 rounded w-1/3"></div> <Skeleton className="h-3 w-1/3" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="text-right ml-3 flex-shrink-0 space-y-2"> <div className="text-right ml-3 flex-shrink-0 space-y-2">
<div className="h-6 bg-gray-200 rounded w-20"></div> <Skeleton className="h-6 w-20" />
<div className="h-4 bg-gray-200 rounded w-16 ml-auto"></div> <Skeleton className="h-4 w-16 ml-auto" />
<div className="h-6 bg-gray-200 rounded w-12 ml-auto"></div> <Skeleton className="h-6 w-12 ml-auto" />
</div> </div>
</div> </div>
</div> </div>
))} ))}
</div> </Card>
); );
} }
return ( return (
<div className="bg-white rounded-lg shadow overflow-hidden"> <Card className="overflow-hidden">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200"> <table className="min-w-full divide-y divide-border">
<thead className="bg-gray-50"> <thead className="bg-muted/50">
<tr> <tr>
<th className="px-6 py-3 text-left"> <th className="px-6 py-3 text-left">
<div className="h-4 bg-gray-200 rounded w-20 animate-pulse"></div> <Skeleton className="h-4 w-20" />
</th> </th>
<th className="px-6 py-3 text-left"> <th className="px-6 py-3 text-left">
<div className="h-4 bg-gray-200 rounded w-16 animate-pulse"></div> <Skeleton className="h-4 w-16" />
</th> </th>
<th className="px-6 py-3 text-left"> <th className="px-6 py-3 text-left">
<div className="h-4 bg-gray-200 rounded w-12 animate-pulse"></div> <Skeleton className="h-4 w-12" />
</th> </th>
<th className="px-6 py-3 text-left"> <th className="px-6 py-3 text-left">
<div className="h-4 bg-gray-200 rounded w-8 animate-pulse"></div> <Skeleton className="h-4 w-8" />
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody className="bg-white divide-y divide-gray-200"> <tbody className="bg-card divide-y divide-border">
{skeletonRows.map((_, index) => ( {skeletonRows.map((_, index) => (
<tr key={index} className="animate-pulse"> <tr key={index}>
<td className="px-6 py-4"> <td className="px-6 py-4">
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<div className="p-2 rounded-full bg-gray-200 flex-shrink-0"> <Skeleton className="h-10 w-10 rounded-full flex-shrink-0" />
<div className="h-4 w-4 bg-gray-300 rounded"></div>
</div>
<div className="flex-1 space-y-2"> <div className="flex-1 space-y-2">
<div className="h-4 bg-gray-200 rounded w-3/4"></div> <Skeleton className="h-4 w-3/4" />
<div className="space-y-1"> <div className="space-y-1">
<div className="h-3 bg-gray-200 rounded w-1/2"></div> <Skeleton className="h-3 w-1/2" />
<div className="h-3 bg-gray-200 rounded w-2/3"></div> <Skeleton className="h-3 w-2/3" />
</div> </div>
</div> </div>
</div> </div>
</td> </td>
<td className="px-6 py-4"> <td className="px-6 py-4">
<div className="text-right"> <div className="text-right">
<div className="h-6 bg-gray-200 rounded w-24 ml-auto mb-1"></div> <Skeleton className="h-6 w-24 ml-auto mb-1" />
</div> </div>
</td> </td>
<td className="px-6 py-4"> <td className="px-6 py-4">
<div className="space-y-1"> <div className="space-y-1">
<div className="h-4 bg-gray-200 rounded w-20"></div> <Skeleton className="h-4 w-20" />
<div className="h-3 bg-gray-200 rounded w-16"></div> <Skeleton className="h-3 w-16" />
</div> </div>
</td> </td>
<td className="px-6 py-4"> <td className="px-6 py-4">
<div className="h-6 bg-gray-200 rounded w-12"></div> <Skeleton className="h-6 w-12" />
</td> </td>
</tr> </tr>
))} ))}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </Card>
); );
} }

View File

@@ -17,6 +17,7 @@ interface PieDataPoint {
name: string; name: string;
value: number; value: number;
color: string; color: string;
[key: string]: string | number;
} }
interface TooltipProps { interface TooltipProps {

View File

@@ -38,7 +38,8 @@ export function AccountCombobox({
); );
const formatAccountName = (account: Account) => { const formatAccountName = (account: Account) => {
const displayName = account.display_name || account.name || "Unnamed Account"; const displayName =
account.display_name || account.name || "Unnamed Account";
return `${displayName} (${account.institution_id})`; return `${displayName} (${account.institution_id})`;
}; };
@@ -105,7 +106,9 @@ export function AccountCombobox({
/> />
<div className="flex flex-col"> <div className="flex flex-col">
<span className="font-medium"> <span className="font-medium">
{account.display_name || account.name || "Unnamed Account"} {account.display_name ||
account.name ||
"Unnamed Account"}
</span> </span>
<span className="text-xs text-gray-500"> <span className="text-xs text-gray-500">
{account.institution_id} {account.institution_id}

View File

@@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const alertVariants = cva( const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{ {
variants: { variants: {
variant: { variant: {

View File

@@ -0,0 +1,26 @@
import * as React from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";
import { cn } from "@/lib/utils";
const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn(
"relative h-2 w-full overflow-hidden rounded-full bg-secondary",
className,
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
));
Progress.displayName = ProgressPrimitive.Root.displayName;
export { Progress };

View File

@@ -0,0 +1,138 @@
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@@ -0,0 +1,15 @@
import { cn } from "@/lib/utils";
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
);
}
export { Skeleton };

View File

@@ -0,0 +1,27 @@
"use client";
import { Toaster as Sonner } from "sonner";
type ToasterProps = React.ComponentProps<typeof Sonner>;
const Toaster = ({ ...props }: ToasterProps) => {
return (
<Sonner
className="toaster group"
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
);
};
export { Toaster };

View File

@@ -42,10 +42,9 @@ export const apiClient = {
id: string, id: string,
updates: AccountUpdate, updates: AccountUpdate,
): Promise<{ id: string; display_name?: string }> => { ): Promise<{ id: string; display_name?: string }> => {
const response = await api.put<ApiResponse<{ id: string; display_name?: string }>>( const response = await api.put<
`/accounts/${id}`, ApiResponse<{ id: string; display_name?: string }>
updates, >(`/accounts/${id}`, updates);
);
return response.data.data; return response.data.data;
}, },