Refactor auto-generated schemas and types formatting
Some checks failed
Build and Push Docker Images / changes (push) Successful in 5s
Build and Push Docker Images / build-backend (push) Has been skipped
Build and Push Docker Images / build-frontend (push) Failing after 42s

Updated the formatting for auto-generated schemas, types, and related files to adhere to consistent coding standards (e.g., double quotes, indentation). No functional changes were made, ensuring behavior remains identical.
This commit is contained in:
2025-03-05 10:13:33 +01:00
parent ffa3f2ffd3
commit c61ad52331
12 changed files with 1193 additions and 914 deletions

View File

@@ -1,13 +1,13 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: 'standalone',
output: "standalone",
// Ensure we can connect to the backend in Docker
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://backend:8000/:path*',
source: "/api/:path*",
destination: "http://backend:8000/:path*",
},
];
},

View File

@@ -1,28 +1,27 @@
import {defineConfig} from '@hey-api/openapi-ts';
import { defineConfig } from "@hey-api/openapi-ts";
import path from "path";
const API_URL = process.env.NEXT_PUBLIC_BACKEND_API_URL || 'http://localhost:8000';
const API_URL =
process.env.NEXT_PUBLIC_BACKEND_API_URL || "http://localhost:8000";
const OPENAPI_URL = `${API_URL}/api/v1/openapi.json`;
const OUTPUT_DIR = path.resolve(__dirname, './src/client');
const OUTPUT_DIR = path.resolve(__dirname, "./src/client");
// const OPENAPI_FILE = path.resolve(__dirname, './openapi.json');
export default defineConfig({
input:
OPENAPI_URL,
input: OPENAPI_URL,
output: {
format: 'prettier',
lint: 'eslint',
format: "prettier",
lint: "eslint",
path: OUTPUT_DIR,
},
plugins: [
'@hey-api/client-axios',
'@hey-api/schemas',
'@hey-api/sdk',
"@hey-api/client-axios",
"@hey-api/schemas",
"@hey-api/sdk",
{
enums: 'javascript',
name: '@hey-api/typescript',
enums: "javascript",
name: "@hey-api/typescript",
},
'@tanstack/react-query',
"@tanstack/react-query",
],
});

View File

@@ -26,7 +26,10 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.2.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-prettier": "^5.2.3",
"openapi-typescript-codegen": "^0.29.0",
"prettier": "^3.5.3",
"tailwindcss": "^4",
"typescript": "^5"
}
@@ -890,6 +893,19 @@
"node": ">=12.4.0"
}
},
"node_modules/@pkgr/core": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -2594,6 +2610,19 @@
}
}
},
"node_modules/eslint-config-prettier": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz",
"integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==",
"dev": true,
"license": "MIT",
"bin": {
"eslint-config-prettier": "build/bin/cli.js"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -2763,6 +2792,37 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
"integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.9.1"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": "*",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-react": {
"version": "7.37.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
@@ -2938,6 +2998,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-glob": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
@@ -5032,6 +5099,35 @@
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5755,6 +5851,23 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/synckit": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.1.0",
"tslib": "^2.6.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
}
},
"node_modules/tailwindcss": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.9.tgz",

View File

@@ -9,6 +9,7 @@
"lint": "next lint",
"docker:build": "docker build -t eventspace-frontend .",
"docker:run": "docker run -p 3000:3000 eventspace-frontend",
"format": "prettier --write .",
"openapi-ts": "openapi-ts"
},
"dependencies": {
@@ -30,7 +31,10 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.2.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-prettier": "^5.2.3",
"openapi-typescript-codegen": "^0.29.0",
"prettier": "^3.5.3",
"tailwindcss": "^4",
"typescript": "^5"
}

View File

