feat: onboarding flow

This commit is contained in:
Nicolas Meienberger
2025-10-02 20:30:02 +02:00
parent 689e92ffc1
commit 0120641e3a
3 changed files with 356 additions and 0 deletions

View File

@@ -2,6 +2,11 @@
import {
type Options,
register,
login,
logout,
getMe,
getStatus,
listVolumes,
createVolume,
testConnection,
@@ -15,6 +20,14 @@ import {
} from "../sdk.gen";
import { queryOptions, type UseMutationOptions, type DefaultError } from "@tanstack/react-query";
import type {
RegisterData,
RegisterResponse,
LoginData,
LoginResponse,
LogoutData,
LogoutResponse,
GetMeData,
GetStatusData,
ListVolumesData,
CreateVolumeData,
CreateVolumeResponse,
@@ -74,6 +87,163 @@ const createQueryKey = <TOptions extends Options>(
return [params];
};
export const registerQueryKey = (options?: Options<RegisterData>) => createQueryKey("register", options);
/**
* Register a new user
*/
export const registerOptions = (options?: Options<RegisterData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await register({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: registerQueryKey(options),
});
};
/**
* Register a new user
*/
export const registerMutation = (
options?: Partial<Options<RegisterData>>,
): UseMutationOptions<RegisterResponse, DefaultError, Options<RegisterData>> => {
const mutationOptions: UseMutationOptions<RegisterResponse, DefaultError, Options<RegisterData>> = {
mutationFn: async (localOptions) => {
const { data } = await register({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
export const loginQueryKey = (options?: Options<LoginData>) => createQueryKey("login", options);
/**
* Login with username and password
*/
export const loginOptions = (options?: Options<LoginData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await login({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: loginQueryKey(options),
});
};
/**
* Login with username and password
*/
export const loginMutation = (
options?: Partial<Options<LoginData>>,
): UseMutationOptions<LoginResponse, DefaultError, Options<LoginData>> => {
const mutationOptions: UseMutationOptions<LoginResponse, DefaultError, Options<LoginData>> = {
mutationFn: async (localOptions) => {
const { data } = await login({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
export const logoutQueryKey = (options?: Options<LogoutData>) => createQueryKey("logout", options);
/**
* Logout current user
*/
export const logoutOptions = (options?: Options<LogoutData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await logout({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: logoutQueryKey(options),
});
};
/**
* Logout current user
*/
export const logoutMutation = (
options?: Partial<Options<LogoutData>>,
): UseMutationOptions<LogoutResponse, DefaultError, Options<LogoutData>> => {
const mutationOptions: UseMutationOptions<LogoutResponse, DefaultError, Options<LogoutData>> = {
mutationFn: async (localOptions) => {
const { data } = await logout({
...options,
...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
};
export const getMeQueryKey = (options?: Options<GetMeData>) => createQueryKey("getMe", options);
/**
* Get current authenticated user
*/
export const getMeOptions = (options?: Options<GetMeData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await getMe({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: getMeQueryKey(options),
});
};
export const getStatusQueryKey = (options?: Options<GetStatusData>) => createQueryKey("getStatus", options);
/**
* Get authentication system status
*/
export const getStatusOptions = (options?: Options<GetStatusData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await getStatus({
...options,
...queryKey[0],
signal,
throwOnError: true,
});
return data;
},
queryKey: getStatusQueryKey(options),
});
};
export const listVolumesQueryKey = (options?: Options<ListVolumesData>) => createQueryKey("listVolumes", options);
/**

View File

@@ -2,6 +2,19 @@
import type { Options as ClientOptions, TDataShape, Client } from "./client";
import type {
RegisterData,
RegisterResponses,
RegisterErrors,
LoginData,
LoginResponses,
LoginErrors,
LogoutData,
LogoutResponses,
GetMeData,
GetMeResponses,
GetMeErrors,
GetStatusData,
GetStatusResponses,
ListVolumesData,
ListVolumesResponses,
CreateVolumeData,
@@ -48,6 +61,56 @@ export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends
meta?: Record<string, unknown>;
};
/**
* Register a new user
*/
export const register = <ThrowOnError extends boolean = false>(options?: Options<RegisterData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).post<RegisterResponses, RegisterErrors, ThrowOnError>({
url: "/api/v1/auth/register",
...options,
});
};
/**
* Login with username and password
*/
export const login = <ThrowOnError extends boolean = false>(options?: Options<LoginData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).post<LoginResponses, LoginErrors, ThrowOnError>({
url: "/api/v1/auth/login",
...options,
});
};
/**
* Logout current user
*/
export const logout = <ThrowOnError extends boolean = false>(options?: Options<LogoutData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).post<LogoutResponses, unknown, ThrowOnError>({
url: "/api/v1/auth/logout",
...options,
});
};
/**
* Get current authenticated user
*/
export const getMe = <ThrowOnError extends boolean = false>(options?: Options<GetMeData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<GetMeResponses, GetMeErrors, ThrowOnError>({
url: "/api/v1/auth/me",
...options,
});
};
/**
* Get authentication system status
*/
export const getStatus = <ThrowOnError extends boolean = false>(options?: Options<GetStatusData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<GetStatusResponses, unknown, ThrowOnError>({
url: "/api/v1/auth/status",
...options,
});
};
/**
* List all volumes
*/

View File

@@ -1,5 +1,128 @@
// This file is auto-generated by @hey-api/openapi-ts
export type RegisterData = {
body?: never;
path?: never;
query?: never;
url: "/api/v1/auth/register";
};
export type RegisterErrors = {
/**
* Invalid request or username already exists
*/
400: unknown;
};
export type RegisterResponses = {
/**
* User created successfully
*/
201: {
message: string;
user: {
id: string;
username: string;
};
};
};
export type RegisterResponse = RegisterResponses[keyof RegisterResponses];
export type LoginData = {
body?: never;
path?: never;
query?: never;
url: "/api/v1/auth/login";
};
export type LoginErrors = {
/**
* Invalid credentials
*/
401: unknown;
};
export type LoginResponses = {
/**
* Login successful
*/
200: {
message: string;
user: {
id: string;
username: string;
};
};
};
export type LoginResponse = LoginResponses[keyof LoginResponses];
export type LogoutData = {
body?: never;
path?: never;
query?: never;
url: "/api/v1/auth/logout";
};
export type LogoutResponses = {
/**
* Logout successful
*/
200: {
message: string;
};
};
export type LogoutResponse = LogoutResponses[keyof LogoutResponses];
export type GetMeData = {
body?: never;
path?: never;
query?: never;
url: "/api/v1/auth/me";
};
export type GetMeErrors = {
/**
* Not authenticated
*/
401: unknown;
};
export type GetMeResponses = {
/**
* Current user information
*/
200: {
message: string;
user: {
id: string;
username: string;
};
};
};
export type GetMeResponse = GetMeResponses[keyof GetMeResponses];
export type GetStatusData = {
body?: never;
path?: never;
query?: never;
url: "/api/v1/auth/status";
};
export type GetStatusResponses = {
/**
* Authentication system status
*/
200: {
hasUsers: boolean;
};
};
export type GetStatusResponse = GetStatusResponses[keyof GetStatusResponses];
export type ListVolumesData = {
body?: never;
path?: never;