diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..035c62e4 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,32 @@ +name: Lint + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +jobs: + lint: + name: Typecheck and Lint + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run typecheck + run: pnpm run typecheck + + - name: Run lint + run: pnpm run lint diff --git a/.husky/pre-commit b/.husky/pre-commit index ae010850..2312dc58 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1 @@ npx lint-staged -pnpm run typecheck diff --git a/.oxlintrc.json b/.oxlintrc.json index 5a904ffe..946fa076 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,6 +1,6 @@ { "$schema": "./node_modules/oxlint/configuration_schema.json", - "ignorePatterns": ["dist"], + "ignorePatterns": ["dist", "src/routeTree.gen.ts"], "overrides": [ { "files": ["**/*.{ts,tsx}"], diff --git a/package.json b/package.json index a49ee7e9..e7b03d77 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@tanstack/react-query": "^5.56.2", "@tanstack/react-query-devtools": "^5.81.2", "@tanstack/react-query-persist-client": "^5.85.9", + "@tanstack/react-router": "^1.136.18", "@types/marked": "^5.0.2", "@types/react-helmet": "^6.1.11", "@vercel/speed-insights": "^1.2.0", @@ -85,7 +86,6 @@ "react-helmet-async": "^2.0.5", "react-hook-form": "^7.53.0", "react-resizable-panels": "^2.1.3", - "react-router-dom": "^6.26.2", "recharts": "^2.12.7", "sonner": "^1.5.0", "tailwind-merge": "^2.5.2", @@ -104,6 +104,8 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", + "@tanstack/router-devtools": "^1.136.18", + "@tanstack/router-vite-plugin": "^1.136.18", "@types/node": "^22.5.5", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", @@ -129,7 +131,8 @@ "lint-staged": { "*.{js,jsx,ts,tsx}": [ "oxlint --fix", - "prettier --write" + "prettier --write", + "bash -c 'pnpm run typecheck'" ], "*.{json,css,scss,md}": [ "prettier --write" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08c084d4..714351af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,6 +110,9 @@ importers: '@tanstack/react-query-persist-client': specifier: ^5.85.9 version: 5.90.2(@tanstack/react-query@5.90.2(react@18.3.1))(react@18.3.1) + '@tanstack/react-router': + specifier: ^1.136.18 + version: 1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/marked': specifier: ^5.0.2 version: 5.0.2 @@ -179,9 +182,6 @@ importers: react-resizable-panels: specifier: ^2.1.3 version: 2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router-dom: - specifier: ^6.26.2 - version: 6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) recharts: specifier: ^2.12.7 version: 2.15.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -219,12 +219,18 @@ importers: '@tailwindcss/typography': specifier: ^0.5.15 version: 0.5.19(tailwindcss@3.4.17) + '@tanstack/router-devtools': + specifier: ^1.136.18 + version: 1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + '@tanstack/router-vite-plugin': + specifier: ^1.136.18 + version: 1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) @@ -239,19 +245,19 @@ importers: version: 18.3.7(@types/react@18.3.24) '@vitejs/plugin-react-swc': specifier: ^4.2.2 - version: 4.2.2(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 4.3.0(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/coverage-v8': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.2(vitest@4.1.2) '@vitest/ui': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.2(vitest@4.1.2) autoprefixer: specifier: ^10.4.20 version: 10.4.21(postcss@8.5.6) baseline-browser-mapping: specifier: ^2.9.5 - version: 2.9.5 + version: 2.10.13 globals: specifier: ^15.9.0 version: 15.15.0 @@ -287,13 +293,13 @@ importers: version: 5.9.2 vite: specifier: ^7.2.7 - version: 7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vite-plugin-pwa: specifier: ^1.2.0 - version: 1.2.0(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0)(workbox-window@7.3.0) + version: 1.2.0(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0)(workbox-window@7.3.0) vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@22.18.6)(@vitest/ui@4.0.15)(jiti@1.21.7)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 4.1.2(@types/node@22.18.6)(@vitest/ui@4.1.2)(jsdom@27.0.0(postcss@8.5.6))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) packages: @@ -335,6 +341,10 @@ packages: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -343,8 +353,8 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -364,8 +374,8 @@ packages: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': @@ -406,6 +416,10 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} @@ -422,11 +436,21 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} + '@babel/parser@7.28.4': + resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/parser@7.28.5': resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} engines: {node: '>=6.9.0'} @@ -475,6 +499,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -763,6 +799,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.5': + resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-escapes@7.27.1': resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} engines: {node: '>=6.9.0'} @@ -798,6 +840,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -810,10 +858,22 @@ packages: resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.4': + resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -861,156 +921,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.10': resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.10': resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.10': resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.10': resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.10': resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.10': resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.10': resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.10': resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.10': resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.10': resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.10': resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.10': resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.10': resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.10': resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.10': resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.10': resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.10': resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.10': resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.10': resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.10': resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.10': resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.10': resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.10': resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.10': resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.10': resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -1750,12 +1966,8 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@remix-run/router@1.23.0': - resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} - engines: {node: '>=14.0.0'} - - '@rolldown/pluginutils@1.0.0-beta.47': - resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} '@rollup/plugin-babel@5.3.1': resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} @@ -1916,8 +2128,8 @@ packages: cpu: [x64] os: [win32] - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} '@supabase/auth-js@2.81.1': resolution: {integrity: sha512-K20GgiSm9XeRLypxYHa5UCnybWc2K0ok0HLbqCej/wRxDpJxToXNOwKt0l7nO8xI1CyQ+GrNfU6bcRzvdbeopQ==} @@ -1946,68 +2158,80 @@ packages: '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} - '@swc/core-darwin-arm64@1.13.19': - resolution: {integrity: sha512-NxDyte9tCJSJ8+R62WDtqwg8eI57lubD52sHyGOfezpJBOPr36bUSGGLyO3Vod9zTGlOu2CpkuzA/2iVw92u1g==} + '@swc/core-darwin-arm64@1.15.21': + resolution: {integrity: sha512-SA8SFg9dp0qKRH8goWsax6bptFE2EdmPf2YRAQW9WoHGf3XKM1bX0nd5UdwxmC5hXsBUZAYf7xSciCler6/oyA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.13.19': - resolution: {integrity: sha512-+w5DYrJndSygFFRDcuPYmx5BljD6oYnAohZ15K1L6SfORHp/BTSIbgSFRKPoyhjuIkDiq3W0um8RoMTOBAcQjQ==} + '@swc/core-darwin-x64@1.15.21': + resolution: {integrity: sha512-//fOVntgowz9+V90lVsNCtyyrtbHp3jWH6Rch7MXHXbcvbLmbCTmssl5DeedUWLLGiAAW1wksBdqdGYOTjaNLw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.13.19': - resolution: {integrity: sha512-7LlfgpdwwYq2q7himNkAAFo4q6jysMLFNoBH6GRP7WL29NcSsl5mPMJjmYZymK+sYq/9MTVieDTQvChzYDsapw==} + '@swc/core-linux-arm-gnueabihf@1.15.21': + resolution: {integrity: sha512-meNI4Sh6h9h8DvIfEc0l5URabYMSuNvyisLmG6vnoYAS43s8ON3NJR8sDHvdP7NJTrLe0q/x2XCn6yL/BeHcZg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.13.19': - resolution: {integrity: sha512-ml3I6Lm2marAQ3UC/TS9t/yILBh/eDSVHAdPpikp652xouWAVW1znUeV6bBSxe1sSZIenv+p55ubKAWq/u84sQ==} + '@swc/core-linux-arm64-gnu@1.15.21': + resolution: {integrity: sha512-QrXlNQnHeXqU2EzLlnsPoWEh8/GtNJLvfMiPsDhk+ht6Xv8+vhvZ5YZ/BokNWSIZiWPKLAqR0M7T92YF5tmD3g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.13.19': - resolution: {integrity: sha512-M/otFc3/rWWkbF6VgbOXVzUKVoE7MFcphTaStxJp4bwb7oP5slYlxMZN51Dk/OTOfvCDo9pTAFDKNyixbkXMDQ==} + '@swc/core-linux-arm64-musl@1.15.21': + resolution: {integrity: sha512-8/yGCMO333ultDaMQivE5CjO6oXDPeeg1IV4sphojPkb0Pv0i6zvcRIkgp60xDB+UxLr6VgHgt+BBgqS959E9g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.13.19': - resolution: {integrity: sha512-NoMUKaOJEdouU4tKF88ggdDHFiRRING+gYLxDqnTfm+sUXaizB5OGBRzvSVDYSXQb1SuUuChnXFPFzwTWbt3ZQ==} + '@swc/core-linux-ppc64-gnu@1.15.21': + resolution: {integrity: sha512-ucW0HzPx0s1dgRvcvuLSPSA/2Kk/VYTv9st8qe1Kc22Gu0Q0rH9+6TcBTmMuNIp0Xs4BPr1uBttmbO1wEGI49Q==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + + '@swc/core-linux-s390x-gnu@1.15.21': + resolution: {integrity: sha512-ulTnOGc5I7YRObE/9NreAhQg94QkiR5qNhhcUZ1iFAYjzg/JGAi1ch+s/Ixe61pMIr8bfVrF0NOaB0f8wjaAfA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + + '@swc/core-linux-x64-gnu@1.15.21': + resolution: {integrity: sha512-D0RokxtM+cPvSqJIKR6uja4hbD+scI9ezo95mBhfSyLUs9wnPPl26sLp1ZPR/EXRdYm3F3S6RUtVi+8QXhT24Q==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.13.19': - resolution: {integrity: sha512-r6krlZwyu8SBaw24QuS1lau2I9q8M+eJV6ITz0rpb6P1Bx0elf9ii5Bhh8ddmIqXXH8kOGSjC/dwcdHbZqAhgw==} + '@swc/core-linux-x64-musl@1.15.21': + resolution: {integrity: sha512-nER8u7VeRfmU6fMDzl1NQAbbB/G7O2avmvCOwIul1uGkZ2/acbPH+DCL9h5+0yd/coNcxMBTL6NGepIew+7C2w==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.13.19': - resolution: {integrity: sha512-awcZSIuxyVn0Dw28VjMvgk1qiDJ6CeQwHkZNUjg2UxVlq23zE01NMMp+zkoGFypmLG9gaGmJSzuoqvk/WCQ5tw==} + '@swc/core-win32-arm64-msvc@1.15.21': + resolution: {integrity: sha512-+/AgNBnjYugUA8C0Do4YzymgvnGbztv7j8HKSQLvR/DQgZPoXQ2B3PqB2mTtGh/X5DhlJWiqnunN35JUgWcAeQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.13.19': - resolution: {integrity: sha512-H5d+KO7ISoLNgYvTbOcCQjJZNM3R7yaYlrMAF13lUr6GSiOUX+92xtM31B+HvzAWI7HtvVe74d29aC1b1TpXFA==} + '@swc/core-win32-ia32-msvc@1.15.21': + resolution: {integrity: sha512-IkSZj8PX/N4HcaFhMQtzmkV8YSnuNoJ0E6OvMwFiOfejPhiKXvl7CdDsn1f4/emYEIDO3fpgZW9DTaCRMDxaDA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.13.19': - resolution: {integrity: sha512-qNoyCpXvv2O3JqXKanRIeoMn03Fho/As+N4Fhe7u0FsYh4VYqGQah4DGDzEP/yjl4Gx1IElhqLGDhCCGMwWaDw==} + '@swc/core-win32-x64-msvc@1.15.21': + resolution: {integrity: sha512-zUyWso7OOENB6e1N1hNuNn8vbvLsTdKQ5WKLgt/JcBNfJhKy/6jmBmqI3GXk/MyvQKd5SLvP7A0F36p7TeDqvw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.13.19': - resolution: {integrity: sha512-V1r4wFdjaZIUIZZrV2Mb/prEeu03xvSm6oatPxsvnXKF9lNh5Jtk9QvUdiVfD9rrvi7bXrAVhg9Wpbmv/2Fl1g==} + '@swc/core@1.15.21': + resolution: {integrity: sha512-fkk7NJcBscrR3/F8jiqlMptRHP650NxqDnspBMrRe5d8xOoCy9MLL5kOBLFXjFLfMo3KQQHhk+/jUULOMlR1uQ==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -2031,6 +2255,10 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + '@tanstack/history@1.133.28': + resolution: {integrity: sha512-B7+x7eP2FFvi3fgd3rNH9o/Eixt+pp0zCIdGhnQbAJjFrlwIKGjGnwyJjhWJ5fMQlGks/E2LdDTqEV4W9Plx7g==} + engines: {node: '>=12'} + '@tanstack/query-async-storage-persister@5.90.2': resolution: {integrity: sha512-oyb7IHW85hsRdSZZNPu5dowQJFX3agOR/1O4M6Qc5V7s5dfnex5CqipEu0tbScNRMc2knna2ihQUiEQuTXWrEQ==} @@ -2060,6 +2288,98 @@ packages: peerDependencies: react: ^18 || ^19 + '@tanstack/react-router-devtools@1.136.18': + resolution: {integrity: sha512-yf/xZ978P3kVPh9i/lThydShnb2PG5hzXVor1GPCQ9UEjHC0zjDngz1VqWww9zNhTA2k9p9T7QCH8SVyOWG6rA==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.136.18 + '@tanstack/router-core': ^1.136.17 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router@1.136.18': + resolution: {integrity: sha512-KXlzIZ5W6LKAl8Ot2p1CJJ7B6ZkXFnfaJEhOkPWHA0K7sTrQYOphMwdFBKyaYUCfoBrygqVM5g17mWMpQ4Va2A==} + engines: {node: '>=12'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.136.17': + resolution: {integrity: sha512-LQsR1Bg9ITRFt9qVU9yrsO6Z3izdva5jzow3s3yUaccBhbryBFQdA5f9HTCpuVidFbqC6eVbi0vGfRkyviK4jw==} + engines: {node: '>=12'} + + '@tanstack/router-devtools-core@1.136.17': + resolution: {integrity: sha512-KlJx89CtMnYDKz1tSBl4y9AiillaVRN81t/YQP2NVoyk1Xz6hkHrd/q/6QJmShHmnhzuY3kWaMzAhP6w0zdRdA==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/router-core': ^1.136.17 + csstype: ^3.0.10 + solid-js: '>=1.9.5' + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-devtools@1.136.18': + resolution: {integrity: sha512-A8kOCPutsgOko7/lT8H3ViFJGdPD4zDVM3Z6OHW4wYGZvFxa4z9igCPi/vsCvTqv/L/juDO7dT8Fj4S/z4pYGA==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.136.18 + csstype: ^3.0.10 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.136.17': + resolution: {integrity: sha512-4kUP5KmaEftN46wz7ZRxNeZSnfBDWfNxPBYDoB1JKx2cILbCvOyCu9l74EqDQ19XSZJ9n3FUYWgWg0pLjSKvtw==} + engines: {node: '>=12'} + + '@tanstack/router-plugin@1.136.18': + resolution: {integrity: sha512-k8MQ+My5njcls2Bvg8J3oi7GjvfNA7smvlPyinYQYCcgJ83e8QT6Mnb6pHOUAJqJx6lBiLfUz/7OC4f1hQ0Ljw==} + engines: {node: '>=12'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.136.18 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.133.19': + resolution: {integrity: sha512-WEp5D2gPxvlLDRXwD/fV7RXjYtqaqJNXKB/L6OyZEbT+9BG/Ib2d7oG9GSUZNNMGPGYAlhBUOi3xutySsk6rxA==} + engines: {node: '>=12'} + + '@tanstack/router-vite-plugin@1.136.18': + resolution: {integrity: sha512-KsOgFjUjknNF1Oyk5h4kynesfs44OOMBDSYvzko2PBL4KPmlisjqzFeRp+9Ohv/Jh56EYqlX21VfCOVDVFhMJg==} + engines: {node: '>=12'} + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + + '@tanstack/virtual-file-routes@1.133.19': + resolution: {integrity: sha512-IKwZENsK7owmW1Lm5FhuHegY/SyQ8KqtL/7mTSnzoKJgfzhrrf9qwKB1rmkKkt+svUuy/Zw3uVEpZtUzQruWtA==} + engines: {node: '>=12'} + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -2068,8 +2388,8 @@ packages: resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@testing-library/react@16.3.0': - resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -2186,54 +2506,54 @@ packages: vue-router: optional: true - '@vitejs/plugin-react-swc@4.2.2': - resolution: {integrity: sha512-x+rE6tsxq/gxrEJN3Nv3dIV60lFflPj94c90b+NNo6n1QV1QQUTLoL0MpaOVasUZ0zqVBn7ead1B5ecx1JAGfA==} + '@vitejs/plugin-react-swc@4.3.0': + resolution: {integrity: sha512-mOkXCII839dHyAt/gpoSlm28JIVDwhZ6tnG6wJxUy2bmOx7UaPjvOyIDf3SFv5s7Eo7HVaq6kRcu6YMEzt5Z7w==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4 || ^5 || ^6 || ^7 + vite: ^4 || ^5 || ^6 || ^7 || ^8 - '@vitest/coverage-v8@4.0.15': - resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==} + '@vitest/coverage-v8@4.1.2': + resolution: {integrity: sha512-sPK//PHO+kAkScb8XITeB1bf7fsk85Km7+rt4eeuRR3VS1/crD47cmV5wicisJmjNdfeokTZwjMk4Mj2d58Mgg==} peerDependencies: - '@vitest/browser': 4.0.15 - vitest: 4.0.15 + '@vitest/browser': 4.1.2 + vitest: 4.1.2 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.15': - resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/expect@4.1.2': + resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} - '@vitest/mocker@4.0.15': - resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + '@vitest/mocker@4.1.2': + resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.15': - resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + '@vitest/pretty-format@4.1.2': + resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} - '@vitest/runner@4.0.15': - resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + '@vitest/runner@4.1.2': + resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} - '@vitest/snapshot@4.0.15': - resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + '@vitest/snapshot@4.1.2': + resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} - '@vitest/spy@4.0.15': - resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + '@vitest/spy@4.1.2': + resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} - '@vitest/ui@4.0.15': - resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==} + '@vitest/ui@4.1.2': + resolution: {integrity: sha512-/irhyeAcKS2u6Zokagf9tqZJ0t8S6kMZq4ZG9BHZv7I+fkRrYfQX4w7geYeC2r6obThz39PDxvXQzZX+qXqGeg==} peerDependencies: - vitest: 4.0.15 + vitest: 4.1.2 - '@vitest/utils@4.0.15': - resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@vitest/utils@4.1.2': + resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} @@ -2271,6 +2591,10 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -2300,8 +2624,12 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} - ast-v8-to-istanbul@0.3.8: - resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} @@ -2325,6 +2653,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + babel-dead-code-elimination@1.0.10: + resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} + babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} peerDependencies: @@ -2343,8 +2674,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.9.5: - resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} + baseline-browser-mapping@2.10.13: + resolution: {integrity: sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==} + engines: {node: '>=6.0.0'} hasBin: true bidi-js@1.0.3: @@ -2395,8 +2727,8 @@ packages: caniuse-lite@1.0.30001745: resolution: {integrity: sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} chokidar@3.6.0: @@ -2466,6 +2798,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + core-js-compat@3.45.1: resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} @@ -2611,6 +2946,10 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -2680,8 +3019,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -2700,10 +3039,20 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} @@ -2723,8 +3072,8 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} fast-deep-equal@3.1.3: @@ -2773,8 +3122,8 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} @@ -2879,7 +3228,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@15.15.0: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} @@ -2889,6 +3238,11 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3118,6 +3472,10 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isbot@5.1.32: + resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3129,10 +3487,6 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} - istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} @@ -3149,12 +3503,12 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - jsdom@27.0.0: resolution: {integrity: sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==} engines: {node: '>=20'} @@ -3249,8 +3603,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.5.1: - resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -3620,19 +3974,6 @@ packages: react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-router-dom@6.30.1: - resolution: {integrity: sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - react-router@6.30.1: - resolution: {integrity: sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-smooth@4.0.4: resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} peerDependencies: @@ -3670,6 +4011,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + recharts-scale@0.4.5: resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} @@ -3778,14 +4123,34 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval-plugins@1.4.0: + resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + + seroval@1.4.0: + resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + engines: {node: '>=10'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3843,6 +4208,9 @@ packages: smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + solid-js@1.9.10: + resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} + sonner@1.7.4: resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} peerDependencies: @@ -3860,6 +4228,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -3872,8 +4244,8 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} @@ -3996,19 +4368,22 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} tldts-core@7.0.16: @@ -4107,6 +4482,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unplugin@2.3.10: + resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} + engines: {node: '>=18.12.0'} + upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} @@ -4142,6 +4521,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -4166,8 +4550,8 @@ packages: '@vite-pwa/assets-generator': optional: true - vite@7.2.7: - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4206,20 +4590,21 @@ packages: yaml: optional: true - vitest@4.0.15: - resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + vitest@4.1.2: + resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.15 - '@vitest/browser-preview': 4.0.15 - '@vitest/browser-webdriverio': 4.0.15 - '@vitest/ui': 4.0.15 + '@vitest/browser-playwright': 4.1.2 + '@vitest/browser-preview': 4.1.2 + '@vitest/browser-webdriverio': 4.1.2 + '@vitest/ui': 4.1.2 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -4258,6 +4643,9 @@ packages: resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -4434,7 +4822,7 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -4447,10 +4835,10 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 '@babel/traverse': 7.28.4 - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -4461,6 +4849,14 @@ snapshots: - supports-color '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.28.5': dependencies: '@babel/parser': 7.28.5 '@babel/types': 7.28.5 @@ -4470,7 +4866,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 '@babel/helper-compilation-targets@7.27.2': dependencies: @@ -4480,15 +4876,15 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -4513,9 +4909,9 @@ snapshots: '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.27.1': + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -4523,7 +4919,7 @@ snapshots: '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -4531,14 +4927,14 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.27.1 '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 '@babel/helper-plugin-utils@7.27.1': {} @@ -4547,28 +4943,30 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} @@ -4576,7 +4974,7 @@ snapshots: '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -4584,17 +4982,25 @@ snapshots: '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/types': 7.28.4 + + '@babel/parser@7.28.4': + dependencies: + '@babel/types': 7.28.4 '@babel/parser@7.28.5': dependencies: '@babel/types': 7.28.5 + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4621,7 +5027,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4639,6 +5045,16 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 @@ -4655,7 +5071,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4681,7 +5097,7 @@ snapshots: '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -4689,7 +5105,7 @@ snapshots: '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -4702,7 +5118,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4716,7 +5132,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4773,7 +5189,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4819,7 +5235,7 @@ snapshots: '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4859,7 +5275,7 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4892,7 +5308,7 @@ snapshots: '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -4901,7 +5317,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -4955,6 +5371,17 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 @@ -5061,19 +5488,42 @@ snapshots: '@babel/types': 7.28.5 esutils: 2.0.3 + '@babel/preset-typescript@7.28.5(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.4) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.28.4': {} '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@babel/traverse@7.28.4': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.3 '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/types': 7.28.5 @@ -5081,11 +5531,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/types@7.28.4': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@1.0.2': {} '@csstools/color-helpers@5.1.0': {} @@ -5117,81 +5577,159 @@ snapshots: '@esbuild/aix-ppc64@0.25.10': optional: true + '@esbuild/aix-ppc64@0.27.4': + optional: true + '@esbuild/android-arm64@0.25.10': optional: true + '@esbuild/android-arm64@0.27.4': + optional: true + '@esbuild/android-arm@0.25.10': optional: true + '@esbuild/android-arm@0.27.4': + optional: true + '@esbuild/android-x64@0.25.10': optional: true + '@esbuild/android-x64@0.27.4': + optional: true + '@esbuild/darwin-arm64@0.25.10': optional: true + '@esbuild/darwin-arm64@0.27.4': + optional: true + '@esbuild/darwin-x64@0.25.10': optional: true + '@esbuild/darwin-x64@0.27.4': + optional: true + '@esbuild/freebsd-arm64@0.25.10': optional: true + '@esbuild/freebsd-arm64@0.27.4': + optional: true + '@esbuild/freebsd-x64@0.25.10': optional: true + '@esbuild/freebsd-x64@0.27.4': + optional: true + '@esbuild/linux-arm64@0.25.10': optional: true + '@esbuild/linux-arm64@0.27.4': + optional: true + '@esbuild/linux-arm@0.25.10': optional: true + '@esbuild/linux-arm@0.27.4': + optional: true + '@esbuild/linux-ia32@0.25.10': optional: true + '@esbuild/linux-ia32@0.27.4': + optional: true + '@esbuild/linux-loong64@0.25.10': optional: true + '@esbuild/linux-loong64@0.27.4': + optional: true + '@esbuild/linux-mips64el@0.25.10': optional: true + '@esbuild/linux-mips64el@0.27.4': + optional: true + '@esbuild/linux-ppc64@0.25.10': optional: true + '@esbuild/linux-ppc64@0.27.4': + optional: true + '@esbuild/linux-riscv64@0.25.10': optional: true + '@esbuild/linux-riscv64@0.27.4': + optional: true + '@esbuild/linux-s390x@0.25.10': optional: true + '@esbuild/linux-s390x@0.27.4': + optional: true + '@esbuild/linux-x64@0.25.10': optional: true + '@esbuild/linux-x64@0.27.4': + optional: true + '@esbuild/netbsd-arm64@0.25.10': optional: true + '@esbuild/netbsd-arm64@0.27.4': + optional: true + '@esbuild/netbsd-x64@0.25.10': optional: true + '@esbuild/netbsd-x64@0.27.4': + optional: true + '@esbuild/openbsd-arm64@0.25.10': optional: true + '@esbuild/openbsd-arm64@0.27.4': + optional: true + '@esbuild/openbsd-x64@0.25.10': optional: true + '@esbuild/openbsd-x64@0.27.4': + optional: true + '@esbuild/openharmony-arm64@0.25.10': optional: true + '@esbuild/openharmony-arm64@0.27.4': + optional: true + '@esbuild/sunos-x64@0.25.10': optional: true + '@esbuild/sunos-x64@0.27.4': + optional: true + '@esbuild/win32-arm64@0.25.10': optional: true + '@esbuild/win32-arm64@0.27.4': + optional: true + '@esbuild/win32-ia32@0.25.10': optional: true + '@esbuild/win32-ia32@0.27.4': + optional: true + '@esbuild/win32-x64@0.25.10': optional: true + '@esbuild/win32-x64@0.27.4': + optional: true + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -5970,9 +6508,7 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@remix-run/router@1.23.0': {} - - '@rolldown/pluginutils@1.0.0-beta.47': {} + '@rolldown/pluginutils@1.0.0-rc.7': {} '@rollup/plugin-babel@5.3.1(@babel/core@7.28.4)(rollup@2.79.2)': dependencies: @@ -6088,7 +6624,7 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.2': optional: true - '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} '@supabase/auth-js@2.81.1': dependencies: @@ -6134,51 +6670,59 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.12 - '@swc/core-darwin-arm64@1.13.19': + '@swc/core-darwin-arm64@1.15.21': + optional: true + + '@swc/core-darwin-x64@1.15.21': optional: true - '@swc/core-darwin-x64@1.13.19': + '@swc/core-linux-arm-gnueabihf@1.15.21': optional: true - '@swc/core-linux-arm-gnueabihf@1.13.19': + '@swc/core-linux-arm64-gnu@1.15.21': optional: true - '@swc/core-linux-arm64-gnu@1.13.19': + '@swc/core-linux-arm64-musl@1.15.21': optional: true - '@swc/core-linux-arm64-musl@1.13.19': + '@swc/core-linux-ppc64-gnu@1.15.21': optional: true - '@swc/core-linux-x64-gnu@1.13.19': + '@swc/core-linux-s390x-gnu@1.15.21': optional: true - '@swc/core-linux-x64-musl@1.13.19': + '@swc/core-linux-x64-gnu@1.15.21': optional: true - '@swc/core-win32-arm64-msvc@1.13.19': + '@swc/core-linux-x64-musl@1.15.21': optional: true - '@swc/core-win32-ia32-msvc@1.13.19': + '@swc/core-win32-arm64-msvc@1.15.21': optional: true - '@swc/core-win32-x64-msvc@1.13.19': + '@swc/core-win32-ia32-msvc@1.15.21': optional: true - '@swc/core@1.13.19': + '@swc/core-win32-x64-msvc@1.15.21': + optional: true + + '@swc/core@1.15.21': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.13.19 - '@swc/core-darwin-x64': 1.13.19 - '@swc/core-linux-arm-gnueabihf': 1.13.19 - '@swc/core-linux-arm64-gnu': 1.13.19 - '@swc/core-linux-arm64-musl': 1.13.19 - '@swc/core-linux-x64-gnu': 1.13.19 - '@swc/core-linux-x64-musl': 1.13.19 - '@swc/core-win32-arm64-msvc': 1.13.19 - '@swc/core-win32-ia32-msvc': 1.13.19 - '@swc/core-win32-x64-msvc': 1.13.19 + '@swc/core-darwin-arm64': 1.15.21 + '@swc/core-darwin-x64': 1.15.21 + '@swc/core-linux-arm-gnueabihf': 1.15.21 + '@swc/core-linux-arm64-gnu': 1.15.21 + '@swc/core-linux-arm64-musl': 1.15.21 + '@swc/core-linux-ppc64-gnu': 1.15.21 + '@swc/core-linux-s390x-gnu': 1.15.21 + '@swc/core-linux-x64-gnu': 1.15.21 + '@swc/core-linux-x64-musl': 1.15.21 + '@swc/core-win32-arm64-msvc': 1.15.21 + '@swc/core-win32-ia32-msvc': 1.15.21 + '@swc/core-win32-x64-msvc': 1.15.21 '@swc/counter@0.1.3': {} @@ -6195,6 +6739,8 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 3.4.17 + '@tanstack/history@1.133.28': {} + '@tanstack/query-async-storage-persister@5.90.2': dependencies: '@tanstack/query-core': 5.90.2 @@ -6225,6 +6771,170 @@ snapshots: '@tanstack/query-core': 5.90.2 react: 18.3.1 + '@tanstack/react-router-devtools@1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)': + dependencies: + '@tanstack/react-router': 1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-devtools-core': 1.136.17(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + '@tanstack/router-core': 1.136.17 + transitivePeerDependencies: + - '@types/node' + - csstype + - jiti + - less + - lightningcss + - sass + - sass-embedded + - solid-js + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/history': 1.133.28 + '@tanstack/react-store': 0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-core': 1.136.17 + isbot: 5.1.32 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-store@0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/store': 0.8.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) + + '@tanstack/router-core@1.136.17': + dependencies: + '@tanstack/history': 1.133.28 + '@tanstack/store': 0.8.0 + cookie-es: 2.0.0 + seroval: 1.4.0 + seroval-plugins: 1.4.0(seroval@1.4.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/router-devtools-core@1.136.17(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)': + dependencies: + '@tanstack/router-core': 1.136.17 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.1.3) + solid-js: 1.9.10 + tiny-invariant: 1.3.3 + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + csstype: 3.1.3 + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/router-devtools@1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)': + dependencies: + '@tanstack/react-router': 1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router-devtools': 1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tanstack/router-core@1.136.17)(@types/node@22.18.6)(csstype@3.1.3)(jiti@1.21.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(solid-js@1.9.10)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + clsx: 2.1.1 + goober: 2.1.18(csstype@3.1.3) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + optionalDependencies: + csstype: 3.1.3 + transitivePeerDependencies: + - '@tanstack/router-core' + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - solid-js + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/router-generator@1.136.17': + dependencies: + '@tanstack/router-core': 1.136.17 + '@tanstack/router-utils': 1.133.19 + '@tanstack/virtual-file-routes': 1.133.19 + prettier: 3.6.2 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.20.6 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@tanstack/router-core': 1.136.17 + '@tanstack/router-generator': 1.136.17 + '@tanstack/router-utils': 1.133.19 + '@tanstack/virtual-file-routes': 1.133.19 + babel-dead-code-elimination: 1.0.10 + chokidar: 3.6.0 + unplugin: 2.3.10 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.133.19': + dependencies: + '@babel/core': 7.28.4 + '@babel/generator': 7.28.3 + '@babel/parser': 7.28.4 + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.4) + ansis: 4.2.0 + diff: 8.0.2 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-vite-plugin@1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@tanstack/router-plugin': 1.136.18(@tanstack/react-router@1.136.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + transitivePeerDependencies: + - '@rsbuild/core' + - '@tanstack/react-router' + - supports-color + - vite + - vite-plugin-solid + - webpack + + '@tanstack/store@0.8.0': {} + + '@tanstack/virtual-file-routes@1.133.19': {} + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.27.1 @@ -6245,7 +6955,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.28.4 '@testing-library/dom': 10.4.1 @@ -6330,80 +7040,79 @@ snapshots: optionalDependencies: react: 18.3.1 - '@vitejs/plugin-react-swc@4.2.2(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.3.0(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@rolldown/pluginutils': 1.0.0-beta.47 - '@swc/core': 1.13.19 - vite: 7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + '@rolldown/pluginutils': 1.0.0-rc.7 + '@swc/core': 1.15.21 + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitest/coverage-v8@4.0.15(vitest@4.0.15)': + '@vitest/coverage-v8@4.1.2(vitest@4.1.2)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.15 - ast-v8-to-istanbul: 0.3.8 + '@vitest/utils': 4.1.2 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - magicast: 0.5.1 + magicast: 0.5.2 obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@types/node@22.18.6)(@vitest/ui@4.0.15)(jiti@1.21.7)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - supports-color + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@types/node@22.18.6)(@vitest/ui@4.1.2)(jsdom@27.0.0(postcss@8.5.6))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/expect@4.0.15': + '@vitest/expect@4.1.2': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.2 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 - chai: 6.2.1 - tinyrainbow: 3.0.3 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + chai: 6.2.2 + tinyrainbow: 3.1.0 - '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@4.1.2(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.1.2 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/pretty-format@4.0.15': + '@vitest/pretty-format@4.1.2': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/runner@4.0.15': + '@vitest/runner@4.1.2': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.1.2 pathe: 2.0.3 - '@vitest/snapshot@4.0.15': + '@vitest/snapshot@4.1.2': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.1.2 + '@vitest/utils': 4.1.2 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.15': {} + '@vitest/spy@4.1.2': {} - '@vitest/ui@4.0.15(vitest@4.0.15)': + '@vitest/ui@4.1.2(vitest@4.1.2)': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.1.2 fflate: 0.8.2 - flatted: 3.3.3 + flatted: 3.4.2 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@types/node@22.18.6)(@vitest/ui@4.0.15)(jiti@1.21.7)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + tinyrainbow: 3.1.0 + vitest: 4.1.2(@types/node@22.18.6)(@vitest/ui@4.1.2)(jsdom@27.0.0(postcss@8.5.6))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils@4.0.15': + '@vitest/utils@4.1.2': dependencies: - '@vitest/pretty-format': 4.0.15 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.2 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 acorn@8.15.0: {} @@ -6432,6 +7141,8 @@ snapshots: ansi-styles@6.2.3: {} + ansis@4.2.0: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -6466,11 +7177,15 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 - ast-v8-to-istanbul@0.3.8: + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + + ast-v8-to-istanbul@1.0.0: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 - js-tokens: 9.0.1 + js-tokens: 10.0.0 async-function@1.0.0: {} @@ -6492,6 +7207,15 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + babel-dead-code-elimination@1.0.10: + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): dependencies: '@babel/compat-data': 7.28.4 @@ -6518,7 +7242,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.9.5: {} + baseline-browser-mapping@2.10.13: {} bidi-js@1.0.3: dependencies: @@ -6549,7 +7273,7 @@ snapshots: browserslist@4.26.2: dependencies: - baseline-browser-mapping: 2.9.5 + baseline-browser-mapping: 2.10.13 caniuse-lite: 1.0.30001745 electron-to-chromium: 1.5.224 node-releases: 2.0.21 @@ -6578,7 +7302,7 @@ snapshots: caniuse-lite@1.0.30001745: {} - chai@6.2.1: {} + chai@6.2.2: {} chokidar@3.6.0: dependencies: @@ -6645,6 +7369,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@2.0.0: {} + core-js-compat@3.45.1: dependencies: browserslist: 4.26.2 @@ -6777,6 +7503,8 @@ snapshots: didyoumean@1.2.2: {} + diff@8.0.2: {} + dlv@1.1.3: {} dom-accessibility-api@0.5.16: {} @@ -6885,7 +7613,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: dependencies: @@ -6933,8 +7661,39 @@ snapshots: '@esbuild/win32-ia32': 0.25.10 '@esbuild/win32-x64': 0.25.10 + esbuild@0.27.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 + escalade@3.2.0: {} + esprima@4.0.1: {} + estree-walker@1.0.1: {} estree-walker@2.0.2: {} @@ -6949,7 +7708,7 @@ snapshots: eventemitter3@5.0.1: {} - expect-type@1.2.2: {} + expect-type@1.3.0: {} fast-deep-equal@3.1.3: {} @@ -6992,7 +7751,7 @@ snapshots: dependencies: to-regex-range: 5.0.1 - flatted@3.3.3: {} + flatted@3.4.2: {} for-each@0.3.5: dependencies: @@ -7119,6 +7878,10 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + goober@2.1.18(csstype@3.1.3): + dependencies: + csstype: 3.1.3 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -7332,6 +8095,8 @@ snapshots: isarray@2.0.5: {} + isbot@5.1.32: {} + isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -7342,14 +8107,6 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@5.0.6: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - transitivePeerDependencies: - - supports-color - istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 @@ -7369,9 +8126,9 @@ snapshots: jiti@1.21.7: {} - js-tokens@4.0.0: {} + js-tokens@10.0.0: {} - js-tokens@9.0.1: {} + js-tokens@4.0.0: {} jsdom@27.0.0(postcss@8.5.6): dependencies: @@ -7482,15 +8239,15 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.5.1: + magicast@0.5.2: dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 source-map-js: 1.2.1 make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 marked@16.3.0: {} @@ -7791,18 +8548,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router-dom@6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@remix-run/router': 1.23.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.30.1(react@18.3.1) - - react-router@6.30.1(react@18.3.1): - dependencies: - '@remix-run/router': 1.23.0 - react: 18.3.1 - react-smooth@4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: fast-equals: 5.3.2 @@ -7842,6 +8587,14 @@ snapshots: dependencies: picomatch: 2.3.1 + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + recharts-scale@0.4.5: dependencies: decimal.js-light: 2.5.1 @@ -7995,12 +8748,24 @@ snapshots: semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 + seroval-plugins@1.3.3(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval-plugins@1.4.0(seroval@1.4.0): + dependencies: + seroval: 1.4.0 + + seroval@1.3.2: {} + + seroval@1.4.0: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -8076,6 +8841,12 @@ snapshots: smob@1.5.0: {} + solid-js@1.9.10: + dependencies: + csstype: 3.1.3 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + sonner@1.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 @@ -8090,6 +8861,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 @@ -8098,7 +8871,7 @@ snapshots: stackback@0.0.2: {} - std-env@3.10.0: {} + std-env@4.0.0: {} stop-iteration-iterator@1.1.0: dependencies: @@ -8283,16 +9056,18 @@ snapshots: tiny-invariant@1.3.3: {} + tiny-warning@1.0.3: {} + tinybench@2.9.0: {} - tinyexec@1.0.2: {} + tinyexec@1.0.4: {} tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} tldts-core@7.0.16: {} @@ -8397,6 +9172,13 @@ snapshots: universalify@2.0.1: {} + unplugin@2.3.10: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + upath@1.2.0: {} update-browserslist-db@1.1.3(browserslist@4.26.2): @@ -8424,6 +9206,10 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + util-deprecate@1.0.2: {} vaul@0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -8452,20 +9238,20 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-pwa@1.2.0(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0)(workbox-window@7.3.0): + vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0)(workbox-window@7.3.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) workbox-build: 7.3.0 workbox-window: 7.3.0 transitivePeerDependencies: - supports-color - vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: - esbuild: 0.25.10 + esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 @@ -8479,44 +9265,34 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vitest@4.0.15(@types/node@22.18.6)(@vitest/ui@4.0.15)(jiti@1.21.7)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 4.0.15 - '@vitest/runner': 4.0.15 - '@vitest/snapshot': 4.0.15 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 - es-module-lexer: 1.7.0 - expect-type: 1.2.2 + vitest@4.1.2(@types/node@22.18.6)(@vitest/ui@4.1.2)(jsdom@27.0.0(postcss@8.5.6))(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(vite@7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 - std-env: 3.10.0 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.2.7(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + tinyrainbow: 3.1.0 + vite: 7.3.1(@types/node@22.18.6)(jiti@1.21.7)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.18.6 - '@vitest/ui': 4.0.15(vitest@4.0.15) + '@vitest/ui': 4.1.2(vitest@4.1.2) jsdom: 27.0.0(postcss@8.5.6) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml w3c-xmlserializer@5.0.0: dependencies: @@ -8530,6 +9306,8 @@ snapshots: webidl-conversions@8.0.0: {} + webpack-virtual-modules@0.6.2: {} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index 75092b4b..00000000 --- a/src/App.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { SpeedInsights } from "@vercel/speed-insights/react"; -import { Toaster } from "@/components/ui/toaster"; -import { Toaster as Sonner } from "@/components/ui/sonner"; -import { TooltipProvider } from "@/components/ui/tooltip"; -import { BrowserRouter } from "react-router-dom"; -import { HelmetProvider } from "react-helmet-async"; -import { CookieConsentBanner } from "@/components/layout/legal/CookieConsentBanner"; -import { OfflineIndicator } from "@/components/ui/OfflineIndicator"; -import { - getSubdomainInfo, - shouldRedirectFromWww, - getNonWwwRedirectUrl, -} from "@/lib/subdomain"; -import { AuthProvider } from "@/contexts/AuthContext"; -import { useState, useEffect } from "react"; -import { FestivalEditionProvider } from "./contexts/FestivalEditionContext"; -import { AppRoutes } from "./components/router/AppRoutes"; - -function App() { - const [subdomainInfo] = useState(() => getSubdomainInfo()); - - // Redirect www.getupline.com to getupline.com - useEffect(() => { - if (shouldRedirectFromWww()) { - window.location.href = getNonWwwRedirectUrl(); - } - }, []); - - return ( - - - - - - - - - - - - - - - - - - ); -} - -export default App; diff --git a/src/components/invite/useInviteValidation.ts b/src/components/invite/useInviteValidation.ts index e4c585cf..ca8f0773 100644 --- a/src/components/invite/useInviteValidation.ts +++ b/src/components/invite/useInviteValidation.ts @@ -1,29 +1,18 @@ -import { useState, useEffect } from "react"; -import { useSearchParams } from "react-router-dom"; +import { useEffect } from "react"; import { useToast } from "@/components/ui/use-toast"; import { useInviteValidationQuery, useInviteMutation, } from "@/hooks/queries/useInviteValidationQuery"; -export function useInviteValidation() { - const [searchParams] = useSearchParams(); - const [inviteToken, setInviteToken] = useState(null); +export function useInviteValidation(inviteToken: string | undefined) { const { toast } = useToast(); - // Extract token from search params - useEffect(() => { - const token = searchParams.get("invite"); - if (token) { - setInviteToken(token); - } - }, [searchParams]); - const { data: inviteValidation, isLoading: isValidating, error: validationError, - } = useInviteValidationQuery(inviteToken); + } = useInviteValidationQuery(inviteToken || null); const inviteMutation = useInviteMutation(); @@ -69,7 +58,6 @@ export function useInviteValidation() { userId, }); - // Show success message with group name if available toast({ title: "Success", description: `Welcome to ${inviteValidation?.group_name || "the group"}!`, @@ -78,22 +66,16 @@ export function useInviteValidation() { return true; } catch (error) { console.error("failed validating invite", error); - // Error handling is done in the mutation return false; } } - function clearInvite() { - setInviteToken(null); - } - return { - inviteToken, + inviteToken: inviteToken || null, inviteValidation, isValidating, validationError: validationError?.message || null, useInvite, - clearInvite, hasValidInvite: inviteValidation?.is_valid === true, }; } diff --git a/src/components/layout/AppFooter.tsx b/src/components/layout/AppFooter.tsx index 5c03054c..d136815e 100644 --- a/src/components/layout/AppFooter.tsx +++ b/src/components/layout/AppFooter.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { Settings } from "lucide-react"; diff --git a/src/components/layout/AppHeader/AdminActions.tsx b/src/components/layout/AppHeader/AdminActions.tsx index 74362467..7ee32c1e 100644 --- a/src/components/layout/AppHeader/AdminActions.tsx +++ b/src/components/layout/AppHeader/AdminActions.tsx @@ -1,6 +1,6 @@ import { Menu, Settings } from "lucide-react"; import { Button } from "@/components/ui/button"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { DropdownMenu, DropdownMenuContent, diff --git a/src/components/layout/AppHeader/AppBranding.tsx b/src/components/layout/AppHeader/AppBranding.tsx index f36925ab..ebc2459e 100644 --- a/src/components/layout/AppHeader/AppBranding.tsx +++ b/src/components/layout/AppHeader/AppBranding.tsx @@ -1,4 +1,4 @@ -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { Music } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; diff --git a/src/components/layout/AppHeader/Navigation.tsx b/src/components/layout/AppHeader/Navigation.tsx index c6d46bae..26572e76 100644 --- a/src/components/layout/AppHeader/Navigation.tsx +++ b/src/components/layout/AppHeader/Navigation.tsx @@ -1,4 +1,4 @@ -import { Link, useNavigate } from "react-router-dom"; +import { Link, useRouter } from "@tanstack/react-router"; import { ArrowLeft, Users } from "lucide-react"; import { Button } from "@/components/ui/button"; import { @@ -49,7 +49,7 @@ export function Navigation({ isMobile, }: NavigationProps) { const { user } = useAuth(); - const navigate = useNavigate(); + const router = useRouter(); return (
@@ -58,7 +58,7 @@ export function Navigation({ navigate(-1)} + onClick={() => router.history.back()} className="border-purple-400/50 text-purple-300 hover:bg-purple-600 hover:text-white hover:border-purple-600 transition-colors" tooltip={backLabel} isMobile={isMobile} diff --git a/src/components/layout/AppHeader/UserMenu.tsx b/src/components/layout/AppHeader/UserMenu.tsx index fc571875..f2cd425e 100644 --- a/src/components/layout/AppHeader/UserMenu.tsx +++ b/src/components/layout/AppHeader/UserMenu.tsx @@ -11,7 +11,7 @@ import { import { Button } from "@/components/ui/button"; import { UserAvatar } from "./UserAvatar"; import { Database } from "@/integrations/supabase/types"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { useUserPermissionsQuery } from "@/hooks/queries/auth/useUserPermissions"; type Profile = Database["public"]["Tables"]["profiles"]["Row"]; diff --git a/src/components/router/EditionRoutes.tsx b/src/components/router/EditionRoutes.tsx deleted file mode 100644 index c6f2c017..00000000 --- a/src/components/router/EditionRoutes.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Navigate, Route } from "react-router-dom"; -import EditionLayout from "@/pages/EditionView/EditionLayout"; -import { SetDetails } from "@/pages/SetDetails"; -import { ExploreSetPage } from "@/pages/ExploreSetPage/ExploreSetPage"; - -// Tab components -import { ArtistsTab } from "@/pages/EditionView/tabs/ArtistsTab/ArtistsTab"; -import { MapTab } from "@/pages/EditionView/tabs/MapTab"; -import { InfoTab } from "@/pages/EditionView/tabs/InfoTab"; -import { SocialTab } from "@/pages/EditionView/tabs/SocialTab"; -import { ScheduleTabTimeline } from "@/pages/EditionView/tabs/ScheduleTab/TimelineTab"; -import { ScheduleTabList } from "@/pages/EditionView/tabs/ScheduleTab/list/ListTab"; -import { ScheduleTab } from "@/pages/EditionView/tabs/ScheduleTab"; - -interface EditionRoutesProps { - basePath: string; - WrapperComponent?: React.ComponentType<{ component: React.ComponentType }>; -} - -export function createEditionRoutes({ - basePath, - WrapperComponent, -}: EditionRoutesProps) { - const EditionComponent = WrapperComponent - ? () => - : EditionLayout; - - const SetDetailsComponent = WrapperComponent - ? () => - : SetDetails; - - const ExploreComponent = WrapperComponent - ? () => - : ExploreSetPage; - - return [ - }> - {/* Nested tab routes */} - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - - , - } - />, - } - />, - ]; -} diff --git a/src/components/router/GlobalRoutes.tsx b/src/components/router/GlobalRoutes.tsx deleted file mode 100644 index bc8794e4..00000000 --- a/src/components/router/GlobalRoutes.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Navigate, Route, Routes } from "react-router-dom"; - -import AdminAnalytics from "@/pages/admin/Analytics/AdminAnalytics"; -import AdminFestivals from "@/pages/admin/festivals/AdminFestivals"; -import FestivalDetail from "@/pages/admin/festivals/FestivalDetail"; -import FestivalEdition from "@/pages/admin/festivals/FestivalEdition"; -import FestivalSets from "@/pages/admin/festivals/FestivalSets"; -import FestivalStages from "@/pages/admin/festivals/FestivalStages"; -import AdminLayout from "@/pages/admin/AdminLayout"; -import CookiePolicy from "@/pages/legal/CookiePolicy"; -import GroupDetail from "@/pages/groups/GroupDetail"; -import Groups from "@/pages/groups/Groups"; -import PrivacyPolicy from "@/pages/legal/PrivacyPolicy"; -import TermsOfService from "@/pages/legal/TermsOfService"; -import NotFound from "@/pages/NotFound"; -import { AdminRolesTable } from "@/pages/admin/Roles/AdminRolesTable"; -import { DuplicateArtistsPage } from "@/pages/admin/ArtistsManagement/DuplicateArtistsPage"; -import { ArtistBulkEditor } from "@/pages/admin/ArtistsManagement/ArtistBulkEditor"; -import { CSVImportPage } from "@/pages/admin/festivals/CSVImportPage"; - -export function GlobalRoutes() { - return ( - - {/* Global routes (not scoped to festival/edition) */} - } /> - } /> - - {/* Admin routes */} - }> - } /> - } /> - } /> - } /> - } /> - } /> - } - /> - }> - }> - }> - } /> - } /> - } /> - - - - - - {/* Legal pages */} - } /> - } /> - } /> - - } /> - - ); -} diff --git a/src/components/router/MainDomainRoutes.tsx b/src/components/router/MainDomainRoutes.tsx deleted file mode 100644 index a0e48892..00000000 --- a/src/components/router/MainDomainRoutes.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Routes, Route } from "react-router-dom"; - -import { SubdomainRedirect } from "./SubdomainRedirect"; -import FestivalSelection from "@/pages/FestivalSelection"; -import EditionSelection from "@/pages/EditionSelection"; -import { GlobalRoutes } from "./GlobalRoutes"; -import { createEditionRoutes } from "./EditionRoutes"; -import { useState } from "react"; - -/** - * Routes for main domain access (getupline.com) - * Includes festival selection and full admin interface - */ -export function MainDomainRoutes() { - const [editionRoutes] = useState( - createEditionRoutes({ - basePath: "/festivals/:festivalSlug/editions/:editionSlug", - WrapperComponent: SubdomainRedirect, - }), - ); - - return ( - <> - - {/* Festival/Edition Selection Routes */} - } /> - {/* Festival routes redirect to subdomains */} - } - /> - {/* Edition routes with subdomain redirect wrapper */} - {editionRoutes} - - } /> - - - ); -} diff --git a/src/components/router/SubdomainRedirect.tsx b/src/components/router/SubdomainRedirect.tsx deleted file mode 100644 index 5aa77b76..00000000 --- a/src/components/router/SubdomainRedirect.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useEffect } from "react"; -import { useParams } from "react-router-dom"; -import { - createFestivalSubdomainUrl, - isMainGetuplineDomain, -} from "@/lib/subdomain"; - -interface SubdomainRedirectProps { - component: React.ComponentType; -} -/** - * Component that redirects main domain festival URLs to subdomains - * Used for: /festivals/boom-festival -> boom-festival.getupline.com - * For localhost development, renders the appropriate component directly - */ -export function SubdomainRedirect({ - component: Component, -}: SubdomainRedirectProps) { - const { festivalSlug, editionSlug, setSlug } = useParams<{ - festivalSlug?: string; - editionSlug?: string; - setSlug?: string; - }>(); - - const shouldNotRedirect = !isMainGetuplineDomain(); - - useEffect(() => { - if (!festivalSlug || shouldNotRedirect) { - return; - } - - // Build the target path based on current route - let targetPath = "/"; - - if (editionSlug && setSlug) { - targetPath = `/editions/${editionSlug}/sets/${setSlug}`; - } else if (editionSlug && window.location.pathname.includes("schedule")) { - targetPath = `/editions/${editionSlug}/schedule`; - } else if (editionSlug) { - targetPath = `/editions/${editionSlug}`; - } - - // Redirect to subdomain - const subdomainUrl = createFestivalSubdomainUrl(festivalSlug, targetPath); - window.location.href = subdomainUrl; - }, [festivalSlug, editionSlug, setSlug, shouldNotRedirect]); - - if (shouldNotRedirect) { - return ; - } - - // Show loading message while redirecting (production only) - return ( - <> -
-
-
Redirecting...
-
- Taking you to{" "} - {festivalSlug - ? `${festivalSlug}.getupline.com` - : "the festival site"} -
-
-
- {/* */} - - ); -} diff --git a/src/components/router/SubdomainRoutes.tsx b/src/components/router/SubdomainRoutes.tsx deleted file mode 100644 index 51b16c19..00000000 --- a/src/components/router/SubdomainRoutes.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Routes, Route } from "react-router-dom"; -import EditionSelection from "@/pages/EditionSelection"; -import { GlobalRoutes } from "./GlobalRoutes"; -import { createEditionRoutes } from "./EditionRoutes"; -import { useState } from "react"; - -/** - * Routes for subdomain access (boom-festival.getupline.com) - * Root path shows edition selection for the festival - */ -export function SubdomainRoutes() { - const [editionRoutes] = useState(() => - createEditionRoutes({ - basePath: "/editions/:editionSlug", - }), - ); - - return ( - - } /> - {/* Edition-specific routes */} - {editionRoutes} - - } /> - - ); -} diff --git a/src/contexts/FestivalEditionContext.tsx b/src/contexts/FestivalEditionContext.tsx index 59faa47a..40402e30 100644 --- a/src/contexts/FestivalEditionContext.tsx +++ b/src/contexts/FestivalEditionContext.tsx @@ -5,7 +5,7 @@ import { useEffect, useMemo, } from "react"; -import { matchPath, Navigate, useLocation } from "react-router-dom"; +import { useLocation, useNavigate } from "@tanstack/react-router"; import { useFestivalBySlugQuery } from "@/hooks/queries/festivals/useFestivalBySlug"; import { Festival } from "@/hooks/queries/festivals/types"; import { useFestivalEditionBySlugQuery } from "@/hooks/queries/festivals/editions/useFestivalEditionBySlug"; @@ -46,10 +46,12 @@ function getSlugs(pathname: string) { let basePath = ""; // For main domain, extract festival slug from URL path if (pathname.includes("/festivals/")) { - const match = matchPath({ path: "/festivals/:festivalSlug/*" }, pathname); - festivalSlug = match?.params.festivalSlug || festivalSlug || ""; - pathname = pathname.replace(`/festivals/${festivalSlug}`, ""); - basePath = `/festivals/${festivalSlug}`; + const festivalMatch = pathname.match(/\/festivals\/([^/]+)/); + if (festivalMatch) { + festivalSlug = festivalMatch[1]; + pathname = pathname.replace(`/festivals/${festivalSlug}`, ""); + basePath = `/festivals/${festivalSlug}`; + } } if (!pathname.includes("/editions")) { @@ -59,26 +61,8 @@ function getSlugs(pathname: string) { }; } - const matchWithSlash = matchPath( - { path: "/editions/:editionSlug/*" }, - pathname, - ); - - if (matchWithSlash) { - const editionSlug = matchWithSlash?.params.editionSlug || ""; - - return { - basePath: basePath + `/editions/${editionSlug}`, - festivalSlug, - editionSlug, - }; - } - const matchWithoutSlash = matchPath( - { path: "/editions/:editionSlug" }, - pathname, - ); - - const editionSlug = matchWithoutSlash?.params.editionSlug || ""; + const editionMatch = pathname.match(/\/editions\/([^/]+)/); + const editionSlug = editionMatch ? editionMatch[1] : ""; return { basePath: basePath + `/editions/${editionSlug}`, @@ -98,6 +82,7 @@ export function FestivalEditionProvider({ children, }: PropsWithChildren) { const { festivalSlug, editionSlug, basePath } = useParseSlugs(); + const navigate = useNavigate(); const festivalQuery = useFestivalBySlugQuery(festivalSlug); @@ -147,6 +132,12 @@ export function FestivalEditionProvider({ } }, [editionQuery.error, toast, editionSlug]); + useEffect(() => { + if (festivalQuery.error || editionQuery.error) { + navigate({ to: "/" }); + } + }, [festivalQuery.error, editionQuery.error, navigate]); + if (festivalQuery.error || editionQuery.error) { return ( @@ -156,7 +147,6 @@ export function FestivalEditionProvider({

No valid festival or edition found

-
diff --git a/src/hooks/useTimelineUrlState.ts b/src/hooks/useTimelineUrlState.ts index 905b6368..3e83bff5 100644 --- a/src/hooks/useTimelineUrlState.ts +++ b/src/hooks/useTimelineUrlState.ts @@ -1,80 +1,79 @@ import { useCallback } from "react"; -import { useSearchParams } from "react-router-dom"; +import { useSearch, useNavigate } from "@tanstack/react-router"; +import type { TimelineSearch } from "@/lib/searchSchemas"; -export type TimelineView = "horizontal" | "list"; -export type TimeFilter = "all" | "morning" | "afternoon" | "evening"; +export type TimelineView = TimelineSearch["view"]; +export type TimeFilter = TimelineSearch["time"]; -export interface TimelineState { - timelineView: TimelineView; - selectedDay: string; // Dynamic based on festival dates - selectedTime: TimeFilter; - selectedStages: string[]; -} - -const defaultState: TimelineState = { - timelineView: "list", - selectedDay: "all", - selectedTime: "all", - selectedStages: [], -}; - -export function useTimelineUrlState() { - const [searchParams, setSearchParams] = useSearchParams(); - - const getStateFromUrl = useCallback((): TimelineState => { - return { - timelineView: - (searchParams.get("view") as TimelineView) || defaultState.timelineView, - selectedDay: searchParams.get("day") || defaultState.selectedDay, - selectedTime: - (searchParams.get("time") as TimeFilter) || defaultState.selectedTime, - selectedStages: - searchParams.get("stages")?.split(",").filter(Boolean) || - defaultState.selectedStages, - }; - }, [searchParams]); - - const updateTimelineState = useCallback( - (updates: Partial) => { - const currentState = getStateFromUrl(); - const newState = { ...currentState, ...updates }; - - const newParams = new URLSearchParams(); +export function useTimelineUrlState(tab: "timeline" | "list" = "timeline") { + const route = + `/festivals/$festivalSlug/editions/$editionSlug/schedule/${tab}` as const; + const state = useSearch({ + from: route, + }); + const navigate = useNavigate({ from: route }); - // Only add non-default values to URL - if (newState.timelineView !== defaultState.timelineView) { - newParams.set("view", newState.timelineView); - } - if (newState.selectedDay !== defaultState.selectedDay) { - newParams.set("day", newState.selectedDay); - } - if (newState.selectedTime !== defaultState.selectedTime) { - newParams.set("time", newState.selectedTime); - } - if (newState.selectedStages.length > 0) { - newParams.set("stages", newState.selectedStages.join(",")); - } + const updateView = useCallback( + (view: TimelineView) => { + navigate({ + to: ".", + search: (prev) => ({ ...prev, view }), + replace: true, + }); + }, + [navigate], + ); - setSearchParams(newParams, { replace: true }); + const updateDay = useCallback( + (day: string) => { + navigate({ + to: ".", + search: (prev) => ({ ...prev, day }), + replace: true, + }); }, - [getStateFromUrl, setSearchParams], + [navigate], ); - const clearTimelineFilters = useCallback(() => { - const currentState = getStateFromUrl(); - const newParams = new URLSearchParams(); + const updateTime = useCallback( + (time: TimeFilter) => { + navigate({ + to: ".", + search: (prev) => ({ ...prev, time }), + replace: true, + }); + }, + [navigate], + ); - // Keep view when clearing filters - if (currentState.timelineView !== defaultState.timelineView) { - newParams.set("view", currentState.timelineView); - } + const updateStages = useCallback( + (stages: string[]) => { + navigate({ + to: ".", + search: (prev) => ({ ...prev, stages }), + replace: true, + }); + }, + [navigate], + ); - setSearchParams(newParams, { replace: true }); - }, [getStateFromUrl, setSearchParams]); + const clearFilters = useCallback(() => { + navigate({ + to: ".", + search: (prev) => ({ view: prev.view }), + replace: true, + }); + }, [navigate]); return { - state: getStateFromUrl(), - updateState: updateTimelineState, - clearFilters: clearTimelineFilters, + view: state.view, + day: state.day, + time: state.time, + stages: state.stages, + updateView, + updateDay, + updateTime, + updateStages, + clearFilters, }; } diff --git a/src/hooks/useUrlState.ts b/src/hooks/useUrlState.ts index b52bb236..1b96ebce 100644 --- a/src/hooks/useUrlState.ts +++ b/src/hooks/useUrlState.ts @@ -1,129 +1,37 @@ import { useCallback } from "react"; -import { useSearchParams } from "react-router-dom"; +import { useNavigate, useSearch } from "@tanstack/react-router"; +import type { FilterSortSearch } from "@/lib/searchSchemas"; -export type SortOption = - | "name-asc" - | "name-desc" - | "rating-desc" - | "popularity-desc" - | "date-asc"; -export type TimelineView = "horizontal" | "list"; -export type MainTab = "artists" | "timeline" | "map" | "info" | "social"; +export type FilterSortState = FilterSortSearch; +export type SortOption = FilterSortSearch["sort"]; +export type TimelineView = FilterSortSearch["timelineView"]; -export interface FilterSortState { - sort: SortOption; - stages: string[]; - genres: string[]; - minRating: number; - timelineView: TimelineView; - use24Hour: boolean; - groupId?: string; - invite?: string; - sortLocked?: boolean; - votePerspective?: string; // For filtering votes by group -} - -const defaultState: FilterSortState = { - sort: "popularity-desc", - stages: [], - genres: [], - minRating: 0, - timelineView: "list", - use24Hour: true, - groupId: undefined, - invite: undefined, - sortLocked: false, - votePerspective: undefined, -}; - -export function useUrlState() { - const [searchParams, setSearchParams] = useSearchParams(); - - const getStateFromUrl = useCallback((): FilterSortState => { - return { - sort: (searchParams.get("sort") as SortOption) || defaultState.sort, - stages: - searchParams.get("stages")?.split(",").filter(Boolean) || - defaultState.stages, - genres: - searchParams.get("genres")?.split(",").filter(Boolean) || - defaultState.genres, - minRating: - parseInt(searchParams.get("minRating") || "0") || - defaultState.minRating, - timelineView: - (searchParams.get("timelineView") as TimelineView) || - defaultState.timelineView, - use24Hour: - searchParams.get("use24Hour") === "true" || defaultState.use24Hour, - groupId: searchParams.get("groupId") || defaultState.groupId, - invite: searchParams.get("invite") || defaultState.invite, - sortLocked: - searchParams.get("sortLocked") === "true" || defaultState.sortLocked, - votePerspective: - searchParams.get("votePerspective") || defaultState.votePerspective, - }; - }, [searchParams]); +export function useUrlState(page: "sets" | "set-detail" = "sets") { + const route = + page === "sets" + ? (`/festivals/$festivalSlug/editions/$editionSlug/sets` as const) + : (`/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug` as const); + const state = useSearch({ from: route }); + const navigate = useNavigate({ from: route }); const updateUrlState = useCallback( - (updates: Partial) => { - const currentState = getStateFromUrl(); - const newState = { ...currentState, ...updates }; - - const newParams = new URLSearchParams(); - - // Only add non-default values to URL - if (newState.sort !== defaultState.sort) { - newParams.set("sort", newState.sort); - } - if (newState.stages.length > 0) { - newParams.set("stages", newState.stages.join(",")); - } - if (newState.genres.length > 0) { - newParams.set("genres", newState.genres.join(",")); - } - if (newState.minRating > 0) { - newParams.set("minRating", newState.minRating.toString()); - } - if (newState.timelineView !== defaultState.timelineView) { - newParams.set("timelineView", newState.timelineView); - } - if (newState.use24Hour !== defaultState.use24Hour) { - newParams.set("use24Hour", newState.use24Hour.toString()); - } - if (newState.groupId) { - newParams.set("groupId", newState.groupId); - } - if (newState.invite) { - newParams.set("invite", newState.invite); - } - if (newState.sortLocked) { - newParams.set("sortLocked", newState.sortLocked.toString()); - } - if (newState.votePerspective) { - newParams.set("votePerspective", newState.votePerspective); - } - - setSearchParams(newParams, { replace: true }); + (updates: Partial) => { + navigate({ + to: ".", + search: (prev) => ({ ...prev, ...updates }), + replace: true, + }); }, - [getStateFromUrl, setSearchParams], + [navigate], ); const clearFilters = useCallback(() => { - const currentState = getStateFromUrl(); - const newParams = new URLSearchParams(); - - // Keep invite parameter when clearing filters - if (currentState.invite) { - newParams.set("invite", currentState.invite); - } - - setSearchParams(newParams, { replace: true }); - }, [getStateFromUrl, setSearchParams]); - - return { - state: getStateFromUrl(), - updateUrlState, - clearFilters, - }; + navigate({ + to: ".", + search: (prev) => ({ invite: prev.invite }), + replace: true, + }); + }, [navigate]); + + return { state, updateUrlState, clearFilters }; } diff --git a/src/lib/searchSchemas.ts b/src/lib/searchSchemas.ts new file mode 100644 index 00000000..804dbe49 --- /dev/null +++ b/src/lib/searchSchemas.ts @@ -0,0 +1,35 @@ +import { z } from "zod"; + +export const sortOptionSchema = z.enum([ + "name-asc", + "name-desc", + "rating-desc", + "popularity-desc", + "date-asc", +]); + +export const timelineViewSchema = z.enum(["horizontal", "list"]); + +export const filterSortSearchSchema = z.object({ + sort: sortOptionSchema.catch("popularity-desc"), + stages: z.array(z.string()).catch([]), + genres: z.array(z.string()).catch([]), + minRating: z.number().catch(0), + timelineView: timelineViewSchema.catch("list"), + use24Hour: z.boolean().catch(true), + groupId: z.string().optional(), + invite: z.string().optional(), + sortLocked: z.boolean().catch(false), + votePerspective: z.string().optional(), +}); + +export type FilterSortSearch = z.infer; + +export const timelineSearchSchema = z.object({ + view: timelineViewSchema.catch("list"), + day: z.string().catch("all"), + time: z.enum(["all", "morning", "afternoon", "evening"]).catch("all"), + stages: z.array(z.string()).catch([]), +}); + +export type TimelineSearch = z.infer; diff --git a/src/main.tsx b/src/main.tsx index 07b40a85..41a44d7f 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,7 +2,9 @@ import { createRoot } from "react-dom/client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { PostHogProvider } from "posthog-js/react"; -import App from "./App.tsx"; +import { RouterProvider, createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen"; +import NotFound from "./pages/NotFound"; import "./index.css"; const queryClient = new QueryClient({ @@ -17,18 +19,34 @@ const queryClient = new QueryClient({ }, }); +const router = createRouter({ + routeTree, + context: { + queryClient, + }, + defaultPreload: "intent", + defaultPreloadStaleTime: 0, + defaultNotFoundComponent: NotFound, +}); + +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + createRoot(document.getElementById("root")!).render( - + , diff --git a/src/pages/EditionSelection.tsx b/src/pages/EditionSelection.tsx index 97f32cc8..9a8331c5 100644 --- a/src/pages/EditionSelection.tsx +++ b/src/pages/EditionSelection.tsx @@ -10,7 +10,7 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; import { AppHeader } from "@/components/layout/AppHeader"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "@tanstack/react-router"; import { useFestivalEditionsForFestivalQuery } from "@/hooks/queries/festivals/editions/useFestivalEditionsForFestival"; import { FestivalEdition } from "@/hooks/queries/festivals/editions/types"; import { useEffect } from "react"; @@ -31,11 +31,20 @@ export default function EditionSelection() { ) { // If we're on a subdomain, navigate to /editions/slug // If we're on main domain, navigate to /festivals/festival-slug/editions/slug - const targetPath = subdomainInfo.isSubdomain - ? `/editions/${editionListQuery.data[0].slug}` - : `/festivals/${festival?.slug}/editions/${editionListQuery.data[0].slug}`; + const editionSlug = editionListQuery.data[0].slug; + const festivalSlug = festival.slug; - navigate(targetPath); + if (subdomainInfo.isSubdomain) { + navigate({ + to: "/festivals/$festivalSlug/editions/$editionSlug", + params: { festivalSlug, editionSlug }, + }); + } else { + navigate({ + to: "/festivals/$festivalSlug/editions/$editionSlug", + params: { festivalSlug, editionSlug }, + }); + } } }, [ editionListQuery.data, diff --git a/src/pages/EditionView/EditionLayout.tsx b/src/pages/EditionView/EditionLayout.tsx index 253da08a..c0645c5c 100644 --- a/src/pages/EditionView/EditionLayout.tsx +++ b/src/pages/EditionView/EditionLayout.tsx @@ -2,7 +2,7 @@ import { AppHeader } from "@/components/layout/AppHeader"; import { MainTabNavigation } from "./TabNavigation/TabNavigation"; import ErrorBoundary from "@/components/ErrorBoundary"; import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; -import { Outlet } from "react-router-dom"; +import { Outlet } from "@tanstack/react-router"; import { useCustomLinksQuery } from "@/hooks/queries/custom-links/useCustomLinks"; export default function EditionView() { diff --git a/src/pages/EditionView/TabNavigation/DesktopTabButton.tsx b/src/pages/EditionView/TabNavigation/DesktopTabButton.tsx index 7f9b27c6..75e46fc5 100644 --- a/src/pages/EditionView/TabNavigation/DesktopTabButton.tsx +++ b/src/pages/EditionView/TabNavigation/DesktopTabButton.tsx @@ -1,26 +1,45 @@ import { cn } from "@/lib/utils"; -import { NavLink } from "react-router-dom"; +import { Link, useParams } from "@tanstack/react-router"; import { TabButtonProps } from "./types"; -export function DesktopTabButton({ config, basePath }: TabButtonProps) { +const tabRoutes = { + sets: "/festivals/$festivalSlug/editions/$editionSlug/sets", + schedule: "/festivals/$festivalSlug/editions/$editionSlug/schedule", + map: "/festivals/$festivalSlug/editions/$editionSlug/map", + info: "/festivals/$festivalSlug/editions/$editionSlug/info", + social: "/festivals/$festivalSlug/editions/$editionSlug/social", + explore: "/festivals/$festivalSlug/editions/$editionSlug/explore", +} as const; + +export function DesktopTabButton({ config }: TabButtonProps) { + const { festivalSlug, editionSlug } = useParams({ + from: "/festivals/$festivalSlug/editions/$editionSlug", + }); + return ( - - cn( - ` - flex items-center justify-center gap-2 + to={tabRoutes[config.key]} + params={{ festivalSlug, editionSlug }} + activeProps={{ + className: cn( + `flex items-center justify-center gap-2 + px-6 py-3 rounded-lg + transition-all duration-200 active:scale-95 + bg-purple-600 text-white shadow-lg`, + ), + }} + inactiveProps={{ + className: cn( + `flex items-center justify-center gap-2 px-6 py-3 rounded-lg - transition-all duration-200 active:scale-95`, - isActive - ? "bg-purple-600 text-white shadow-lg" - : "text-purple-200 hover:text-white hover:bg-white/10", - ) - } + transition-all duration-200 active:scale-95 + text-purple-200 hover:text-white hover:bg-white/10`, + ), + }} > {config.label} - + ); } diff --git a/src/pages/EditionView/TabNavigation/MobileTabButton.tsx b/src/pages/EditionView/TabNavigation/MobileTabButton.tsx index d77f95e1..a4408c51 100644 --- a/src/pages/EditionView/TabNavigation/MobileTabButton.tsx +++ b/src/pages/EditionView/TabNavigation/MobileTabButton.tsx @@ -1,29 +1,39 @@ -import { NavLink } from "react-router-dom"; +import { Link, useParams, useMatchRoute } from "@tanstack/react-router"; import { TabButtonProps } from "./types"; -export function MobileTabButton({ config, basePath }: TabButtonProps) { +const tabRoutes = { + sets: "/festivals/$festivalSlug/editions/$editionSlug/sets", + schedule: "/festivals/$festivalSlug/editions/$editionSlug/schedule", + map: "/festivals/$festivalSlug/editions/$editionSlug/map", + info: "/festivals/$festivalSlug/editions/$editionSlug/info", + social: "/festivals/$festivalSlug/editions/$editionSlug/social", + explore: "/festivals/$festivalSlug/editions/$editionSlug/explore", +} as const; + +export function MobileTabButton({ config }: TabButtonProps) { + const { festivalSlug, editionSlug } = useParams({ + from: "/festivals/$festivalSlug/editions/$editionSlug", + }); + const matchRoute = useMatchRoute(); + const isActive = !!matchRoute({ to: tabRoutes[config.key] }); + return ( - ` - flex-1 flex flex-col items-center justify-center + to={tabRoutes[config.key]} + params={{ festivalSlug, editionSlug }} + className={`flex-1 flex flex-col items-center justify-center py-2 px-1 transition-colors duration-200 min-h-16 - ${isActive ? "text-purple-400" : "text-gray-400 active:text-purple-300"} - `} + ${isActive ? "text-purple-400" : "text-gray-400 active:text-purple-300"}`} > - {({ isActive }) => ( - <> - - - {config.shortLabel} - - - )} - + + + {config.shortLabel} + + ); } diff --git a/src/pages/EditionView/tabs/ArtistsTab/ArtistsTab.tsx b/src/pages/EditionView/tabs/ArtistsTab/ArtistsTab.tsx index cf3c310d..c18d1922 100644 --- a/src/pages/EditionView/tabs/ArtistsTab/ArtistsTab.tsx +++ b/src/pages/EditionView/tabs/ArtistsTab/ArtistsTab.tsx @@ -7,7 +7,7 @@ import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; import { PageTitle } from "@/components/PageTitle/PageTitle"; export function ArtistsTab() { - const { state: urlState, updateUrlState, clearFilters } = useUrlState(); + const { state: urlState, updateUrlState, clearFilters } = useUrlState("sets"); const { edition, festival } = useFestivalEdition(); // Fetch sets for the current edition diff --git a/src/pages/EditionView/tabs/ArtistsTab/SetCard/SetImage.tsx b/src/pages/EditionView/tabs/ArtistsTab/SetCard/SetImage.tsx index 8964e75f..74ec8120 100644 --- a/src/pages/EditionView/tabs/ArtistsTab/SetCard/SetImage.tsx +++ b/src/pages/EditionView/tabs/ArtistsTab/SetCard/SetImage.tsx @@ -1,4 +1,4 @@ -import { Link } from "react-router-dom"; +import { Link, useParams } from "@tanstack/react-router"; import { ArtistImageLoader } from "@/components/ArtistImageLoader"; import { useFestivalSet } from "../FestivalSetContext"; import { MixedArtistImage } from "@/pages/SetDetails/MixedArtistImage"; @@ -10,6 +10,9 @@ interface SetImageProps { export function SetImage({ className = "", size = "lg" }: SetImageProps) { const { set } = useFestivalSet(); + const { festivalSlug, editionSlug } = useParams({ + from: "/festivals/$festivalSlug/editions/$editionSlug", + }); const isMultiArtist = set.artists.length > 1; const sizeClasses = { @@ -21,7 +24,11 @@ export function SetImage({ className = "", size = "lg" }: SetImageProps) { const containerClass = `${sizeClasses[size]} ${className} overflow-hidden rounded-lg hover:opacity-90 transition-opacity cursor-pointer`; return ( - + {isMultiArtist ? ( - cn( + {label} - + ); } diff --git a/src/pages/EditionView/tabs/ScheduleTab/TimelineControls.tsx b/src/pages/EditionView/tabs/ScheduleTab/TimelineControls.tsx index 4fb5d305..fc7ec782 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/TimelineControls.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/TimelineControls.tsx @@ -6,17 +6,17 @@ import { FilterContainer } from "@/components/filters/FilterContainer"; export function TimelineControls() { const [isExpanded, setIsExpanded] = useState(false); - const { state, updateState, clearFilters } = useTimelineUrlState(); - const { selectedStages } = state; + const { stages, updateStages, clearFilters } = + useTimelineUrlState("timeline"); function handleStageToggle(stageId: string) { - const newStages = selectedStages.includes(stageId) - ? selectedStages.filter((id) => id !== stageId) - : [...selectedStages, stageId]; - updateState({ selectedStages: newStages }); + const newStages = stages.includes(stageId) + ? stages.filter((id) => id !== stageId) + : [...stages, stageId]; + updateStages(newStages); } - const activeFilterCount = selectedStages.length; + const activeFilterCount = stages.length; const hasActiveFilters = activeFilterCount > 0; return ( @@ -37,14 +37,12 @@ export function TimelineControls() { {isExpanded && (
{ - // TODO: Implement jump to today functionality console.log("Jump to today"); }} onJumpToTime={(timeOfDay) => { - // TODO: Implement jump to time functionality console.log("Jump to", timeOfDay); }} /> diff --git a/src/pages/EditionView/tabs/ScheduleTab/horizontal/SetHeader.tsx b/src/pages/EditionView/tabs/ScheduleTab/horizontal/SetHeader.tsx index 138f78b7..fd3e55f4 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/horizontal/SetHeader.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/horizontal/SetHeader.tsx @@ -1,4 +1,4 @@ -import { Link } from "react-router-dom"; +import { Link, useParams } from "@tanstack/react-router"; import type { ScheduleSet } from "@/hooks/useScheduleData"; interface SetHeaderProps { @@ -6,10 +6,13 @@ interface SetHeaderProps { } export function SetHeader({ set }: SetHeaderProps) { + const { festivalSlug = "", editionSlug = "" } = useParams({ strict: false }); + return (
{set.name} diff --git a/src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx b/src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx index f625036c..a05b4d89 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx @@ -19,8 +19,11 @@ export function Timeline() { editionSets, stagesQuery.data, ); - const { state: filters } = useTimelineUrlState(); - const { selectedDay, selectedTime, selectedStages } = filters; + const { + day: selectedDay, + time: selectedTime, + stages: selectedStages, + } = useTimelineUrlState("timeline"); const timelineData = useMemo(() => { if (!edition || !edition.start_date || !edition.end_date) { diff --git a/src/pages/EditionView/tabs/ScheduleTab/list/ListFilters.tsx b/src/pages/EditionView/tabs/ScheduleTab/list/ListFilters.tsx index 06afecd8..17b106de 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/list/ListFilters.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/list/ListFilters.tsx @@ -8,20 +8,25 @@ import { FilterContainer } from "@/components/filters/FilterContainer"; export function ListFilters() { const [isExpanded, setIsExpanded] = useState(false); - const { state, updateState, clearFilters } = useTimelineUrlState(); - const { selectedDay, selectedTime, selectedStages } = state; + const { + day, + time, + stages, + updateDay, + updateTime, + updateStages, + clearFilters, + } = useTimelineUrlState("list"); function handleStageToggle(stageId: string) { - const newStages = selectedStages.includes(stageId) - ? selectedStages.filter((id) => id !== stageId) - : [...selectedStages, stageId]; - updateState({ selectedStages: newStages }); + const newStages = stages.includes(stageId) + ? stages.filter((id) => id !== stageId) + : [...stages, stageId]; + updateStages(newStages); } const activeFilterCount = - (selectedDay !== "all" ? 1 : 0) + - (selectedTime !== "all" ? 1 : 0) + - selectedStages.length; + (day !== "all" ? 1 : 0) + (time !== "all" ? 1 : 0) + stages.length; const hasActiveFilters = activeFilterCount > 0; const shouldShowFilters = isExpanded; @@ -44,16 +49,10 @@ export function ListFilters() { {shouldShowFilters && (
- updateState({ selectedDay: day })} - /> - updateState({ selectedTime: time })} - /> + +
diff --git a/src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx b/src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx index a5d6f7b7..896d2fa0 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx @@ -22,8 +22,11 @@ export function ListSchedule() { editionSets, stagesQuery.data, ); - const { state: filters } = useTimelineUrlState(); - const { selectedDay, selectedTime, selectedStages } = filters; + const { + day: selectedDay, + time: selectedTime, + stages: selectedStages, + } = useTimelineUrlState("list"); const timeSlots = useMemo(() => { if (!scheduleDays.length) return []; diff --git a/src/pages/EditionView/tabs/ScheduleTab/list/MobileSetCard.tsx b/src/pages/EditionView/tabs/ScheduleTab/list/MobileSetCard.tsx index 513b244e..ca66ba03 100644 --- a/src/pages/EditionView/tabs/ScheduleTab/list/MobileSetCard.tsx +++ b/src/pages/EditionView/tabs/ScheduleTab/list/MobileSetCard.tsx @@ -1,5 +1,5 @@ import { Card, CardContent } from "@/components/ui/card"; -import { Link } from "react-router-dom"; +import { Link, useParams } from "@tanstack/react-router"; import { Clock } from "lucide-react"; import { format, differenceInMinutes } from "date-fns"; import { VoteButtons } from "../VoteButtons"; @@ -11,6 +11,7 @@ interface MobileSetCardProps { } export function MobileSetCard({ set }: MobileSetCardProps) { + const { festivalSlug = "", editionSlug = "" } = useParams({ strict: false }); const duration = set.startTime && set.endTime ? differenceInMinutes(set.endTime, set.startTime) @@ -22,7 +23,8 @@ export function MobileSetCard({ set }: MobileSetCardProps) { {/* Artist name */}
{set.name} diff --git a/src/pages/ExploreSetPage/ExploreSetPage.tsx b/src/pages/ExploreSetPage/ExploreSetPage.tsx index f2c8d37b..f9c8eb95 100644 --- a/src/pages/ExploreSetPage/ExploreSetPage.tsx +++ b/src/pages/ExploreSetPage/ExploreSetPage.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "@tanstack/react-router"; import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; import { LoadingState } from "./components/LoadingState"; import { EmptyState } from "./components/EmptyState"; @@ -55,7 +55,6 @@ export function ExploreSetPage() {
{ if (isLastSet) { - navigate(`${basePath}/sets`); + navigate({ from: "/festivals/$festivalSlug/editions/$editionSlug/explore", to: "../sets" }); } else { setDirection(null); } @@ -143,7 +142,7 @@ export function ExploreSetPage() { setSkippedCount((prev) => prev + 1); setTimeout(() => { if (isLastSet) { - navigate(`${basePath}/sets`); + navigate({ from: "/festivals/$festivalSlug/editions/$editionSlug/explore", to: "../sets" }); } else { setCurrentIndex((prev) => prev + 1); setDirection(null); diff --git a/src/pages/ExploreSetPage/components/EmptyState.tsx b/src/pages/ExploreSetPage/components/EmptyState.tsx index ff60746c..e5a944da 100644 --- a/src/pages/ExploreSetPage/components/EmptyState.tsx +++ b/src/pages/ExploreSetPage/components/EmptyState.tsx @@ -1,6 +1,6 @@ import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; interface EmptyStateProps { basePath: string; diff --git a/src/pages/ExploreSetPage/components/ExplorePageHeader.tsx b/src/pages/ExploreSetPage/components/ExplorePageHeader.tsx index 746a214d..3e16adbe 100644 --- a/src/pages/ExploreSetPage/components/ExplorePageHeader.tsx +++ b/src/pages/ExploreSetPage/components/ExplorePageHeader.tsx @@ -1,11 +1,10 @@ -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; import { ExplorationProgress } from "../ExplorationProgress"; import { ProgressInfoTooltip } from "./ProgressInfoTooltip"; interface ExplorePageHeaderProps { - basePath: string; editionName: string; currentIndex: number; totalSets: number; @@ -15,7 +14,6 @@ interface ExplorePageHeaderProps { } export function ExplorePageHeader({ - basePath, editionName, currentIndex, totalSets, @@ -32,7 +30,10 @@ export function ExplorePageHeader({ size="sm" className="text-white hover:bg-white/20 flex items-center " > - + Back diff --git a/src/pages/FestivalSelection.tsx b/src/pages/FestivalSelection.tsx index 5121b421..23f0a085 100644 --- a/src/pages/FestivalSelection.tsx +++ b/src/pages/FestivalSelection.tsx @@ -13,7 +13,7 @@ import { createFestivalSubdomainUrl, isMainGetuplineDomain, } from "@/lib/subdomain"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { useCustomLinksQuery } from "@/hooks/queries/custom-links/useCustomLinks"; import { PageTitle } from "@/components/PageTitle/PageTitle"; import { TopBar } from "@/components/layout/TopBar"; @@ -101,10 +101,22 @@ function FestivalCard({ festival }: { festival: Festival }) { (link) => link.link_type === "website", )?.url; + function handleClick(e: React.MouseEvent) { + const isMain = isMainGetuplineDomain(); + + if (isMain) { + e.preventDefault(); + const subdomainUrl = createFestivalSubdomainUrl(festival.slug); + window.location.href = subdomainUrl; + } + } + return ( diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx index e6022176..15e8b5e0 100644 --- a/src/pages/NotFound.tsx +++ b/src/pages/NotFound.tsx @@ -1,4 +1,4 @@ -import { useLocation } from "react-router-dom"; +import { useLocation } from "@tanstack/react-router"; import { useEffect } from "react"; function NotFound() { diff --git a/src/pages/SetDetails.tsx b/src/pages/SetDetails.tsx index 5af8f680..d665a9f5 100644 --- a/src/pages/SetDetails.tsx +++ b/src/pages/SetDetails.tsx @@ -1,4 +1,4 @@ -import { useParams } from "react-router-dom"; +import { useParams } from "@tanstack/react-router"; import { ArtistImageCard } from "./SetDetails/SetImageCard"; import { MixedArtistImage } from "./SetDetails/MixedArtistImage"; import { SetInfoCard } from "./SetDetails/SetInfoCard"; @@ -18,9 +18,11 @@ import { FestivalIndicator } from "@/components/layout/AppHeader/FestivalIndicat export function SetDetails() { const { user } = useAuth(); - const { setSlug } = useParams<{ setSlug: string }>(); + const { setSlug } = useParams({ + from: "/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug", + }); const { edition, festival } = useFestivalEdition(); - const { state: urlState } = useUrlState(); + const { state: urlState } = useUrlState("set-detail"); const setQuery = useSetBySlugQuery({ slug: setSlug, editionId: edition?.id, diff --git a/src/pages/SetDetails/SetNotFoundState.tsx b/src/pages/SetDetails/SetNotFoundState.tsx index e130bd05..e06b9010 100644 --- a/src/pages/SetDetails/SetNotFoundState.tsx +++ b/src/pages/SetDetails/SetNotFoundState.tsx @@ -1,4 +1,4 @@ -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { Button } from "@/components/ui/button"; import { ArrowLeft, Music } from "lucide-react"; import { useFestivalEdition } from "@/contexts/FestivalEditionContext"; diff --git a/src/pages/admin/AdminLayout.tsx b/src/pages/admin/AdminLayout.tsx index 6c4af123..92929a07 100644 --- a/src/pages/admin/AdminLayout.tsx +++ b/src/pages/admin/AdminLayout.tsx @@ -1,6 +1,6 @@ import { useAuth } from "@/contexts/AuthContext"; import { TopBar } from "@/components/layout/TopBar"; -import { Outlet, useNavigate, useLocation } from "react-router-dom"; +import { Outlet, useNavigate, useLocation } from "@tanstack/react-router"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useUserPermissionsQuery } from "@/hooks/queries/auth/useUserPermissions"; import { useEffect } from "react"; @@ -21,12 +21,12 @@ export default function AdminLayout() { if (authLoading || isLoadingPermissions) return; if (!user) { - navigate("/"); + navigate({ to: "/" }); return; } if (!canEdit) { - navigate("/"); + navigate({ to: "/" }); } }, [user, authLoading, navigate, isLoadingPermissions, canEdit]); @@ -43,16 +43,16 @@ export default function AdminLayout() { function handleTabChange(value: string) { switch (value) { case "artists": - navigate("/admin"); + navigate({ to: "/admin" }); break; case "festivals": - navigate("/admin/festivals"); + navigate({ to: "/admin/festivals" }); break; case "analytics": - navigate("/admin/analytics"); + navigate({ to: "/admin/analytics" }); break; case "admins": - navigate("/admin/admins"); + navigate({ to: "/admin/admins" }); break; } } diff --git a/src/pages/admin/ArtistsManagement/DuplicateArtistsPage.tsx b/src/pages/admin/ArtistsManagement/DuplicateArtistsPage.tsx index 57d3301f..2c9b5745 100644 --- a/src/pages/admin/ArtistsManagement/DuplicateArtistsPage.tsx +++ b/src/pages/admin/ArtistsManagement/DuplicateArtistsPage.tsx @@ -6,7 +6,7 @@ import { AlertTriangle, Copy, ArrowLeft, Zap } from "lucide-react"; import { useDuplicateArtistsQuery } from "@/hooks/queries/artists/useDuplicateArtists"; import { DuplicateGroupCard } from "./DuplicateGroupCard"; import { BulkMergeDialog } from "./BulkMergeDialog"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; export function DuplicateArtistsPage() { const duplicatesQuery = useDuplicateArtistsQuery(); diff --git a/src/pages/admin/ArtistsManagement/components/BulkEditorHeader.tsx b/src/pages/admin/ArtistsManagement/components/BulkEditorHeader.tsx index 46513b9f..b4434652 100644 --- a/src/pages/admin/ArtistsManagement/components/BulkEditorHeader.tsx +++ b/src/pages/admin/ArtistsManagement/components/BulkEditorHeader.tsx @@ -1,7 +1,7 @@ import { CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Grid3X3, Plus, Copy } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { SoundCloudSyncButton } from "./SoundCloudSyncButton"; interface BulkEditorHeaderProps { diff --git a/src/pages/admin/festivals/AdminFestivals.tsx b/src/pages/admin/festivals/AdminFestivals.tsx index 98d7f23f..ee163d3f 100644 --- a/src/pages/admin/festivals/AdminFestivals.tsx +++ b/src/pages/admin/festivals/AdminFestivals.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Outlet, useNavigate, useParams } from "react-router-dom"; +import { Outlet, useNavigate, useParams } from "@tanstack/react-router"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Calendar, Plus } from "lucide-react"; import { FestivalDialog } from "./FestivalDialog"; @@ -12,15 +12,16 @@ export default function AdminFestivals() { const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const navigate = useNavigate(); - const { festivalSlug = "" } = useParams<{ - festivalSlug?: string; - }>(); + const { festivalSlug = "" } = useParams({ strict: false }); function handleFestivalChange(festivalSlug: string) { if (festivalSlug === "none") { - navigate("/admin/festivals"); + navigate({ to: "/admin/festivals" }); } else { - navigate(`/admin/festivals/${festivalSlug}`); + navigate({ + to: "/admin/festivals/$festivalSlug", + params: { festivalSlug }, + }); } } diff --git a/src/pages/admin/festivals/CSVImportPage.tsx b/src/pages/admin/festivals/CSVImportPage.tsx index d9fed105..0c7dbb41 100644 --- a/src/pages/admin/festivals/CSVImportPage.tsx +++ b/src/pages/admin/festivals/CSVImportPage.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { useParams, useNavigate, useSearchParams } from "react-router-dom"; +import { useParams, useNavigate, useSearch } from "@tanstack/react-router"; import { useToast } from "@/hooks/use-toast"; import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; @@ -51,10 +51,14 @@ function getUserTimezone(): string { } export function CSVImportPage() { - const { festivalId: urlFestivalId, editionId: urlEditionId } = useParams(); + const { festivalId: urlFestivalId, editionId: urlEditionId } = useParams({ + from: "/admin/festivals/$festivalId/$editionId/import", + }); const navigate = useNavigate(); - const [searchParams] = useSearchParams(); - const defaultTab = (searchParams.get("tab") as "stages" | "sets") || "stages"; + const search = useSearch({ + from: "/admin/festivals/$festivalId/$editionId/import", + }); + const defaultTab = search.tab || "stages"; const [selectedFestivalId, setSelectedFestivalId] = useState( urlFestivalId || "", @@ -102,13 +106,20 @@ export function CSVImportPage() { function handleFestivalChange(festivalId: string) { setSelectedFestivalId(festivalId); setSelectedEditionId(""); - navigate(`/admin/festivals/${festivalId}/import`, { replace: true }); + navigate({ + to: "/admin/festivals/import", + search: (prev) => ({ tab: prev.tab }), + replace: true, + }); } function handleEditionChange(editionId: string) { setSelectedEditionId(editionId); - if (selectedFestivalId) { - navigate(`/admin/festivals/${selectedFestivalId}/${editionId}/import`, { + if (selectedFestivalId && editionId) { + navigate({ + to: "/admin/festivals/$festivalId/$editionId/import", + params: { festivalId: selectedFestivalId, editionId }, + search: (prev) => ({ ...prev }), replace: true, }); } @@ -321,7 +332,7 @@ export function CSVImportPage() {
); } diff --git a/src/pages/admin/festivals/SetsManagement/SetManagement.tsx b/src/pages/admin/festivals/SetsManagement/SetManagement.tsx index a41c0c1e..fbb5ff5d 100644 --- a/src/pages/admin/festivals/SetsManagement/SetManagement.tsx +++ b/src/pages/admin/festivals/SetsManagement/SetManagement.tsx @@ -1,25 +1,30 @@ import { useState } from "react"; -import { Link, useOutletContext } from "react-router-dom"; +import { Link, useParams } from "@tanstack/react-router"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Loader2, Plus, Music, Upload } from "lucide-react"; import { FestivalSet } from "@/hooks/queries/sets/useSets"; -import { useSetsQuery } from "@/hooks/queries/sets/useSets"; -import { FestivalEdition } from "@/hooks/queries/festivals/editions/types"; +import { useSetsByEditionQuery } from "@/hooks/queries/sets/useSetsByEdition"; import { useDeleteSetMutation } from "@/hooks/queries/sets/useDeleteSet"; +import { useFestivalEditionBySlugQuery } from "@/hooks/queries/festivals/editions/useFestivalEditionBySlug"; import { SetFormDialog } from "../SetFormDialog"; import { SetsTable } from "../SetsTable"; -interface SetManagementProps {} - -export function SetManagement(_props: SetManagementProps) { - // All hooks must be at the top level - const { edition } = useOutletContext<{ edition: FestivalEdition }>(); - const { data: sets = [], isLoading } = useSetsQuery(); +export function SetManagement() { + const { festivalSlug, editionSlug } = useParams({ + from: "/admin/festivals/$festivalSlug/editions/$editionSlug/sets", + }); + const editionQuery = useFestivalEditionBySlugQuery({ + festivalSlug, + editionSlug, + }); + const setsQuery = useSetsByEditionQuery(editionQuery.data?.id); const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingSet, setEditingSet] = useState(null); const deleteSetMutation = useDeleteSetMutation(); + const isLoading = editionQuery.isLoading || setsQuery.isLoading; + function handleCreate() { setEditingSet(null); setIsDialogOpen(true); @@ -47,12 +52,7 @@ export function SetManagement(_props: SetManagementProps) { setEditingSet(null); } - // Filter sets by selected edition - const filteredSets = sets.filter( - (set) => set.festival_edition_id === edition.id, - ); - - if (isLoading) { + if (isLoading || !editionQuery.data) { return ( @@ -74,7 +74,12 @@ export function SetManagement(_props: SetManagementProps) {
- +
diff --git a/src/pages/groups/GroupDetail.tsx b/src/pages/groups/GroupDetail.tsx index f55e26df..1745f71b 100644 --- a/src/pages/groups/GroupDetail.tsx +++ b/src/pages/groups/GroupDetail.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useParams, useNavigate, Link } from "react-router-dom"; +import { useParams, useNavigate, Link } from "@tanstack/react-router"; import { TopBar } from "@/components/layout/TopBar"; import { Card, @@ -20,7 +20,7 @@ import { useGroupMembersQuery } from "@/hooks/queries/groups/useGroupMembers"; import { useRemoveMemberMutation } from "@/hooks/queries/groups/useRemoveMember"; function GroupDetail() { - const { groupSlug } = useParams<{ groupSlug: string }>(); + const { groupSlug } = useParams({ from: "/groups/$groupSlug" }); const navigate = useNavigate(); const { user, loading: authLoading } = useAuth(); const { toast } = useToast(); @@ -42,12 +42,12 @@ function GroupDetail() { if (authLoading) return; // Wait for auth to load if (!groupSlug) { - navigate("/groups"); + navigate({ to: "/groups" }); return; } if (!user) { - navigate("/"); // Redirect to home to sign in + navigate({ to: "/" }); // Redirect to home to sign in return; } @@ -58,7 +58,7 @@ function GroupDetail() { description: "Failed to fetch group details", variant: "destructive", }); - navigate("/groups"); + navigate({ to: "/groups" }); } }, [groupSlug, user, authLoading, groupError, navigate, toast]); diff --git a/src/pages/groups/Groups.tsx b/src/pages/groups/Groups.tsx index 199833c1..299ee3c1 100644 --- a/src/pages/groups/Groups.tsx +++ b/src/pages/groups/Groups.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "@tanstack/react-router"; import { useAuth } from "@/contexts/AuthContext"; import { useUserGroupsQuery } from "@/hooks/queries/groups/useUserGroups"; import { useUserPermissionsQuery } from "@/hooks/queries/auth/useUserPermissions"; @@ -96,7 +96,7 @@ function Groups() { isOpen={createDialogOpen} onOpenChange={setCreateDialogOpen} onGroupCreated={(groupSlug) => { - navigate(`/groups/${groupSlug}`); + navigate({ to: "/groups/$groupSlug", params: { groupSlug } }); setCreateDialogOpen(false); }} /> diff --git a/src/pages/groups/Groups/GroupCard.tsx b/src/pages/groups/Groups/GroupCard.tsx index 02e0a3f6..c7e8a6b1 100644 --- a/src/pages/groups/Groups/GroupCard.tsx +++ b/src/pages/groups/Groups/GroupCard.tsx @@ -8,7 +8,7 @@ import { } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Users, Trash2, Crown } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; import { useLeaveGroupMutation } from "@/hooks/queries/groups/useLeaveGroup"; import { Group } from "@/types/groups"; import { useAuth } from "@/contexts/AuthContext"; @@ -26,7 +26,7 @@ export function GroupCard({ const leaveGroupMutation = useLeaveGroupMutation(); return ( - +
diff --git a/src/pages/groups/Groups/SignInRequired.tsx b/src/pages/groups/Groups/SignInRequired.tsx index e3a4e8a2..83fb0ea1 100644 --- a/src/pages/groups/Groups/SignInRequired.tsx +++ b/src/pages/groups/Groups/SignInRequired.tsx @@ -6,7 +6,7 @@ import { CardContent, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; export function SignInRequired() { return ( diff --git a/src/pages/legal/CookiePolicy.tsx b/src/pages/legal/CookiePolicy.tsx index 63a8e851..ef0753af 100644 --- a/src/pages/legal/CookiePolicy.tsx +++ b/src/pages/legal/CookiePolicy.tsx @@ -1,7 +1,7 @@ import { TopBar } from "@/components/layout/TopBar"; import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; function CookiePolicy() { return ( diff --git a/src/pages/legal/PrivacyPolicy.tsx b/src/pages/legal/PrivacyPolicy.tsx index e68a3cef..feccea57 100644 --- a/src/pages/legal/PrivacyPolicy.tsx +++ b/src/pages/legal/PrivacyPolicy.tsx @@ -1,7 +1,7 @@ import { TopBar } from "@/components/layout/TopBar"; import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; function PrivacyPolicy() { return ( diff --git a/src/pages/legal/TermsOfService.tsx b/src/pages/legal/TermsOfService.tsx index db287014..a62bd088 100644 --- a/src/pages/legal/TermsOfService.tsx +++ b/src/pages/legal/TermsOfService.tsx @@ -1,7 +1,7 @@ import { TopBar } from "@/components/layout/TopBar"; import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; -import { Link } from "react-router-dom"; +import { Link } from "@tanstack/react-router"; function TermsOfService() { return ( diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts new file mode 100644 index 00000000..e2fb11cd --- /dev/null +++ b/src/routeTree.gen.ts @@ -0,0 +1,769 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as TermsRouteImport } from './routes/terms' +import { Route as PrivacyRouteImport } from './routes/privacy' +import { Route as CookiesRouteImport } from './routes/cookies' +import { Route as AdminRouteImport } from './routes/admin' +import { Route as IndexRouteImport } from './routes/index' +import { Route as GroupsIndexRouteImport } from './routes/groups/index' +import { Route as GroupsGroupSlugRouteImport } from './routes/groups/$groupSlug' +import { Route as AdminFestivalsRouteImport } from './routes/admin/festivals' +import { Route as AdminArtistsRouteImport } from './routes/admin/artists' +import { Route as AdminAnalyticsRouteImport } from './routes/admin/analytics' +import { Route as AdminAdminsRouteImport } from './routes/admin/admins' +import { Route as FestivalsFestivalSlugIndexRouteImport } from './routes/festivals/$festivalSlug/index' +import { Route as AdminFestivalsImportRouteImport } from './routes/admin/festivals/import' +import { Route as AdminFestivalsFestivalSlugRouteImport } from './routes/admin/festivals/$festivalSlug' +import { Route as AdminArtistsDuplicatesRouteImport } from './routes/admin/artists/duplicates' +import { Route as FestivalsFestivalSlugEditionsEditionSlugRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug' +import { Route as FestivalsFestivalSlugEditionsEditionSlugSocialRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/social' +import { Route as FestivalsFestivalSlugEditionsEditionSlugSetsRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/sets' +import { Route as FestivalsFestivalSlugEditionsEditionSlugScheduleRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/schedule' +import { Route as FestivalsFestivalSlugEditionsEditionSlugMapRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/map' +import { Route as FestivalsFestivalSlugEditionsEditionSlugInfoRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/info' +import { Route as FestivalsFestivalSlugEditionsEditionSlugExploreRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/explore' +import { Route as AdminFestivalsFestivalSlugEditionsEditionSlugRouteImport } from './routes/admin/festivals/$festivalSlug/editions/$editionSlug' +import { Route as AdminFestivalsFestivalIdEditionIdImportRouteImport } from './routes/admin/festivals/$festivalId.$editionId.import' +import { Route as FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/sets.$setSlug' +import { Route as FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' +import { Route as FestivalsFestivalSlugEditionsEditionSlugScheduleListRouteImport } from './routes/festivals/$festivalSlug/editions/$editionSlug/schedule/list' +import { Route as AdminFestivalsFestivalSlugEditionsEditionSlugStagesRouteImport } from './routes/admin/festivals/$festivalSlug/editions/$editionSlug/stages' +import { Route as AdminFestivalsFestivalSlugEditionsEditionSlugSetsRouteImport } from './routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + +const TermsRoute = TermsRouteImport.update({ + id: '/terms', + path: '/terms', + getParentRoute: () => rootRouteImport, +} as any) +const PrivacyRoute = PrivacyRouteImport.update({ + id: '/privacy', + path: '/privacy', + getParentRoute: () => rootRouteImport, +} as any) +const CookiesRoute = CookiesRouteImport.update({ + id: '/cookies', + path: '/cookies', + getParentRoute: () => rootRouteImport, +} as any) +const AdminRoute = AdminRouteImport.update({ + id: '/admin', + path: '/admin', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const GroupsIndexRoute = GroupsIndexRouteImport.update({ + id: '/groups/', + path: '/groups/', + getParentRoute: () => rootRouteImport, +} as any) +const GroupsGroupSlugRoute = GroupsGroupSlugRouteImport.update({ + id: '/groups/$groupSlug', + path: '/groups/$groupSlug', + getParentRoute: () => rootRouteImport, +} as any) +const AdminFestivalsRoute = AdminFestivalsRouteImport.update({ + id: '/festivals', + path: '/festivals', + getParentRoute: () => AdminRoute, +} as any) +const AdminArtistsRoute = AdminArtistsRouteImport.update({ + id: '/artists', + path: '/artists', + getParentRoute: () => AdminRoute, +} as any) +const AdminAnalyticsRoute = AdminAnalyticsRouteImport.update({ + id: '/analytics', + path: '/analytics', + getParentRoute: () => AdminRoute, +} as any) +const AdminAdminsRoute = AdminAdminsRouteImport.update({ + id: '/admins', + path: '/admins', + getParentRoute: () => AdminRoute, +} as any) +const FestivalsFestivalSlugIndexRoute = + FestivalsFestivalSlugIndexRouteImport.update({ + id: '/festivals/$festivalSlug/', + path: '/festivals/$festivalSlug/', + getParentRoute: () => rootRouteImport, + } as any) +const AdminFestivalsImportRoute = AdminFestivalsImportRouteImport.update({ + id: '/import', + path: '/import', + getParentRoute: () => AdminFestivalsRoute, +} as any) +const AdminFestivalsFestivalSlugRoute = + AdminFestivalsFestivalSlugRouteImport.update({ + id: '/$festivalSlug', + path: '/$festivalSlug', + getParentRoute: () => AdminFestivalsRoute, + } as any) +const AdminArtistsDuplicatesRoute = AdminArtistsDuplicatesRouteImport.update({ + id: '/duplicates', + path: '/duplicates', + getParentRoute: () => AdminArtistsRoute, +} as any) +const FestivalsFestivalSlugEditionsEditionSlugRoute = + FestivalsFestivalSlugEditionsEditionSlugRouteImport.update({ + id: '/festivals/$festivalSlug/editions/$editionSlug', + path: '/festivals/$festivalSlug/editions/$editionSlug', + getParentRoute: () => rootRouteImport, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugSocialRoute = + FestivalsFestivalSlugEditionsEditionSlugSocialRouteImport.update({ + id: '/social', + path: '/social', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugSetsRoute = + FestivalsFestivalSlugEditionsEditionSlugSetsRouteImport.update({ + id: '/sets', + path: '/sets', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugScheduleRoute = + FestivalsFestivalSlugEditionsEditionSlugScheduleRouteImport.update({ + id: '/schedule', + path: '/schedule', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugMapRoute = + FestivalsFestivalSlugEditionsEditionSlugMapRouteImport.update({ + id: '/map', + path: '/map', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugInfoRoute = + FestivalsFestivalSlugEditionsEditionSlugInfoRouteImport.update({ + id: '/info', + path: '/info', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugExploreRoute = + FestivalsFestivalSlugEditionsEditionSlugExploreRouteImport.update({ + id: '/explore', + path: '/explore', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const AdminFestivalsFestivalSlugEditionsEditionSlugRoute = + AdminFestivalsFestivalSlugEditionsEditionSlugRouteImport.update({ + id: '/editions/$editionSlug', + path: '/editions/$editionSlug', + getParentRoute: () => AdminFestivalsFestivalSlugRoute, + } as any) +const AdminFestivalsFestivalIdEditionIdImportRoute = + AdminFestivalsFestivalIdEditionIdImportRouteImport.update({ + id: '/$festivalId/$editionId/import', + path: '/$festivalId/$editionId/import', + getParentRoute: () => AdminFestivalsRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute = + FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRouteImport.update({ + id: '/$setSlug', + path: '/$setSlug', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugSetsRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute = + FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRouteImport.update({ + id: '/timeline', + path: '/timeline', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugScheduleRoute, + } as any) +const FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute = + FestivalsFestivalSlugEditionsEditionSlugScheduleListRouteImport.update({ + id: '/list', + path: '/list', + getParentRoute: () => FestivalsFestivalSlugEditionsEditionSlugScheduleRoute, + } as any) +const AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute = + AdminFestivalsFestivalSlugEditionsEditionSlugStagesRouteImport.update({ + id: '/stages', + path: '/stages', + getParentRoute: () => AdminFestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) +const AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute = + AdminFestivalsFestivalSlugEditionsEditionSlugSetsRouteImport.update({ + id: '/sets', + path: '/sets', + getParentRoute: () => AdminFestivalsFestivalSlugEditionsEditionSlugRoute, + } as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/admin': typeof AdminRouteWithChildren + '/cookies': typeof CookiesRoute + '/privacy': typeof PrivacyRoute + '/terms': typeof TermsRoute + '/admin/admins': typeof AdminAdminsRoute + '/admin/analytics': typeof AdminAnalyticsRoute + '/admin/artists': typeof AdminArtistsRouteWithChildren + '/admin/festivals': typeof AdminFestivalsRouteWithChildren + '/groups/$groupSlug': typeof GroupsGroupSlugRoute + '/groups': typeof GroupsIndexRoute + '/admin/artists/duplicates': typeof AdminArtistsDuplicatesRoute + '/admin/festivals/$festivalSlug': typeof AdminFestivalsFestivalSlugRouteWithChildren + '/admin/festivals/import': typeof AdminFestivalsImportRoute + '/festivals/$festivalSlug': typeof FestivalsFestivalSlugIndexRoute + '/festivals/$festivalSlug/editions/$editionSlug': typeof FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/admin/festivals/$festivalId/$editionId/import': typeof AdminFestivalsFestivalIdEditionIdImportRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug': typeof AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/explore': typeof FestivalsFestivalSlugEditionsEditionSlugExploreRoute + '/festivals/$festivalSlug/editions/$editionSlug/info': typeof FestivalsFestivalSlugEditionsEditionSlugInfoRoute + '/festivals/$festivalSlug/editions/$editionSlug/map': typeof FestivalsFestivalSlugEditionsEditionSlugMapRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/sets': typeof FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/social': typeof FestivalsFestivalSlugEditionsEditionSlugSocialRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/sets': typeof AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/stages': typeof AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/list': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute + '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug': typeof FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/admin': typeof AdminRouteWithChildren + '/cookies': typeof CookiesRoute + '/privacy': typeof PrivacyRoute + '/terms': typeof TermsRoute + '/admin/admins': typeof AdminAdminsRoute + '/admin/analytics': typeof AdminAnalyticsRoute + '/admin/artists': typeof AdminArtistsRouteWithChildren + '/admin/festivals': typeof AdminFestivalsRouteWithChildren + '/groups/$groupSlug': typeof GroupsGroupSlugRoute + '/groups': typeof GroupsIndexRoute + '/admin/artists/duplicates': typeof AdminArtistsDuplicatesRoute + '/admin/festivals/$festivalSlug': typeof AdminFestivalsFestivalSlugRouteWithChildren + '/admin/festivals/import': typeof AdminFestivalsImportRoute + '/festivals/$festivalSlug': typeof FestivalsFestivalSlugIndexRoute + '/festivals/$festivalSlug/editions/$editionSlug': typeof FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/admin/festivals/$festivalId/$editionId/import': typeof AdminFestivalsFestivalIdEditionIdImportRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug': typeof AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/explore': typeof FestivalsFestivalSlugEditionsEditionSlugExploreRoute + '/festivals/$festivalSlug/editions/$editionSlug/info': typeof FestivalsFestivalSlugEditionsEditionSlugInfoRoute + '/festivals/$festivalSlug/editions/$editionSlug/map': typeof FestivalsFestivalSlugEditionsEditionSlugMapRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/sets': typeof FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/social': typeof FestivalsFestivalSlugEditionsEditionSlugSocialRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/sets': typeof AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/stages': typeof AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/list': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute + '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug': typeof FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/admin': typeof AdminRouteWithChildren + '/cookies': typeof CookiesRoute + '/privacy': typeof PrivacyRoute + '/terms': typeof TermsRoute + '/admin/admins': typeof AdminAdminsRoute + '/admin/analytics': typeof AdminAnalyticsRoute + '/admin/artists': typeof AdminArtistsRouteWithChildren + '/admin/festivals': typeof AdminFestivalsRouteWithChildren + '/groups/$groupSlug': typeof GroupsGroupSlugRoute + '/groups/': typeof GroupsIndexRoute + '/admin/artists/duplicates': typeof AdminArtistsDuplicatesRoute + '/admin/festivals/$festivalSlug': typeof AdminFestivalsFestivalSlugRouteWithChildren + '/admin/festivals/import': typeof AdminFestivalsImportRoute + '/festivals/$festivalSlug/': typeof FestivalsFestivalSlugIndexRoute + '/festivals/$festivalSlug/editions/$editionSlug': typeof FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/admin/festivals/$festivalId/$editionId/import': typeof AdminFestivalsFestivalIdEditionIdImportRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug': typeof AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/explore': typeof FestivalsFestivalSlugEditionsEditionSlugExploreRoute + '/festivals/$festivalSlug/editions/$editionSlug/info': typeof FestivalsFestivalSlugEditionsEditionSlugInfoRoute + '/festivals/$festivalSlug/editions/$editionSlug/map': typeof FestivalsFestivalSlugEditionsEditionSlugMapRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/sets': typeof FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren + '/festivals/$festivalSlug/editions/$editionSlug/social': typeof FestivalsFestivalSlugEditionsEditionSlugSocialRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/sets': typeof AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute + '/admin/festivals/$festivalSlug/editions/$editionSlug/stages': typeof AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/list': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute + '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline': typeof FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute + '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug': typeof FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/admin' + | '/cookies' + | '/privacy' + | '/terms' + | '/admin/admins' + | '/admin/analytics' + | '/admin/artists' + | '/admin/festivals' + | '/groups/$groupSlug' + | '/groups' + | '/admin/artists/duplicates' + | '/admin/festivals/$festivalSlug' + | '/admin/festivals/import' + | '/festivals/$festivalSlug' + | '/festivals/$festivalSlug/editions/$editionSlug' + | '/admin/festivals/$festivalId/$editionId/import' + | '/admin/festivals/$festivalSlug/editions/$editionSlug' + | '/festivals/$festivalSlug/editions/$editionSlug/explore' + | '/festivals/$festivalSlug/editions/$editionSlug/info' + | '/festivals/$festivalSlug/editions/$editionSlug/map' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule' + | '/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/festivals/$festivalSlug/editions/$editionSlug/social' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/stages' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/list' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' + | '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/admin' + | '/cookies' + | '/privacy' + | '/terms' + | '/admin/admins' + | '/admin/analytics' + | '/admin/artists' + | '/admin/festivals' + | '/groups/$groupSlug' + | '/groups' + | '/admin/artists/duplicates' + | '/admin/festivals/$festivalSlug' + | '/admin/festivals/import' + | '/festivals/$festivalSlug' + | '/festivals/$festivalSlug/editions/$editionSlug' + | '/admin/festivals/$festivalId/$editionId/import' + | '/admin/festivals/$festivalSlug/editions/$editionSlug' + | '/festivals/$festivalSlug/editions/$editionSlug/explore' + | '/festivals/$festivalSlug/editions/$editionSlug/info' + | '/festivals/$festivalSlug/editions/$editionSlug/map' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule' + | '/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/festivals/$festivalSlug/editions/$editionSlug/social' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/stages' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/list' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' + | '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug' + id: + | '__root__' + | '/' + | '/admin' + | '/cookies' + | '/privacy' + | '/terms' + | '/admin/admins' + | '/admin/analytics' + | '/admin/artists' + | '/admin/festivals' + | '/groups/$groupSlug' + | '/groups/' + | '/admin/artists/duplicates' + | '/admin/festivals/$festivalSlug' + | '/admin/festivals/import' + | '/festivals/$festivalSlug/' + | '/festivals/$festivalSlug/editions/$editionSlug' + | '/admin/festivals/$festivalId/$editionId/import' + | '/admin/festivals/$festivalSlug/editions/$editionSlug' + | '/festivals/$festivalSlug/editions/$editionSlug/explore' + | '/festivals/$festivalSlug/editions/$editionSlug/info' + | '/festivals/$festivalSlug/editions/$editionSlug/map' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule' + | '/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/festivals/$festivalSlug/editions/$editionSlug/social' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + | '/admin/festivals/$festivalSlug/editions/$editionSlug/stages' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/list' + | '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' + | '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + AdminRoute: typeof AdminRouteWithChildren + CookiesRoute: typeof CookiesRoute + PrivacyRoute: typeof PrivacyRoute + TermsRoute: typeof TermsRoute + GroupsGroupSlugRoute: typeof GroupsGroupSlugRoute + GroupsIndexRoute: typeof GroupsIndexRoute + FestivalsFestivalSlugIndexRoute: typeof FestivalsFestivalSlugIndexRoute + FestivalsFestivalSlugEditionsEditionSlugRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/terms': { + id: '/terms' + path: '/terms' + fullPath: '/terms' + preLoaderRoute: typeof TermsRouteImport + parentRoute: typeof rootRouteImport + } + '/privacy': { + id: '/privacy' + path: '/privacy' + fullPath: '/privacy' + preLoaderRoute: typeof PrivacyRouteImport + parentRoute: typeof rootRouteImport + } + '/cookies': { + id: '/cookies' + path: '/cookies' + fullPath: '/cookies' + preLoaderRoute: typeof CookiesRouteImport + parentRoute: typeof rootRouteImport + } + '/admin': { + id: '/admin' + path: '/admin' + fullPath: '/admin' + preLoaderRoute: typeof AdminRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/groups/': { + id: '/groups/' + path: '/groups' + fullPath: '/groups' + preLoaderRoute: typeof GroupsIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/groups/$groupSlug': { + id: '/groups/$groupSlug' + path: '/groups/$groupSlug' + fullPath: '/groups/$groupSlug' + preLoaderRoute: typeof GroupsGroupSlugRouteImport + parentRoute: typeof rootRouteImport + } + '/admin/festivals': { + id: '/admin/festivals' + path: '/festivals' + fullPath: '/admin/festivals' + preLoaderRoute: typeof AdminFestivalsRouteImport + parentRoute: typeof AdminRoute + } + '/admin/artists': { + id: '/admin/artists' + path: '/artists' + fullPath: '/admin/artists' + preLoaderRoute: typeof AdminArtistsRouteImport + parentRoute: typeof AdminRoute + } + '/admin/analytics': { + id: '/admin/analytics' + path: '/analytics' + fullPath: '/admin/analytics' + preLoaderRoute: typeof AdminAnalyticsRouteImport + parentRoute: typeof AdminRoute + } + '/admin/admins': { + id: '/admin/admins' + path: '/admins' + fullPath: '/admin/admins' + preLoaderRoute: typeof AdminAdminsRouteImport + parentRoute: typeof AdminRoute + } + '/festivals/$festivalSlug/': { + id: '/festivals/$festivalSlug/' + path: '/festivals/$festivalSlug' + fullPath: '/festivals/$festivalSlug' + preLoaderRoute: typeof FestivalsFestivalSlugIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/admin/festivals/import': { + id: '/admin/festivals/import' + path: '/import' + fullPath: '/admin/festivals/import' + preLoaderRoute: typeof AdminFestivalsImportRouteImport + parentRoute: typeof AdminFestivalsRoute + } + '/admin/festivals/$festivalSlug': { + id: '/admin/festivals/$festivalSlug' + path: '/$festivalSlug' + fullPath: '/admin/festivals/$festivalSlug' + preLoaderRoute: typeof AdminFestivalsFestivalSlugRouteImport + parentRoute: typeof AdminFestivalsRoute + } + '/admin/artists/duplicates': { + id: '/admin/artists/duplicates' + path: '/duplicates' + fullPath: '/admin/artists/duplicates' + preLoaderRoute: typeof AdminArtistsDuplicatesRouteImport + parentRoute: typeof AdminArtistsRoute + } + '/festivals/$festivalSlug/editions/$editionSlug': { + id: '/festivals/$festivalSlug/editions/$editionSlug' + path: '/festivals/$festivalSlug/editions/$editionSlug' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRouteImport + parentRoute: typeof rootRouteImport + } + '/festivals/$festivalSlug/editions/$editionSlug/social': { + id: '/festivals/$festivalSlug/editions/$editionSlug/social' + path: '/social' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/social' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSocialRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/sets': { + id: '/festivals/$festivalSlug/editions/$editionSlug/sets' + path: '/sets' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/sets' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSetsRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/schedule': { + id: '/festivals/$festivalSlug/editions/$editionSlug/schedule' + path: '/schedule' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/schedule' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/map': { + id: '/festivals/$festivalSlug/editions/$editionSlug/map' + path: '/map' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/map' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugMapRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/info': { + id: '/festivals/$festivalSlug/editions/$editionSlug/info' + path: '/info' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/info' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugInfoRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/explore': { + id: '/festivals/$festivalSlug/editions/$editionSlug/explore' + path: '/explore' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/explore' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugExploreRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugRoute + } + '/admin/festivals/$festivalSlug/editions/$editionSlug': { + id: '/admin/festivals/$festivalSlug/editions/$editionSlug' + path: '/editions/$editionSlug' + fullPath: '/admin/festivals/$festivalSlug/editions/$editionSlug' + preLoaderRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugRouteImport + parentRoute: typeof AdminFestivalsFestivalSlugRoute + } + '/admin/festivals/$festivalId/$editionId/import': { + id: '/admin/festivals/$festivalId/$editionId/import' + path: '/$festivalId/$editionId/import' + fullPath: '/admin/festivals/$festivalId/$editionId/import' + preLoaderRoute: typeof AdminFestivalsFestivalIdEditionIdImportRouteImport + parentRoute: typeof AdminFestivalsRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug': { + id: '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug' + path: '/$setSlug' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSetsRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline': { + id: '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' + path: '/timeline' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRoute + } + '/festivals/$festivalSlug/editions/$editionSlug/schedule/list': { + id: '/festivals/$festivalSlug/editions/$editionSlug/schedule/list' + path: '/list' + fullPath: '/festivals/$festivalSlug/editions/$editionSlug/schedule/list' + preLoaderRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleListRouteImport + parentRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRoute + } + '/admin/festivals/$festivalSlug/editions/$editionSlug/stages': { + id: '/admin/festivals/$festivalSlug/editions/$editionSlug/stages' + path: '/stages' + fullPath: '/admin/festivals/$festivalSlug/editions/$editionSlug/stages' + preLoaderRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugStagesRouteImport + parentRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugRoute + } + '/admin/festivals/$festivalSlug/editions/$editionSlug/sets': { + id: '/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + path: '/sets' + fullPath: '/admin/festivals/$festivalSlug/editions/$editionSlug/sets' + preLoaderRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugSetsRouteImport + parentRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugRoute + } + } +} + +interface AdminArtistsRouteChildren { + AdminArtistsDuplicatesRoute: typeof AdminArtistsDuplicatesRoute +} + +const AdminArtistsRouteChildren: AdminArtistsRouteChildren = { + AdminArtistsDuplicatesRoute: AdminArtistsDuplicatesRoute, +} + +const AdminArtistsRouteWithChildren = AdminArtistsRoute._addFileChildren( + AdminArtistsRouteChildren, +) + +interface AdminFestivalsFestivalSlugEditionsEditionSlugRouteChildren { + AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute + AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute +} + +const AdminFestivalsFestivalSlugEditionsEditionSlugRouteChildren: AdminFestivalsFestivalSlugEditionsEditionSlugRouteChildren = + { + AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute: + AdminFestivalsFestivalSlugEditionsEditionSlugSetsRoute, + AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute: + AdminFestivalsFestivalSlugEditionsEditionSlugStagesRoute, + } + +const AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren = + AdminFestivalsFestivalSlugEditionsEditionSlugRoute._addFileChildren( + AdminFestivalsFestivalSlugEditionsEditionSlugRouteChildren, + ) + +interface AdminFestivalsFestivalSlugRouteChildren { + AdminFestivalsFestivalSlugEditionsEditionSlugRoute: typeof AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren +} + +const AdminFestivalsFestivalSlugRouteChildren: AdminFestivalsFestivalSlugRouteChildren = + { + AdminFestivalsFestivalSlugEditionsEditionSlugRoute: + AdminFestivalsFestivalSlugEditionsEditionSlugRouteWithChildren, + } + +const AdminFestivalsFestivalSlugRouteWithChildren = + AdminFestivalsFestivalSlugRoute._addFileChildren( + AdminFestivalsFestivalSlugRouteChildren, + ) + +interface AdminFestivalsRouteChildren { + AdminFestivalsFestivalSlugRoute: typeof AdminFestivalsFestivalSlugRouteWithChildren + AdminFestivalsImportRoute: typeof AdminFestivalsImportRoute + AdminFestivalsFestivalIdEditionIdImportRoute: typeof AdminFestivalsFestivalIdEditionIdImportRoute +} + +const AdminFestivalsRouteChildren: AdminFestivalsRouteChildren = { + AdminFestivalsFestivalSlugRoute: AdminFestivalsFestivalSlugRouteWithChildren, + AdminFestivalsImportRoute: AdminFestivalsImportRoute, + AdminFestivalsFestivalIdEditionIdImportRoute: + AdminFestivalsFestivalIdEditionIdImportRoute, +} + +const AdminFestivalsRouteWithChildren = AdminFestivalsRoute._addFileChildren( + AdminFestivalsRouteChildren, +) + +interface AdminRouteChildren { + AdminAdminsRoute: typeof AdminAdminsRoute + AdminAnalyticsRoute: typeof AdminAnalyticsRoute + AdminArtistsRoute: typeof AdminArtistsRouteWithChildren + AdminFestivalsRoute: typeof AdminFestivalsRouteWithChildren +} + +const AdminRouteChildren: AdminRouteChildren = { + AdminAdminsRoute: AdminAdminsRoute, + AdminAnalyticsRoute: AdminAnalyticsRoute, + AdminArtistsRoute: AdminArtistsRouteWithChildren, + AdminFestivalsRoute: AdminFestivalsRouteWithChildren, +} + +const AdminRouteWithChildren = AdminRoute._addFileChildren(AdminRouteChildren) + +interface FestivalsFestivalSlugEditionsEditionSlugScheduleRouteChildren { + FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute + FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute +} + +const FestivalsFestivalSlugEditionsEditionSlugScheduleRouteChildren: FestivalsFestivalSlugEditionsEditionSlugScheduleRouteChildren = + { + FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute: + FestivalsFestivalSlugEditionsEditionSlugScheduleListRoute, + FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute: + FestivalsFestivalSlugEditionsEditionSlugScheduleTimelineRoute, + } + +const FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren = + FestivalsFestivalSlugEditionsEditionSlugScheduleRoute._addFileChildren( + FestivalsFestivalSlugEditionsEditionSlugScheduleRouteChildren, + ) + +interface FestivalsFestivalSlugEditionsEditionSlugSetsRouteChildren { + FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute +} + +const FestivalsFestivalSlugEditionsEditionSlugSetsRouteChildren: FestivalsFestivalSlugEditionsEditionSlugSetsRouteChildren = + { + FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute: + FestivalsFestivalSlugEditionsEditionSlugSetsSetSlugRoute, + } + +const FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren = + FestivalsFestivalSlugEditionsEditionSlugSetsRoute._addFileChildren( + FestivalsFestivalSlugEditionsEditionSlugSetsRouteChildren, + ) + +interface FestivalsFestivalSlugEditionsEditionSlugRouteChildren { + FestivalsFestivalSlugEditionsEditionSlugExploreRoute: typeof FestivalsFestivalSlugEditionsEditionSlugExploreRoute + FestivalsFestivalSlugEditionsEditionSlugInfoRoute: typeof FestivalsFestivalSlugEditionsEditionSlugInfoRoute + FestivalsFestivalSlugEditionsEditionSlugMapRoute: typeof FestivalsFestivalSlugEditionsEditionSlugMapRoute + FestivalsFestivalSlugEditionsEditionSlugScheduleRoute: typeof FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren + FestivalsFestivalSlugEditionsEditionSlugSetsRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren + FestivalsFestivalSlugEditionsEditionSlugSocialRoute: typeof FestivalsFestivalSlugEditionsEditionSlugSocialRoute +} + +const FestivalsFestivalSlugEditionsEditionSlugRouteChildren: FestivalsFestivalSlugEditionsEditionSlugRouteChildren = + { + FestivalsFestivalSlugEditionsEditionSlugExploreRoute: + FestivalsFestivalSlugEditionsEditionSlugExploreRoute, + FestivalsFestivalSlugEditionsEditionSlugInfoRoute: + FestivalsFestivalSlugEditionsEditionSlugInfoRoute, + FestivalsFestivalSlugEditionsEditionSlugMapRoute: + FestivalsFestivalSlugEditionsEditionSlugMapRoute, + FestivalsFestivalSlugEditionsEditionSlugScheduleRoute: + FestivalsFestivalSlugEditionsEditionSlugScheduleRouteWithChildren, + FestivalsFestivalSlugEditionsEditionSlugSetsRoute: + FestivalsFestivalSlugEditionsEditionSlugSetsRouteWithChildren, + FestivalsFestivalSlugEditionsEditionSlugSocialRoute: + FestivalsFestivalSlugEditionsEditionSlugSocialRoute, + } + +const FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren = + FestivalsFestivalSlugEditionsEditionSlugRoute._addFileChildren( + FestivalsFestivalSlugEditionsEditionSlugRouteChildren, + ) + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + AdminRoute: AdminRouteWithChildren, + CookiesRoute: CookiesRoute, + PrivacyRoute: PrivacyRoute, + TermsRoute: TermsRoute, + GroupsGroupSlugRoute: GroupsGroupSlugRoute, + GroupsIndexRoute: GroupsIndexRoute, + FestivalsFestivalSlugIndexRoute: FestivalsFestivalSlugIndexRoute, + FestivalsFestivalSlugEditionsEditionSlugRoute: + FestivalsFestivalSlugEditionsEditionSlugRouteWithChildren, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/src/components/router/AppRoutes.tsx b/src/routes/__root.tsx similarity index 50% rename from src/components/router/AppRoutes.tsx rename to src/routes/__root.tsx index d62b7b23..b2b84a37 100644 --- a/src/components/router/AppRoutes.tsx +++ b/src/routes/__root.tsx @@ -1,34 +1,71 @@ +import { createRootRoute, Outlet, useSearch } from "@tanstack/react-router"; +import { SpeedInsights } from "@vercel/speed-insights/react"; +import { Toaster } from "@/components/ui/toaster"; +import { Toaster as Sonner } from "@/components/ui/sonner"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import { CookieConsentBanner } from "@/components/layout/legal/CookieConsentBanner"; +import { OfflineIndicator } from "@/components/ui/OfflineIndicator"; +import { AppFooter } from "@/components/layout/AppFooter"; +import { TanStackRouterDevtools } from "@tanstack/router-devtools"; +import { HelmetProvider } from "react-helmet-async"; +import { AuthProvider } from "@/contexts/AuthContext"; +import { FestivalEditionProvider } from "@/contexts/FestivalEditionContext"; import { useAuth } from "@/contexts/AuthContext"; import { useInviteValidation } from "@/components/invite/useInviteValidation"; import { InviteLandingPage } from "@/components/invite/InviteLandingPage"; -import { MainDomainRoutes } from "./MainDomainRoutes"; -import { SubdomainRoutes } from "./SubdomainRoutes"; -import { AppFooter } from "@/components/layout/AppFooter"; -import { useMemo } from "react"; +import { OnboardingDialog } from "@/components/onboarding/OnboardingDialog"; import { useProfileQuery } from "@/hooks/queries/auth/useProfile"; -import { OnboardingDialog } from "../onboarding/OnboardingDialog"; +import { useMemo, useEffect } from "react"; +import { shouldRedirectFromWww, getNonWwwRedirectUrl } from "@/lib/subdomain"; +import { z } from "zod"; + +const rootSearchSchema = z.object({ + invite: z.string().optional(), +}); + +export const Route = createRootRoute({ + component: RootComponent, + validateSearch: rootSearchSchema, +}); -interface AppRoutesProps { - subdomainInfo: { - festivalSlug: string | null; - isSubdomain: boolean; - isMainDomain: boolean; - }; +function RootComponent() { + return ( + + + + + + + + + + + + + {import.meta.env.DEV && } + + + ); } -export function AppRoutes({ subdomainInfo }: AppRoutesProps) { +function RootContent() { const { user, loading: authLoading, needsOnboarding } = useAuth(); + const search = useSearch({ from: "__root__" }); const { inviteValidation, isValidating, hasValidInvite } = - useInviteValidation(); + useInviteValidation(search.invite); - // Get profile loading state to prevent dialog flashing const { isLoading: profileLoading } = useProfileQuery(user?.id); const showOnboarding = useMemo(() => { return !!user && !authLoading && !profileLoading && needsOnboarding; }, [user, authLoading, profileLoading, needsOnboarding]); - // Show loading while validating invite + useEffect(() => { + if (shouldRedirectFromWww()) { + window.location.href = getNonWwwRedirectUrl(); + } + }, []); + if (isValidating) { return (
@@ -37,19 +74,15 @@ export function AppRoutes({ subdomainInfo }: AppRoutesProps) { ); } - // Show invite landing page if there's a valid invite and user is not logged in if (hasValidInvite && !user && inviteValidation) { return ( { - // Invite processing is now handled in useAuth hook - }} + onSignupSuccess={() => {}} /> ); } - // Show error page for invalid invites if (inviteValidation && !inviteValidation.is_valid) { return (
@@ -67,27 +100,17 @@ export function AppRoutes({ subdomainInfo }: AppRoutesProps) { ); } - // Normal routing flow return (
- {subdomainInfo.festivalSlug && subdomainInfo.isSubdomain ? ( - // Festival-specific routing: subdomain or path-based - - ) : ( - // Main domain routing: getupline.com or localhost without festival path - - )} +
{user && ( { - // Onboarding completion is handled by the dialog itself - // The username update will trigger hasUsername to become true - }} + onComplete={() => {}} /> )}
diff --git a/src/routes/admin.tsx b/src/routes/admin.tsx new file mode 100644 index 00000000..79599dbc --- /dev/null +++ b/src/routes/admin.tsx @@ -0,0 +1,14 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; +import AdminLayout from "@/pages/admin/AdminLayout"; + +export const Route = createFileRoute("/admin")({ + component: AdminLayout, + beforeLoad: ({ location }) => { + if (location.pathname === "/admin" || location.pathname === "/admin/") { + throw redirect({ + to: "/admin/artists", + search: location.search, + }); + } + }, +}); diff --git a/src/routes/admin/admins.tsx b/src/routes/admin/admins.tsx new file mode 100644 index 00000000..971af9ea --- /dev/null +++ b/src/routes/admin/admins.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { AdminRolesTable } from "@/pages/admin/Roles/AdminRolesTable"; + +export const Route = createFileRoute("/admin/admins")({ + component: AdminRolesTable, +}); diff --git a/src/routes/admin/analytics.tsx b/src/routes/admin/analytics.tsx new file mode 100644 index 00000000..6a942779 --- /dev/null +++ b/src/routes/admin/analytics.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import AdminAnalytics from "@/pages/admin/Analytics/AdminAnalytics"; + +export const Route = createFileRoute("/admin/analytics")({ + component: AdminAnalytics, +}); diff --git a/src/routes/admin/artists.tsx b/src/routes/admin/artists.tsx new file mode 100644 index 00000000..3442a2c1 --- /dev/null +++ b/src/routes/admin/artists.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ArtistBulkEditor } from "@/pages/admin/ArtistsManagement/ArtistBulkEditor"; + +export const Route = createFileRoute("/admin/artists")({ + component: ArtistBulkEditor, +}); diff --git a/src/routes/admin/artists/duplicates.tsx b/src/routes/admin/artists/duplicates.tsx new file mode 100644 index 00000000..e9edf8af --- /dev/null +++ b/src/routes/admin/artists/duplicates.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { DuplicateArtistsPage } from "@/pages/admin/ArtistsManagement/DuplicateArtistsPage"; + +export const Route = createFileRoute("/admin/artists/duplicates")({ + component: DuplicateArtistsPage, +}); diff --git a/src/routes/admin/festivals.tsx b/src/routes/admin/festivals.tsx new file mode 100644 index 00000000..a2c1c642 --- /dev/null +++ b/src/routes/admin/festivals.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import AdminFestivals from "@/pages/admin/festivals/AdminFestivals"; + +export const Route = createFileRoute("/admin/festivals")({ + component: AdminFestivals, +}); diff --git a/src/routes/admin/festivals/$festivalId.$editionId.import.tsx b/src/routes/admin/festivals/$festivalId.$editionId.import.tsx new file mode 100644 index 00000000..90715693 --- /dev/null +++ b/src/routes/admin/festivals/$festivalId.$editionId.import.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { z } from "zod"; +import { CSVImportPage } from "@/pages/admin/festivals/CSVImportPage"; + +const importSearchSchema = z.object({ + tab: z.enum(["stages", "sets"]).optional(), +}); + +export const Route = createFileRoute( + "/admin/festivals/$festivalId/$editionId/import", +)({ + component: CSVImportPage, + validateSearch: importSearchSchema, +}); diff --git a/src/routes/admin/festivals/$festivalSlug.tsx b/src/routes/admin/festivals/$festivalSlug.tsx new file mode 100644 index 00000000..001dac62 --- /dev/null +++ b/src/routes/admin/festivals/$festivalSlug.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import FestivalDetail from "@/pages/admin/festivals/FestivalDetail"; + +export const Route = createFileRoute("/admin/festivals/$festivalSlug")({ + component: FestivalDetail, +}); diff --git a/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug.tsx b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug.tsx new file mode 100644 index 00000000..bbda59fd --- /dev/null +++ b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug.tsx @@ -0,0 +1,72 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; +import FestivalEdition from "@/pages/admin/festivals/FestivalEdition"; +import { editionsKeys } from "@/hooks/queries/festivals/editions/types"; +import type { QueryClient } from "@tanstack/react-query"; + +async function fetchFestivalEditionBySlug({ + festivalSlug, + editionSlug, +}: { + festivalSlug: string; + editionSlug: string; +}) { + const { supabase } = await import("@/integrations/supabase/client"); + + // First get the festival ID from the slug + const { data: festival, error: festivalError } = await supabase + .from("festivals") + .select("*") + .eq("archived", false) + .eq("slug", festivalSlug) + .single(); + + if (festivalError) { + throw new Error("Failed to load festival"); + } + + const { data, error } = await supabase + .from("festival_editions") + .select("*") + .eq("archived", false) + .eq("festival_id", festival.id) + .eq("slug", editionSlug) + .single(); + + if (error) { + throw new Error("Failed to load festival edition"); + } + + return data; +} + +export const Route = createFileRoute( + "/admin/festivals/$festivalSlug/editions/$editionSlug", +)({ + component: FestivalEdition, + beforeLoad: async ({ params, location, context }) => { + const queryClient = (context as { queryClient: QueryClient }).queryClient; + if (params?.editionSlug && location.pathname.endsWith(params.editionSlug)) { + throw redirect({ + to: "/admin/festivals/$festivalSlug/editions/$editionSlug/stages", + params, + search: location.search as Record, + }); + } + + // Prefetch edition data so it's available to all child routes + await queryClient.ensureQueryData({ + queryKey: editionsKeys.bySlug(params.festivalSlug, params.editionSlug), + queryFn: () => + fetchFestivalEditionBySlug({ + festivalSlug: params.festivalSlug, + editionSlug: params.editionSlug, + }), + }); + + return { + ...context, + festivalSlug: params.festivalSlug, + editionSlug: params.editionSlug, + }; + }, +}); diff --git a/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets.tsx b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets.tsx new file mode 100644 index 00000000..64ab930b --- /dev/null +++ b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import FestivalSets from "@/pages/admin/festivals/FestivalSets"; + +export const Route = createFileRoute( + "/admin/festivals/$festivalSlug/editions/$editionSlug/sets", +)({ + component: FestivalSets, +}); diff --git a/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/stages.tsx b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/stages.tsx new file mode 100644 index 00000000..f7f0ad5c --- /dev/null +++ b/src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/stages.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import FestivalStages from "@/pages/admin/festivals/FestivalStages"; + +export const Route = createFileRoute( + "/admin/festivals/$festivalSlug/editions/$editionSlug/stages", +)({ + component: FestivalStages, +}); diff --git a/src/routes/admin/festivals/import.tsx b/src/routes/admin/festivals/import.tsx new file mode 100644 index 00000000..d7071bc0 --- /dev/null +++ b/src/routes/admin/festivals/import.tsx @@ -0,0 +1,12 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { CSVImportPage } from "@/pages/admin/festivals/CSVImportPage"; +import { z } from "zod"; + +const importSearchSchema = z.object({ + tab: z.enum(["sets", "stages"]).optional(), +}); + +export const Route = createFileRoute("/admin/festivals/import")({ + component: CSVImportPage, + validateSearch: importSearchSchema, +}); diff --git a/src/routes/cookies.tsx b/src/routes/cookies.tsx new file mode 100644 index 00000000..deb75940 --- /dev/null +++ b/src/routes/cookies.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import CookiePolicy from "@/pages/legal/CookiePolicy"; + +export const Route = createFileRoute("/cookies")({ + component: CookiePolicy, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug.tsx new file mode 100644 index 00000000..69253782 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug.tsx @@ -0,0 +1,17 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; +import EditionLayout from "@/pages/EditionView/EditionLayout"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug", +)({ + component: EditionLayout, + beforeLoad: ({ params, location }) => { + if (params?.editionSlug && location.pathname.endsWith(params.editionSlug)) { + throw redirect({ + to: "/festivals/$festivalSlug/editions/$editionSlug/sets", + params, + search: location.search as Record, + }); + } + }, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/explore.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/explore.tsx new file mode 100644 index 00000000..c1350468 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/explore.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ExploreSetPage } from "@/pages/ExploreSetPage/ExploreSetPage"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/explore", +)({ + component: ExploreSetPage, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/info.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/info.tsx new file mode 100644 index 00000000..dea13545 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/info.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { InfoTab } from "@/pages/EditionView/tabs/InfoTab"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/info", +)({ + component: InfoTab, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/map.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/map.tsx new file mode 100644 index 00000000..0b06ebba --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/map.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { MapTab } from "@/pages/EditionView/tabs/MapTab"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/map", +)({ + component: MapTab, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule.tsx new file mode 100644 index 00000000..8d3baf0c --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule.tsx @@ -0,0 +1,19 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; +import { ScheduleTab } from "@/pages/EditionView/tabs/ScheduleTab"; +import { filterSortSearchSchema } from "@/lib/searchSchemas"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/schedule", +)({ + component: ScheduleTab, + validateSearch: filterSortSearchSchema, + beforeLoad: ({ params, location }) => { + if (location.pathname.endsWith("/schedule")) { + throw redirect({ + to: "/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline", + params, + search: location.search as Record, + }); + } + }, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/list.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/list.tsx new file mode 100644 index 00000000..095f5d61 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/list.tsx @@ -0,0 +1,10 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ScheduleTabList } from "@/pages/EditionView/tabs/ScheduleTab/list/ListTab"; +import { timelineSearchSchema } from "@/lib/searchSchemas"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/schedule/list", +)({ + component: ScheduleTabList, + validateSearch: timelineSearchSchema, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline.tsx new file mode 100644 index 00000000..cfd15d06 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline.tsx @@ -0,0 +1,10 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ScheduleTabTimeline } from "@/pages/EditionView/tabs/ScheduleTab/TimelineTab"; +import { timelineSearchSchema } from "@/lib/searchSchemas"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/schedule/timeline", +)({ + component: ScheduleTabTimeline, + validateSearch: timelineSearchSchema, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.$setSlug.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.$setSlug.tsx new file mode 100644 index 00000000..f48f47da --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.$setSlug.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { SetDetails } from "@/pages/SetDetails"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/sets/$setSlug", +)({ + component: SetDetails, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.tsx new file mode 100644 index 00000000..6441afc2 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/sets.tsx @@ -0,0 +1,10 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { ArtistsTab } from "@/pages/EditionView/tabs/ArtistsTab/ArtistsTab"; +import { filterSortSearchSchema } from "@/lib/searchSchemas"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/sets", +)({ + component: ArtistsTab, + validateSearch: filterSortSearchSchema, +}); diff --git a/src/routes/festivals/$festivalSlug/editions/$editionSlug/social.tsx b/src/routes/festivals/$festivalSlug/editions/$editionSlug/social.tsx new file mode 100644 index 00000000..6516ca98 --- /dev/null +++ b/src/routes/festivals/$festivalSlug/editions/$editionSlug/social.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { SocialTab } from "@/pages/EditionView/tabs/SocialTab"; + +export const Route = createFileRoute( + "/festivals/$festivalSlug/editions/$editionSlug/social", +)({ + component: SocialTab, +}); diff --git a/src/routes/festivals/$festivalSlug/index.tsx b/src/routes/festivals/$festivalSlug/index.tsx new file mode 100644 index 00000000..229cb57f --- /dev/null +++ b/src/routes/festivals/$festivalSlug/index.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import EditionSelection from "@/pages/EditionSelection"; + +export const Route = createFileRoute("/festivals/$festivalSlug/")({ + component: EditionSelection, +}); diff --git a/src/routes/groups/$groupSlug.tsx b/src/routes/groups/$groupSlug.tsx new file mode 100644 index 00000000..0ba2e6c3 --- /dev/null +++ b/src/routes/groups/$groupSlug.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import GroupDetail from "@/pages/groups/GroupDetail"; + +export const Route = createFileRoute("/groups/$groupSlug")({ + component: GroupDetail, +}); diff --git a/src/routes/groups/index.tsx b/src/routes/groups/index.tsx new file mode 100644 index 00000000..1b657ccf --- /dev/null +++ b/src/routes/groups/index.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import Groups from "@/pages/groups/Groups"; + +export const Route = createFileRoute("/groups/")({ + component: Groups, +}); diff --git a/src/routes/index.tsx b/src/routes/index.tsx new file mode 100644 index 00000000..9490df64 --- /dev/null +++ b/src/routes/index.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import FestivalSelection from "@/pages/FestivalSelection"; + +export const Route = createFileRoute("/")({ + component: FestivalSelection, +}); diff --git a/src/routes/privacy.tsx b/src/routes/privacy.tsx new file mode 100644 index 00000000..a5e572f9 --- /dev/null +++ b/src/routes/privacy.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import PrivacyPolicy from "@/pages/legal/PrivacyPolicy"; + +export const Route = createFileRoute("/privacy")({ + component: PrivacyPolicy, +}); diff --git a/src/routes/terms.tsx b/src/routes/terms.tsx new file mode 100644 index 00000000..97cf3683 --- /dev/null +++ b/src/routes/terms.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import TermsOfService from "@/pages/legal/TermsOfService"; + +export const Route = createFileRoute("/terms")({ + component: TermsOfService, +}); diff --git a/vite.config.ts b/vite.config.ts index 0a0672f2..74be376c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react-swc"; import path from "path"; import { VitePWA } from "vite-plugin-pwa"; +import { TanStackRouterVite } from "@tanstack/router-vite-plugin"; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => ({ @@ -11,6 +12,7 @@ export default defineConfig(({ mode }) => ({ }, plugins: [ react(), + TanStackRouterVite(), VitePWA({ registerType: "autoUpdate", devOptions: {