@@ -1,22 +1,53 @@
// This file is auto-generated by @hey-api/openapi-ts
import { type Options, rootGet, register, login, loginOauth, refreshToken, changePassword, getCurrentUserInfo } from '../sdk.gen';
import { queryOptions, type UseMutationOptions } from '@tanstack/react-query';
import type { RootGetData, RegisterData, RegisterError, RegisterResponse, LoginData, LoginError, LoginResponse, LoginOauthData, LoginOauthError, LoginOauthResponse, RefreshTokenData, RefreshTokenError, RefreshTokenResponse, ChangePasswordData, ChangePasswordError, GetCurrentUserInfoData } from '../types.gen';
import type { AxiosError } from 'axios';
import { client as _heyApiClient } from '../client.gen';
import {
type Options,
rootGet,
register,
login,
loginOauth,
refreshToken,
changePassword,
getCurrentUserInfo,
} from "../sdk.gen";
import { queryOptions, type UseMutationOptions } from "@tanstack/react-query";
import type {
RootGetData,
RegisterData,
RegisterError,
RegisterResponse,
LoginData,
LoginError,
LoginResponse,
LoginOauthData,
LoginOauthError,
LoginOauthResponse,
RefreshTokenData,
RefreshTokenError,
RefreshTokenResponse,
ChangePasswordData,
ChangePasswordError,
GetCurrentUserInfoData,
} from "../types.gen";
import type { AxiosError } from "axios";
import { client as _heyApiClient } from "../client.gen";
export type QueryKey<TOptions extends Options> = [
Pick<TOptions, 'baseURL' | 'body' | 'headers' | 'path' | 'query'> & {
Pick<TOptions, "baseURL" | "body" | "headers" | "path" | "query"> & {
_id: string;
_infinite?: boolean;
}
},
];
const createQueryKey = <TOptions extends Options>(id: string, options?: TOptions, infinite?: boolean): [
QueryKey<TOptions>[0]
] => {
const params: QueryKey<TOptions>[0] = { _id: id, baseURL: (options?.client ?? _heyApiClient).getConfig().baseURL } as QueryKey<TOptions>[0];
const createQueryKey = <TOptions extends Options>(
id: string,
options?: TOptions,
infinite?: boolean,
): [QueryKey<TOptions>[0]] => {
const params: QueryKey<TOptions>[0] = {
_id: id,
baseURL: (options?.client ?? _heyApiClient).getConfig().baseURL,
} as QueryKey<TOptions>[0];
if (infinite) {
params._infinite = infinite;
}
@@ -32,12 +63,11 @@ const createQueryKey = <TOptions extends Options>(id: string, options?: TOptions
if (options?.query) {
params.query = options.query;
}
return [
params
];
return [params];
};
export const rootGetQueryKey = (options?: Options<RootGetData>) => createQueryKey('rootGet', options);
export const rootGetQueryKey = (options?: Options<RootGetData>) =>
createQueryKey("rootGet", options);
export const rootGetOptions = (options?: Options<RootGetData>) => {
return queryOptions({
@@ -46,15 +76,16 @@ export const rootGetOptions = (options?: Options<RootGetData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: rootGetQueryKey(options)
queryKey: rootGetQueryKey(options),
});
};
export const registerQueryKey = (options: Options<RegisterData>) => createQueryKey('register', options);
export const registerQueryKey = (options: Options<RegisterData>) =>
createQueryKey("register", options);
export const registerOptions = (options: Options<RegisterData>) => {
return queryOptions({
@@ -63,29 +94,34 @@ export const registerOptions = (options: Options<RegisterData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: registerQueryKey(options)
queryKey: registerQueryKey(options),
});
};
export const registerMutation = (options?: Partial<Options<RegisterData>>) => {
const mutationOptions: UseMutationOptions<RegisterResponse, AxiosError<RegisterError>, Options<RegisterData>> = {
const mutationOptions: UseMutationOptions<
RegisterResponse,
AxiosError<RegisterError>,
Options<RegisterData>
> = {
mutationFn: async (localOptions) => {
const { data } = await register({
...options,
...localOptions,
throwOnError: true
throwOnError: true,
});
return data;
}
},
};
return mutationOptions;
};
export const loginQueryKey = (options: Options<LoginData>) => createQueryKey('login', options);
export const loginQueryKey = (options: Options<LoginData>) =>
createQueryKey("login", options);
export const loginOptions = (options: Options<LoginData>) => {
return queryOptions({
@@ -94,29 +130,34 @@ export const loginOptions = (options: Options<LoginData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: loginQueryKey(options)
queryKey: loginQueryKey(options),
});
};
export const loginMutation = (options?: Partial<Options<LoginData>>) => {
const mutationOptions: UseMutationOptions<LoginResponse, AxiosError<LoginError>, Options<LoginData>> = {
const mutationOptions: UseMutationOptions<
LoginResponse,
AxiosError<LoginError>,
Options<LoginData>
> = {
mutationFn: async (localOptions) => {
const { data } = await login({
...options,
...localOptions,
throwOnError: true
throwOnError: true,
});
return data;
}
},
};
return mutationOptions;
};
export const loginOauthQueryKey = (options: Options<LoginOauthData>) => createQueryKey('loginOauth', options);
export const loginOauthQueryKey = (options: Options<LoginOauthData>) =>
createQueryKey("loginOauth", options);
export const loginOauthOptions = (options: Options<LoginOauthData>) => {
return queryOptions({
@@ -125,29 +166,36 @@ export const loginOauthOptions = (options: Options<LoginOauthData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: loginOauthQueryKey(options)
queryKey: loginOauthQueryKey(options),
});
};
export const loginOauthMutation = (options?: Partial<Options<LoginOauthData>>) => {
const mutationOptions: UseMutationOptions<LoginOauthResponse, AxiosError<LoginOauthError>, Options<LoginOauthData>> = {
export const loginOauthMutation = (
options?: Partial<Options<LoginOauthData>>,
) => {
const mutationOptions: UseMutationOptions<
LoginOauthResponse,
AxiosError<LoginOauthError>,
Options<LoginOauthData>
> = {
mutationFn: async (localOptions) => {
const { data } = await loginOauth({
...options,
...localOptions,
throwOnError: true
throwOnError: true,
});
return data;
}
},
};
return mutationOptions;
};
export const refreshTokenQueryKey = (options: Options<RefreshTokenData>) => createQueryKey('refreshToken', options);
export const refreshTokenQueryKey = (options: Options<RefreshTokenData>) =>
createQueryKey("refreshToken", options);
export const refreshTokenOptions = (options: Options<RefreshTokenData>) => {
return queryOptions({
@@ -156,29 +204,36 @@ export const refreshTokenOptions = (options: Options<RefreshTokenData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: refreshTokenQueryKey(options)
queryKey: refreshTokenQueryKey(options),
});
};
export const refreshTokenMutation = (options?: Partial<Options<RefreshTokenData>>) => {
const mutationOptions: UseMutationOptions<RefreshTokenResponse, AxiosError<RefreshTokenError>, Options<RefreshTokenData>> = {
export const refreshTokenMutation = (
options?: Partial<Options<RefreshTokenData>>,
) => {
const mutationOptions: UseMutationOptions<
RefreshTokenResponse,
AxiosError<RefreshTokenError>,
Options<RefreshTokenData>
> = {
mutationFn: async (localOptions) => {
const { data } = await refreshToken({
...options,
...localOptions,
throwOnError: true
throwOnError: true,
});
return data;
}
},
};
return mutationOptions;
};
export const changePasswordQueryKey = (options: Options<ChangePasswordData>) => createQueryKey('changePassword', options);
export const changePasswordQueryKey = (options: Options<ChangePasswordData>) =>
createQueryKey("changePassword", options);
export const changePasswordOptions = (options: Options<ChangePasswordData>) => {
return queryOptions({
@@ -187,41 +242,51 @@ export const changePasswordOptions = (options: Options<ChangePasswordData>) => {
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: changePasswordQueryKey(options)
queryKey: changePasswordQueryKey(options),
});
};
export const changePasswordMutation = (options?: Partial<Options<ChangePasswordData>>) => {
const mutationOptions: UseMutationOptions<unknown, AxiosError<ChangePasswordError>, Options<ChangePasswordData>> = {
export const changePasswordMutation = (
options?: Partial<Options<ChangePasswordData>>,
) => {
const mutationOptions: UseMutationOptions<
unknown,
AxiosError<ChangePasswordError>,
Options<ChangePasswordData>
> = {
mutationFn: async (localOptions) => {
const { data } = await changePassword({
...options,
...localOptions,
throwOnError: true
throwOnError: true,
});
return data;
}
},
};
return mutationOptions;
};
export const getCurrentUserInfoQueryKey = (options?: Options<GetCurrentUserInfoData>) => createQueryKey('getCurrentUserInfo', options);
export const getCurrentUserInfoQueryKey = (
options?: Options<GetCurrentUserInfoData>,
) => createQueryKey("getCurrentUserInfo", options);
export const getCurrentUserInfoOptions = (options?: Options<GetCurrentUserInfoData>) => {
export const getCurrentUserInfoOptions = (
options?: Options<GetCurrentUserInfoData>,
) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await getCurrentUserInfo({
...options,
...queryKey[0],
signal,
throwOnError: true
throwOnError: true,
});
return data;
},
queryKey: getCurrentUserInfoQueryKey(options)
queryKey: getCurrentUserInfoQueryKey(options),
});
};

View File

@@ -1,7 +1,12 @@
// This file is auto-generated by @hey-api/openapi-ts
import type { ClientOptions } from './types.gen';
import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-axios';
import type { ClientOptions } from "./types.gen";
import {
type Config,
type ClientOptions as DefaultClientOptions,
createClient,
createConfig,
} from "@hey-api/client-axios";
/**
* The `createClientConfig()` function will be called on client initialization
@@ -11,8 +16,13 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient,
* `setConfig()`. This is useful for example if you're using Next.js
* to ensure your client always has the correct values.
*/
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> =
(
override?: Config<DefaultClientOptions & T>,
) => Config<Required<DefaultClientOptions> & T>;
export const client = createClient(createConfig<ClientOptions>({
baseURL: 'http://localhost:8000'
}));
export const client = createClient(
createConfig<ClientOptions>({
baseURL: "http://localhost:8000",
}),
);

View File

@@ -1,3 +1,3 @@
// This file is auto-generated by @hey-api/openapi-ts
export * from './types.gen';
export * from './sdk.gen';
export * from "./types.gen";
export * from "./sdk.gen";

View File

@@ -3,17 +3,17 @@
export const Body_change_passwordSchema = {
properties: {
current_password: {
type: 'string',
title: 'Current Password'
type: "string",
title: "Current Password",
},
new_password: {
type: 'string',
title: 'New Password'
}
type: "string",
title: "New Password",
},
type: 'object',
required: ['current_password', 'new_password'],
title: 'Body_change_password'
},
type: "object",
required: ["current_password", "new_password"],
title: "Body_change_password",
} as const;
export const Body_login_oauthSchema = {
@@ -21,242 +21,249 @@ export const Body_login_oauthSchema = {
grant_type: {
anyOf: [
{
type: 'string',
pattern: '^password$'
type: "string",
pattern: "^password$",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Grant Type'
title: "Grant Type",
},
username: {
type: 'string',
title: 'Username'
type: "string",
title: "Username",
},
password: {
type: 'string',
title: 'Password'
type: "string",
title: "Password",
},
scope: {
type: 'string',
title: 'Scope',
default: ''
type: "string",
title: "Scope",
default: "",
},
client_id: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Client Id'
title: "Client Id",
},
client_secret: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
],
title: 'Client Secret'
}
type: "null",
},
type: 'object',
required: ['username', 'password'],
title: 'Body_login_oauth'
],
title: "Client Secret",
},
},
type: "object",
required: ["username", "password"],
title: "Body_login_oauth",
} as const;
export const HTTPValidationErrorSchema = {
properties: {
detail: {
items: {
'$ref': '#/components/schemas/ValidationError'
$ref: "#/components/schemas/ValidationError",
},
type: 'array',
title: 'Detail'
}
type: "array",
title: "Detail",
},
type: 'object',
title: 'HTTPValidationError'
},
type: "object",
title: "HTTPValidationError",
} as const;
export const LoginRequestSchema = {
properties: {
email: {
type: 'string',
format: 'email',
title: 'Email'
type: "string",
format: "email",
title: "Email",
},
password: {
type: 'string',
title: 'Password'
}
type: "string",
title: "Password",
},
type: 'object',
required: ['email', 'password'],
title: 'LoginRequest'
},
type: "object",
required: ["email", "password"],
title: "LoginRequest",
} as const;
export const RefreshTokenRequestSchema = {
properties: {
refresh_token: {
type: 'string',
title: 'Refresh Token'
}
type: "string",
title: "Refresh Token",
},
type: 'object',
required: ['refresh_token'],
title: 'RefreshTokenRequest'
},
type: "object",
required: ["refresh_token"],
title: "RefreshTokenRequest",
} as const;
export const TokenSchema = {
properties: {
access_token: {
type: 'string',
title: 'Access Token'
type: "string",
title: "Access Token",
},
refresh_token: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Refresh Token'
title: "Refresh Token",
},
token_type: {
type: 'string',
title: 'Token Type',
default: 'bearer'
}
type: "string",
title: "Token Type",
default: "bearer",
},
type: 'object',
required: ['access_token'],
title: 'Token'
},
type: "object",
required: ["access_token"],
title: "Token",
} as const;
export const UserCreateSchema = {
properties: {
email: {
type: 'string',
format: 'email',
title: 'Email'
type: "string",
format: "email",
title: "Email",
},
first_name: {
type: 'string',
title: 'First Name'
type: "string",
title: "First Name",
},
last_name: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Last Name'
title: "Last Name",
},
phone_number: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Phone Number'
title: "Phone Number",
},
password: {
type: 'string',
title: 'Password'
type: "string",
title: "Password",
},
is_superuser: {
type: 'boolean',
title: 'Is Superuser',
default: false
}
type: "boolean",
title: "Is Superuser",
default: false,
},
type: 'object',
required: ['email', 'first_name', 'password'],
title: 'UserCreate'
},
type: "object",
required: ["email", "first_name", "password"],
title: "UserCreate",
} as const;
export const UserResponseSchema = {
properties: {
email: {
type: 'string',
format: 'email',
title: 'Email'
type: "string",
format: "email",
title: "Email",
},
first_name: {
type: 'string',
title: 'First Name'
type: "string",
title: "First Name",
},
last_name: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Last Name'
title: "Last Name",
},
phone_number: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'null'
}
type: "null",
},
],
title: 'Phone Number'
title: "Phone Number",
},
id: {
type: 'string',
format: 'uuid',
title: 'Id'
type: "string",
format: "uuid",
title: "Id",
},
is_active: {
type: 'boolean',
title: 'Is Active'
type: "boolean",
title: "Is Active",
},
is_superuser: {
type: 'boolean',
title: 'Is Superuser'
type: "boolean",
title: "Is Superuser",
},
created_at: {
type: 'string',
format: 'date-time',
title: 'Created At'
type: "string",
format: "date-time",
title: "Created At",
},
updated_at: {
anyOf: [
{
type: 'string',
format: 'date-time'
type: "string",
format: "date-time",
},
{
type: 'null'
}
],
title: 'Updated At'
}
type: "null",
},
type: 'object',
required: ['email', 'first_name', 'id', 'is_active', 'is_superuser', 'created_at'],
title: 'UserResponse'
],
title: "Updated At",
},
},
type: "object",
required: [
"email",
"first_name",
"id",
"is_active",
"is_superuser",
"created_at",
],
title: "UserResponse",
} as const;
export const ValidationErrorSchema = {
@@ -265,26 +272,26 @@ export const ValidationErrorSchema = {
items: {
anyOf: [
{
type: 'string'
type: "string",
},
{
type: 'integer'
}
]
type: "integer",
},
type: 'array',
title: 'Location'
],
},
type: "array",
title: "Location",
},
msg: {
type: 'string',
title: 'Message'
type: "string",
title: "Message",
},
type: {
type: 'string',
title: 'Error Type'
}
type: "string",
title: "Error Type",
},
type: 'object',
required: ['loc', 'msg', 'type'],
title: 'ValidationError'
},
type: "object",
required: ["loc", "msg", "type"],
title: "ValidationError",
} as const;

