From d6ab716c37cffe9746904e6ec6866b0ba100082b Mon Sep 17 00:00:00 2001 From: Amr Gaber Date: Mon, 20 Jul 2026 20:30:53 -0500 Subject: [PATCH] Wire the contact form to the API contact endpoint The form previously showed a success card without sending anything. - Generate the orval API client for the first time (pnpm generate-api): typed React Query hooks, zod schemas, and MSW mocks under src/api/generated; add @faker-js/faker (dev) which the generated mocks import - Contact page submits through useSubmitContactContactPost with real states: button disables to "Sending..." while pending, a role=alert error line renders on failure, and the thank-you card only appears after the API accepts the message - Add the hidden honeypot field (website) the API uses to drop bot submissions, and minLength on the message field matching the API's validation --- package.json | 1 + pnpm-lock.yaml | 107 ++-- src/api/generated/hooks/admin/admin.msw.ts | 41 ++ src/api/generated/hooks/admin/admin.ts | 122 ++++ src/api/generated/hooks/auth/auth.msw.ts | 89 +++ src/api/generated/hooks/auth/auth.ts | 540 +++++++++++++++++ .../generated/hooks/contact/contact.msw.ts | 43 ++ src/api/generated/hooks/contact/contact.ts | 124 ++++ .../generated/hooks/default/default.msw.ts | 40 ++ src/api/generated/hooks/default/default.ts | 251 ++++++++ .../generated/hooks/features/features.msw.ts | 43 ++ src/api/generated/hooks/features/features.ts | 144 +++++ src/api/generated/hooks/notes/notes.msw.ts | 97 +++ src/api/generated/hooks/notes/notes.ts | 555 ++++++++++++++++++ .../types/bodyAuthJwtLoginAuthJwtLoginPost.ts | 16 + src/api/generated/types/contactCreate.ts | 30 + src/api/generated/types/errorModel.ts | 12 + src/api/generated/types/errorModelDetail.ts | 9 + .../generated/types/hTTPValidationError.ts | 12 + src/api/generated/types/index.ts | 24 + .../generated/types/listFlagsFlagsGet200.ts | 9 + .../types/listNotesNotesGetParams.ts | 12 + src/api/generated/types/noteCreate.ts | 19 + src/api/generated/types/noteRead.ts | 22 + src/api/generated/types/noteUpdate.ts | 15 + src/api/generated/types/roleUpdate.ts | 11 + .../types/submitContactContactPost202.ts | 9 + src/api/generated/types/userCreate.ts | 19 + src/api/generated/types/userRead.ts | 20 + src/api/generated/types/validationError.ts | 16 + src/api/generated/types/validationErrorCtx.ts | 9 + src/api/generated/zod/admin/admin.ts | 37 ++ src/api/generated/zod/auth/auth.ts | 54 ++ src/api/generated/zod/contact/contact.ts | 34 ++ src/api/generated/zod/default/default.ts | 22 + src/api/generated/zod/features/features.ts | 16 + src/api/generated/zod/notes/notes.ts | 105 ++++ src/pages/contact/contact-page.tsx | 39 +- 38 files changed, 2723 insertions(+), 45 deletions(-) create mode 100644 src/api/generated/hooks/admin/admin.msw.ts create mode 100644 src/api/generated/hooks/admin/admin.ts create mode 100644 src/api/generated/hooks/auth/auth.msw.ts create mode 100644 src/api/generated/hooks/auth/auth.ts create mode 100644 src/api/generated/hooks/contact/contact.msw.ts create mode 100644 src/api/generated/hooks/contact/contact.ts create mode 100644 src/api/generated/hooks/default/default.msw.ts create mode 100644 src/api/generated/hooks/default/default.ts create mode 100644 src/api/generated/hooks/features/features.msw.ts create mode 100644 src/api/generated/hooks/features/features.ts create mode 100644 src/api/generated/hooks/notes/notes.msw.ts create mode 100644 src/api/generated/hooks/notes/notes.ts create mode 100644 src/api/generated/types/bodyAuthJwtLoginAuthJwtLoginPost.ts create mode 100644 src/api/generated/types/contactCreate.ts create mode 100644 src/api/generated/types/errorModel.ts create mode 100644 src/api/generated/types/errorModelDetail.ts create mode 100644 src/api/generated/types/hTTPValidationError.ts create mode 100644 src/api/generated/types/index.ts create mode 100644 src/api/generated/types/listFlagsFlagsGet200.ts create mode 100644 src/api/generated/types/listNotesNotesGetParams.ts create mode 100644 src/api/generated/types/noteCreate.ts create mode 100644 src/api/generated/types/noteRead.ts create mode 100644 src/api/generated/types/noteUpdate.ts create mode 100644 src/api/generated/types/roleUpdate.ts create mode 100644 src/api/generated/types/submitContactContactPost202.ts create mode 100644 src/api/generated/types/userCreate.ts create mode 100644 src/api/generated/types/userRead.ts create mode 100644 src/api/generated/types/validationError.ts create mode 100644 src/api/generated/types/validationErrorCtx.ts create mode 100644 src/api/generated/zod/admin/admin.ts create mode 100644 src/api/generated/zod/auth/auth.ts create mode 100644 src/api/generated/zod/contact/contact.ts create mode 100644 src/api/generated/zod/default/default.ts create mode 100644 src/api/generated/zod/features/features.ts create mode 100644 src/api/generated/zod/notes/notes.ts diff --git a/package.json b/package.json index bf04b37..5a4e56a 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@faker-js/faker": "^10.5.0", "@tailwindcss/vite": "^4.2.1", "@tanstack/react-query-devtools": "^5.90.0", "@tanstack/react-router-devtools": "^1.156.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9102d38..aa7fb01 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -60,6 +60,9 @@ importers: '@eslint/js': specifier: ^10.0.1 version: 10.0.1(eslint@10.0.3(jiti@2.6.1)) + '@faker-js/faker': + specifier: ^10.5.0 + version: 10.5.0 '@tailwindcss/vite': specifier: ^4.2.1 version: 4.2.1(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -134,7 +137,7 @@ importers: version: 2.12.10(@types/node@25.5.0)(typescript@5.9.3) orval: specifier: ^8.5.3 - version: 8.5.3(prettier@3.8.1)(typescript@5.9.3) + version: 8.5.3(@faker-js/faker@10.5.0)(prettier@3.8.1)(typescript@5.9.3) prettier: specifier: ^3.8.1 version: 3.8.1 @@ -690,6 +693,10 @@ packages: '@noble/hashes': optional: true + '@faker-js/faker@10.5.0': + resolution: {integrity: sha512-bsxD8WLS5lIj7aaoCx1YJkktqYj5vlBUE6HWzu2Q51ksrGJ0H737ECCKlFU7Yf8Br45z9t99frBp/J7kzbMPAg==} + engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -1611,36 +1618,42 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': resolution: {integrity: sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': resolution: {integrity: sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': resolution: {integrity: sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': resolution: {integrity: sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': resolution: {integrity: sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': resolution: {integrity: sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==} @@ -1758,24 +1771,28 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.2.1': resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.2.1': resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.2.1': resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.2.1': resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} @@ -2851,48 +2868,56 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.31.1: resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.31.1: resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.31.1: resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.31.1: resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} @@ -4205,6 +4230,8 @@ snapshots: '@exodus/bytes@1.15.0': {} + '@faker-js/faker@10.5.0': {} + '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -4325,23 +4352,23 @@ snapshots: '@open-draft/until@2.1.0': {} - '@orval/angular@8.5.3(typescript@5.9.3)': + '@orval/angular@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/axios@8.5.3(typescript@5.9.3)': + '@orval/axios@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/core@8.5.3(typescript@5.9.3)': + '@orval/core@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: '@scalar/openapi-types': 0.5.3 acorn: 8.16.0 @@ -4353,23 +4380,25 @@ snapshots: globby: 16.1.0 remeda: 2.33.6 typedoc: 0.28.17(typescript@5.9.3) + optionalDependencies: + '@faker-js/faker': 10.5.0 transitivePeerDependencies: - supports-color - typescript - '@orval/fetch@8.5.3(typescript@5.9.3)': + '@orval/fetch@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) '@scalar/openapi-types': 0.5.3 transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/hono@8.5.3(typescript@5.9.3)': + '@orval/hono@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) - '@orval/zod': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/zod': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) fs-extra: 11.3.3 remeda: 2.33.6 transitivePeerDependencies: @@ -4377,56 +4406,56 @@ snapshots: - supports-color - typescript - '@orval/mcp@8.5.3(typescript@5.9.3)': + '@orval/mcp@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) - '@orval/fetch': 8.5.3(typescript@5.9.3) - '@orval/zod': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/fetch': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/zod': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/mock@8.5.3(typescript@5.9.3)': + '@orval/mock@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) remeda: 2.33.6 transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/query@8.5.3(typescript@5.9.3)': + '@orval/query@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) - '@orval/fetch': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/fetch': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) remeda: 2.33.6 transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/solid-start@8.5.3(typescript@5.9.3)': + '@orval/solid-start@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) '@scalar/openapi-types': 0.5.3 transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/swr@8.5.3(typescript@5.9.3)': + '@orval/swr@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) - '@orval/fetch': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/fetch': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - '@faker-js/faker' - supports-color - typescript - '@orval/zod@8.5.3(typescript@5.9.3)': + '@orval/zod@8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3)': dependencies: - '@orval/core': 8.5.3(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) remeda: 2.33.6 transitivePeerDependencies: - '@faker-js/faker' @@ -6693,20 +6722,20 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - orval@8.5.3(prettier@3.8.1)(typescript@5.9.3): + orval@8.5.3(@faker-js/faker@10.5.0)(prettier@3.8.1)(typescript@5.9.3): dependencies: '@commander-js/extra-typings': 14.0.0(commander@14.0.2) - '@orval/angular': 8.5.3(typescript@5.9.3) - '@orval/axios': 8.5.3(typescript@5.9.3) - '@orval/core': 8.5.3(typescript@5.9.3) - '@orval/fetch': 8.5.3(typescript@5.9.3) - '@orval/hono': 8.5.3(typescript@5.9.3) - '@orval/mcp': 8.5.3(typescript@5.9.3) - '@orval/mock': 8.5.3(typescript@5.9.3) - '@orval/query': 8.5.3(typescript@5.9.3) - '@orval/solid-start': 8.5.3(typescript@5.9.3) - '@orval/swr': 8.5.3(typescript@5.9.3) - '@orval/zod': 8.5.3(typescript@5.9.3) + '@orval/angular': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/axios': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/core': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/fetch': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/hono': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/mcp': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/mock': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/query': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/solid-start': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/swr': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) + '@orval/zod': 8.5.3(@faker-js/faker@10.5.0)(typescript@5.9.3) '@scalar/json-magic': 0.11.7 '@scalar/openapi-parser': 0.24.17 '@scalar/openapi-types': 0.5.3 diff --git a/src/api/generated/hooks/admin/admin.msw.ts b/src/api/generated/hooks/admin/admin.msw.ts new file mode 100644 index 0000000..3617843 --- /dev/null +++ b/src/api/generated/hooks/admin/admin.msw.ts @@ -0,0 +1,41 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + faker +} from '@faker-js/faker'; + +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + +import type { + UserRead +} from '../../types'; + + +export const getUpdateUserRoleAdminUsersUserIdRolePatchResponseMock = (overrideResponse: Partial> = {}): UserRead => ({id: faker.string.uuid(), email: faker.internet.email(), is_active: faker.datatype.boolean(), is_superuser: faker.datatype.boolean(), is_verified: faker.datatype.boolean(), name: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), role: faker.string.alpha({length: {min: 10, max: 20}}), ...overrideResponse}) + + +export const getUpdateUserRoleAdminUsersUserIdRolePatchMockHandler = (overrideResponse?: UserRead | ((info: Parameters[1]>[0]) => Promise | UserRead), options?: RequestHandlerOptions) => { + return http.patch('*/admin/users/:userId/role', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getUpdateUserRoleAdminUsersUserIdRolePatchResponseMock(), + { status: 200 + }) + }, options) +} +export const getAdminMock = () => [ + getUpdateUserRoleAdminUsersUserIdRolePatchMockHandler() +] diff --git a/src/api/generated/hooks/admin/admin.ts b/src/api/generated/hooks/admin/admin.ts new file mode 100644 index 0000000..ced727a --- /dev/null +++ b/src/api/generated/hooks/admin/admin.ts @@ -0,0 +1,122 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useMutation +} from '@tanstack/react-query'; +import type { + MutationFunction, + QueryClient, + UseMutationOptions, + UseMutationResult +} from '@tanstack/react-query'; + +import type { + HTTPValidationError, + RoleUpdate, + UserRead +} from '../../types'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * Update a user's role. Requires admin role. + * @summary Update User Role + */ +export type updateUserRoleAdminUsersUserIdRolePatchResponse200 = { + data: UserRead + status: 200 +} + +export type updateUserRoleAdminUsersUserIdRolePatchResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type updateUserRoleAdminUsersUserIdRolePatchResponseSuccess = (updateUserRoleAdminUsersUserIdRolePatchResponse200) & { + headers: Headers; +}; +export type updateUserRoleAdminUsersUserIdRolePatchResponseError = (updateUserRoleAdminUsersUserIdRolePatchResponse422) & { + headers: Headers; +}; + +export type updateUserRoleAdminUsersUserIdRolePatchResponse = (updateUserRoleAdminUsersUserIdRolePatchResponseSuccess | updateUserRoleAdminUsersUserIdRolePatchResponseError) + +export const getUpdateUserRoleAdminUsersUserIdRolePatchUrl = (userId: string,) => { + + + + + return `/admin/users/${userId}/role` +} + +export const updateUserRoleAdminUsersUserIdRolePatch = async (userId: string, + roleUpdate: RoleUpdate, options?: RequestInit): Promise => { + + return orvalClient(getUpdateUserRoleAdminUsersUserIdRolePatchUrl(userId), + { + ...options, + method: 'PATCH', + headers: { 'Content-Type': 'application/json', ...options?.headers }, + body: JSON.stringify( + roleUpdate,) + } +);} + + + + +export const getUpdateUserRoleAdminUsersUserIdRolePatchMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{userId: string;data: RoleUpdate}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{userId: string;data: RoleUpdate}, TContext> => { + +const mutationKey = ['updateUserRoleAdminUsersUserIdRolePatch']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {userId: string;data: RoleUpdate}> = (props) => { + const {userId,data} = props ?? {}; + + return updateUserRoleAdminUsersUserIdRolePatch(userId,data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type UpdateUserRoleAdminUsersUserIdRolePatchMutationResult = NonNullable>> + export type UpdateUserRoleAdminUsersUserIdRolePatchMutationBody = RoleUpdate + export type UpdateUserRoleAdminUsersUserIdRolePatchMutationError = HTTPValidationError + + /** + * @summary Update User Role + */ +export const useUpdateUserRoleAdminUsersUserIdRolePatch = (options?: { mutation?:UseMutationOptions>, TError,{userId: string;data: RoleUpdate}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {userId: string;data: RoleUpdate}, + TContext + > => { + return useMutation(getUpdateUserRoleAdminUsersUserIdRolePatchMutationOptions(options), queryClient); + } + \ No newline at end of file diff --git a/src/api/generated/hooks/auth/auth.msw.ts b/src/api/generated/hooks/auth/auth.msw.ts new file mode 100644 index 0000000..78c60a3 --- /dev/null +++ b/src/api/generated/hooks/auth/auth.msw.ts @@ -0,0 +1,89 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + faker +} from '@faker-js/faker'; + +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + +import type { + UserRead +} from '../../types'; + + +export const getRegisterRegisterAuthRegisterPostResponseMock = (overrideResponse: Partial> = {}): UserRead => ({id: faker.string.uuid(), email: faker.internet.email(), is_active: faker.datatype.boolean(), is_superuser: faker.datatype.boolean(), is_verified: faker.datatype.boolean(), name: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), role: faker.string.alpha({length: {min: 10, max: 20}}), ...overrideResponse}) + +export const getGetCurrentUserAuthMeGetResponseMock = (overrideResponse: Partial> = {}): UserRead => ({id: faker.string.uuid(), email: faker.internet.email(), is_active: faker.datatype.boolean(), is_superuser: faker.datatype.boolean(), is_verified: faker.datatype.boolean(), name: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), role: faker.string.alpha({length: {min: 10, max: 20}}), ...overrideResponse}) + + +export const getRefreshAccessTokenAuthRefreshPostMockHandler = (overrideResponse?: void | ((info: Parameters[1]>[0]) => Promise | void), options?: RequestHandlerOptions) => { + return http.post('*/auth/refresh', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 204 + }) + }, options) +} + +export const getAuthJwtLogoutAuthJwtLogoutPostMockHandler = (overrideResponse?: unknown | void | ((info: Parameters[1]>[0]) => Promise | unknown | void), options?: RequestHandlerOptions) => { + return http.post('*/auth/jwt/logout', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 200 + }) + }, options) +} + +export const getAuthJwtLoginAuthJwtLoginPostMockHandler = (overrideResponse?: unknown | void | ((info: Parameters[1]>[0]) => Promise | unknown | void), options?: RequestHandlerOptions) => { + return http.post('*/auth/jwt/login', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 200 + }) + }, options) +} + +export const getRegisterRegisterAuthRegisterPostMockHandler = (overrideResponse?: UserRead | ((info: Parameters[1]>[0]) => Promise | UserRead), options?: RequestHandlerOptions) => { + return http.post('*/auth/register', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getRegisterRegisterAuthRegisterPostResponseMock(), + { status: 201 + }) + }, options) +} + +export const getGetCurrentUserAuthMeGetMockHandler = (overrideResponse?: UserRead | ((info: Parameters[1]>[0]) => Promise | UserRead), options?: RequestHandlerOptions) => { + return http.get('*/auth/me', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getGetCurrentUserAuthMeGetResponseMock(), + { status: 200 + }) + }, options) +} +export const getAuthMock = () => [ + getRefreshAccessTokenAuthRefreshPostMockHandler(), + getAuthJwtLogoutAuthJwtLogoutPostMockHandler(), + getAuthJwtLoginAuthJwtLoginPostMockHandler(), + getRegisterRegisterAuthRegisterPostMockHandler(), + getGetCurrentUserAuthMeGetMockHandler() +] diff --git a/src/api/generated/hooks/auth/auth.ts b/src/api/generated/hooks/auth/auth.ts new file mode 100644 index 0000000..cf2f97b --- /dev/null +++ b/src/api/generated/hooks/auth/auth.ts @@ -0,0 +1,540 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import type { + BodyAuthJwtLoginAuthJwtLoginPost, + ErrorModel, + HTTPValidationError, + UserCreate, + UserRead +} from '../../types'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * @summary Refresh Access Token + */ +export type refreshAccessTokenAuthRefreshPostResponse204 = { + data: void + status: 204 +} + +export type refreshAccessTokenAuthRefreshPostResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type refreshAccessTokenAuthRefreshPostResponseSuccess = (refreshAccessTokenAuthRefreshPostResponse204) & { + headers: Headers; +}; +export type refreshAccessTokenAuthRefreshPostResponseError = (refreshAccessTokenAuthRefreshPostResponse422) & { + headers: Headers; +}; + +export type refreshAccessTokenAuthRefreshPostResponse = (refreshAccessTokenAuthRefreshPostResponseSuccess | refreshAccessTokenAuthRefreshPostResponseError) + +export const getRefreshAccessTokenAuthRefreshPostUrl = () => { + + + + + return `/auth/refresh` +} + +export const refreshAccessTokenAuthRefreshPost = async ( options?: RequestInit): Promise => { + + return orvalClient(getRefreshAccessTokenAuthRefreshPostUrl(), + { + ...options, + method: 'POST' + + + } +);} + + + + +export const getRefreshAccessTokenAuthRefreshPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,void, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,void, TContext> => { + +const mutationKey = ['refreshAccessTokenAuthRefreshPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, void> = () => { + + + return refreshAccessTokenAuthRefreshPost(requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type RefreshAccessTokenAuthRefreshPostMutationResult = NonNullable>> + + export type RefreshAccessTokenAuthRefreshPostMutationError = HTTPValidationError + + /** + * @summary Refresh Access Token + */ +export const useRefreshAccessTokenAuthRefreshPost = (options?: { mutation?:UseMutationOptions>, TError,void, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + void, + TContext + > => { + return useMutation(getRefreshAccessTokenAuthRefreshPostMutationOptions(options), queryClient); + } + /** + * @summary Auth:Jwt.Logout + */ +export type authJwtLogoutAuthJwtLogoutPostResponse200 = { + data: unknown + status: 200 +} + +export type authJwtLogoutAuthJwtLogoutPostResponse204 = { + data: void + status: 204 +} + +export type authJwtLogoutAuthJwtLogoutPostResponse401 = { + data: void + status: 401 +} + +export type authJwtLogoutAuthJwtLogoutPostResponseSuccess = (authJwtLogoutAuthJwtLogoutPostResponse200 | authJwtLogoutAuthJwtLogoutPostResponse204) & { + headers: Headers; +}; +export type authJwtLogoutAuthJwtLogoutPostResponseError = (authJwtLogoutAuthJwtLogoutPostResponse401) & { + headers: Headers; +}; + +export type authJwtLogoutAuthJwtLogoutPostResponse = (authJwtLogoutAuthJwtLogoutPostResponseSuccess | authJwtLogoutAuthJwtLogoutPostResponseError) + +export const getAuthJwtLogoutAuthJwtLogoutPostUrl = () => { + + + + + return `/auth/jwt/logout` +} + +export const authJwtLogoutAuthJwtLogoutPost = async ( options?: RequestInit): Promise => { + + return orvalClient(getAuthJwtLogoutAuthJwtLogoutPostUrl(), + { + ...options, + method: 'POST' + + + } +);} + + + + +export const getAuthJwtLogoutAuthJwtLogoutPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,void, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,void, TContext> => { + +const mutationKey = ['authJwtLogoutAuthJwtLogoutPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, void> = () => { + + + return authJwtLogoutAuthJwtLogoutPost(requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type AuthJwtLogoutAuthJwtLogoutPostMutationResult = NonNullable>> + + export type AuthJwtLogoutAuthJwtLogoutPostMutationError = void + + /** + * @summary Auth:Jwt.Logout + */ +export const useAuthJwtLogoutAuthJwtLogoutPost = (options?: { mutation?:UseMutationOptions>, TError,void, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + void, + TContext + > => { + return useMutation(getAuthJwtLogoutAuthJwtLogoutPostMutationOptions(options), queryClient); + } + /** + * @summary Auth:Jwt.Login + */ +export type authJwtLoginAuthJwtLoginPostResponse200 = { + data: unknown + status: 200 +} + +export type authJwtLoginAuthJwtLoginPostResponse204 = { + data: void + status: 204 +} + +export type authJwtLoginAuthJwtLoginPostResponse400 = { + data: ErrorModel + status: 400 +} + +export type authJwtLoginAuthJwtLoginPostResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type authJwtLoginAuthJwtLoginPostResponseSuccess = (authJwtLoginAuthJwtLoginPostResponse200 | authJwtLoginAuthJwtLoginPostResponse204) & { + headers: Headers; +}; +export type authJwtLoginAuthJwtLoginPostResponseError = (authJwtLoginAuthJwtLoginPostResponse400 | authJwtLoginAuthJwtLoginPostResponse422) & { + headers: Headers; +}; + +export type authJwtLoginAuthJwtLoginPostResponse = (authJwtLoginAuthJwtLoginPostResponseSuccess | authJwtLoginAuthJwtLoginPostResponseError) + +export const getAuthJwtLoginAuthJwtLoginPostUrl = () => { + + + + + return `/auth/jwt/login` +} + +export const authJwtLoginAuthJwtLoginPost = async (bodyAuthJwtLoginAuthJwtLoginPost: BodyAuthJwtLoginAuthJwtLoginPost, options?: RequestInit): Promise => { + const formUrlEncoded = new URLSearchParams(); +if(bodyAuthJwtLoginAuthJwtLoginPost.grant_type !== undefined && bodyAuthJwtLoginAuthJwtLoginPost.grant_type !== null) { + formUrlEncoded.append(`grant_type`, bodyAuthJwtLoginAuthJwtLoginPost.grant_type); + } +formUrlEncoded.append(`username`, bodyAuthJwtLoginAuthJwtLoginPost.username); +formUrlEncoded.append(`password`, bodyAuthJwtLoginAuthJwtLoginPost.password); +if(bodyAuthJwtLoginAuthJwtLoginPost.scope !== undefined) { + formUrlEncoded.append(`scope`, bodyAuthJwtLoginAuthJwtLoginPost.scope); + } +if(bodyAuthJwtLoginAuthJwtLoginPost.client_id !== undefined && bodyAuthJwtLoginAuthJwtLoginPost.client_id !== null) { + formUrlEncoded.append(`client_id`, bodyAuthJwtLoginAuthJwtLoginPost.client_id); + } +if(bodyAuthJwtLoginAuthJwtLoginPost.client_secret !== undefined && bodyAuthJwtLoginAuthJwtLoginPost.client_secret !== null) { + formUrlEncoded.append(`client_secret`, bodyAuthJwtLoginAuthJwtLoginPost.client_secret); + } + + return orvalClient(getAuthJwtLoginAuthJwtLoginPostUrl(), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded', ...options?.headers }, + body: + formUrlEncoded, + } +);} + + + + +export const getAuthJwtLoginAuthJwtLoginPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{data: BodyAuthJwtLoginAuthJwtLoginPost}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{data: BodyAuthJwtLoginAuthJwtLoginPost}, TContext> => { + +const mutationKey = ['authJwtLoginAuthJwtLoginPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {data: BodyAuthJwtLoginAuthJwtLoginPost}> = (props) => { + const {data} = props ?? {}; + + return authJwtLoginAuthJwtLoginPost(data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type AuthJwtLoginAuthJwtLoginPostMutationResult = NonNullable>> + export type AuthJwtLoginAuthJwtLoginPostMutationBody = BodyAuthJwtLoginAuthJwtLoginPost + export type AuthJwtLoginAuthJwtLoginPostMutationError = ErrorModel | HTTPValidationError + + /** + * @summary Auth:Jwt.Login + */ +export const useAuthJwtLoginAuthJwtLoginPost = (options?: { mutation?:UseMutationOptions>, TError,{data: BodyAuthJwtLoginAuthJwtLoginPost}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: BodyAuthJwtLoginAuthJwtLoginPost}, + TContext + > => { + return useMutation(getAuthJwtLoginAuthJwtLoginPostMutationOptions(options), queryClient); + } + /** + * @summary Register:Register + */ +export type registerRegisterAuthRegisterPostResponse201 = { + data: UserRead + status: 201 +} + +export type registerRegisterAuthRegisterPostResponse400 = { + data: ErrorModel + status: 400 +} + +export type registerRegisterAuthRegisterPostResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type registerRegisterAuthRegisterPostResponseSuccess = (registerRegisterAuthRegisterPostResponse201) & { + headers: Headers; +}; +export type registerRegisterAuthRegisterPostResponseError = (registerRegisterAuthRegisterPostResponse400 | registerRegisterAuthRegisterPostResponse422) & { + headers: Headers; +}; + +export type registerRegisterAuthRegisterPostResponse = (registerRegisterAuthRegisterPostResponseSuccess | registerRegisterAuthRegisterPostResponseError) + +export const getRegisterRegisterAuthRegisterPostUrl = () => { + + + + + return `/auth/register` +} + +export const registerRegisterAuthRegisterPost = async (userCreate: UserCreate, options?: RequestInit): Promise => { + + return orvalClient(getRegisterRegisterAuthRegisterPostUrl(), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...options?.headers }, + body: JSON.stringify( + userCreate,) + } +);} + + + + +export const getRegisterRegisterAuthRegisterPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{data: UserCreate}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{data: UserCreate}, TContext> => { + +const mutationKey = ['registerRegisterAuthRegisterPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {data: UserCreate}> = (props) => { + const {data} = props ?? {}; + + return registerRegisterAuthRegisterPost(data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type RegisterRegisterAuthRegisterPostMutationResult = NonNullable>> + export type RegisterRegisterAuthRegisterPostMutationBody = UserCreate + export type RegisterRegisterAuthRegisterPostMutationError = ErrorModel | HTTPValidationError + + /** + * @summary Register:Register + */ +export const useRegisterRegisterAuthRegisterPost = (options?: { mutation?:UseMutationOptions>, TError,{data: UserCreate}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: UserCreate}, + TContext + > => { + return useMutation(getRegisterRegisterAuthRegisterPostMutationOptions(options), queryClient); + } + /** + * @summary Get Current User + */ +export type getCurrentUserAuthMeGetResponse200 = { + data: UserRead + status: 200 +} + +export type getCurrentUserAuthMeGetResponseSuccess = (getCurrentUserAuthMeGetResponse200) & { + headers: Headers; +}; +; + +export type getCurrentUserAuthMeGetResponse = (getCurrentUserAuthMeGetResponseSuccess) + +export const getGetCurrentUserAuthMeGetUrl = () => { + + + + + return `/auth/me` +} + +export const getCurrentUserAuthMeGet = async ( options?: RequestInit): Promise => { + + return orvalClient(getGetCurrentUserAuthMeGetUrl(), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getGetCurrentUserAuthMeGetQueryKey = () => { + return [ + `/auth/me` + ] as const; + } + + +export const getGetCurrentUserAuthMeGetQueryOptions = >, TError = unknown>( options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getGetCurrentUserAuthMeGetQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => getCurrentUserAuthMeGet({ signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type GetCurrentUserAuthMeGetQueryResult = NonNullable>> +export type GetCurrentUserAuthMeGetQueryError = unknown + + +export function useGetCurrentUserAuthMeGet>, TError = unknown>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useGetCurrentUserAuthMeGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useGetCurrentUserAuthMeGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary Get Current User + */ + +export function useGetCurrentUserAuthMeGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getGetCurrentUserAuthMeGetQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + diff --git a/src/api/generated/hooks/contact/contact.msw.ts b/src/api/generated/hooks/contact/contact.msw.ts new file mode 100644 index 0000000..762f379 --- /dev/null +++ b/src/api/generated/hooks/contact/contact.msw.ts @@ -0,0 +1,43 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + faker +} from '@faker-js/faker'; + +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + +import type { + SubmitContactContactPost202 +} from '../../types'; + + +export const getSubmitContactContactPostResponseMock = (): SubmitContactContactPost202 => ({ + [faker.string.alphanumeric(5)]: faker.string.alpha({length: {min: 10, max: 20}}) + }) + + +export const getSubmitContactContactPostMockHandler = (overrideResponse?: SubmitContactContactPost202 | ((info: Parameters[1]>[0]) => Promise | SubmitContactContactPost202), options?: RequestHandlerOptions) => { + return http.post('*/contact', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getSubmitContactContactPostResponseMock(), + { status: 202 + }) + }, options) +} +export const getContactMock = () => [ + getSubmitContactContactPostMockHandler() +] diff --git a/src/api/generated/hooks/contact/contact.ts b/src/api/generated/hooks/contact/contact.ts new file mode 100644 index 0000000..51d60d8 --- /dev/null +++ b/src/api/generated/hooks/contact/contact.ts @@ -0,0 +1,124 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useMutation +} from '@tanstack/react-query'; +import type { + MutationFunction, + QueryClient, + UseMutationOptions, + UseMutationResult +} from '@tanstack/react-query'; + +import type { + ContactCreate, + HTTPValidationError, + SubmitContactContactPost202 +} from '../../types'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * Accept a contact-form submission and email it to the site inbox. + +Public endpoint (no auth); rate-limited in main. Honeypot submissions +are accepted but silently dropped so bots get no signal. + * @summary Submit Contact + */ +export type submitContactContactPostResponse202 = { + data: SubmitContactContactPost202 + status: 202 +} + +export type submitContactContactPostResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type submitContactContactPostResponseSuccess = (submitContactContactPostResponse202) & { + headers: Headers; +}; +export type submitContactContactPostResponseError = (submitContactContactPostResponse422) & { + headers: Headers; +}; + +export type submitContactContactPostResponse = (submitContactContactPostResponseSuccess | submitContactContactPostResponseError) + +export const getSubmitContactContactPostUrl = () => { + + + + + return `/contact` +} + +export const submitContactContactPost = async (contactCreate: ContactCreate, options?: RequestInit): Promise => { + + return orvalClient(getSubmitContactContactPostUrl(), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...options?.headers }, + body: JSON.stringify( + contactCreate,) + } +);} + + + + +export const getSubmitContactContactPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{data: ContactCreate}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{data: ContactCreate}, TContext> => { + +const mutationKey = ['submitContactContactPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {data: ContactCreate}> = (props) => { + const {data} = props ?? {}; + + return submitContactContactPost(data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type SubmitContactContactPostMutationResult = NonNullable>> + export type SubmitContactContactPostMutationBody = ContactCreate + export type SubmitContactContactPostMutationError = HTTPValidationError + + /** + * @summary Submit Contact + */ +export const useSubmitContactContactPost = (options?: { mutation?:UseMutationOptions>, TError,{data: ContactCreate}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: ContactCreate}, + TContext + > => { + return useMutation(getSubmitContactContactPostMutationOptions(options), queryClient); + } + \ No newline at end of file diff --git a/src/api/generated/hooks/default/default.msw.ts b/src/api/generated/hooks/default/default.msw.ts new file mode 100644 index 0000000..d96d428 --- /dev/null +++ b/src/api/generated/hooks/default/default.msw.ts @@ -0,0 +1,40 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + + + +export const getRootGetMockHandler = (overrideResponse?: unknown | ((info: Parameters[1]>[0]) => Promise | unknown), options?: RequestHandlerOptions) => { + return http.get('*/', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 200 + }) + }, options) +} + +export const getHealthCheckHealthGetMockHandler = (overrideResponse?: unknown | ((info: Parameters[1]>[0]) => Promise | unknown), options?: RequestHandlerOptions) => { + return http.get('*/health', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 200 + }) + }, options) +} +export const getDefaultMock = () => [ + getRootGetMockHandler(), + getHealthCheckHealthGetMockHandler() +] diff --git a/src/api/generated/hooks/default/default.ts b/src/api/generated/hooks/default/default.ts new file mode 100644 index 0000000..49eeb27 --- /dev/null +++ b/src/api/generated/hooks/default/default.ts @@ -0,0 +1,251 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * Health check endpoint. + * @summary Root + */ +export type rootGetResponse200 = { + data: unknown + status: 200 +} + +export type rootGetResponseSuccess = (rootGetResponse200) & { + headers: Headers; +}; +; + +export type rootGetResponse = (rootGetResponseSuccess) + +export const getRootGetUrl = () => { + + + + + return `/` +} + +export const rootGet = async ( options?: RequestInit): Promise => { + + return orvalClient(getRootGetUrl(), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getRootGetQueryKey = () => { + return [ + `/` + ] as const; + } + + +export const getRootGetQueryOptions = >, TError = unknown>( options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getRootGetQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => rootGet({ signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type RootGetQueryResult = NonNullable>> +export type RootGetQueryError = unknown + + +export function useRootGet>, TError = unknown>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useRootGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useRootGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary Root + */ + +export function useRootGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getRootGetQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + +/** + * Detailed health check. + * @summary Health Check + */ +export type healthCheckHealthGetResponse200 = { + data: unknown + status: 200 +} + +export type healthCheckHealthGetResponseSuccess = (healthCheckHealthGetResponse200) & { + headers: Headers; +}; +; + +export type healthCheckHealthGetResponse = (healthCheckHealthGetResponseSuccess) + +export const getHealthCheckHealthGetUrl = () => { + + + + + return `/health` +} + +export const healthCheckHealthGet = async ( options?: RequestInit): Promise => { + + return orvalClient(getHealthCheckHealthGetUrl(), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getHealthCheckHealthGetQueryKey = () => { + return [ + `/health` + ] as const; + } + + +export const getHealthCheckHealthGetQueryOptions = >, TError = unknown>( options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getHealthCheckHealthGetQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => healthCheckHealthGet({ signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type HealthCheckHealthGetQueryResult = NonNullable>> +export type HealthCheckHealthGetQueryError = unknown + + +export function useHealthCheckHealthGet>, TError = unknown>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useHealthCheckHealthGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useHealthCheckHealthGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary Health Check + */ + +export function useHealthCheckHealthGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getHealthCheckHealthGetQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + diff --git a/src/api/generated/hooks/features/features.msw.ts b/src/api/generated/hooks/features/features.msw.ts new file mode 100644 index 0000000..9841791 --- /dev/null +++ b/src/api/generated/hooks/features/features.msw.ts @@ -0,0 +1,43 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + faker +} from '@faker-js/faker'; + +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + +import type { + ListFlagsFlagsGet200 +} from '../../types'; + + +export const getListFlagsFlagsGetResponseMock = (): ListFlagsFlagsGet200 => ({ + [faker.string.alphanumeric(5)]: faker.datatype.boolean() + }) + + +export const getListFlagsFlagsGetMockHandler = (overrideResponse?: ListFlagsFlagsGet200 | ((info: Parameters[1]>[0]) => Promise | ListFlagsFlagsGet200), options?: RequestHandlerOptions) => { + return http.get('*/flags', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getListFlagsFlagsGetResponseMock(), + { status: 200 + }) + }, options) +} +export const getFeaturesMock = () => [ + getListFlagsFlagsGetMockHandler() +] diff --git a/src/api/generated/hooks/features/features.ts b/src/api/generated/hooks/features/features.ts new file mode 100644 index 0000000..6044630 --- /dev/null +++ b/src/api/generated/hooks/features/features.ts @@ -0,0 +1,144 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import type { + ListFlagsFlagsGet200 +} from '../../types'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * Return enabled feature flags for the current user. + * @summary List Flags + */ +export type listFlagsFlagsGetResponse200 = { + data: ListFlagsFlagsGet200 + status: 200 +} + +export type listFlagsFlagsGetResponseSuccess = (listFlagsFlagsGetResponse200) & { + headers: Headers; +}; +; + +export type listFlagsFlagsGetResponse = (listFlagsFlagsGetResponseSuccess) + +export const getListFlagsFlagsGetUrl = () => { + + + + + return `/flags` +} + +export const listFlagsFlagsGet = async ( options?: RequestInit): Promise => { + + return orvalClient(getListFlagsFlagsGetUrl(), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getListFlagsFlagsGetQueryKey = () => { + return [ + `/flags` + ] as const; + } + + +export const getListFlagsFlagsGetQueryOptions = >, TError = unknown>( options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getListFlagsFlagsGetQueryKey(); + + + + const queryFn: QueryFunction>> = ({ signal }) => listFlagsFlagsGet({ signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type ListFlagsFlagsGetQueryResult = NonNullable>> +export type ListFlagsFlagsGetQueryError = unknown + + +export function useListFlagsFlagsGet>, TError = unknown>( + options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useListFlagsFlagsGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useListFlagsFlagsGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary List Flags + */ + +export function useListFlagsFlagsGet>, TError = unknown>( + options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getListFlagsFlagsGetQueryOptions(options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + diff --git a/src/api/generated/hooks/notes/notes.msw.ts b/src/api/generated/hooks/notes/notes.msw.ts new file mode 100644 index 0000000..95dd142 --- /dev/null +++ b/src/api/generated/hooks/notes/notes.msw.ts @@ -0,0 +1,97 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + faker +} from '@faker-js/faker'; + +import { + HttpResponse, + http +} from 'msw'; +import type { + RequestHandlerOptions +} from 'msw'; + +import type { + NoteRead +} from '../../types'; + + +export const getListNotesNotesGetResponseMock = (): NoteRead[] => (Array.from({ length: faker.number.int({min: 1, max: 10}) }, (_, i) => i + 1).map(() => ({title: faker.string.alpha({length: {min: 1, max: 200}}), body: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), id: faker.string.uuid(), created_at: faker.date.past().toISOString().slice(0, 19) + 'Z', updated_at: faker.date.past().toISOString().slice(0, 19) + 'Z'}))) + +export const getCreateNoteNotesPostResponseMock = (overrideResponse: Partial> = {}): NoteRead => ({title: faker.string.alpha({length: {min: 1, max: 200}}), body: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), id: faker.string.uuid(), created_at: faker.date.past().toISOString().slice(0, 19) + 'Z', updated_at: faker.date.past().toISOString().slice(0, 19) + 'Z', ...overrideResponse}) + +export const getGetNoteNotesNoteIdGetResponseMock = (overrideResponse: Partial> = {}): NoteRead => ({title: faker.string.alpha({length: {min: 1, max: 200}}), body: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), id: faker.string.uuid(), created_at: faker.date.past().toISOString().slice(0, 19) + 'Z', updated_at: faker.date.past().toISOString().slice(0, 19) + 'Z', ...overrideResponse}) + +export const getUpdateNoteNotesNoteIdPatchResponseMock = (overrideResponse: Partial> = {}): NoteRead => ({title: faker.string.alpha({length: {min: 1, max: 200}}), body: faker.helpers.arrayElement([faker.helpers.arrayElement([faker.string.alpha({length: {min: 10, max: 20}}),null,]), undefined]), id: faker.string.uuid(), created_at: faker.date.past().toISOString().slice(0, 19) + 'Z', updated_at: faker.date.past().toISOString().slice(0, 19) + 'Z', ...overrideResponse}) + + +export const getListNotesNotesGetMockHandler = (overrideResponse?: NoteRead[] | ((info: Parameters[1]>[0]) => Promise | NoteRead[]), options?: RequestHandlerOptions) => { + return http.get('*/notes', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getListNotesNotesGetResponseMock(), + { status: 200 + }) + }, options) +} + +export const getCreateNoteNotesPostMockHandler = (overrideResponse?: NoteRead | ((info: Parameters[1]>[0]) => Promise | NoteRead), options?: RequestHandlerOptions) => { + return http.post('*/notes', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getCreateNoteNotesPostResponseMock(), + { status: 201 + }) + }, options) +} + +export const getGetNoteNotesNoteIdGetMockHandler = (overrideResponse?: NoteRead | ((info: Parameters[1]>[0]) => Promise | NoteRead), options?: RequestHandlerOptions) => { + return http.get('*/notes/:noteId', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getGetNoteNotesNoteIdGetResponseMock(), + { status: 200 + }) + }, options) +} + +export const getUpdateNoteNotesNoteIdPatchMockHandler = (overrideResponse?: NoteRead | ((info: Parameters[1]>[0]) => Promise | NoteRead), options?: RequestHandlerOptions) => { + return http.patch('*/notes/:noteId', async (info: Parameters[1]>[0]) => { + + + return HttpResponse.json(overrideResponse !== undefined + ? (typeof overrideResponse === "function" ? await overrideResponse(info) : overrideResponse) + : getUpdateNoteNotesNoteIdPatchResponseMock(), + { status: 200 + }) + }, options) +} + +export const getDeleteNoteNotesNoteIdDeleteMockHandler = (overrideResponse?: void | ((info: Parameters[1]>[0]) => Promise | void), options?: RequestHandlerOptions) => { + return http.delete('*/notes/:noteId', async (info: Parameters[1]>[0]) => { + if (typeof overrideResponse === 'function') {await overrideResponse(info); } + + return new HttpResponse(null, + { status: 204 + }) + }, options) +} +export const getNotesMock = () => [ + getListNotesNotesGetMockHandler(), + getCreateNoteNotesPostMockHandler(), + getGetNoteNotesNoteIdGetMockHandler(), + getUpdateNoteNotesNoteIdPatchMockHandler(), + getDeleteNoteNotesNoteIdDeleteMockHandler() +] diff --git a/src/api/generated/hooks/notes/notes.ts b/src/api/generated/hooks/notes/notes.ts new file mode 100644 index 0000000..d957386 --- /dev/null +++ b/src/api/generated/hooks/notes/notes.ts @@ -0,0 +1,555 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import { + useMutation, + useQuery +} from '@tanstack/react-query'; +import type { + DataTag, + DefinedInitialDataOptions, + DefinedUseQueryResult, + MutationFunction, + QueryClient, + QueryFunction, + QueryKey, + UndefinedInitialDataOptions, + UseMutationOptions, + UseMutationResult, + UseQueryOptions, + UseQueryResult +} from '@tanstack/react-query'; + +import type { + HTTPValidationError, + ListNotesNotesGetParams, + NoteCreate, + NoteRead, + NoteUpdate +} from '../../types'; + +import { orvalClient } from '../../../orval-client'; + + +type SecondParameter unknown> = Parameters[1]; + + + +/** + * List the current user's notes. + * @summary List Notes + */ +export type listNotesNotesGetResponse200 = { + data: NoteRead[] + status: 200 +} + +export type listNotesNotesGetResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type listNotesNotesGetResponseSuccess = (listNotesNotesGetResponse200) & { + headers: Headers; +}; +export type listNotesNotesGetResponseError = (listNotesNotesGetResponse422) & { + headers: Headers; +}; + +export type listNotesNotesGetResponse = (listNotesNotesGetResponseSuccess | listNotesNotesGetResponseError) + +export const getListNotesNotesGetUrl = (params?: ListNotesNotesGetParams,) => { + const normalizedParams = new URLSearchParams(); + + Object.entries(params || {}).forEach(([key, value]) => { + + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : value.toString()) + } + }); + + const stringifiedParams = normalizedParams.toString(); + + return stringifiedParams.length > 0 ? `/notes?${stringifiedParams}` : `/notes` +} + +export const listNotesNotesGet = async (params?: ListNotesNotesGetParams, options?: RequestInit): Promise => { + + return orvalClient(getListNotesNotesGetUrl(params), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getListNotesNotesGetQueryKey = (params?: ListNotesNotesGetParams,) => { + return [ + `/notes`, ...(params ? [params] : []) + ] as const; + } + + +export const getListNotesNotesGetQueryOptions = >, TError = HTTPValidationError>(params?: ListNotesNotesGetParams, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getListNotesNotesGetQueryKey(params); + + + + const queryFn: QueryFunction>> = ({ signal }) => listNotesNotesGet(params, { signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type ListNotesNotesGetQueryResult = NonNullable>> +export type ListNotesNotesGetQueryError = HTTPValidationError + + +export function useListNotesNotesGet>, TError = HTTPValidationError>( + params: undefined | ListNotesNotesGetParams, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useListNotesNotesGet>, TError = HTTPValidationError>( + params?: ListNotesNotesGetParams, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useListNotesNotesGet>, TError = HTTPValidationError>( + params?: ListNotesNotesGetParams, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary List Notes + */ + +export function useListNotesNotesGet>, TError = HTTPValidationError>( + params?: ListNotesNotesGetParams, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getListNotesNotesGetQueryOptions(params,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + +/** + * Create a new note for the current user. + * @summary Create Note + */ +export type createNoteNotesPostResponse201 = { + data: NoteRead + status: 201 +} + +export type createNoteNotesPostResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type createNoteNotesPostResponseSuccess = (createNoteNotesPostResponse201) & { + headers: Headers; +}; +export type createNoteNotesPostResponseError = (createNoteNotesPostResponse422) & { + headers: Headers; +}; + +export type createNoteNotesPostResponse = (createNoteNotesPostResponseSuccess | createNoteNotesPostResponseError) + +export const getCreateNoteNotesPostUrl = () => { + + + + + return `/notes` +} + +export const createNoteNotesPost = async (noteCreate: NoteCreate, options?: RequestInit): Promise => { + + return orvalClient(getCreateNoteNotesPostUrl(), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...options?.headers }, + body: JSON.stringify( + noteCreate,) + } +);} + + + + +export const getCreateNoteNotesPostMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{data: NoteCreate}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{data: NoteCreate}, TContext> => { + +const mutationKey = ['createNoteNotesPost']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {data: NoteCreate}> = (props) => { + const {data} = props ?? {}; + + return createNoteNotesPost(data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type CreateNoteNotesPostMutationResult = NonNullable>> + export type CreateNoteNotesPostMutationBody = NoteCreate + export type CreateNoteNotesPostMutationError = HTTPValidationError + + /** + * @summary Create Note + */ +export const useCreateNoteNotesPost = (options?: { mutation?:UseMutationOptions>, TError,{data: NoteCreate}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {data: NoteCreate}, + TContext + > => { + return useMutation(getCreateNoteNotesPostMutationOptions(options), queryClient); + } + /** + * Get a single note by ID (must belong to current user). + * @summary Get Note + */ +export type getNoteNotesNoteIdGetResponse200 = { + data: NoteRead + status: 200 +} + +export type getNoteNotesNoteIdGetResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type getNoteNotesNoteIdGetResponseSuccess = (getNoteNotesNoteIdGetResponse200) & { + headers: Headers; +}; +export type getNoteNotesNoteIdGetResponseError = (getNoteNotesNoteIdGetResponse422) & { + headers: Headers; +}; + +export type getNoteNotesNoteIdGetResponse = (getNoteNotesNoteIdGetResponseSuccess | getNoteNotesNoteIdGetResponseError) + +export const getGetNoteNotesNoteIdGetUrl = (noteId: string,) => { + + + + + return `/notes/${noteId}` +} + +export const getNoteNotesNoteIdGet = async (noteId: string, options?: RequestInit): Promise => { + + return orvalClient(getGetNoteNotesNoteIdGetUrl(noteId), + { + ...options, + method: 'GET' + + + } +);} + + + + + +export const getGetNoteNotesNoteIdGetQueryKey = (noteId: string,) => { + return [ + `/notes/${noteId}` + ] as const; + } + + +export const getGetNoteNotesNoteIdGetQueryOptions = >, TError = HTTPValidationError>(noteId: string, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} +) => { + +const {query: queryOptions, request: requestOptions} = options ?? {}; + + const queryKey = queryOptions?.queryKey ?? getGetNoteNotesNoteIdGetQueryKey(noteId); + + + + const queryFn: QueryFunction>> = ({ signal }) => getNoteNotesNoteIdGet(noteId, { signal, ...requestOptions }); + + + + + + return { queryKey, queryFn, enabled: !!(noteId), ...queryOptions} as UseQueryOptions>, TError, TData> & { queryKey: DataTag } +} + +export type GetNoteNotesNoteIdGetQueryResult = NonNullable>> +export type GetNoteNotesNoteIdGetQueryError = HTTPValidationError + + +export function useGetNoteNotesNoteIdGet>, TError = HTTPValidationError>( + noteId: string, options: { query:Partial>, TError, TData>> & Pick< + DefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): DefinedUseQueryResult & { queryKey: DataTag } +export function useGetNoteNotesNoteIdGet>, TError = HTTPValidationError>( + noteId: string, options?: { query?:Partial>, TError, TData>> & Pick< + UndefinedInitialDataOptions< + Awaited>, + TError, + Awaited> + > , 'initialData' + >, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +export function useGetNoteNotesNoteIdGet>, TError = HTTPValidationError>( + noteId: string, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } +/** + * @summary Get Note + */ + +export function useGetNoteNotesNoteIdGet>, TError = HTTPValidationError>( + noteId: string, options?: { query?:Partial>, TError, TData>>, request?: SecondParameter} + , queryClient?: QueryClient + ): UseQueryResult & { queryKey: DataTag } { + + const queryOptions = getGetNoteNotesNoteIdGetQueryOptions(noteId,options) + + const query = useQuery(queryOptions, queryClient) as UseQueryResult & { queryKey: DataTag }; + + return { ...query, queryKey: queryOptions.queryKey }; +} + + + + +/** + * Update a note (must belong to current user). + * @summary Update Note + */ +export type updateNoteNotesNoteIdPatchResponse200 = { + data: NoteRead + status: 200 +} + +export type updateNoteNotesNoteIdPatchResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type updateNoteNotesNoteIdPatchResponseSuccess = (updateNoteNotesNoteIdPatchResponse200) & { + headers: Headers; +}; +export type updateNoteNotesNoteIdPatchResponseError = (updateNoteNotesNoteIdPatchResponse422) & { + headers: Headers; +}; + +export type updateNoteNotesNoteIdPatchResponse = (updateNoteNotesNoteIdPatchResponseSuccess | updateNoteNotesNoteIdPatchResponseError) + +export const getUpdateNoteNotesNoteIdPatchUrl = (noteId: string,) => { + + + + + return `/notes/${noteId}` +} + +export const updateNoteNotesNoteIdPatch = async (noteId: string, + noteUpdate: NoteUpdate, options?: RequestInit): Promise => { + + return orvalClient(getUpdateNoteNotesNoteIdPatchUrl(noteId), + { + ...options, + method: 'PATCH', + headers: { 'Content-Type': 'application/json', ...options?.headers }, + body: JSON.stringify( + noteUpdate,) + } +);} + + + + +export const getUpdateNoteNotesNoteIdPatchMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{noteId: string;data: NoteUpdate}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{noteId: string;data: NoteUpdate}, TContext> => { + +const mutationKey = ['updateNoteNotesNoteIdPatch']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {noteId: string;data: NoteUpdate}> = (props) => { + const {noteId,data} = props ?? {}; + + return updateNoteNotesNoteIdPatch(noteId,data,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type UpdateNoteNotesNoteIdPatchMutationResult = NonNullable>> + export type UpdateNoteNotesNoteIdPatchMutationBody = NoteUpdate + export type UpdateNoteNotesNoteIdPatchMutationError = HTTPValidationError + + /** + * @summary Update Note + */ +export const useUpdateNoteNotesNoteIdPatch = (options?: { mutation?:UseMutationOptions>, TError,{noteId: string;data: NoteUpdate}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {noteId: string;data: NoteUpdate}, + TContext + > => { + return useMutation(getUpdateNoteNotesNoteIdPatchMutationOptions(options), queryClient); + } + /** + * Delete a note (must belong to current user). + * @summary Delete Note + */ +export type deleteNoteNotesNoteIdDeleteResponse204 = { + data: void + status: 204 +} + +export type deleteNoteNotesNoteIdDeleteResponse422 = { + data: HTTPValidationError + status: 422 +} + +export type deleteNoteNotesNoteIdDeleteResponseSuccess = (deleteNoteNotesNoteIdDeleteResponse204) & { + headers: Headers; +}; +export type deleteNoteNotesNoteIdDeleteResponseError = (deleteNoteNotesNoteIdDeleteResponse422) & { + headers: Headers; +}; + +export type deleteNoteNotesNoteIdDeleteResponse = (deleteNoteNotesNoteIdDeleteResponseSuccess | deleteNoteNotesNoteIdDeleteResponseError) + +export const getDeleteNoteNotesNoteIdDeleteUrl = (noteId: string,) => { + + + + + return `/notes/${noteId}` +} + +export const deleteNoteNotesNoteIdDelete = async (noteId: string, options?: RequestInit): Promise => { + + return orvalClient(getDeleteNoteNotesNoteIdDeleteUrl(noteId), + { + ...options, + method: 'DELETE' + + + } +);} + + + + +export const getDeleteNoteNotesNoteIdDeleteMutationOptions = (options?: { mutation?:UseMutationOptions>, TError,{noteId: string}, TContext>, request?: SecondParameter} +): UseMutationOptions>, TError,{noteId: string}, TContext> => { + +const mutationKey = ['deleteNoteNotesNoteIdDelete']; +const {mutation: mutationOptions, request: requestOptions} = options ? + options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ? + options + : {...options, mutation: {...options.mutation, mutationKey}} + : {mutation: { mutationKey, }, request: undefined}; + + + + + const mutationFn: MutationFunction>, {noteId: string}> = (props) => { + const {noteId} = props ?? {}; + + return deleteNoteNotesNoteIdDelete(noteId,requestOptions) + } + + + + + + + return { mutationFn, ...mutationOptions }} + + export type DeleteNoteNotesNoteIdDeleteMutationResult = NonNullable>> + + export type DeleteNoteNotesNoteIdDeleteMutationError = HTTPValidationError + + /** + * @summary Delete Note + */ +export const useDeleteNoteNotesNoteIdDelete = (options?: { mutation?:UseMutationOptions>, TError,{noteId: string}, TContext>, request?: SecondParameter} + , queryClient?: QueryClient): UseMutationResult< + Awaited>, + TError, + {noteId: string}, + TContext + > => { + return useMutation(getDeleteNoteNotesNoteIdDeleteMutationOptions(options), queryClient); + } + \ No newline at end of file diff --git a/src/api/generated/types/bodyAuthJwtLoginAuthJwtLoginPost.ts b/src/api/generated/types/bodyAuthJwtLoginAuthJwtLoginPost.ts new file mode 100644 index 0000000..2d177e8 --- /dev/null +++ b/src/api/generated/types/bodyAuthJwtLoginAuthJwtLoginPost.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export interface BodyAuthJwtLoginAuthJwtLoginPost { + grant_type?: string | null; + username: string; + password: string; + scope?: string; + client_id?: string | null; + client_secret?: string | null; +} diff --git a/src/api/generated/types/contactCreate.ts b/src/api/generated/types/contactCreate.ts new file mode 100644 index 0000000..e8cb4fa --- /dev/null +++ b/src/api/generated/types/contactCreate.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * A message submitted through the public contact form. + */ +export interface ContactCreate { + /** + * @minLength 1 + * @maxLength 120 + */ + name: string; + email: string; + /** + * @minLength 1 + * @maxLength 200 + */ + subject: string; + /** + * @minLength 10 + * @maxLength 5000 + */ + message: string; + website?: string; +} diff --git a/src/api/generated/types/errorModel.ts b/src/api/generated/types/errorModel.ts new file mode 100644 index 0000000..8cc0e95 --- /dev/null +++ b/src/api/generated/types/errorModel.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import type { ErrorModelDetail } from './errorModelDetail'; + +export interface ErrorModel { + detail: ErrorModelDetail; +} diff --git a/src/api/generated/types/errorModelDetail.ts b/src/api/generated/types/errorModelDetail.ts new file mode 100644 index 0000000..c3d76d9 --- /dev/null +++ b/src/api/generated/types/errorModelDetail.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export type ErrorModelDetail = string | {[key: string]: string}; diff --git a/src/api/generated/types/hTTPValidationError.ts b/src/api/generated/types/hTTPValidationError.ts new file mode 100644 index 0000000..aaeb6f3 --- /dev/null +++ b/src/api/generated/types/hTTPValidationError.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import type { ValidationError } from './validationError'; + +export interface HTTPValidationError { + detail?: ValidationError[]; +} diff --git a/src/api/generated/types/index.ts b/src/api/generated/types/index.ts new file mode 100644 index 0000000..6743ce2 --- /dev/null +++ b/src/api/generated/types/index.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export * from './bodyAuthJwtLoginAuthJwtLoginPost'; +export * from './contactCreate'; +export * from './errorModel'; +export * from './errorModelDetail'; +export * from './hTTPValidationError'; +export * from './listFlagsFlagsGet200'; +export * from './listNotesNotesGetParams'; +export * from './noteCreate'; +export * from './noteRead'; +export * from './noteUpdate'; +export * from './roleUpdate'; +export * from './submitContactContactPost202'; +export * from './userCreate'; +export * from './userRead'; +export * from './validationError'; +export * from './validationErrorCtx'; \ No newline at end of file diff --git a/src/api/generated/types/listFlagsFlagsGet200.ts b/src/api/generated/types/listFlagsFlagsGet200.ts new file mode 100644 index 0000000..8098030 --- /dev/null +++ b/src/api/generated/types/listFlagsFlagsGet200.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export type ListFlagsFlagsGet200 = {[key: string]: boolean}; diff --git a/src/api/generated/types/listNotesNotesGetParams.ts b/src/api/generated/types/listNotesNotesGetParams.ts new file mode 100644 index 0000000..3d5d6b0 --- /dev/null +++ b/src/api/generated/types/listNotesNotesGetParams.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export type ListNotesNotesGetParams = { +skip?: number; +limit?: number; +}; diff --git a/src/api/generated/types/noteCreate.ts b/src/api/generated/types/noteCreate.ts new file mode 100644 index 0000000..a4dd48c --- /dev/null +++ b/src/api/generated/types/noteCreate.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * Schema for creating a new note. + */ +export interface NoteCreate { + /** + * @minLength 1 + * @maxLength 200 + */ + title: string; + body?: string | null; +} diff --git a/src/api/generated/types/noteRead.ts b/src/api/generated/types/noteRead.ts new file mode 100644 index 0000000..3de686f --- /dev/null +++ b/src/api/generated/types/noteRead.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * Schema for reading a note (includes id and timestamps). + */ +export interface NoteRead { + /** + * @minLength 1 + * @maxLength 200 + */ + title: string; + body?: string | null; + id: string; + created_at: string; + updated_at: string; +} diff --git a/src/api/generated/types/noteUpdate.ts b/src/api/generated/types/noteUpdate.ts new file mode 100644 index 0000000..57f4b9f --- /dev/null +++ b/src/api/generated/types/noteUpdate.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * Schema for updating a note. All fields optional. + */ +export interface NoteUpdate { + title?: string | null; + body?: string | null; +} diff --git a/src/api/generated/types/roleUpdate.ts b/src/api/generated/types/roleUpdate.ts new file mode 100644 index 0000000..524adc4 --- /dev/null +++ b/src/api/generated/types/roleUpdate.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export interface RoleUpdate { + role: string; +} diff --git a/src/api/generated/types/submitContactContactPost202.ts b/src/api/generated/types/submitContactContactPost202.ts new file mode 100644 index 0000000..a09f96c --- /dev/null +++ b/src/api/generated/types/submitContactContactPost202.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export type SubmitContactContactPost202 = {[key: string]: string}; diff --git a/src/api/generated/types/userCreate.ts b/src/api/generated/types/userCreate.ts new file mode 100644 index 0000000..1e88ca3 --- /dev/null +++ b/src/api/generated/types/userCreate.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * Schema for creating a new user. + */ +export interface UserCreate { + email: string; + password: string; + is_active?: boolean | null; + is_superuser?: boolean | null; + is_verified?: boolean | null; + name?: string | null; +} diff --git a/src/api/generated/types/userRead.ts b/src/api/generated/types/userRead.ts new file mode 100644 index 0000000..e3a39ef --- /dev/null +++ b/src/api/generated/types/userRead.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +/** + * Schema for reading user data. + */ +export interface UserRead { + id: string; + email: string; + is_active?: boolean; + is_superuser?: boolean; + is_verified?: boolean; + name?: string | null; + role?: string; +} diff --git a/src/api/generated/types/validationError.ts b/src/api/generated/types/validationError.ts new file mode 100644 index 0000000..0992d9b --- /dev/null +++ b/src/api/generated/types/validationError.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import type { ValidationErrorCtx } from './validationErrorCtx'; + +export interface ValidationError { + loc: (string | number)[]; + msg: string; + type: string; + input?: unknown; + ctx?: ValidationErrorCtx; +} diff --git a/src/api/generated/types/validationErrorCtx.ts b/src/api/generated/types/validationErrorCtx.ts new file mode 100644 index 0000000..89664bc --- /dev/null +++ b/src/api/generated/types/validationErrorCtx.ts @@ -0,0 +1,9 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ + +export type ValidationErrorCtx = { [key: string]: unknown }; diff --git a/src/api/generated/zod/admin/admin.ts b/src/api/generated/zod/admin/admin.ts new file mode 100644 index 0000000..6923ce0 --- /dev/null +++ b/src/api/generated/zod/admin/admin.ts @@ -0,0 +1,37 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * Update a user's role. Requires admin role. + * @summary Update User Role + */ +export const UpdateUserRoleAdminUsersUserIdRolePatchParams = zod.object({ + "user_id": zod.uuid() +}) + +export const UpdateUserRoleAdminUsersUserIdRolePatchBody = zod.object({ + "role": zod.string() +}) + +export const updateUserRoleAdminUsersUserIdRolePatchResponseIsActiveDefault = true; +export const updateUserRoleAdminUsersUserIdRolePatchResponseIsSuperuserDefault = false; +export const updateUserRoleAdminUsersUserIdRolePatchResponseIsVerifiedDefault = false; +export const updateUserRoleAdminUsersUserIdRolePatchResponseRoleDefault = `user`; + +export const UpdateUserRoleAdminUsersUserIdRolePatchResponse = zod.object({ + "id": zod.uuid(), + "email": zod.email(), + "is_active": zod.boolean().default(updateUserRoleAdminUsersUserIdRolePatchResponseIsActiveDefault), + "is_superuser": zod.boolean().default(updateUserRoleAdminUsersUserIdRolePatchResponseIsSuperuserDefault), + "is_verified": zod.boolean().default(updateUserRoleAdminUsersUserIdRolePatchResponseIsVerifiedDefault), + "name": zod.union([zod.string(),zod.null()]).optional(), + "role": zod.string().default(updateUserRoleAdminUsersUserIdRolePatchResponseRoleDefault) +}).describe('Schema for reading user data.') + diff --git a/src/api/generated/zod/auth/auth.ts b/src/api/generated/zod/auth/auth.ts new file mode 100644 index 0000000..c4fb741 --- /dev/null +++ b/src/api/generated/zod/auth/auth.ts @@ -0,0 +1,54 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * @summary Auth:Jwt.Logout + */ +export const AuthJwtLogoutAuthJwtLogoutPostResponse = zod.unknown() + +/** + * @summary Auth:Jwt.Login + */ +export const AuthJwtLoginAuthJwtLoginPostResponse = zod.unknown() + +/** + * @summary Register:Register + */ +export const registerRegisterAuthRegisterPostBodyIsActiveDefault = true; +export const registerRegisterAuthRegisterPostBodyIsSuperuserDefault = false; +export const registerRegisterAuthRegisterPostBodyIsVerifiedDefault = false; + +export const RegisterRegisterAuthRegisterPostBody = zod.object({ + "email": zod.email(), + "password": zod.string(), + "is_active": zod.union([zod.boolean(),zod.null()]).default(registerRegisterAuthRegisterPostBodyIsActiveDefault), + "is_superuser": zod.union([zod.boolean(),zod.null()]).default(registerRegisterAuthRegisterPostBodyIsSuperuserDefault), + "is_verified": zod.union([zod.boolean(),zod.null()]).default(registerRegisterAuthRegisterPostBodyIsVerifiedDefault), + "name": zod.union([zod.string(),zod.null()]).optional() +}).describe('Schema for creating a new user.') + +/** + * @summary Get Current User + */ +export const getCurrentUserAuthMeGetResponseIsActiveDefault = true; +export const getCurrentUserAuthMeGetResponseIsSuperuserDefault = false; +export const getCurrentUserAuthMeGetResponseIsVerifiedDefault = false; +export const getCurrentUserAuthMeGetResponseRoleDefault = `user`; + +export const GetCurrentUserAuthMeGetResponse = zod.object({ + "id": zod.uuid(), + "email": zod.email(), + "is_active": zod.boolean().default(getCurrentUserAuthMeGetResponseIsActiveDefault), + "is_superuser": zod.boolean().default(getCurrentUserAuthMeGetResponseIsSuperuserDefault), + "is_verified": zod.boolean().default(getCurrentUserAuthMeGetResponseIsVerifiedDefault), + "name": zod.union([zod.string(),zod.null()]).optional(), + "role": zod.string().default(getCurrentUserAuthMeGetResponseRoleDefault) +}).describe('Schema for reading user data.') + diff --git a/src/api/generated/zod/contact/contact.ts b/src/api/generated/zod/contact/contact.ts new file mode 100644 index 0000000..db3ea02 --- /dev/null +++ b/src/api/generated/zod/contact/contact.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * Accept a contact-form submission and email it to the site inbox. + +Public endpoint (no auth); rate-limited in main. Honeypot submissions +are accepted but silently dropped so bots get no signal. + * @summary Submit Contact + */ +export const submitContactContactPostBodyNameMax = 120; + +export const submitContactContactPostBodySubjectMax = 200; + +export const submitContactContactPostBodyMessageMin = 10; +export const submitContactContactPostBodyMessageMax = 5000; + +export const submitContactContactPostBodyWebsiteDefault = ``; + +export const SubmitContactContactPostBody = zod.object({ + "name": zod.string().min(1).max(submitContactContactPostBodyNameMax), + "email": zod.email(), + "subject": zod.string().min(1).max(submitContactContactPostBodySubjectMax), + "message": zod.string().min(submitContactContactPostBodyMessageMin).max(submitContactContactPostBodyMessageMax), + "website": zod.string().default(submitContactContactPostBodyWebsiteDefault) +}).describe('A message submitted through the public contact form.') + diff --git a/src/api/generated/zod/default/default.ts b/src/api/generated/zod/default/default.ts new file mode 100644 index 0000000..495992f --- /dev/null +++ b/src/api/generated/zod/default/default.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * Health check endpoint. + * @summary Root + */ +export const RootGetResponse = zod.unknown() + +/** + * Detailed health check. + * @summary Health Check + */ +export const HealthCheckHealthGetResponse = zod.unknown() + diff --git a/src/api/generated/zod/features/features.ts b/src/api/generated/zod/features/features.ts new file mode 100644 index 0000000..37e8117 --- /dev/null +++ b/src/api/generated/zod/features/features.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * Return enabled feature flags for the current user. + * @summary List Flags + */ +export const ListFlagsFlagsGetResponse = zod.record(zod.string(), zod.boolean()) + diff --git a/src/api/generated/zod/notes/notes.ts b/src/api/generated/zod/notes/notes.ts new file mode 100644 index 0000000..b1d8eae --- /dev/null +++ b/src/api/generated/zod/notes/notes.ts @@ -0,0 +1,105 @@ +/** + * Generated by orval v8.5.3 🍺 + * Do not edit manually. + * API Template + * FastAPI template with async PostgreSQL and cookie-based JWT auth + * OpenAPI spec version: 0.2.0 + */ +import * as zod from 'zod'; + + +/** + * List the current user's notes. + * @summary List Notes + */ +export const listNotesNotesGetQuerySkipDefault = 0; +export const listNotesNotesGetQueryLimitDefault = 100; + +export const ListNotesNotesGetQueryParams = zod.object({ + "skip": zod.number().default(listNotesNotesGetQuerySkipDefault), + "limit": zod.number().default(listNotesNotesGetQueryLimitDefault) +}) + +export const listNotesNotesGetResponseTitleMax = 200; + + + +export const ListNotesNotesGetResponseItem = zod.object({ + "title": zod.string().min(1).max(listNotesNotesGetResponseTitleMax), + "body": zod.union([zod.string(),zod.null()]).optional(), + "id": zod.uuid(), + "created_at": zod.iso.datetime({}), + "updated_at": zod.iso.datetime({}) +}).describe('Schema for reading a note (includes id and timestamps).') +export const ListNotesNotesGetResponse = zod.array(ListNotesNotesGetResponseItem) + +/** + * Create a new note for the current user. + * @summary Create Note + */ +export const createNoteNotesPostBodyTitleMax = 200; + + + +export const CreateNoteNotesPostBody = zod.object({ + "title": zod.string().min(1).max(createNoteNotesPostBodyTitleMax), + "body": zod.union([zod.string(),zod.null()]).optional() +}).describe('Schema for creating a new note.') + +/** + * Get a single note by ID (must belong to current user). + * @summary Get Note + */ +export const GetNoteNotesNoteIdGetParams = zod.object({ + "note_id": zod.uuid() +}) + +export const getNoteNotesNoteIdGetResponseTitleMax = 200; + + + +export const GetNoteNotesNoteIdGetResponse = zod.object({ + "title": zod.string().min(1).max(getNoteNotesNoteIdGetResponseTitleMax), + "body": zod.union([zod.string(),zod.null()]).optional(), + "id": zod.uuid(), + "created_at": zod.iso.datetime({}), + "updated_at": zod.iso.datetime({}) +}).describe('Schema for reading a note (includes id and timestamps).') + +/** + * Update a note (must belong to current user). + * @summary Update Note + */ +export const UpdateNoteNotesNoteIdPatchParams = zod.object({ + "note_id": zod.uuid() +}) + +export const updateNoteNotesNoteIdPatchBodyTitleOneMax = 200; + + + +export const UpdateNoteNotesNoteIdPatchBody = zod.object({ + "title": zod.union([zod.string().min(1).max(updateNoteNotesNoteIdPatchBodyTitleOneMax),zod.null()]).optional(), + "body": zod.union([zod.string(),zod.null()]).optional() +}).describe('Schema for updating a note. All fields optional.') + +export const updateNoteNotesNoteIdPatchResponseTitleMax = 200; + + + +export const UpdateNoteNotesNoteIdPatchResponse = zod.object({ + "title": zod.string().min(1).max(updateNoteNotesNoteIdPatchResponseTitleMax), + "body": zod.union([zod.string(),zod.null()]).optional(), + "id": zod.uuid(), + "created_at": zod.iso.datetime({}), + "updated_at": zod.iso.datetime({}) +}).describe('Schema for reading a note (includes id and timestamps).') + +/** + * Delete a note (must belong to current user). + * @summary Delete Note + */ +export const DeleteNoteNotesNoteIdDeleteParams = zod.object({ + "note_id": zod.uuid() +}) + diff --git a/src/pages/contact/contact-page.tsx b/src/pages/contact/contact-page.tsx index 5716b54..6d39fb0 100644 --- a/src/pages/contact/contact-page.tsx +++ b/src/pages/contact/contact-page.tsx @@ -1,4 +1,4 @@ -import { useState } from "react" +import { useSubmitContactContactPost } from "@/api/generated/hooks/contact/contact" import { SocialLinks } from "@/components/social-links" import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" @@ -6,12 +6,21 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" export function ContactPage() { - const [submitted, setSubmitted] = useState(false) + const mutation = useSubmitContactContactPost() + const submitted = mutation.isSuccess function handleSubmit(e: React.FormEvent) { e.preventDefault() - // TODO: wire to FastAPI backend - setSubmitted(true) + const form = new FormData(e.currentTarget) + mutation.mutate({ + data: { + name: String(form.get("name") ?? ""), + email: String(form.get("email") ?? ""), + subject: String(form.get("subject") ?? ""), + message: String(form.get("message") ?? ""), + website: String(form.get("website") ?? ""), + }, + }) } return ( @@ -58,18 +67,36 @@ export function ContactPage() { + {/* Honeypot — humans never see or fill this; the API drops + submissions where it's non-empty. */} +