diff --git a/client/cms/openapi-ts.config.ts b/client/cms/openapi-ts.config.ts index c0d6eef..cb1c382 100644 --- a/client/cms/openapi-ts.config.ts +++ b/client/cms/openapi-ts.config.ts @@ -5,7 +5,11 @@ export default defineConfig({ output: 'src/client', plugins: [ '@hey-api/typescript', - '@tanstack/react-query', + { + name: '@tanstack/react-query', + infiniteQueryOptions: true, + infiniteQueryKeys: true, + }, 'zod', { name: '@hey-api/transformers', diff --git a/client/cms/package.json b/client/cms/package.json index 0f0db0f..64f3e2a 100644 --- a/client/cms/package.json +++ b/client/cms/package.json @@ -59,18 +59,20 @@ "lucide-react": "^0.562.0", "next-themes": "^0.4.6", "qrcode": "^1.5.4", + "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-error-boundary": "^6.1.0", "react-hook-form": "^7.69.0", "react-markdown": "^10.1.0", + "react-spinners": "^0.17.0", "recharts": "2.15.4", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", "utf8": "^3.0.0", "vaul": "^1.1.2", - "zod": "^4.2.1", + "zod": "^3.25.76", "zustand": "^5.0.9" }, "devDependencies": { @@ -79,6 +81,7 @@ "@eslint-react/eslint-plugin": "^2.3.13", "@eslint/js": "^9.39.1", "@hey-api/openapi-ts": "0.91.0", + "@redux-devtools/extension": "^3.3.0", "@storybook/addon-a11y": "^10.2.3", "@storybook/addon-docs": "^10.2.3", "@storybook/addon-onboarding": "^10.2.3", diff --git a/client/cms/pnpm-lock.yaml b/client/cms/pnpm-lock.yaml index f61ca18..669b020 100644 --- a/client/cms/pnpm-lock.yaml +++ b/client/cms/pnpm-lock.yaml @@ -100,10 +100,10 @@ importers: version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@tanstack/zod-adapter': specifier: ^1.143.4 - version: 1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@4.3.5) + version: 1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@3.25.76) '@tanstack/zod-form-adapter': specifier: ^0.42.1 - version: 0.42.1(zod@4.3.5) + version: 0.42.1(zod@3.25.76) '@uiw/react-md-editor': specifier: ^4.0.11 version: 4.0.11(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -143,6 +143,9 @@ importers: qrcode: specifier: ^1.5.4 version: 1.5.4 + radix-ui: + specifier: ^1.4.3 + version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: specifier: ^19.2.0 version: 19.2.3 @@ -158,6 +161,9 @@ importers: react-markdown: specifier: ^10.1.0 version: 10.1.0(@types/react@19.2.8)(react@19.2.3) + react-spinners: + specifier: ^0.17.0 + version: 0.17.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) recharts: specifier: 2.15.4 version: 2.15.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -177,8 +183,8 @@ importers: specifier: ^1.1.2 version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) zod: - specifier: ^4.2.1 - version: 4.3.5 + specifier: ^3.25.76 + version: 3.25.76 zustand: specifier: ^5.0.9 version: 5.0.10(@types/react@19.2.8)(immer@11.1.3)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) @@ -198,6 +204,9 @@ importers: '@hey-api/openapi-ts': specifier: 0.91.0 version: 0.91.0(magicast@0.5.1)(typescript@5.9.3) + '@redux-devtools/extension': + specifier: ^3.3.0 + version: 3.3.0(redux@5.0.1) '@storybook/addon-a11y': specifier: ^10.2.3 version: 10.2.3(storybook@10.2.3(@testing-library/dom@10.4.1)(prettier@3.8.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) @@ -1122,6 +1131,45 @@ packages: '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + '@radix-ui/react-accessible-icon@1.1.7': + resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-accordion@1.2.12': + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-alert-dialog@1.1.15': + resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-arrow@1.1.7': resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} peerDependencies: @@ -1135,6 +1183,32 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-aspect-ratio@1.1.7': + resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-avatar@1.1.11': resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} peerDependencies: @@ -1161,6 +1235,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collapsible@1.1.12': + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-collection@1.1.7': resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} peerDependencies: @@ -1183,6 +1270,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-context-menu@2.2.16': + resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-context@1.1.2': resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: @@ -1271,6 +1371,32 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-form@0.1.8': + resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-hover-card@1.1.15': + resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -1280,6 +1406,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-label@2.1.8': resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} peerDependencies: @@ -1306,6 +1445,71 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-menubar@1.1.16': + resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-navigation-menu@1.2.14': + resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-one-time-password-field@0.1.8': + resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-password-toggle-field@0.1.3': + resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-popper@1.2.8': resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} peerDependencies: @@ -1371,6 +1575,32 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-progress@1.1.7': + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.8': + resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-roving-focus@1.1.11': resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} peerDependencies: @@ -1384,6 +1614,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-select@2.2.6': resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} peerDependencies: @@ -1397,6 +1640,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-separator@1.1.8': resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} peerDependencies: @@ -1410,6 +1666,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-slider@1.3.6': + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.2.3': resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: @@ -1454,6 +1723,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-toast@1.2.15': + resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-toggle-group@1.1.11': resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} peerDependencies: @@ -1480,6 +1762,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-toolbar@1.1.11': + resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-tooltip@1.2.8': resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} peerDependencies: @@ -1590,6 +1885,11 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@redux-devtools/extension@3.3.0': + resolution: {integrity: sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==} + peerDependencies: + redux: ^3.1.0 || ^4.0.0 || ^5.0.0 + '@rolldown/pluginutils@1.0.0-beta.53': resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} @@ -3586,6 +3886,9 @@ packages: immer@11.1.3: resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==} + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -4359,6 +4662,19 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + radix-ui@1.4.3: + resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} @@ -4438,6 +4754,12 @@ packages: 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 + react-spinners@0.17.0: + resolution: {integrity: sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -4484,6 +4806,9 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -6007,6 +6332,46 @@ snapshots: '@radix-ui/primitive@1.1.3': {} + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6016,6 +6381,28 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-context': 1.1.3(@types/react@19.2.8)(react@19.2.3) @@ -6045,6 +6432,22 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) @@ -6063,6 +6466,20 @@ snapshots: optionalDependencies: '@types/react': 19.2.8 + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-context@1.1.2(@types/react@19.2.8)(react@19.2.3)': dependencies: react: 19.2.3 @@ -6148,6 +6565,37 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-id@1.1.1(@types/react@19.2.8)(react@19.2.3)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) @@ -6155,6 +6603,15 @@ snapshots: optionalDependencies: '@types/react': 19.2.8 + '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6190,6 +6647,105 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + aria-hidden: 1.2.6 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-remove-scroll: 2.7.2(@types/react@19.2.8)(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6246,6 +6802,34 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6263,6 +6847,23 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/number': 1.1.1 @@ -6292,6 +6893,15 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6301,6 +6911,25 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.8)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-slot@1.2.3(@types/react@19.2.8)(react@19.2.3)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) @@ -6346,6 +6975,26 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6372,6 +7021,21 @@ snapshots: '@types/react': 19.2.8 '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6464,6 +7128,12 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@redux-devtools/extension@3.3.0(redux@5.0.1)': + dependencies: + '@babel/runtime': 7.28.6 + immutable: 4.3.7 + redux: 5.0.1 + '@rolldown/pluginutils@1.0.0-beta.53': {} '@rollup/pluginutils@5.3.0(rollup@4.55.2)': @@ -6977,15 +7647,15 @@ snapshots: '@tanstack/virtual-file-routes@1.145.4': {} - '@tanstack/zod-adapter@1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@4.3.5)': + '@tanstack/zod-adapter@1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@3.25.76)': dependencies: '@tanstack/react-router': 1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: 4.3.5 + zod: 3.25.76 - '@tanstack/zod-form-adapter@0.42.1(zod@4.3.5)': + '@tanstack/zod-form-adapter@0.42.1(zod@3.25.76)': dependencies: '@tanstack/form-core': 0.42.1 - zod: 4.3.5 + zod: 3.25.76 '@testing-library/dom@10.4.1': dependencies: @@ -8676,6 +9346,8 @@ snapshots: immer@11.1.3: {} + immutable@4.3.7: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -9606,6 +10278,69 @@ snapshots: quansync@0.2.11: {} + radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.8)(react@19.2.3) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + rc9@2.1.2: dependencies: defu: 6.1.4 @@ -9713,6 +10448,11 @@ snapshots: react-dom: 19.2.3(react@19.2.3) react-transition-group: 4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-spinners@0.17.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-style-singleton@2.2.3(@types/react@19.2.8)(react@19.2.3): dependencies: get-nonce: 1.0.1 @@ -9768,6 +10508,8 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 + redux@5.0.1: {} + refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 diff --git a/client/cms/src/client/@tanstack/react-query.gen.ts b/client/cms/src/client/@tanstack/react-query.gen.ts index c823dd3..89fcd78 100644 --- a/client/cms/src/client/@tanstack/react-query.gen.ts +++ b/client/cms/src/client/@tanstack/react-query.gen.ts @@ -3,8 +3,8 @@ import { type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; import { client } from '../client.gen'; -import { getAuthRedirect, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit, postEventJoin, postKycQuery, postKycSession } from '../sdk.gen'; -import type { GetAuthRedirectData, GetAuthRedirectError, GetEventCheckinData, GetEventCheckinError, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryResponse, GetEventCheckinResponse, GetEventInfoData, GetEventInfoError, GetEventInfoResponse, GetEventListData, GetEventListError, GetEventListResponse, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdResponse, GetUserInfoData, GetUserInfoError, GetUserInfoResponse, GetUserListData, GetUserListError, GetUserListResponse, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateResponse, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeResponse, PostAuthMagicData, PostAuthMagicError, PostAuthMagicResponse, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshResponse, PostAuthTokenData, PostAuthTokenError, PostAuthTokenResponse, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitResponse, PostEventJoinData, PostEventJoinError, PostEventJoinResponse, PostKycQueryData, PostKycQueryError, PostKycQueryResponse, PostKycSessionData, PostKycSessionError, PostKycSessionResponse } from '../types.gen'; +import { getAuthRedirect, getEventAttendance, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit, postEventJoin, postKycQuery, postKycSession } from '../sdk.gen'; +import type { GetAuthRedirectData, GetAuthRedirectError, GetEventAttendanceData, GetEventAttendanceError, GetEventAttendanceResponse, GetEventCheckinData, GetEventCheckinError, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryResponse, GetEventCheckinResponse, GetEventInfoData, GetEventInfoError, GetEventInfoResponse, GetEventListData, GetEventListError, GetEventListResponse, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdResponse, GetUserInfoData, GetUserInfoError, GetUserInfoResponse, GetUserListData, GetUserListError, GetUserListResponse, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateResponse, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeResponse, PostAuthMagicData, PostAuthMagicError, PostAuthMagicResponse, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshResponse, PostAuthTokenData, PostAuthTokenError, PostAuthTokenResponse, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitResponse, PostEventJoinData, PostEventJoinError, PostEventJoinResponse, PostKycQueryData, PostKycQueryError, PostKycQueryResponse, PostKycSessionData, PostKycSessionError, PostKycSessionResponse } from '../types.gen'; /** * Exchange Auth Code @@ -135,6 +135,26 @@ export const postAuthTokenMutation = (options?: Partial) => createQueryKey('getEventAttendance', options); + +/** + * Get Attendance List + * + * Retrieves the list of attendees, including user info and decrypted KYC data for a specified event. + */ +export const getEventAttendanceOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getEventAttendance({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getEventAttendanceQueryKey(options) +}); + export const getEventCheckinQueryKey = (options: Options) => createQueryKey('getEventCheckin', options); /** @@ -289,7 +309,7 @@ export const getEventListInfiniteQueryKey = (options: Options) * * Fetches a list of events with support for pagination via limit and offset. Data is retrieved directly from the database for consistency. */ -export const getEventListInfiniteOptions = (options: Options) => infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( +export const getEventListInfiniteOptions = (options: Options) => infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( // @ts-ignore { queryFn: async ({ pageParam, queryKey, signal }) => { @@ -349,14 +369,14 @@ export const postKycSessionMutation = (options?: Partial) => createQueryKey('getUserInfo', options); +export const getUserInfoQueryKey = (options: Options) => createQueryKey('getUserInfo', options); /** * Get My User Information * * Fetches the complete profile data for the user associated with the provided session/token. */ -export const getUserInfoOptions = (options?: Options) => queryOptions>({ +export const getUserInfoOptions = (options: Options) => queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getUserInfo({ ...options, diff --git a/client/cms/src/client/index.ts b/client/cms/src/client/index.ts index a853517..0b14418 100644 --- a/client/cms/src/client/index.ts +++ b/client/cms/src/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { getAuthRedirect, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit, postEventJoin, postKycQuery, postKycSession } from './sdk.gen'; -export type { ClientOptions, DataEventIndexDoc, DataUserIndexDoc, GetAuthRedirectData, GetAuthRedirectError, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinError, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryErrors, GetEventCheckinQueryResponse, GetEventCheckinQueryResponses, GetEventCheckinResponse, GetEventCheckinResponses, GetEventInfoData, GetEventInfoError, GetEventInfoErrors, GetEventInfoResponse, GetEventInfoResponses, GetEventListData, GetEventListError, GetEventListErrors, GetEventListResponse, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponse, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoError, GetUserInfoErrors, GetUserInfoResponse, GetUserInfoResponses, GetUserListData, GetUserListError, GetUserListErrors, GetUserListResponse, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateErrors, PatchUserUpdateResponse, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeErrors, PostAuthExchangeResponse, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicError, PostAuthMagicErrors, PostAuthMagicResponse, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenError, PostAuthTokenErrors, PostAuthTokenResponse, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponse, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinError, PostEventJoinErrors, PostEventJoinResponse, PostEventJoinResponses, PostKycQueryData, PostKycQueryError, PostKycQueryErrors, PostKycQueryResponse, PostKycQueryResponses, PostKycSessionData, PostKycSessionError, PostKycSessionErrors, PostKycSessionResponse, PostKycSessionResponses, ServiceAuthExchangeData, ServiceAuthExchangeResponse, ServiceAuthMagicData, ServiceAuthMagicResponse, ServiceAuthRefreshData, ServiceAuthTokenData, ServiceAuthTokenResponse, ServiceEventCheckinQueryResponse, ServiceEventCheckinResponse, ServiceEventCheckinSubmitData, ServiceEventEventJoinData, ServiceKycKycQueryData, ServiceKycKycQueryResponse, ServiceKycKycSessionData, ServiceKycKycSessionResponse, ServiceUserUserInfoData, UtilsRespStatus } from './types.gen'; +export { getAuthRedirect, getEventAttendance, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit, postEventJoin, postKycQuery, postKycSession } from './sdk.gen'; +export type { ClientOptions, DataEventIndexDoc, DataUserIndexDoc, GetAuthRedirectData, GetAuthRedirectError, GetAuthRedirectErrors, GetEventAttendanceData, GetEventAttendanceError, GetEventAttendanceErrors, GetEventAttendanceResponse, GetEventAttendanceResponses, GetEventCheckinData, GetEventCheckinError, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryErrors, GetEventCheckinQueryResponse, GetEventCheckinQueryResponses, GetEventCheckinResponse, GetEventCheckinResponses, GetEventInfoData, GetEventInfoError, GetEventInfoErrors, GetEventInfoResponse, GetEventInfoResponses, GetEventListData, GetEventListError, GetEventListErrors, GetEventListResponse, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponse, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoError, GetUserInfoErrors, GetUserInfoResponse, GetUserInfoResponses, GetUserListData, GetUserListError, GetUserListErrors, GetUserListResponse, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateErrors, PatchUserUpdateResponse, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeErrors, PostAuthExchangeResponse, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicError, PostAuthMagicErrors, PostAuthMagicResponse, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenError, PostAuthTokenErrors, PostAuthTokenResponse, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponse, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinError, PostEventJoinErrors, PostEventJoinResponse, PostEventJoinResponses, PostKycQueryData, PostKycQueryError, PostKycQueryErrors, PostKycQueryResponse, PostKycQueryResponses, PostKycSessionData, PostKycSessionError, PostKycSessionErrors, PostKycSessionResponse, PostKycSessionResponses, ServiceAuthExchangeData, ServiceAuthExchangeResponse, ServiceAuthMagicData, ServiceAuthMagicResponse, ServiceAuthRefreshData, ServiceAuthTokenData, ServiceAuthTokenResponse, ServiceEventAttendanceListResponse, ServiceEventCheckinQueryResponse, ServiceEventCheckinResponse, ServiceEventCheckinSubmitData, ServiceEventEventJoinData, ServiceKycKycQueryData, ServiceKycKycQueryResponse, ServiceKycKycSessionData, ServiceKycKycSessionResponse, ServiceUserUserInfoData, UtilsRespStatus } from './types.gen'; diff --git a/client/cms/src/client/sdk.gen.ts b/client/cms/src/client/sdk.gen.ts index 475743d..ae9f15d 100644 --- a/client/cms/src/client/sdk.gen.ts +++ b/client/cms/src/client/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { GetAuthRedirectData, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryErrors, GetEventCheckinQueryResponses, GetEventCheckinResponses, GetEventInfoData, GetEventInfoErrors, GetEventInfoResponses, GetEventListData, GetEventListErrors, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoErrors, GetUserInfoResponses, GetUserListData, GetUserListErrors, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateErrors, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeErrors, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicErrors, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenErrors, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinErrors, PostEventJoinResponses, PostKycQueryData, PostKycQueryErrors, PostKycQueryResponses, PostKycSessionData, PostKycSessionErrors, PostKycSessionResponses } from './types.gen'; +import type { GetAuthRedirectData, GetAuthRedirectErrors, GetEventAttendanceData, GetEventAttendanceErrors, GetEventAttendanceResponses, GetEventCheckinData, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryErrors, GetEventCheckinQueryResponses, GetEventCheckinResponses, GetEventInfoData, GetEventInfoErrors, GetEventInfoResponses, GetEventListData, GetEventListErrors, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoErrors, GetUserInfoResponses, GetUserListData, GetUserListErrors, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateErrors, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeErrors, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicErrors, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenErrors, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinErrors, PostEventJoinResponses, PostKycQueryData, PostKycQueryErrors, PostKycQueryResponses, PostKycSessionData, PostKycSessionErrors, PostKycSessionResponses } from './types.gen'; export type Options = Options2 & { /** @@ -81,6 +81,13 @@ export const postAuthToken = (options: Opt } }); +/** + * Get Attendance List + * + * Retrieves the list of attendees, including user info and decrypted KYC data for a specified event. + */ +export const getEventAttendance = (options: Options) => (options.client ?? client).get({ url: '/event/attendance', ...options }); + /** * Generate Check-in Code * @@ -170,7 +177,7 @@ export const postKycSession = (options: Op * * Fetches the complete profile data for the user associated with the provided session/token. */ -export const getUserInfo = (options?: Options) => (options?.client ?? client).get({ url: '/user/info', ...options }); +export const getUserInfo = (options: Options) => (options.client ?? client).get({ url: '/user/info', ...options }); /** * Get Other User Information diff --git a/client/cms/src/client/types.gen.ts b/client/cms/src/client/types.gen.ts index 85a22d1..379bdc7 100644 --- a/client/cms/src/client/types.gen.ts +++ b/client/cms/src/client/types.gen.ts @@ -5,9 +5,13 @@ export type ClientOptions = { }; export type DataEventIndexDoc = { + checkin_count?: number; description?: string; + enable_kyc?: boolean; end_time?: string; event_id?: string; + is_joined?: boolean; + join_count?: number; name?: string; start_time?: string; thumbnail?: string; @@ -60,6 +64,13 @@ export type ServiceAuthTokenResponse = { refresh_token?: string; }; +export type ServiceEventAttendanceListResponse = { + attendance_id?: string; + kyc_info?: unknown; + kyc_type?: string; + user_info?: ServiceUserUserInfoData; +}; + export type ServiceEventCheckinQueryResponse = { checkin_at?: string; }; @@ -132,6 +143,12 @@ export type PostAuthExchangeData = { * Exchange Request Credentials */ body: ServiceAuthExchangeData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/auth/exchange'; @@ -182,6 +199,12 @@ export type PostAuthMagicData = { * Magic Link Request Data */ body: ServiceAuthMagicData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/auth/magic'; @@ -285,6 +308,12 @@ export type PostAuthRefreshData = { * Refresh Token Body */ body: ServiceAuthRefreshData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/auth/refresh'; @@ -335,6 +364,12 @@ export type PostAuthTokenData = { * Token Request Body */ body: ServiceAuthTokenData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/auth/token'; @@ -380,8 +415,72 @@ export type PostAuthTokenResponses = { export type PostAuthTokenResponse = PostAuthTokenResponses[keyof PostAuthTokenResponses]; +export type GetEventAttendanceData = { + body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; + path?: never; + query: { + /** + * Event UUID + */ + event_id: string; + }; + url: '/event/attendance'; +}; + +export type GetEventAttendanceErrors = { + /** + * Invalid Input + */ + 400: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Unauthorized + */ + 401: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Internal Server Error + */ + 500: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; +}; + +export type GetEventAttendanceError = GetEventAttendanceErrors[keyof GetEventAttendanceErrors]; + +export type GetEventAttendanceResponses = { + /** + * Successful retrieval + */ + 200: UtilsRespStatus & { + data?: Array; + }; +}; + +export type GetEventAttendanceResponse = GetEventAttendanceResponses[keyof GetEventAttendanceResponses]; + export type GetEventCheckinData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query: { /** @@ -514,6 +613,12 @@ export type PostEventCheckinSubmitResponse = PostEventCheckinSubmitResponses[key export type GetEventInfoData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query: { /** @@ -577,6 +682,12 @@ export type PostEventJoinData = { * Event Join Details (UserId and EventId are required) */ body: ServiceEventEventJoinData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/event/join'; @@ -600,7 +711,7 @@ export type PostEventJoinErrors = { }; }; /** - * Unauthorized / Missing User ID + * Unauthorized / Missing User ID / Event Limit Exceeded */ 403: UtilsRespStatus & { data?: { @@ -634,16 +745,22 @@ export type PostEventJoinResponse = PostEventJoinResponses[keyof PostEventJoinRe export type GetEventListData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; - query: { + query?: { /** * Maximum number of events to return (default 20) */ - limit?: string; + limit?: number; /** * Number of events to skip */ - offset: string; + offset?: number; }; url: '/event/list'; }; @@ -693,6 +810,12 @@ export type PostKycQueryData = { * KYC query data (KycId) */ body: ServiceKycKycQueryData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/kyc/query'; @@ -743,6 +866,12 @@ export type PostKycSessionData = { * KYC session data (Type and Base64 Identity) */ body: ServiceKycKycSessionData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/kyc/session'; @@ -790,6 +919,12 @@ export type PostKycSessionResponse = PostKycSessionResponses[keyof PostKycSessio export type GetUserInfoData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/user/info'; @@ -837,6 +972,12 @@ export type GetUserInfoResponse = GetUserInfoResponses[keyof GetUserInfoResponse export type GetUserInfoByUserIdData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path: { /** * Other user id @@ -897,6 +1038,12 @@ export type GetUserInfoByUserIdResponse = GetUserInfoByUserIdResponses[keyof Get export type GetUserListData = { body?: never; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query: { /** @@ -956,6 +1103,12 @@ export type PatchUserUpdateData = { * Updated User Profile Data */ body: ServiceUserUserInfoData; + headers: { + /** + * latest + */ + 'X-Api-Version': string; + }; path?: never; query?: never; url: '/user/update'; diff --git a/client/cms/src/client/zod.gen.ts b/client/cms/src/client/zod.gen.ts index 19c081d..3303d44 100644 --- a/client/cms/src/client/zod.gen.ts +++ b/client/cms/src/client/zod.gen.ts @@ -3,184 +3,228 @@ import { z } from 'zod'; export const zDataEventIndexDoc = z.object({ - description: z.optional(z.string()), - end_time: z.optional(z.string()), - event_id: z.optional(z.string()), - name: z.optional(z.string()), - start_time: z.optional(z.string()), - thumbnail: z.optional(z.string()), - type: z.optional(z.string()) + checkin_count: z.number().int().optional(), + description: z.string().optional(), + enable_kyc: z.boolean().optional(), + end_time: z.string().optional(), + event_id: z.string().optional(), + is_joined: z.boolean().optional(), + join_count: z.number().int().optional(), + name: z.string().optional(), + start_time: z.string().optional(), + thumbnail: z.string().optional(), + type: z.string().optional() }); export const zDataUserIndexDoc = z.object({ - avatar: z.optional(z.string()), - email: z.optional(z.string()), - nickname: z.optional(z.string()), - subtitle: z.optional(z.string()), - type: z.optional(z.string()), - user_id: z.optional(z.string()), - username: z.optional(z.string()) + avatar: z.string().optional(), + email: z.string().optional(), + nickname: z.string().optional(), + subtitle: z.string().optional(), + type: z.string().optional(), + user_id: z.string().optional(), + username: z.string().optional() }); export const zServiceAuthExchangeData = z.object({ - client_id: z.optional(z.string()), - redirect_uri: z.optional(z.string()), - state: z.optional(z.string()) + client_id: z.string().optional(), + redirect_uri: z.string().optional(), + state: z.string().optional() }); export const zServiceAuthExchangeResponse = z.object({ - redirect_uri: z.optional(z.string()) + redirect_uri: z.string().optional() }); export const zServiceAuthMagicData = z.object({ - client_id: z.optional(z.string()), - client_ip: z.optional(z.string()), - email: z.optional(z.string()), - redirect_uri: z.optional(z.string()), - state: z.optional(z.string()), - turnstile_token: z.optional(z.string()) + client_id: z.string().optional(), + client_ip: z.string().optional(), + email: z.string().optional(), + redirect_uri: z.string().optional(), + state: z.string().optional(), + turnstile_token: z.string().optional() }); export const zServiceAuthMagicResponse = z.object({ - uri: z.optional(z.string()) + uri: z.string().optional() }); export const zServiceAuthRefreshData = z.object({ - refresh_token: z.optional(z.string()) + refresh_token: z.string().optional() }); export const zServiceAuthTokenData = z.object({ - code: z.optional(z.string()) + code: z.string().optional() }); export const zServiceAuthTokenResponse = z.object({ - access_token: z.optional(z.string()), - refresh_token: z.optional(z.string()) + access_token: z.string().optional(), + refresh_token: z.string().optional() }); export const zServiceEventCheckinQueryResponse = z.object({ - checkin_at: z.optional(z.string()) + checkin_at: z.string().optional() }); export const zServiceEventCheckinResponse = z.object({ - checkin_code: z.optional(z.string()) + checkin_code: z.string().optional() }); export const zServiceEventCheckinSubmitData = z.object({ - checkin_code: z.optional(z.string()) + checkin_code: z.string().optional() }); export const zServiceEventEventJoinData = z.object({ - event_id: z.optional(z.string()), - kyc_id: z.optional(z.string()) + event_id: z.string().optional(), + kyc_id: z.string().optional() }); export const zServiceKycKycQueryData = z.object({ - kyc_id: z.optional(z.string()) + kyc_id: z.string().optional() }); export const zServiceKycKycQueryResponse = z.object({ - status: z.optional(z.string()) + status: z.string().optional() }); export const zServiceKycKycSessionData = z.object({ - identity: z.optional(z.string()), - type: z.optional(z.string()) + identity: z.string().optional(), + type: z.string().optional() }); export const zServiceKycKycSessionResponse = z.object({ - kyc_id: z.optional(z.string()), - redirect_uri: z.optional(z.string()), - status: z.optional(z.string()) + kyc_id: z.string().optional(), + redirect_uri: z.string().optional(), + status: z.string().optional() }); export const zServiceUserUserInfoData = z.object({ - allow_public: z.optional(z.boolean()), - avatar: z.optional(z.string()), - bio: z.optional(z.string()), - email: z.optional(z.string()), - nickname: z.optional(z.string()), - permission_level: z.optional(z.int()), - subtitle: z.optional(z.string()), - user_id: z.optional(z.string()), - username: z.optional(z.string()) + allow_public: z.boolean().optional(), + avatar: z.string().optional(), + bio: z.string().optional(), + email: z.string().optional(), + nickname: z.string().optional(), + permission_level: z.number().int().optional(), + subtitle: z.string().optional(), + user_id: z.string().optional(), + username: z.string().optional() +}); + +export const zServiceEventAttendanceListResponse = z.object({ + attendance_id: z.string().optional(), + kyc_info: z.unknown().optional(), + kyc_type: z.string().optional(), + user_info: zServiceUserUserInfoData.optional() }); export const zUtilsRespStatus = z.object({ - code: z.optional(z.int()), - data: z.optional(z.unknown()), - error_id: z.optional(z.string()), - status: z.optional(z.string()) + code: z.number().int().optional(), + data: z.unknown().optional(), + error_id: z.string().optional(), + status: z.string().optional() }); export const zPostAuthExchangeData = z.object({ body: zServiceAuthExchangeData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful exchange */ export const zPostAuthExchangeResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceAuthExchangeResponse) + data: zServiceAuthExchangeResponse.optional() })); export const zPostAuthMagicData = z.object({ body: zServiceAuthMagicData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful request */ export const zPostAuthMagicResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceAuthMagicResponse) + data: zServiceAuthMagicResponse.optional() })); export const zGetAuthRedirectData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ client_id: z.string(), redirect_uri: z.string(), code: z.string(), - state: z.optional(z.string()) + state: z.string().optional() }) }); export const zPostAuthRefreshData = z.object({ body: zServiceAuthRefreshData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful rotation */ export const zPostAuthRefreshResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceAuthTokenResponse) + data: zServiceAuthTokenResponse.optional() })); export const zPostAuthTokenData = z.object({ body: zServiceAuthTokenData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful token issuance */ export const zPostAuthTokenResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceAuthTokenResponse) + data: zServiceAuthTokenResponse.optional() +})); + +export const zGetEventAttendanceData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + event_id: z.string() + }), + headers: z.object({ + 'X-Api-Version': z.string() + }) +}); + +/** + * Successful retrieval + */ +export const zGetEventAttendanceResponse = zUtilsRespStatus.and(z.object({ + data: z.array(zServiceEventAttendanceListResponse).optional() })); export const zGetEventCheckinData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ event_id: z.string() + }), + headers: z.object({ + 'X-Api-Version': z.string() }) }); @@ -188,12 +232,12 @@ export const zGetEventCheckinData = z.object({ * Successfully generated code */ export const zGetEventCheckinResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceEventCheckinResponse) + data: zServiceEventCheckinResponse.optional() })); export const zGetEventCheckinQueryData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ event_id: z.string() }) @@ -203,27 +247,30 @@ export const zGetEventCheckinQueryData = z.object({ * Current attendance status */ export const zGetEventCheckinQueryResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceEventCheckinQueryResponse) + data: zServiceEventCheckinQueryResponse.optional() })); export const zPostEventCheckinSubmitData = z.object({ body: zServiceEventCheckinSubmitData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); /** * Attendance marked successfully */ export const zPostEventCheckinSubmitResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(z.record(z.string(), z.unknown())) + data: z.record(z.unknown()).optional() })); export const zGetEventInfoData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ event_id: z.string() + }), + headers: z.object({ + 'X-Api-Version': z.string() }) }); @@ -231,28 +278,34 @@ export const zGetEventInfoData = z.object({ * Successful retrieval */ export const zGetEventInfoResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zDataEventIndexDoc) + data: zDataEventIndexDoc.optional() })); export const zPostEventJoinData = z.object({ body: zServiceEventEventJoinData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successfully joined the event */ export const zPostEventJoinResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(z.record(z.string(), z.unknown())) + data: z.record(z.unknown()).optional() })); export const zGetEventListData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - limit: z.optional(z.string()), - offset: z.string() + limit: z.number().int().optional(), + offset: z.number().int().optional() + }).optional(), + headers: z.object({ + 'X-Api-Version': z.string() }) }); @@ -260,69 +313,84 @@ export const zGetEventListData = z.object({ * Successful paginated list retrieval */ export const zGetEventListResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(z.array(zDataEventIndexDoc)) + data: z.array(zDataEventIndexDoc).optional() })); export const zPostKycQueryData = z.object({ body: zServiceKycKycQueryData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Query processed (success/pending/failed) */ export const zPostKycQueryResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceKycKycQueryResponse) + data: zServiceKycKycQueryResponse.optional() })); export const zPostKycSessionData = z.object({ body: zServiceKycKycSessionData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Session created successfully */ export const zPostKycSessionResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceKycKycSessionResponse) + data: zServiceKycKycSessionResponse.optional() })); export const zGetUserInfoData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful profile retrieval */ export const zGetUserInfoResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceUserUserInfoData) + data: zServiceUserUserInfoData.optional() })); export const zGetUserInfoByUserIdData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ user_id: z.string() }), - query: z.optional(z.never()) + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful profile retrieval */ export const zGetUserInfoByUserIdResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(zServiceUserUserInfoData) + data: zServiceUserUserInfoData.optional() })); export const zGetUserListData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - limit: z.optional(z.string()), + limit: z.string().optional(), offset: z.string() + }), + headers: z.object({ + 'X-Api-Version': z.string() }) }); @@ -330,18 +398,21 @@ export const zGetUserListData = z.object({ * Successful paginated list retrieval */ export const zGetUserListResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(z.array(zDataUserIndexDoc)) + data: z.array(zDataUserIndexDoc).optional() })); export const zPatchUserUpdateData = z.object({ body: zServiceUserUserInfoData, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional(), + headers: z.object({ + 'X-Api-Version': z.string() + }) }); /** * Successful profile update */ export const zPatchUserUpdateResponse = zUtilsRespStatus.and(z.object({ - data: z.optional(z.record(z.string(), z.unknown())) + data: z.record(z.unknown()).optional() })); diff --git a/client/cms/src/components/events/event-card.view.tsx b/client/cms/src/components/events/event-card.view.tsx index 3b5d5fd..a065653 100644 --- a/client/cms/src/components/events/event-card.view.tsx +++ b/client/cms/src/components/events/event-card.view.tsx @@ -2,7 +2,6 @@ import type { EventInfo } from './types'; import dayjs from 'dayjs'; import { Calendar } from 'lucide-react'; import { Badge } from '@/components/ui/badge'; -import { Button } from '@/components/ui/button'; import { Card, CardAction, @@ -13,7 +12,8 @@ import { } from '@/components/ui/card'; import { Skeleton } from '../ui/skeleton'; -export function EventCardView({ type, coverImage, eventName, description, startTime, endTime, onJoinEvent }: EventInfo) { +export function EventCardView({ eventInfo, actionFooter }: { eventInfo: EventInfo; actionFooter: React.ReactNode }) { + const { type, coverImage, eventName, description, startTime, endTime } = eventInfo; const startDayJs = dayjs(startTime); const endDayJs = dayjs(endTime); return ( @@ -41,7 +41,7 @@ export function EventCardView({ type, coverImage, eventName, description, startT - + {actionFooter} ); diff --git a/client/cms/src/components/events/event-grid.container.tsx b/client/cms/src/components/events/event-grid.container.tsx index 41d47f1..868600b 100644 --- a/client/cms/src/components/events/event-grid.container.tsx +++ b/client/cms/src/components/events/event-grid.container.tsx @@ -1,23 +1,40 @@ import type { EventInfo } from './types'; import PlaceholderImage from '@/assets/event-placeholder.png'; import { useGetEvents } from '@/hooks/data/useGetEvents'; -import { useJoinEvent } from '@/hooks/data/useJoinEvent'; +import { Button } from '../ui/button'; +import { DialogTrigger } from '../ui/dialog'; import { EventGridView } from './event-grid.view'; +import { KycDialogContainer } from './kyc/kyc.dialog.container'; export function EventGridContainer() { const { data, isLoading } = useGetEvents(); - const { mutate } = useJoinEvent(); const allEvents: EventInfo[] = isLoading ? [] : data.pages.flatMap(page => page.data!).map(it => ({ - type: it.type! as EventInfo['type'], - coverImage: it.thumbnail! || PlaceholderImage, - eventName: it.name!, - description: it.description!, - startTime: new Date(it.start_time!), - endTime: new Date(it.end_time!), - onJoinEvent: () => mutate({ body: { event_id: it.event_id } }), - } satisfies EventInfo)); + type: it.type! as EventInfo['type'], + eventId: it.event_id!, + isJoined: it.is_joined!, + requireKyc: it.enable_kyc!, + coverImage: it.thumbnail! || PlaceholderImage, + eventName: it.name!, + description: it.description!, + startTime: new Date(it.start_time!), + endTime: new Date(it.end_time!), + } satisfies EventInfo)); - return ; + return ( + (eventInfo.isJoined + ? + : ( + + + + + + ) + )} + /> + ); } diff --git a/client/cms/src/components/events/event-grid.view.tsx b/client/cms/src/components/events/event-grid.view.tsx index 79c90c1..e5186bd 100644 --- a/client/cms/src/components/events/event-grid.view.tsx +++ b/client/cms/src/components/events/event-grid.view.tsx @@ -1,11 +1,11 @@ import type { EventInfo } from './types'; import { EventCardView } from './event-card.view'; -export function EventGridView({ events }: { events: EventInfo[] }) { +export function EventGridView({ events, assembleFooter }: { events: EventInfo[]; assembleFooter: (event: EventInfo) => React.ReactNode }) { return (
{events.map(event => ( - + ))}
); diff --git a/client/cms/src/components/events/kyc/kyc-failed.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-failed.dialog.view.tsx new file mode 100644 index 0000000..768ee0e --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc-failed.dialog.view.tsx @@ -0,0 +1,18 @@ +import { X } from 'lucide-react'; +import { DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; + +export function KycFailedDialogView() { + return ( + + + 失败 + +

提交身份认证失败,请重试。

+
+ +
+
+
+
+ ); +} diff --git a/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx new file mode 100644 index 0000000..238f666 --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx @@ -0,0 +1,177 @@ +import type { KycSubmission } from './kyc.types'; +import { useForm } from '@tanstack/react-form'; +import { useState } from 'react'; +import { toast } from 'sonner'; +import z from 'zod'; +import { + Field, + FieldError, + FieldLabel, +} from '@/components/ui/field'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Button } from '../../ui/button'; +import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog'; + +const CnridSchema = z.object({ + cnrid: z.string().min(18, '身份证号应为18位').max(18, '身份证号应为18位'), + name: z.string().min(2, '姓名应至少2个字符').max(10, '姓名应不超过10个字符'), +}); + +function CnridForm({ onSubmit }: { onSubmit: OnSubmit }) { + const form = useForm({ + defaultValues: { + cnrid: '', + name: '', + }, + validators: { + onSubmit: CnridSchema, + }, + onSubmit: async (values) => { + await onSubmit({ + method: 'cnrid', + ...values.value, + }).catch(() => { + toast('认证失败,请稍后再试'); + }); + }, + }); + return ( +
{ + e.preventDefault(); + e.stopPropagation(); + void form.handleSubmit(); + }} + className="flex flex-col gap-4" + > + + {field => ( + + 姓名 + field.handleChange(e.target.value)} + /> + + + )} + + + {field => ( + + 身份证号 + field.handleChange(e.target.value)} + /> + + + )} + + + [state.canSubmit, state.isPristine, state.isSubmitting]} + children={([canSubmit, isPristine, isSubmitting]) => ( + + )} + /> + +
+ ); +} + +const PassportSchema = z.object({ + passportId: z.string().min(9, '护照号应为9个字符').max(9, '护照号应为9个字符'), +}); + +function PassportForm({ onSubmit }: { onSubmit: OnSubmit }) { + const form = useForm({ + defaultValues: { + passportId: '', + }, + validators: { + onSubmit: PassportSchema, + }, + onSubmit: async (values) => { + await onSubmit({ + method: 'passport', + ...values.value, + }).catch(() => { + toast('认证失败,请稍后再试'); + }); + }, + }); + return ( +
{ + e.preventDefault(); + e.stopPropagation(); + void form.handleSubmit(); + }} + className="flex flex-col gap-4" + > + + {field => ( + + 护照号 + field.handleChange(e.target.value)} + /> + + + )} + + + [state.canSubmit, state.isPristine, state.isSubmitting]} + children={([canSubmit, isPristine, isSubmitting]) => ( + + )} + /> + +
+ ); +} + +type OnSubmit = (submission: KycSubmission) => Promise; + +export function KycMethodSelectionDialogView({ onSubmit }: { onSubmit: OnSubmit }) { + const [kycMethod, setKycMethod] = useState(null); + + return ( + + + 选择身份认证模式 + +

我们支持身份证和护照认证。

+
+
+ + + {kycMethod === 'cnrid' && } + {kycMethod === 'passport' && } +
+ ); +} diff --git a/client/cms/src/components/events/kyc/kyc-pending.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-pending.dialog.view.tsx new file mode 100644 index 0000000..5de1c35 --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc-pending.dialog.view.tsx @@ -0,0 +1,18 @@ +import { HashLoader } from 'react-spinners/esm'; +import { DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; + +export function KycPendingDialogView() { + return ( + + + 等待身份认证结果 + +

认证页面已打开。正在等待认证服务器回传数据...

+
+ +
+
+
+
+ ); +} diff --git a/client/cms/src/components/events/kyc/kyc-prompt.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-prompt.dialog.view.tsx new file mode 100644 index 0000000..ff604c0 --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc-prompt.dialog.view.tsx @@ -0,0 +1,24 @@ +import { Button } from '../../ui/button'; +import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog'; + +export function KycPromptDialogView({ next }: { next: () => void }) { + return ( + + + 需要身份认证 + +

为了确保会议的安全性及合规性,我们需要对参会者进行实名认证。

+

您的个人隐私对我们至关重要:

+
    +
  • 数据加密:您的所有个人敏感信息均会通过 AES-256 标准进行强加密存储。
  • +
  • 用途限制:收集的信息仅用于本次活动的身份核实,不会用于任何商业用途。
  • +
  • 按时销毁:所有身份证明文件及关联的敏感原始数据将在活动完成后最多 30 天内从服务器中彻底删除。
  • +
+
+
+ + + +
+ ); +} diff --git a/client/cms/src/components/events/kyc/kyc-success.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-success.dialog.view.tsx new file mode 100644 index 0000000..867b20a --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc-success.dialog.view.tsx @@ -0,0 +1,18 @@ +import { Check } from 'lucide-react'; +import { DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../ui/dialog'; + +export function KycSuccessDialogView() { + return ( + + + 成功 + +

已完成身份认证。

+
+ +
+
+
+
+ ); +} diff --git a/client/cms/src/components/events/kyc/kyc.dialog.container.tsx b/client/cms/src/components/events/kyc/kyc.dialog.container.tsx new file mode 100644 index 0000000..ad7953c --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc.dialog.container.tsx @@ -0,0 +1,129 @@ +import type { KycSubmission } from './kyc.types'; +import { Dialog } from '@radix-ui/react-dialog'; +import { useQueryClient } from '@tanstack/react-query'; +import { useCallback, useEffect, useState } from 'react'; +import { useStore } from 'zustand'; +import { postEventJoin, postKycQuery } from '@/client'; +import { getEventListInfiniteQueryKey } from '@/client/@tanstack/react-query.gen'; +import { useCreateKycSession } from '@/hooks/data/useCreateKycSession'; +import { ver } from '@/lib/apiVersion'; +import { KycFailedDialogView } from './kyc-failed.dialog.view'; +import { KycMethodSelectionDialogView } from './kyc-method-selection.dialog.view'; +import { KycPendingDialogView } from './kyc-pending.dialog.view'; +import { KycPromptDialogView } from './kyc-prompt.dialog.view'; +import { KycSuccessDialogView } from './kyc-success.dialog.view'; +import { createKycStore } from './kyc.state'; + +export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: string; children: React.ReactNode }) { + const [store] = useState(() => createKycStore(eventIdToJoin)); + const isDialogOpen = useStore(store, s => s.isDialogOpen); + const setIsDialogOpen = useStore(store, s => s.setIsDialogOpen); + const stage = useStore(store, s => s.stage); + const setStage = useStore(store, s => s.setStage); + const setKycId = useStore(store, s => s.setKycId); + + const { mutateAsync } = useCreateKycSession(); + const queryClient = useQueryClient(); + + const joinEvent = useCallback(async (eventId: string, kycId: string, abortSignal?: AbortSignal) => { + try { + await postEventJoin({ + signal: abortSignal, + body: { event_id: eventId, kyc_id: kycId }, + headers: ver('20260205'), + }); + setStage('success'); + } + catch (e) { + console.error('Error joining event:', e); + setStage('failed'); + } + }, [setStage]); + + const onKycSessionCreate = useCallback(async (submission: KycSubmission) => { + try { + const { data } = await mutateAsync(submission); + setKycId(data!.kyc_id!); + if (data!.status === 'success') { + await joinEvent(eventIdToJoin, data!.kyc_id!, undefined); + } + else if (data!.status === 'processing') { + window.open(data!.redirect_uri, '_blank'); + setStage('pending'); + } + } + catch (e) { + console.error(e); + setStage('failed'); + } + }, [eventIdToJoin, joinEvent, mutateAsync, setKycId, setStage]); + + useEffect(() => { + if (stage !== 'pending' || !isDialogOpen) { + return; + } + + const controller = new AbortController(); + let timer: NodeJS.Timeout; + + const poll = async () => { + try { + const { data } = await postKycQuery({ + signal: controller.signal, + body: { kyc_id: store.getState().kycId! }, + headers: ver('20260205'), + }); + + const status = data?.data?.status; + + if (status === 'success') { + void joinEvent(eventIdToJoin, store.getState().kycId!, controller.signal); + } + else if (status === 'failed') { + setStage('failed'); + } + else if (status === 'pending') { + timer = setTimeout(() => void poll(), 1000); + } + else { + // What the fuck? + setStage('failed'); + } + } + catch (e) { + if ((e as Error).name === 'AbortError') + return; + console.error('Error fetching KYC status:', e); + setStage('failed'); + } + }; + + void poll(); + + return () => { + controller.abort(); + clearTimeout(timer); + }; + }, [stage, store, setStage, isDialogOpen, joinEvent, eventIdToJoin]); + + return ( + { + if (!open) { + void queryClient.invalidateQueries({ + queryKey: getEventListInfiniteQueryKey({ query: {}, headers: ver('20260205') }), + }); + } + setIsDialogOpen(open); + }} + > + {children} + {stage === 'prompt' && setStage('methodSelection')} />} + {stage === 'methodSelection' && } + {stage === 'pending' && } + {stage === 'success' && } + {stage === 'failed' && } + + ); +} diff --git a/client/cms/src/components/events/kyc/kyc.state.ts b/client/cms/src/components/events/kyc/kyc.state.ts new file mode 100644 index 0000000..34fc1bb --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc.state.ts @@ -0,0 +1,34 @@ +import { createStore } from 'zustand'; +import { devtools } from 'zustand/middleware'; + +interface KycState { + isDialogOpen: boolean; + eventIdToJoin: string; + kycId: string | null; + stage: 'prompt' | 'methodSelection' | 'pending' | 'success' | 'failed'; + + setIsDialogOpen: (open: boolean) => void; + setStage: (stage: KycState['stage']) => void; + setKycId: (kycId: string) => void; +} + +export function createKycStore(eventIdToJoin: string) { + const initialState = { + isDialogOpen: false, + eventIdToJoin, + kycId: null, + stage: 'prompt' as const, + }; + return createStore()(devtools(set => ({ + ...initialState, + setIsDialogOpen: (open: boolean) => set(() => + open + ? { ...initialState, isDialogOpen: true } + : { ...initialState, isDialogOpen: false }, + ), + setStage: (stage: KycState['stage']) => set(() => ({ stage })), + setKycId: (kycId: string) => set(() => ({ kycId })), + }))); +} + +export type KycStore = ReturnType; diff --git a/client/cms/src/components/events/kyc/kyc.types.ts b/client/cms/src/components/events/kyc/kyc.types.ts new file mode 100644 index 0000000..4a9f0a1 --- /dev/null +++ b/client/cms/src/components/events/kyc/kyc.types.ts @@ -0,0 +1,8 @@ +export type KycSubmission = { + method: 'cnrid'; + cnrid: string; + name: string; +} | { + method: 'passport'; + passportId: string; +}; diff --git a/client/cms/src/components/events/types.ts b/client/cms/src/components/events/types.ts index 22f52de..6564ba3 100644 --- a/client/cms/src/components/events/types.ts +++ b/client/cms/src/components/events/types.ts @@ -1,9 +1,11 @@ export interface EventInfo { type: 'official' | 'party'; + eventId: string; + isJoined: boolean; + requireKyc: boolean; coverImage: string; eventName: string; description: string; startTime: Date; endTime: Date; - onJoinEvent: () => void; } diff --git a/client/cms/src/components/profile/edit-profile.dialog.view.tsx b/client/cms/src/components/profile/edit-profile.dialog.view.tsx index e4437c4..ed4f5dd 100644 --- a/client/cms/src/components/profile/edit-profile.dialog.view.tsx +++ b/client/cms/src/components/profile/edit-profile.dialog.view.tsx @@ -30,7 +30,7 @@ const formSchema = z.object({ username: z.string().min(5), nickname: z.string(), subtitle: z.string(), - avatar: z.url().or(z.literal('')), + avatar: z.string().url().or(z.literal('')), allow_public: z.boolean(), }); export function EditProfileDialogView({ user, updateProfile }: { user: ServiceUserUserInfoData; updateProfile: (data: ServiceUserUserInfoData) => Promise }) { diff --git a/client/cms/src/hooks/data/useCreateKycSession.ts b/client/cms/src/hooks/data/useCreateKycSession.ts new file mode 100644 index 0000000..4f0c342 --- /dev/null +++ b/client/cms/src/hooks/data/useCreateKycSession.ts @@ -0,0 +1,45 @@ +import type { KycSubmission } from '@/components/events/kyc/kyc.types'; +import { useMutation } from '@tanstack/react-query'; +import { postKycSessionMutation } from '@/client/@tanstack/react-query.gen'; +import { ver } from '@/lib/apiVersion'; +import { utf8ToBase64 } from '@/lib/utils'; + +type CreateKycSessionBase64Payload = { + // Cnrid + legal_name: string; + resident_id: string; +} | { + // Passport + id: string; +}; + +export function useCreateKycSession() { + const mutation = useMutation({ + ...postKycSessionMutation(), + }); + + return { + ...mutation, + mutate: null, // Don't ever use this + mutateAsync: async (data: KycSubmission) => { + const payload = utf8ToBase64(JSON.stringify( + data.method === 'cnrid' + ? { + legal_name: data.name, + resident_id: data.cnrid, + } satisfies CreateKycSessionBase64Payload + : { + id: data.passportId, + } satisfies CreateKycSessionBase64Payload, + )); + const response = await mutation.mutateAsync({ + body: { + identity: payload, + type: data.method, + }, + headers: ver('20260205'), + }); + return response; + }, + }; +} diff --git a/client/cms/src/hooks/data/useGetEvents.ts b/client/cms/src/hooks/data/useGetEvents.ts index 4e02244..854969a 100644 --- a/client/cms/src/hooks/data/useGetEvents.ts +++ b/client/cms/src/hooks/data/useGetEvents.ts @@ -1,19 +1,19 @@ import { useInfiniteQuery } from '@tanstack/react-query'; import { isNil } from 'lodash-es'; import { getEventListInfiniteOptions } from '@/client/@tanstack/react-query.gen'; - -const LIMIT = 12; +import { ver } from '@/lib/apiVersion'; export function useGetEvents() { return useInfiniteQuery({ ...getEventListInfiniteOptions({ - query: { limit: String(LIMIT), offset: String(0) }, + query: {}, + headers: ver('20260205'), }), - initialPageParam: '0', + initialPageParam: 0, getNextPageParam: (lastPage, allPages) => { const currentData = lastPage?.data; - if (!isNil(currentData) && currentData.length === LIMIT) { - return String(allPages.length * LIMIT); + if (!isNil(currentData) && currentData.length === 20) { + return allPages.length * 20; } return undefined; }, diff --git a/client/cms/src/hooks/data/useJoinEvent.ts b/client/cms/src/hooks/data/useJoinEvent.ts deleted file mode 100644 index ae273ac..0000000 --- a/client/cms/src/hooks/data/useJoinEvent.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from '@tanstack/react-query'; -import { postEventJoinMutation } from '@/client/@tanstack/react-query.gen'; - -export function useJoinEvent() { - return useMutation({ - ...postEventJoinMutation(), - }); -} diff --git a/client/cms/src/hooks/data/useUpdateUser.ts b/client/cms/src/hooks/data/useUpdateUser.ts index d99a302..c3940ea 100644 --- a/client/cms/src/hooks/data/useUpdateUser.ts +++ b/client/cms/src/hooks/data/useUpdateUser.ts @@ -1,16 +1,17 @@ import type { ServiceUserUserInfoData } from '@/client'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { getUserInfoByUserIdQueryKey, getUserInfoQueryKey, patchUserUpdateMutation } from '@/client/@tanstack/react-query.gen'; +import { ver } from '@/lib/apiVersion'; export function useUpdateUser() { const queryClient = useQueryClient(); - const data: { data: ServiceUserUserInfoData | undefined } | undefined = queryClient.getQueryData(getUserInfoQueryKey()); + const data: { data: ServiceUserUserInfoData | undefined } | undefined = queryClient.getQueryData(getUserInfoQueryKey({ headers: ver('20260205') })); return useMutation({ ...patchUserUpdateMutation(), onSuccess: async () => { - await queryClient.invalidateQueries({ queryKey: getUserInfoQueryKey() }); + await queryClient.invalidateQueries({ queryKey: getUserInfoQueryKey({ headers: ver('20260205') }) }); if ((data?.data?.user_id) != null) { - await queryClient.invalidateQueries({ queryKey: getUserInfoByUserIdQueryKey({ path: { user_id: data.data.user_id } }) }); + await queryClient.invalidateQueries({ queryKey: getUserInfoByUserIdQueryKey({ path: { user_id: data.data.user_id }, headers: ver('20260205') }) }); } }, }); diff --git a/client/cms/src/hooks/data/useUserInfo.ts b/client/cms/src/hooks/data/useUserInfo.ts index 369b0ee..b1b9d81 100644 --- a/client/cms/src/hooks/data/useUserInfo.ts +++ b/client/cms/src/hooks/data/useUserInfo.ts @@ -3,17 +3,18 @@ import { getUserInfoByUserIdOptions, getUserInfoOptions, } from '@/client/@tanstack/react-query.gen'; +import { ver } from '@/lib/apiVersion'; export function useUserInfo() { return useSuspenseQuery({ - ...getUserInfoOptions(), + ...getUserInfoOptions({ headers: ver('20260205') }), staleTime: 10 * 60 * 1000, }); } export function useOtherUserInfo(userId: string) { return useSuspenseQuery({ - ...getUserInfoByUserIdOptions({ path: { user_id: userId } }), + ...getUserInfoByUserIdOptions({ path: { user_id: userId }, headers: ver('20260205') }), staleTime: 10 * 60 * 1000, retry: (_failureCount, error) => error.code !== 403, }); diff --git a/client/cms/src/lib/apiVersion.ts b/client/cms/src/lib/apiVersion.ts new file mode 100644 index 0000000..0c757ea --- /dev/null +++ b/client/cms/src/lib/apiVersion.ts @@ -0,0 +1,5 @@ +export function ver(version: string) { + return { + 'X-Api-Version': version, + }; +} diff --git a/client/cms/src/lib/utils.ts b/client/cms/src/lib/utils.ts index 4306642..9c08cf1 100644 --- a/client/cms/src/lib/utils.ts +++ b/client/cms/src/lib/utils.ts @@ -1,3 +1,4 @@ +import type { Query } from '@tanstack/react-query'; import type { ClassValue } from 'clsx'; // eslint-disable-next-line unicorn/prefer-node-protocol import { Buffer } from 'buffer'; @@ -17,3 +18,12 @@ export function base64ToUtf8(base64: string): string { export function utf8ToBase64(utf8: string): string { return Buffer.from(utf8, 'utf-8').toString('base64'); } + +export function invalidateBlurry(id: string) { + return { + predicate: (query: Query) => { + const key = query.queryKey[0] as { _id: string }; + return key?._id === id; + }, + }; +} diff --git a/client/cms/src/stories/events/event-card.stories.tsx b/client/cms/src/stories/events/event-card.stories.tsx index 9180224..b07b120 100644 --- a/client/cms/src/stories/events/event-card.stories.tsx +++ b/client/cms/src/stories/events/event-card.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { EventCardSkeleton } from '@/components/events/event-card.skeleton'; import { EventCardView } from '@/components/events/event-card.view'; +import { Button } from '@/components/ui/button'; const meta = { title: 'Events/EventCard', @@ -12,25 +13,35 @@ type Story = StoryObj; export const Primary: Story = { args: { - type: 'official', - coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true', - eventName: 'Nix CN Conference 26.05', - description: 'Event Description', - startTime: new Date('2026-06-13T04:00:00.000Z'), - endTime: new Date('2026-06-14T04:00:00.000Z'), - onJoinEvent: () => { }, + eventInfo: { + eventId: '1', + type: 'official', + requireKyc: true, + isJoined: false, + coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true', + eventName: 'Nix CN Conference 26.05', + description: 'Event Description', + startTime: new Date('2026-06-13T04:00:00.000Z'), + endTime: new Date('2026-06-14T04:00:00.000Z'), + }, + actionFooter: , }, }; export const Loading: Story = { render: () => , args: { - type: 'official', - coverImage: '', - eventName: '', - description: '', - startTime: new Date(0), - endTime: new Date(0), - onJoinEvent: () => { }, + eventInfo: { + eventId: '1', + type: 'official', + requireKyc: true, + coverImage: '', + isJoined: false, + eventName: '', + description: '', + startTime: new Date(0), + endTime: new Date(0), + }, + actionFooter: , }, }; diff --git a/client/cms/src/stories/events/event-grid.stories.tsx b/client/cms/src/stories/events/event-grid.stories.tsx index bb63feb..055ed05 100644 --- a/client/cms/src/stories/events/event-grid.stories.tsx +++ b/client/cms/src/stories/events/event-grid.stories.tsx @@ -1,6 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { EventGridSkeleton } from '@/components/events/event-grid.skeleton'; import { EventGridView } from '@/components/events/event-grid.view'; +import { Button } from '@/components/ui/button'; +import { Skeleton as UiSkeleton } from '@/components/ui/skeleton'; const meta = { title: 'Events/EventGrid', @@ -14,42 +16,51 @@ export const Primary: Story = { args: { events: [ { + eventId: '1', + requireKyc: true, + isJoined: false, type: 'official', coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true', eventName: 'Nix CN Conference 26.05', description: 'Event Description', startTime: new Date('2026-06-13T04:00:00.000Z'), endTime: new Date('2026-06-14T04:00:00.000Z'), - onJoinEvent: () => { }, }, { + eventId: '2', + requireKyc: true, + isJoined: false, type: 'official', coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-moonscape.png?raw=true', eventName: 'Nix CN Conference 26.05', description: 'Event Description', startTime: new Date('2026-06-13T04:00:00.000Z'), endTime: new Date('2026-06-14T04:00:00.000Z'), - onJoinEvent: () => { }, }, { + eventId: '3', + requireKyc: true, + isJoined: false, type: 'official', coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-nineish-catppuccin-latte.png?raw=true', eventName: 'Nix CN Conference 26.05', description: 'Event Description', startTime: new Date('2026-06-13T04:00:00.000Z'), endTime: new Date('2026-06-14T04:00:00.000Z'), - onJoinEvent: () => { }, }, { + eventId: '4', + requireKyc: true, + isJoined: false, type: 'official', coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nixos-wallpaper-catppuccin-macchiato.png?raw=true', eventName: 'Nix CN Conference 26.05', description: 'Event Description', startTime: new Date('2026-06-13T04:00:00.000Z'), endTime: new Date('2026-06-14T04:00:00.000Z'), - onJoinEvent: () => { }, }, ], + assembleFooter: () => , }, }; @@ -57,5 +68,6 @@ export const Skeleton: Story = { render: () => , args: { events: [], + assembleFooter: () => , }, }; diff --git a/client/cms/src/stories/events/kyc-dialog.stories.tsx b/client/cms/src/stories/events/kyc-dialog.stories.tsx new file mode 100644 index 0000000..f2c04ad --- /dev/null +++ b/client/cms/src/stories/events/kyc-dialog.stories.tsx @@ -0,0 +1,51 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { KycFailedDialogView } from '@/components/events/kyc/kyc-failed.dialog.view'; +import { KycMethodSelectionDialogView } from '@/components/events/kyc/kyc-method-selection.dialog.view'; +import { KycPendingDialogView } from '@/components/events/kyc/kyc-pending.dialog.view'; +import { KycPromptDialogView } from '@/components/events/kyc/kyc-prompt.dialog.view'; +import { KycSuccessDialogView } from '@/components/events/kyc/kyc-success.dialog.view'; +import { Dialog } from '@/components/ui/dialog'; + +const meta = { + title: 'Events/KycDialog', + component: KycPromptDialogView, + decorators: [ + Story => ( + + + + ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Prompt: Story = { + args: { + }, +}; + +export const MethodSelection: Story = { + render: () => Promise.resolve()} />, + args: { + }, +}; + +export const Pending: Story = { + render: () => , + args: { + }, +}; + +export const Success: Story = { + render: () => , + args: { + }, +}; + +export const Failed: Story = { + render: () => , + args: { + }, +};