View File

@@ -1,10 +1,37 @@
// This file is auto-generated by @hey-api/openapi-ts
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from '@hey-api/client-axios';
import type { RootGetData, RootGetResponse, RegisterData, RegisterResponse, RegisterError, LoginData, LoginResponse, LoginError, LoginOauthData, LoginOauthResponse, LoginOauthError, RefreshTokenData, RefreshTokenResponse, RefreshTokenError, ChangePasswordData, ChangePasswordError, GetCurrentUserInfoData, GetCurrentUserInfoResponse } from './types.gen';
import { client as _heyApiClient } from './client.gen';
import {
type Options as ClientOptions,
type TDataShape,
type Client,
urlSearchParamsBodySerializer,
} from "@hey-api/client-axios";
import type {
RootGetData,
RootGetResponse,
RegisterData,
RegisterResponse,
RegisterError,
LoginData,
LoginResponse,
LoginError,
LoginOauthData,
LoginOauthResponse,
LoginOauthError,
RefreshTokenData,
RefreshTokenResponse,
RefreshTokenError,
ChangePasswordData,
ChangePasswordError,
GetCurrentUserInfoData,
GetCurrentUserInfoResponse,
} from "./types.gen";
import { client as _heyApiClient } from "./client.gen";
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
export type Options<
TData extends TDataShape = TDataShape,
ThrowOnError extends boolean = boolean,
> = ClientOptions<TData, ThrowOnError> & {
/**
* You can provide a client instance returned by `createClient()` instead of
* individual options. This might be also useful if you want to implement a
@@ -21,11 +48,17 @@ export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends
/**
* Root
*/
export const rootGet = <ThrowOnError extends boolean = false>(options?: Options<RootGetData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<RootGetResponse, unknown, ThrowOnError>({
responseType: 'text',
url: '/',
...options
export const rootGet = <ThrowOnError extends boolean = false>(
options?: Options<RootGetData, ThrowOnError>,
) => {
return (options?.client ?? _heyApiClient).get<
RootGetResponse,
unknown,
ThrowOnError
>({
responseType: "text",
url: "/",
...options,
});
};
@@ -36,14 +69,20 @@ export const rootGet = <ThrowOnError extends boolean = false>(options?: Options<
* Returns:
* The created user information.
*/
export const register = <ThrowOnError extends boolean = false>(options: Options<RegisterData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<RegisterResponse, RegisterError, ThrowOnError>({
url: '/api/v1/auth/register',
export const register = <ThrowOnError extends boolean = false>(
options: Options<RegisterData, ThrowOnError>,
) => {
return (options.client ?? _heyApiClient).post<
RegisterResponse,
RegisterError,
ThrowOnError
>({
url: "/api/v1/auth/register",
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
"Content-Type": "application/json",
...options?.headers,
},
});
};
@@ -54,14 +93,20 @@ export const register = <ThrowOnError extends boolean = false>(options: Options<
* Returns:
* Access and refresh tokens.
*/
export const login = <ThrowOnError extends boolean = false>(options: Options<LoginData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<LoginResponse, LoginError, ThrowOnError>({
url: '/api/v1/auth/login',
export const login = <ThrowOnError extends boolean = false>(
options: Options<LoginData, ThrowOnError>,
) => {
return (options.client ?? _heyApiClient).post<
LoginResponse,
LoginError,
ThrowOnError
>({
url: "/api/v1/auth/login",
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
"Content-Type": "application/json",
...options?.headers,
},
});
};
@@ -72,15 +117,21 @@ export const login = <ThrowOnError extends boolean = false>(options: Options<Log
* Returns:
* Access and refresh tokens.
*/
export const loginOauth = <ThrowOnError extends boolean = false>(options: Options<LoginOauthData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<LoginOauthResponse, LoginOauthError, ThrowOnError>({
export const loginOauth = <ThrowOnError extends boolean = false>(
options: Options<LoginOauthData, ThrowOnError>,
) => {
return (options.client ?? _heyApiClient).post<
LoginOauthResponse,
LoginOauthError,
ThrowOnError
>({
...urlSearchParamsBodySerializer,
url: '/api/v1/auth/login/oauth',
url: "/api/v1/auth/login/oauth",
...options,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
...options?.headers
}
"Content-Type": "application/x-www-form-urlencoded",
...options?.headers,
},
});
};
@@ -91,14 +142,20 @@ export const loginOauth = <ThrowOnError extends boolean = false>(options: Option
* Returns:
* New access and refresh tokens.
*/
export const refreshToken = <ThrowOnError extends boolean = false>(options: Options<RefreshTokenData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<RefreshTokenResponse, RefreshTokenError, ThrowOnError>({
url: '/api/v1/auth/refresh',
export const refreshToken = <ThrowOnError extends boolean = false>(
options: Options<RefreshTokenData, ThrowOnError>,
) => {
return (options.client ?? _heyApiClient).post<
RefreshTokenResponse,
RefreshTokenError,
ThrowOnError
>({
url: "/api/v1/auth/refresh",
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
"Content-Type": "application/json",
...options?.headers,
},
});
};
@@ -108,20 +165,26 @@ export const refreshToken = <ThrowOnError extends boolean = false>(options: Opti
*
* Requires authentication.
*/
export const changePassword = <ThrowOnError extends boolean = false>(options: Options<ChangePasswordData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<unknown, ChangePasswordError, ThrowOnError>({
export const changePassword = <ThrowOnError extends boolean = false>(
options: Options<ChangePasswordData, ThrowOnError>,
) => {
return (options.client ?? _heyApiClient).post<
unknown,
ChangePasswordError,
ThrowOnError
>({
security: [
{
scheme: 'bearer',
type: 'http'
}
scheme: "bearer",
type: "http",
},
],
url: '/api/v1/auth/change-password',
url: "/api/v1/auth/change-password",
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
"Content-Type": "application/json",
...options?.headers,
},
});
};
@@ -131,15 +194,21 @@ export const changePassword = <ThrowOnError extends boolean = false>(options: Op
*
* Requires authentication.
*/
export const getCurrentUserInfo = <ThrowOnError extends boolean = false>(options?: Options<GetCurrentUserInfoData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<GetCurrentUserInfoResponse, unknown, ThrowOnError>({
export const getCurrentUserInfo = <ThrowOnError extends boolean = false>(
options?: Options<GetCurrentUserInfoData, ThrowOnError>,
) => {
return (options?.client ?? _heyApiClient).get<
GetCurrentUserInfoResponse,
unknown,
ThrowOnError
>({
security: [
{
scheme: 'bearer',
type: 'http'
}
scheme: "bearer",
type: "http",
},
],
url: '/api/v1/auth/me',
...options
url: "/api/v1/auth/me",
...options,
});
};

View File

@@ -64,7 +64,7 @@ export type RootGetData = {
body?: never;
path?: never;
query?: never;
url: '/';
url: "/";
};
export type RootGetResponses = {
@@ -80,7 +80,7 @@ export type RegisterData = {
body: UserCreate;
path?: never;
query?: never;
url: '/api/v1/auth/register';
url: "/api/v1/auth/register";
};
export type RegisterErrors = {
@@ -105,7 +105,7 @@ export type LoginData = {
body: LoginRequest;
path?: never;
query?: never;
url: '/api/v1/auth/login';
url: "/api/v1/auth/login";
};
export type LoginErrors = {
@@ -130,7 +130,7 @@ export type LoginOauthData = {
body: BodyLoginOauth;
path?: never;
query?: never;
url: '/api/v1/auth/login/oauth';
url: "/api/v1/auth/login/oauth";
};
export type LoginOauthErrors = {
@@ -155,7 +155,7 @@ export type RefreshTokenData = {
body: RefreshTokenRequest;
path?: never;
query?: never;
url: '/api/v1/auth/refresh';
url: "/api/v1/auth/refresh";
};
export type RefreshTokenErrors = {
@@ -174,13 +174,14 @@ export type RefreshTokenResponses = {
200: Token;
};
export type RefreshTokenResponse = RefreshTokenResponses[keyof RefreshTokenResponses];
export type RefreshTokenResponse =
RefreshTokenResponses[keyof RefreshTokenResponses];
export type ChangePasswordData = {
body: BodyChangePassword;
path?: never;
query?: never;
url: '/api/v1/auth/change-password';
url: "/api/v1/auth/change-password";
};
export type ChangePasswordErrors = {
@@ -190,7 +191,8 @@ export type ChangePasswordErrors = {
422: HttpValidationError;
};
export type ChangePasswordError = ChangePasswordErrors[keyof ChangePasswordErrors];
export type ChangePasswordError =
ChangePasswordErrors[keyof ChangePasswordErrors];
export type ChangePasswordResponses = {
/**
@@ -203,7 +205,7 @@ export type GetCurrentUserInfoData = {
body?: never;
path?: never;
query?: never;
url: '/api/v1/auth/me';
url: "/api/v1/auth/me";
};
export type GetCurrentUserInfoResponses = {
@@ -213,8 +215,9 @@ export type GetCurrentUserInfoResponses = {
200: UserResponse;
};
export type GetCurrentUserInfoResponse = GetCurrentUserInfoResponses[keyof GetCurrentUserInfoResponses];
export type GetCurrentUserInfoResponse =
GetCurrentUserInfoResponses[keyof GetCurrentUserInfoResponses];
export type ClientOptions = {
baseURL: 'http://localhost:8000' | (string & {});
baseURL: "http://localhost:8000" | (string & {});
};

View File

@@ -1,12 +1,23 @@
'use client';
"use client";
import React, {createContext, useContext, useState, useEffect, ReactNode, useCallback, useMemo} from 'react';
import {useRouter, usePathname} from 'next/navigation';
import {jwtDecode} from 'jwt-decode';
import {client} from '@/client/client.gen';
import {useMutation, useQueryClient, useQuery, type UseQueryOptions} from '@tanstack/react-query';
import {loginMutation, getCurrentUserInfoOptions} from '@/client/@tanstack/react-query.gen';
import {LoginRequest, UserResponse, Token} from '@/client/types.gen';
import React, {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import { usePathname, useRouter } from "next/navigation";
import { jwtDecode } from "jwt-decode";
import { client } from "@/client/client.gen";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
getCurrentUserInfoOptions,
loginMutation,
} from "@/client/@tanstack/react-query.gen";
import { LoginRequest, Token, UserResponse } from "@/client/types.gen";
// JWT token payload interface
interface TokenPayload {
@@ -34,12 +45,9 @@ const defaultAuthState: AuthContextState = {
isAuthenticated: false,
isLoading: true,
error: null,
login: async () => {
},
logout: () => {
},
refreshToken: async () => {
},
login: async () => {},
logout: () => {},
refreshToken: async () => {},
};
// Create context
@@ -49,24 +57,27 @@ const AuthContext = createContext<AuthContextState>(defaultAuthState);
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
};
// Token management
const TOKEN_KEY = 'accessToken';
const REFRESH_TOKEN_KEY = 'refreshToken';
const TOKEN_KEY = "accessToken";
const REFRESH_TOKEN_KEY = "refreshToken";
// Get token from storage
const getStoredToken = (): string | null => {
if (typeof window === 'undefined') return null;
if (typeof window === "undefined") return null;
return localStorage.getItem(TOKEN_KEY);
};
// Store token in storage
const storeToken = (token: string | null, refreshToken: string | null = null): void => {
if (typeof window === 'undefined') return;
const storeToken = (
token: string | null,
refreshToken: string | null = null,
): void => {
if (typeof window === "undefined") return;
if (token) {
localStorage.setItem(TOKEN_KEY, token);
@@ -97,7 +108,7 @@ interface AuthProviderProps {
}
// Auth Provider Component
export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProviderProps) => {
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [isInitializing, setIsInitializing] = useState(true);
const router = useRouter();
const pathname = usePathname();
@@ -112,12 +123,13 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
if (token) {
client.setConfig({
headers: {
Authorization: `Bearer ${token}`
}
Authorization: `Bearer ${token}`,
},
});
}
}, []);
// Check if current token is valid (not expired)
const hasValidToken = useCallback((): boolean => {
const token = getStoredToken();
return Boolean(token && !isTokenExpired(token));
@@ -129,7 +141,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
enabled: hasValidToken(),
retry: false,
staleTime: 5 * 60 * 1000, // 5 minutes
} as UseQueryOptions;
};
// Use the query without onError in the options
const { data: user, isLoading, error, refetch } = useQuery(userQueryOptions);
@@ -143,10 +155,11 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
}, [error]);
// Login function
const login = useCallback(async (credentials: LoginRequest): Promise<void> => {
const login = useCallback(
async (credentials: LoginRequest): Promise<void> => {
try {
const response = await loginMutationHook.mutateAsync({
body: credentials
body: credentials,
});
// Store tokens
@@ -155,22 +168,24 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
// Configure client with new token
client.setConfig({
headers: {
Authorization: `Bearer ${response.access_token}`
}
Authorization: `Bearer ${response.access_token}`,
},
});
// Trigger user data fetch
await refetch();
// Redirect after login
if (pathname === '/login') {
router.push('/dashboard');
if (pathname === "/login") {
router.push("/dashboard");
}
} catch (error) {
console.error('Login failed:', error);
console.error("Login failed:", error);
throw error;
}
}, [loginMutationHook, refetch, router, pathname]);
},
[loginMutationHook, refetch, router, pathname],
);
// Logout function
const logout = useCallback((): void => {
@@ -180,17 +195,17 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
// Remove auth headers
client.setConfig({
headers: {
Authorization: undefined
}
Authorization: undefined,
},
});
// Clear user from cache
queryClient.invalidateQueries({
queryKey: getCurrentUserInfoOptions().queryKey
queryKey: getCurrentUserInfoOptions().queryKey,
});
// Redirect to login page
router.push('/login');
router.push("/login");
}, [router, queryClient]);
// Refresh token function
@@ -204,7 +219,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
try {
const response = await client.post<Token>({
url: '/api/v1/auth/refresh',
url: "/api/v1/auth/refresh",
body: { refresh_token: refreshTokenValue },
});
@@ -217,15 +232,14 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
// Update client headers
client.setConfig({
headers: {
Authorization: `Bearer ${newTokens.access_token}`
}
Authorization: `Bearer ${newTokens.access_token}`,
},
});
}
// Refetch user data
await refetch();
} catch (error) {
console.error('Token refresh failed:', error);
console.error("Token refresh failed:", error);
logout();
}
}, [logout, refetch]);
@@ -246,43 +260,41 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
if (isInitializing) return;
const protectedRoutes = [
'/admin',
'/dashboard',
'/events/create',
'/events/edit',
'/profile',
"/admin",
"/dashboard",
"/events/create",
"/events/edit",
"/profile",
];
const publicOnlyRoutes = [
'/login',
'/register',
];
const publicOnlyRoutes = ["/login", "/register"];
const publicRoutes = [
'/',
'/invite',
'/rsvp',
];
const publicRoutes = ["/", "/invite", "/rsvp"];
const isProtectedRoute = protectedRoutes.some(route => pathname?.startsWith(route));
const isPublicOnlyRoute = publicOnlyRoutes.some(route => pathname === route);
const isProtectedRoute = protectedRoutes.some((route) =>
pathname?.startsWith(route),
);
const isPublicOnlyRoute = publicOnlyRoutes.some(
(route) => pathname === route,
);
// Handle loading state
if (isLoading && isProtectedRoute) return;
// Redirect to login if not authenticated but trying to access protected route
if (isProtectedRoute && !user) {
router.push(`/login?redirect=${encodeURIComponent(pathname || '')}`);
router.push(`/login?redirect=${encodeURIComponent(pathname || "")}`);
}
// Redirect to dashboard if authenticated but trying to access public-only route
if (isPublicOnlyRoute && user) {
router.push('/dashboard');
router.push("/dashboard");
}
}, [user, isLoading, pathname, router, isInitializing]);
// Create the context value
const value = useMemo<AuthContextState>(() => ({
const value = useMemo<AuthContextState>(
() => ({
user: user as UserResponse | null,
isAuthenticated: !!user,
isLoading: isInitializing || isLoading,
@@ -290,12 +302,9 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProvid
login,
logout,
refreshToken,
}), [user, isInitializing, isLoading, error, login, logout, refreshToken]);
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
}),
[user, isInitializing, isLoading, error, login, logout, refreshToken],
);
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};