⬆️ Upgrade Biome to the latest version (#1861)

This commit is contained in:
Alejandra
2025-09-09 14:45:10 +02:00
committed by GitHub
parent 61174f1806
commit f813161912
39 changed files with 1962 additions and 2134 deletions

View File

@@ -1,25 +1,21 @@
import type { ApiRequestOptions } from "./ApiRequestOptions"
import type { ApiResult } from "./ApiResult"
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
export class ApiError extends Error {
public readonly url: string
public readonly status: number
public readonly statusText: string
public readonly body: unknown
public readonly request: ApiRequestOptions
public readonly url: string;
public readonly status: number;
public readonly statusText: string;
public readonly body: unknown;
public readonly request: ApiRequestOptions;
constructor(
request: ApiRequestOptions,
response: ApiResult,
message: string,
) {
super(message)
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
super(message);
this.name = "ApiError"
this.url = response.url
this.status = response.status
this.statusText = response.statusText
this.body = response.body
this.request = request
}
}
this.name = 'ApiError';
this.url = response.url;
this.status = response.status;
this.statusText = response.statusText;
this.body = response.body;
this.request = request;
}
}

View File

@@ -1,21 +1,21 @@
export type ApiRequestOptions<T = unknown> = {
readonly body?: any
readonly cookies?: Record<string, unknown>
readonly errors?: Record<number | string, string>
readonly formData?: Record<string, unknown> | any[] | Blob | File
readonly headers?: Record<string, unknown>
readonly mediaType?: string
readonly method:
| "DELETE"
| "GET"
| "HEAD"
| "OPTIONS"
| "PATCH"
| "POST"
| "PUT"
readonly path?: Record<string, unknown>
readonly query?: Record<string, unknown>
readonly responseHeader?: string
readonly responseTransformer?: (data: unknown) => Promise<T>
readonly url: string
}
readonly body?: any;
readonly cookies?: Record<string, unknown>;
readonly errors?: Record<number | string, string>;
readonly formData?: Record<string, unknown> | any[] | Blob | File;
readonly headers?: Record<string, unknown>;
readonly mediaType?: string;
readonly method:
| 'DELETE'
| 'GET'
| 'HEAD'
| 'OPTIONS'
| 'PATCH'
| 'POST'
| 'PUT';
readonly path?: Record<string, unknown>;
readonly query?: Record<string, unknown>;
readonly responseHeader?: string;
readonly responseTransformer?: (data: unknown) => Promise<T>;
readonly url: string;
};

View File

@@ -1,7 +1,7 @@
export type ApiResult<TData = any> = {
readonly body: TData
readonly ok: boolean
readonly status: number
readonly statusText: string
readonly url: string
}
readonly body: TData;
readonly ok: boolean;
readonly status: number;
readonly statusText: string;
readonly url: string;
};

View File

@@ -1,126 +1,126 @@
export class CancelError extends Error {
constructor(message: string) {
super(message)
this.name = "CancelError"
}
constructor(message: string) {
super(message);
this.name = 'CancelError';
}
public get isCancelled(): boolean {
return true
}
public get isCancelled(): boolean {
return true;
}
}
export interface OnCancel {
readonly isResolved: boolean
readonly isRejected: boolean
readonly isCancelled: boolean
readonly isResolved: boolean;
readonly isRejected: boolean;
readonly isCancelled: boolean;
(cancelHandler: () => void): void
(cancelHandler: () => void): void;
}
export class CancelablePromise<T> implements Promise<T> {
private _isResolved: boolean
private _isRejected: boolean
private _isCancelled: boolean
readonly cancelHandlers: (() => void)[]
readonly promise: Promise<T>
private _resolve?: (value: T | PromiseLike<T>) => void
private _reject?: (reason?: unknown) => void
private _isResolved: boolean;
private _isRejected: boolean;
private _isCancelled: boolean;
readonly cancelHandlers: (() => void)[];
readonly promise: Promise<T>;
private _resolve?: (value: T | PromiseLike<T>) => void;
private _reject?: (reason?: unknown) => void;
constructor(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: unknown) => void,
onCancel: OnCancel,
) => void,
) {
this._isResolved = false
this._isRejected = false
this._isCancelled = false
this.cancelHandlers = []
this.promise = new Promise<T>((resolve, reject) => {
this._resolve = resolve
this._reject = reject
constructor(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: unknown) => void,
onCancel: OnCancel
) => void
) {
this._isResolved = false;
this._isRejected = false;
this._isCancelled = false;
this.cancelHandlers = [];
this.promise = new Promise<T>((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
const onResolve = (value: T | PromiseLike<T>): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return
}
this._isResolved = true
if (this._resolve) this._resolve(value)
}
const onResolve = (value: T | PromiseLike<T>): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isResolved = true;
if (this._resolve) this._resolve(value);
};
const onReject = (reason?: unknown): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return
}
this._isRejected = true
if (this._reject) this._reject(reason)
}
const onReject = (reason?: unknown): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isRejected = true;
if (this._reject) this._reject(reason);
};
const onCancel = (cancelHandler: () => void): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return
}
this.cancelHandlers.push(cancelHandler)
}
const onCancel = (cancelHandler: () => void): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this.cancelHandlers.push(cancelHandler);
};
Object.defineProperty(onCancel, "isResolved", {
get: (): boolean => this._isResolved,
})
Object.defineProperty(onCancel, 'isResolved', {
get: (): boolean => this._isResolved,
});
Object.defineProperty(onCancel, "isRejected", {
get: (): boolean => this._isRejected,
})
Object.defineProperty(onCancel, 'isRejected', {
get: (): boolean => this._isRejected,
});
Object.defineProperty(onCancel, "isCancelled", {
get: (): boolean => this._isCancelled,
})
Object.defineProperty(onCancel, 'isCancelled', {
get: (): boolean => this._isCancelled,
});
return executor(onResolve, onReject, onCancel as OnCancel)
})
}
return executor(onResolve, onReject, onCancel as OnCancel);
});
}
get [Symbol.toStringTag]() {
return "Cancellable Promise"
}
get [Symbol.toStringTag]() {
return "Cancellable Promise";
}
public then<TResult1 = T, TResult2 = never>(
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
onRejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
): Promise<TResult1 | TResult2> {
return this.promise.then(onFulfilled, onRejected)
}
public then<TResult1 = T, TResult2 = never>(
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
onRejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null
): Promise<TResult1 | TResult2> {
return this.promise.then(onFulfilled, onRejected);
}
public catch<TResult = never>(
onRejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,
): Promise<T | TResult> {
return this.promise.catch(onRejected)
}
public catch<TResult = never>(
onRejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null
): Promise<T | TResult> {
return this.promise.catch(onRejected);
}
public finally(onFinally?: (() => void) | null): Promise<T> {
return this.promise.finally(onFinally)
}
public finally(onFinally?: (() => void) | null): Promise<T> {
return this.promise.finally(onFinally);
}
public cancel(): void {
if (this._isResolved || this._isRejected || this._isCancelled) {
return
}
this._isCancelled = true
if (this.cancelHandlers.length) {
try {
for (const cancelHandler of this.cancelHandlers) {
cancelHandler()
}
} catch (error) {
console.warn("Cancellation threw an error", error)
return
}
}
this.cancelHandlers.length = 0
if (this._reject) this._reject(new CancelError("Request aborted"))
}
public cancel(): void {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isCancelled = true;
if (this.cancelHandlers.length) {
try {
for (const cancelHandler of this.cancelHandlers) {
cancelHandler();
}
} catch (error) {
console.warn('Cancellation threw an error', error);
return;
}
}
this.cancelHandlers.length = 0;
if (this._reject) this._reject(new CancelError('Request aborted'));
}
public get isCancelled(): boolean {
return this._isCancelled
}
}
public get isCancelled(): boolean {
return this._isCancelled;
}
}

View File

@@ -1,57 +1,57 @@
import type { AxiosRequestConfig, AxiosResponse } from "axios"
import type { ApiRequestOptions } from "./ApiRequestOptions"
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { ApiRequestOptions } from './ApiRequestOptions';
type Headers = Record<string, string>
type Middleware<T> = (value: T) => T | Promise<T>
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>
type Headers = Record<string, string>;
type Middleware<T> = (value: T) => T | Promise<T>;
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>;
export class Interceptors<T> {
_fns: Middleware<T>[]
_fns: Middleware<T>[];
constructor() {
this._fns = []
this._fns = [];
}
eject(fn: Middleware<T>): void {
const index = this._fns.indexOf(fn)
const index = this._fns.indexOf(fn);
if (index !== -1) {
this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)]
this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)];
}
}
use(fn: Middleware<T>): void {
this._fns = [...this._fns, fn]
this._fns = [...this._fns, fn];
}
}
export type OpenAPIConfig = {
BASE: string
CREDENTIALS: "include" | "omit" | "same-origin"
ENCODE_PATH?: ((path: string) => string) | undefined
HEADERS?: Headers | Resolver<Headers> | undefined
PASSWORD?: string | Resolver<string> | undefined
TOKEN?: string | Resolver<string> | undefined
USERNAME?: string | Resolver<string> | undefined
VERSION: string
WITH_CREDENTIALS: boolean
interceptors: {
request: Interceptors<AxiosRequestConfig>
response: Interceptors<AxiosResponse>
}
}
BASE: string;
CREDENTIALS: 'include' | 'omit' | 'same-origin';
ENCODE_PATH?: ((path: string) => string) | undefined;
HEADERS?: Headers | Resolver<Headers> | undefined;
PASSWORD?: string | Resolver<string> | undefined;
TOKEN?: string | Resolver<string> | undefined;
USERNAME?: string | Resolver<string> | undefined;
VERSION: string;
WITH_CREDENTIALS: boolean;
interceptors: {
request: Interceptors<AxiosRequestConfig>;
response: Interceptors<AxiosResponse>;
};
};
export const OpenAPI: OpenAPIConfig = {
BASE: "",
CREDENTIALS: "include",
ENCODE_PATH: undefined,
HEADERS: undefined,
PASSWORD: undefined,
TOKEN: undefined,
USERNAME: undefined,
VERSION: "0.1.0",
WITH_CREDENTIALS: false,
interceptors: {
request: new Interceptors(),
response: new Interceptors(),
},
}
BASE: '',
CREDENTIALS: 'include',
ENCODE_PATH: undefined,
HEADERS: undefined,
PASSWORD: undefined,
TOKEN: undefined,
USERNAME: undefined,
VERSION: '0.1.0',
WITH_CREDENTIALS: false,
interceptors: {
request: new Interceptors(),
response: new Interceptors(),
},
};

View File

@@ -1,325 +1,301 @@
import axios from "axios"
import type {
AxiosError,
AxiosRequestConfig,
AxiosResponse,
AxiosInstance,
} from "axios"
import axios from 'axios';
import type { AxiosError, AxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios';
import { ApiError } from "./ApiError"
import type { ApiRequestOptions } from "./ApiRequestOptions"
import type { ApiResult } from "./ApiResult"
import { CancelablePromise } from "./CancelablePromise"
import type { OnCancel } from "./CancelablePromise"
import type { OpenAPIConfig } from "./OpenAPI"
import { ApiError } from './ApiError';
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import type { OpenAPIConfig } from './OpenAPI';
export const isString = (value: unknown): value is string => {
return typeof value === "string"
}
return typeof value === 'string';
};
export const isStringWithValue = (value: unknown): value is string => {
return isString(value) && value !== ""
}
return isString(value) && value !== '';
};
export const isBlob = (value: any): value is Blob => {
return value instanceof Blob
}
return value instanceof Blob;
};
export const isFormData = (value: unknown): value is FormData => {
return value instanceof FormData
}
return value instanceof FormData;
};
export const isSuccess = (status: number): boolean => {
return status >= 200 && status < 300
}
return status >= 200 && status < 300;
};
export const base64 = (str: string): string => {
try {
return btoa(str)
} catch (err) {
// @ts-ignore
return Buffer.from(str).toString("base64")
}
}
try {
return btoa(str);
} catch (err) {
// @ts-ignore
return Buffer.from(str).toString('base64');
}
};
export const getQueryString = (params: Record<string, unknown>): string => {
const qs: string[] = []
const qs: string[] = [];
const append = (key: string, value: unknown) => {
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
}
const append = (key: string, value: unknown) => {
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
};
const encodePair = (key: string, value: unknown) => {
if (value === undefined || value === null) {
return
}
const encodePair = (key: string, value: unknown) => {
if (value === undefined || value === null) {
return;
}
if (value instanceof Date) {
append(key, value.toISOString())
} else if (Array.isArray(value)) {
value.forEach((v) => encodePair(key, v))
} else if (typeof value === "object") {
Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v))
} else {
append(key, value)
}
}
if (value instanceof Date) {
append(key, value.toISOString());
} else if (Array.isArray(value)) {
value.forEach(v => encodePair(key, v));
} else if (typeof value === 'object') {
Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v));
} else {
append(key, value);
}
};
Object.entries(params).forEach(([key, value]) => encodePair(key, value))
Object.entries(params).forEach(([key, value]) => encodePair(key, value));
return qs.length ? `?${qs.join("&")}` : ""
}
return qs.length ? `?${qs.join('&')}` : '';
};
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
const encoder = config.ENCODE_PATH || encodeURI
const encoder = config.ENCODE_PATH || encodeURI;
const path = options.url
.replace("{api-version}", config.VERSION)
.replace(/{(.*?)}/g, (substring: string, group: string) => {
if (options.path?.hasOwnProperty(group)) {
return encoder(String(options.path[group]))
}
return substring
})
const path = options.url
.replace('{api-version}', config.VERSION)
.replace(/{(.*?)}/g, (substring: string, group: string) => {
if (options.path?.hasOwnProperty(group)) {
return encoder(String(options.path[group]));
}
return substring;
});
const url = config.BASE + path
return options.query ? url + getQueryString(options.query) : url
}
const url = config.BASE + path;
return options.query ? url + getQueryString(options.query) : url;
};
export const getFormData = (
options: ApiRequestOptions,
): FormData | undefined => {
if (options.formData) {
const formData = new FormData()
export const getFormData = (options: ApiRequestOptions): FormData | undefined => {
if (options.formData) {
const formData = new FormData();
const process = (key: string, value: unknown) => {
if (isString(value) || isBlob(value)) {
formData.append(key, value)
} else {
formData.append(key, JSON.stringify(value))
}
}
const process = (key: string, value: unknown) => {
if (isString(value) || isBlob(value)) {
formData.append(key, value);
} else {
formData.append(key, JSON.stringify(value));
}
};
Object.entries(options.formData)
.filter(([, value]) => value !== undefined && value !== null)
.forEach(([key, value]) => {
if (Array.isArray(value)) {
value.forEach((v) => process(key, v))
} else {
process(key, value)
}
})
Object.entries(options.formData)
.filter(([, value]) => value !== undefined && value !== null)
.forEach(([key, value]) => {
if (Array.isArray(value)) {
value.forEach(v => process(key, v));
} else {
process(key, value);
}
});
return formData
}
return undefined
}
return formData;
}
return undefined;
};
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>;
export const resolve = async <T>(
options: ApiRequestOptions<T>,
resolver?: T | Resolver<T>,
): Promise<T | undefined> => {
if (typeof resolver === "function") {
return (resolver as Resolver<T>)(options)
}
return resolver
}
export const resolve = async <T>(options: ApiRequestOptions<T>, resolver?: T | Resolver<T>): Promise<T | undefined> => {
if (typeof resolver === 'function') {
return (resolver as Resolver<T>)(options);
}
return resolver;
};
export const getHeaders = async <T>(
config: OpenAPIConfig,
options: ApiRequestOptions<T>,
): Promise<Record<string, string>> => {
const [token, username, password, additionalHeaders] = await Promise.all([
// @ts-ignore
resolve(options, config.TOKEN),
// @ts-ignore
resolve(options, config.USERNAME),
// @ts-ignore
resolve(options, config.PASSWORD),
// @ts-ignore
resolve(options, config.HEADERS),
])
export const getHeaders = async <T>(config: OpenAPIConfig, options: ApiRequestOptions<T>): Promise<Record<string, string>> => {
const [token, username, password, additionalHeaders] = await Promise.all([
// @ts-ignore
resolve(options, config.TOKEN),
// @ts-ignore
resolve(options, config.USERNAME),
// @ts-ignore
resolve(options, config.PASSWORD),
// @ts-ignore
resolve(options, config.HEADERS),
]);
const headers = Object.entries({
Accept: "application/json",
...additionalHeaders,
...options.headers,
})
.filter(([, value]) => value !== undefined && value !== null)
.reduce(
(headers, [key, value]) => ({
...headers,
[key]: String(value),
}),
{} as Record<string, string>,
)
const headers = Object.entries({
Accept: 'application/json',
...additionalHeaders,
...options.headers,
})
.filter(([, value]) => value !== undefined && value !== null)
.reduce((headers, [key, value]) => ({
...headers,
[key]: String(value),
}), {} as Record<string, string>);
if (isStringWithValue(token)) {
headers["Authorization"] = `Bearer ${token}`
}
if (isStringWithValue(token)) {
headers['Authorization'] = `Bearer ${token}`;
}
if (isStringWithValue(username) && isStringWithValue(password)) {
const credentials = base64(`${username}:${password}`)
headers["Authorization"] = `Basic ${credentials}`
}
if (isStringWithValue(username) && isStringWithValue(password)) {
const credentials = base64(`${username}:${password}`);
headers['Authorization'] = `Basic ${credentials}`;
}
if (options.body !== undefined) {
if (options.mediaType) {
headers["Content-Type"] = options.mediaType
} else if (isBlob(options.body)) {
headers["Content-Type"] = options.body.type || "application/octet-stream"
} else if (isString(options.body)) {
headers["Content-Type"] = "text/plain"
} else if (!isFormData(options.body)) {
headers["Content-Type"] = "application/json"
}
} else if (options.formData !== undefined) {
if (options.mediaType) {
headers["Content-Type"] = options.mediaType
}
}
if (options.body !== undefined) {
if (options.mediaType) {
headers['Content-Type'] = options.mediaType;
} else if (isBlob(options.body)) {
headers['Content-Type'] = options.body.type || 'application/octet-stream';
} else if (isString(options.body)) {
headers['Content-Type'] = 'text/plain';
} else if (!isFormData(options.body)) {
headers['Content-Type'] = 'application/json';
}
} else if (options.formData !== undefined) {
if (options.mediaType) {
headers['Content-Type'] = options.mediaType;
}
}
return headers
}
return headers;
};
export const getRequestBody = (options: ApiRequestOptions): unknown => {
if (options.body) {
return options.body
}
return undefined
}
if (options.body) {
return options.body;
}
return undefined;
};
export const sendRequest = async <T>(
config: OpenAPIConfig,
options: ApiRequestOptions<T>,
url: string,
body: unknown,
formData: FormData | undefined,
headers: Record<string, string>,
onCancel: OnCancel,
axiosClient: AxiosInstance,
config: OpenAPIConfig,
options: ApiRequestOptions<T>,
url: string,
body: unknown,
formData: FormData | undefined,
headers: Record<string, string>,
onCancel: OnCancel,
axiosClient: AxiosInstance
): Promise<AxiosResponse<T>> => {
const controller = new AbortController()
const controller = new AbortController();
let requestConfig: AxiosRequestConfig = {
data: body ?? formData,
headers,
method: options.method,
signal: controller.signal,
url,
withCredentials: config.WITH_CREDENTIALS,
}
let requestConfig: AxiosRequestConfig = {
data: body ?? formData,
headers,
method: options.method,
signal: controller.signal,
url,
withCredentials: config.WITH_CREDENTIALS,
};
onCancel(() => controller.abort())
onCancel(() => controller.abort());
for (const fn of config.interceptors.request._fns) {
requestConfig = await fn(requestConfig)
}
for (const fn of config.interceptors.request._fns) {
requestConfig = await fn(requestConfig);
}
try {
return await axiosClient.request(requestConfig)
} catch (error) {
const axiosError = error as AxiosError<T>
if (axiosError.response) {
return axiosError.response
}
throw error
}
}
try {
return await axiosClient.request(requestConfig);
} catch (error) {
const axiosError = error as AxiosError<T>;
if (axiosError.response) {
return axiosError.response;
}
throw error;
}
};
export const getResponseHeader = (
response: AxiosResponse<unknown>,
responseHeader?: string,
): string | undefined => {
if (responseHeader) {
const content = response.headers[responseHeader]
if (isString(content)) {
return content
}
}
return undefined
}
export const getResponseHeader = (response: AxiosResponse<unknown>, responseHeader?: string): string | undefined => {
if (responseHeader) {
const content = response.headers[responseHeader];
if (isString(content)) {
return content;
}
}
return undefined;
};
export const getResponseBody = (response: AxiosResponse<unknown>): unknown => {
if (response.status !== 204) {
return response.data
}
return undefined
}
if (response.status !== 204) {
return response.data;
}
return undefined;
};
export const catchErrorCodes = (
options: ApiRequestOptions,
result: ApiResult,
): void => {
const errors: Record<number, string> = {
400: "Bad Request",
401: "Unauthorized",
402: "Payment Required",
403: "Forbidden",
404: "Not Found",
405: "Method Not Allowed",
406: "Not Acceptable",
407: "Proxy Authentication Required",
408: "Request Timeout",
409: "Conflict",
410: "Gone",
411: "Length Required",
412: "Precondition Failed",
413: "Payload Too Large",
414: "URI Too Long",
415: "Unsupported Media Type",
416: "Range Not Satisfiable",
417: "Expectation Failed",
418: "Im a teapot",
421: "Misdirected Request",
422: "Unprocessable Content",
423: "Locked",
424: "Failed Dependency",
425: "Too Early",
426: "Upgrade Required",
428: "Precondition Required",
429: "Too Many Requests",
431: "Request Header Fields Too Large",
451: "Unavailable For Legal Reasons",
500: "Internal Server Error",
501: "Not Implemented",
502: "Bad Gateway",
503: "Service Unavailable",
504: "Gateway Timeout",
505: "HTTP Version Not Supported",
506: "Variant Also Negotiates",
507: "Insufficient Storage",
508: "Loop Detected",
510: "Not Extended",
511: "Network Authentication Required",
...options.errors,
}
export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => {
const errors: Record<number, string> = {
400: 'Bad Request',
401: 'Unauthorized',
402: 'Payment Required',
403: 'Forbidden',
404: 'Not Found',
405: 'Method Not Allowed',
406: 'Not Acceptable',
407: 'Proxy Authentication Required',
408: 'Request Timeout',
409: 'Conflict',
410: 'Gone',
411: 'Length Required',
412: 'Precondition Failed',
413: 'Payload Too Large',
414: 'URI Too Long',
415: 'Unsupported Media Type',
416: 'Range Not Satisfiable',
417: 'Expectation Failed',
418: 'Im a teapot',
421: 'Misdirected Request',
422: 'Unprocessable Content',
423: 'Locked',
424: 'Failed Dependency',
425: 'Too Early',
426: 'Upgrade Required',
428: 'Precondition Required',
429: 'Too Many Requests',
431: 'Request Header Fields Too Large',
451: 'Unavailable For Legal Reasons',
500: 'Internal Server Error',
501: 'Not Implemented',
502: 'Bad Gateway',
503: 'Service Unavailable',
504: 'Gateway Timeout',
505: 'HTTP Version Not Supported',
506: 'Variant Also Negotiates',
507: 'Insufficient Storage',
508: 'Loop Detected',
510: 'Not Extended',
511: 'Network Authentication Required',
...options.errors,
}
const error = errors[result.status]
if (error) {
throw new ApiError(options, result, error)
}
const error = errors[result.status];
if (error) {
throw new ApiError(options, result, error);
}
if (!result.ok) {
const errorStatus = result.status ?? "unknown"
const errorStatusText = result.statusText ?? "unknown"
const errorBody = (() => {
try {
return JSON.stringify(result.body, null, 2)
} catch (e) {
return undefined
}
})()
if (!result.ok) {
const errorStatus = result.status ?? 'unknown';
const errorStatusText = result.statusText ?? 'unknown';
const errorBody = (() => {
try {
return JSON.stringify(result.body, null, 2);
} catch (e) {
return undefined;
}
})();
throw new ApiError(
options,
result,
`Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`,
)
}
}
throw new ApiError(options, result,
`Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`
);
}
};
/**
* Request method
@@ -329,59 +305,43 @@ export const catchErrorCodes = (
* @returns CancelablePromise<T>
* @throws ApiError
*/
export const request = <T>(
config: OpenAPIConfig,
options: ApiRequestOptions<T>,
axiosClient: AxiosInstance = axios,
): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(config, options)
const formData = getFormData(options)
const body = getRequestBody(options)
const headers = await getHeaders(config, options)
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions<T>, axiosClient: AxiosInstance = axios): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(config, options);
if (!onCancel.isCancelled) {
let response = await sendRequest<T>(
config,
options,
url,
body,
formData,
headers,
onCancel,
axiosClient,
)
if (!onCancel.isCancelled) {
let response = await sendRequest<T>(config, options, url, body, formData, headers, onCancel, axiosClient);
for (const fn of config.interceptors.response._fns) {
response = await fn(response)
}
for (const fn of config.interceptors.response._fns) {
response = await fn(response);
}
const responseBody = getResponseBody(response)
const responseHeader = getResponseHeader(
response,
options.responseHeader,
)
const responseBody = getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);
let transformedBody = responseBody
if (options.responseTransformer && isSuccess(response.status)) {
transformedBody = await options.responseTransformer(responseBody)
}
let transformedBody = responseBody;
if (options.responseTransformer && isSuccess(response.status)) {
transformedBody = await options.responseTransformer(responseBody)
}
const result: ApiResult = {
url,
ok: isSuccess(response.status),
status: response.status,
statusText: response.statusText,
body: responseHeader ?? transformedBody,
}
const result: ApiResult = {
url,
ok: isSuccess(response.status),
status: response.status,
statusText: response.statusText,
body: responseHeader ?? transformedBody,
};
catchErrorCodes(options, result)
catchErrorCodes(options, result);
resolve(result.body)
}
} catch (error) {
reject(error)
}
})
}
resolve(result.body);
}
} catch (error) {
reject(error);
}
});
};

View File

@@ -1,6 +1,6 @@
// This file is auto-generated by @hey-api/openapi-ts
export { ApiError } from "./core/ApiError"
export { CancelablePromise, CancelError } from "./core/CancelablePromise"
export { OpenAPI, type OpenAPIConfig } from "./core/OpenAPI"
export * from "./sdk.gen"
export * from "./types.gen"
export { ApiError } from './core/ApiError';
export { CancelablePromise, CancelError } from './core/CancelablePromise';
export { OpenAPI, type OpenAPIConfig } from './core/OpenAPI';
export * from './sdk.gen';
export * from './types.gen';

View File

@@ -1,526 +1,526 @@
// This file is auto-generated by @hey-api/openapi-ts
export const Body_login_login_access_tokenSchema = {
properties: {
grant_type: {
anyOf: [
{
type: "string",
pattern: "password",
properties: {
grant_type: {
anyOf: [
{
type: 'string',
pattern: 'password'
},
{
type: 'null'
}
],
title: 'Grant Type'
},
{
type: "null",
username: {
type: 'string',
title: 'Username'
},
],
title: "Grant Type",
},
username: {
type: "string",
title: "Username",
},
password: {
type: "string",
title: "Password",
},
scope: {
type: "string",
title: "Scope",
default: "",
},
client_id: {
anyOf: [
{
type: "string",
password: {
type: 'string',
title: 'Password'
},
{
type: "null",
scope: {
type: 'string',
title: 'Scope',
default: ''
},
],
title: "Client Id",
client_id: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Client Id'
},
client_secret: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Client Secret'
}
},
client_secret: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Client Secret",
},
},
type: "object",
required: ["username", "password"],
title: "Body_login-login_access_token",
} as const
type: 'object',
required: ['username', 'password'],
title: 'Body_login-login_access_token'
} as const;
export const HTTPValidationErrorSchema = {
properties: {
detail: {
items: {
$ref: "#/components/schemas/ValidationError",
},
type: "array",
title: "Detail",
properties: {
detail: {
items: {
'$ref': '#/components/schemas/ValidationError'
},
type: 'array',
title: 'Detail'
}
},
},
type: "object",
title: "HTTPValidationError",
} as const
type: 'object',
title: 'HTTPValidationError'
} as const;
export const ItemCreateSchema = {
properties: {
title: {
type: "string",
maxLength: 255,
minLength: 1,
title: "Title",
},
description: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
title: {
type: 'string',
maxLength: 255,
minLength: 1,
title: 'Title'
},
{
type: "null",
},
],
title: "Description",
description: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Description'
}
},
},
type: "object",
required: ["title"],
title: "ItemCreate",
} as const
type: 'object',
required: ['title'],
title: 'ItemCreate'
} as const;
export const ItemPublicSchema = {
properties: {
title: {
type: "string",
maxLength: 255,
minLength: 1,
title: "Title",
},
description: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
title: {
type: 'string',
maxLength: 255,
minLength: 1,
title: 'Title'
},
{
type: "null",
description: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Description'
},
],
title: "Description",
id: {
type: 'string',
format: 'uuid',
title: 'Id'
},
owner_id: {
type: 'string',
format: 'uuid',
title: 'Owner Id'
}
},
id: {
type: "string",
format: "uuid",
title: "Id",
},
owner_id: {
type: "string",
format: "uuid",
title: "Owner Id",
},
},
type: "object",
required: ["title", "id", "owner_id"],
title: "ItemPublic",
} as const
type: 'object',
required: ['title', 'id', 'owner_id'],
title: 'ItemPublic'
} as const;
export const ItemUpdateSchema = {
properties: {
title: {
anyOf: [
{
type: "string",
maxLength: 255,
minLength: 1,
properties: {
title: {
anyOf: [
{
type: 'string',
maxLength: 255,
minLength: 1
},
{
type: 'null'
}
],
title: 'Title'
},
{
type: "null",
},
],
title: "Title",
description: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Description'
}
},
description: {
anyOf: [
{
type: "string",
maxLength: 255,
},
{
type: "null",
},
],
title: "Description",
},
},
type: "object",
title: "ItemUpdate",
} as const
type: 'object',
title: 'ItemUpdate'
} as const;
export const ItemsPublicSchema = {
properties: {
data: {
items: {
$ref: "#/components/schemas/ItemPublic",
},
type: "array",
title: "Data",
properties: {
data: {
items: {
'$ref': '#/components/schemas/ItemPublic'
},
type: 'array',
title: 'Data'
},
count: {
type: 'integer',
title: 'Count'
}
},
count: {
type: "integer",
title: "Count",
},
},
type: "object",
required: ["data", "count"],
title: "ItemsPublic",
} as const
type: 'object',
required: ['data', 'count'],
title: 'ItemsPublic'
} as const;
export const MessageSchema = {
properties: {
message: {
type: "string",
title: "Message",
properties: {
message: {
type: 'string',
title: 'Message'
}
},
},
type: "object",
required: ["message"],
title: "Message",
} as const
type: 'object',
required: ['message'],
title: 'Message'
} as const;
export const NewPasswordSchema = {
properties: {
token: {
type: "string",
title: "Token",
properties: {
token: {
type: 'string',
title: 'Token'
},
new_password: {
type: 'string',
maxLength: 40,
minLength: 8,
title: 'New Password'
}
},
new_password: {
type: "string",
maxLength: 40,
minLength: 8,
title: "New Password",
},
},
type: "object",
required: ["token", "new_password"],
title: "NewPassword",
} as const
type: 'object',
required: ['token', 'new_password'],
title: 'NewPassword'
} as const;
export const PrivateUserCreateSchema = {
properties: {
email: {
type: "string",
title: "Email",
properties: {
email: {
type: 'string',
title: 'Email'
},
password: {
type: 'string',
title: 'Password'
},
full_name: {
type: 'string',
title: 'Full Name'
},
is_verified: {
type: 'boolean',
title: 'Is Verified',
default: false
}
},
password: {
type: "string",
title: "Password",
},
full_name: {
type: "string",
title: "Full Name",
},
is_verified: {
type: "boolean",
title: "Is Verified",
default: false,
},
},
type: "object",
required: ["email", "password", "full_name"],
title: "PrivateUserCreate",
} as const
type: 'object',
required: ['email', 'password', 'full_name'],
title: 'PrivateUserCreate'
} as const;
export const TokenSchema = {
properties: {
access_token: {
type: "string",
title: "Access Token",
properties: {
access_token: {
type: 'string',
title: 'Access Token'
},
token_type: {
type: 'string',
title: 'Token Type',
default: 'bearer'
}
},
token_type: {
type: "string",
title: "Token Type",
default: "bearer",
},
},
type: "object",
required: ["access_token"],
title: "Token",
} as const
type: 'object',
required: ['access_token'],
title: 'Token'
} as const;
export const UpdatePasswordSchema = {
properties: {
current_password: {
type: "string",
maxLength: 40,
minLength: 8,
title: "Current Password",
properties: {
current_password: {
type: 'string',
maxLength: 40,
minLength: 8,
title: 'Current Password'
},
new_password: {
type: 'string',
maxLength: 40,
minLength: 8,
title: 'New Password'
}
},
new_password: {
type: "string",
maxLength: 40,
minLength: 8,
title: "New Password",
},
},
type: "object",
required: ["current_password", "new_password"],
title: "UpdatePassword",
} as const
type: 'object',
required: ['current_password', 'new_password'],
title: 'UpdatePassword'
} as const;
export const UserCreateSchema = {
properties: {
email: {
type: "string",
maxLength: 255,
format: "email",
title: "Email",
},
is_active: {
type: "boolean",
title: "Is Active",
default: true,
},
is_superuser: {
type: "boolean",
title: "Is Superuser",
default: false,
},
full_name: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
email: {
type: 'string',
maxLength: 255,
format: 'email',
title: 'Email'
},
{
type: "null",
is_active: {
type: 'boolean',
title: 'Is Active',
default: true
},
],
title: "Full Name",
is_superuser: {
type: 'boolean',
title: 'Is Superuser',
default: false
},
full_name: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Full Name'
},
password: {
type: 'string',
maxLength: 40,
minLength: 8,
title: 'Password'
}
},
password: {
type: "string",
maxLength: 40,
minLength: 8,
title: "Password",
},
},
type: "object",
required: ["email", "password"],
title: "UserCreate",
} as const
type: 'object',
required: ['email', 'password'],
title: 'UserCreate'
} as const;
export const UserPublicSchema = {
properties: {
email: {
type: "string",
maxLength: 255,
format: "email",
title: "Email",
},
is_active: {
type: "boolean",
title: "Is Active",
default: true,
},
is_superuser: {
type: "boolean",
title: "Is Superuser",
default: false,
},
full_name: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
email: {
type: 'string',
maxLength: 255,
format: 'email',
title: 'Email'
},
{
type: "null",
is_active: {
type: 'boolean',
title: 'Is Active',
default: true
},
],
title: "Full Name",
is_superuser: {
type: 'boolean',
title: 'Is Superuser',
default: false
},
full_name: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Full Name'
},
id: {
type: 'string',
format: 'uuid',
title: 'Id'
}
},
id: {
type: "string",
format: "uuid",
title: "Id",
},
},
type: "object",
required: ["email", "id"],
title: "UserPublic",
} as const
type: 'object',
required: ['email', 'id'],
title: 'UserPublic'
} as const;
export const UserRegisterSchema = {
properties: {
email: {
type: "string",
maxLength: 255,
format: "email",
title: "Email",
},
password: {
type: "string",
maxLength: 40,
minLength: 8,
title: "Password",
},
full_name: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
email: {
type: 'string',
maxLength: 255,
format: 'email',
title: 'Email'
},
{
type: "null",
password: {
type: 'string',
maxLength: 40,
minLength: 8,
title: 'Password'
},
],
title: "Full Name",
full_name: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Full Name'
}
},
},
type: "object",
required: ["email", "password"],
title: "UserRegister",
} as const
type: 'object',
required: ['email', 'password'],
title: 'UserRegister'
} as const;
export const UserUpdateSchema = {
properties: {
email: {
anyOf: [
{
type: "string",
maxLength: 255,
format: "email",
properties: {
email: {
anyOf: [
{
type: 'string',
maxLength: 255,
format: 'email'
},
{
type: 'null'
}
],
title: 'Email'
},
{
type: "null",
is_active: {
type: 'boolean',
title: 'Is Active',
default: true
},
],
title: "Email",
is_superuser: {
type: 'boolean',
title: 'Is Superuser',
default: false
},
full_name: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Full Name'
},
password: {
anyOf: [
{
type: 'string',
maxLength: 40,
minLength: 8
},
{
type: 'null'
}
],
title: 'Password'
}
},
is_active: {
type: "boolean",
title: "Is Active",
default: true,
},
is_superuser: {
type: "boolean",
title: "Is Superuser",
default: false,
},
full_name: {
anyOf: [
{
type: "string",
maxLength: 255,
},
{
type: "null",
},
],
title: "Full Name",
},
password: {
anyOf: [
{
type: "string",
maxLength: 40,
minLength: 8,
},
{
type: "null",
},
],
title: "Password",
},
},
type: "object",
title: "UserUpdate",
} as const
type: 'object',
title: 'UserUpdate'
} as const;
export const UserUpdateMeSchema = {
properties: {
full_name: {
anyOf: [
{
type: "string",
maxLength: 255,
properties: {
full_name: {
anyOf: [
{
type: 'string',
maxLength: 255
},
{
type: 'null'
}
],
title: 'Full Name'
},
{
type: "null",
},
],
title: "Full Name",
email: {
anyOf: [
{
type: 'string',
maxLength: 255,
format: 'email'
},
{
type: 'null'
}
],
title: 'Email'
}
},
email: {
anyOf: [
{
type: "string",
maxLength: 255,
format: "email",
},
{
type: "null",
},
],
title: "Email",
},
},
type: "object",
title: "UserUpdateMe",
} as const
type: 'object',
title: 'UserUpdateMe'
} as const;
export const UsersPublicSchema = {
properties: {
data: {
items: {
$ref: "#/components/schemas/UserPublic",
},
type: "array",
title: "Data",
properties: {
data: {
items: {
'$ref': '#/components/schemas/UserPublic'
},
type: 'array',
title: 'Data'
},
count: {
type: 'integer',
title: 'Count'
}
},
count: {
type: "integer",
title: "Count",
},
},
type: "object",
required: ["data", "count"],
title: "UsersPublic",
} as const
type: 'object',
required: ['data', 'count'],
title: 'UsersPublic'
} as const;
export const ValidationErrorSchema = {
properties: {
loc: {
items: {
anyOf: [
{
type: "string",
},
{
type: "integer",
},
],
},
type: "array",
title: "Location",
properties: {
loc: {
items: {
anyOf: [
{
type: 'string'
},
{
type: 'integer'
}
]
},
type: 'array',
title: 'Location'
},
msg: {
type: 'string',
title: 'Message'
},
type: {
type: 'string',
title: 'Error Type'
}
},
msg: {
type: "string",
title: "Message",
},
type: {
type: "string",
title: "Error Type",
},
},
type: "object",
required: ["loc", "msg", "type"],
title: "ValidationError",
} as const
type: 'object',
required: ['loc', 'msg', 'type'],
title: 'ValidationError'
} as const;

File diff suppressed because it is too large Load Diff

View File

@@ -1,234 +1,234 @@
// This file is auto-generated by @hey-api/openapi-ts
export type Body_login_login_access_token = {
grant_type?: string | null
username: string
password: string
scope?: string
client_id?: string | null
client_secret?: string | null
}
grant_type?: (string | null);
username: string;
password: string;
scope?: string;
client_id?: (string | null);
client_secret?: (string | null);
};
export type HTTPValidationError = {
detail?: Array<ValidationError>
}
detail?: Array<ValidationError>;
};
export type ItemCreate = {
title: string
description?: string | null
}
title: string;
description?: (string | null);
};
export type ItemPublic = {
title: string
description?: string | null
id: string
owner_id: string
}
title: string;
description?: (string | null);
id: string;
owner_id: string;
};
export type ItemsPublic = {
data: Array<ItemPublic>
count: number
}
data: Array<ItemPublic>;
count: number;
};
export type ItemUpdate = {
title?: string | null
description?: string | null
}
title?: (string | null);
description?: (string | null);
};
export type Message = {
message: string
}
message: string;
};
export type NewPassword = {
token: string
new_password: string
}
token: string;
new_password: string;
};
export type PrivateUserCreate = {
email: string
password: string
full_name: string
is_verified?: boolean
}
email: string;
password: string;
full_name: string;
is_verified?: boolean;
};
export type Token = {
access_token: string
token_type?: string
}
access_token: string;
token_type?: string;
};
export type UpdatePassword = {
current_password: string
new_password: string
}
current_password: string;
new_password: string;
};
export type UserCreate = {
email: string
is_active?: boolean
is_superuser?: boolean
full_name?: string | null
password: string
}
email: string;
is_active?: boolean;
is_superuser?: boolean;
full_name?: (string | null);
password: string;
};
export type UserPublic = {
email: string
is_active?: boolean
is_superuser?: boolean
full_name?: string | null
id: string
}
email: string;
is_active?: boolean;
is_superuser?: boolean;
full_name?: (string | null);
id: string;
};
export type UserRegister = {
email: string
password: string
full_name?: string | null
}
email: string;
password: string;
full_name?: (string | null);
};
export type UsersPublic = {
data: Array<UserPublic>
count: number
}
data: Array<UserPublic>;
count: number;
};
export type UserUpdate = {
email?: string | null
is_active?: boolean
is_superuser?: boolean
full_name?: string | null
password?: string | null
}
email?: (string | null);
is_active?: boolean;
is_superuser?: boolean;
full_name?: (string | null);
password?: (string | null);
};
export type UserUpdateMe = {
full_name?: string | null
email?: string | null
}
full_name?: (string | null);
email?: (string | null);
};
export type ValidationError = {
loc: Array<string | number>
msg: string
type: string
}
loc: Array<(string | number)>;
msg: string;
type: string;
};
export type ItemsReadItemsData = {
limit?: number
skip?: number
}
limit?: number;
skip?: number;
};
export type ItemsReadItemsResponse = ItemsPublic
export type ItemsReadItemsResponse = (ItemsPublic);
export type ItemsCreateItemData = {
requestBody: ItemCreate
}
requestBody: ItemCreate;
};
export type ItemsCreateItemResponse = ItemPublic
export type ItemsCreateItemResponse = (ItemPublic);
export type ItemsReadItemData = {
id: string
}
id: string;
};
export type ItemsReadItemResponse = ItemPublic
export type ItemsReadItemResponse = (ItemPublic);
export type ItemsUpdateItemData = {
id: string
requestBody: ItemUpdate
}
id: string;
requestBody: ItemUpdate;
};
export type ItemsUpdateItemResponse = ItemPublic
export type ItemsUpdateItemResponse = (ItemPublic);
export type ItemsDeleteItemData = {
id: string
}
id: string;
};
export type ItemsDeleteItemResponse = Message
export type ItemsDeleteItemResponse = (Message);
export type LoginLoginAccessTokenData = {
formData: Body_login_login_access_token
}
formData: Body_login_login_access_token;
};
export type LoginLoginAccessTokenResponse = Token
export type LoginLoginAccessTokenResponse = (Token);
export type LoginTestTokenResponse = UserPublic
export type LoginTestTokenResponse = (UserPublic);
export type LoginRecoverPasswordData = {
email: string
}
email: string;
};
export type LoginRecoverPasswordResponse = Message
export type LoginRecoverPasswordResponse = (Message);
export type LoginResetPasswordData = {
requestBody: NewPassword
}
requestBody: NewPassword;
};
export type LoginResetPasswordResponse = Message
export type LoginResetPasswordResponse = (Message);
export type LoginRecoverPasswordHtmlContentData = {
email: string
}
email: string;
};
export type LoginRecoverPasswordHtmlContentResponse = string
export type LoginRecoverPasswordHtmlContentResponse = (string);
export type PrivateCreateUserData = {
requestBody: PrivateUserCreate
}
requestBody: PrivateUserCreate;
};
export type PrivateCreateUserResponse = UserPublic
export type PrivateCreateUserResponse = (UserPublic);
export type UsersReadUsersData = {
limit?: number
skip?: number
}
limit?: number;
skip?: number;
};
export type UsersReadUsersResponse = UsersPublic
export type UsersReadUsersResponse = (UsersPublic);
export type UsersCreateUserData = {
requestBody: UserCreate
}
requestBody: UserCreate;
};
export type UsersCreateUserResponse = UserPublic
export type UsersCreateUserResponse = (UserPublic);
export type UsersReadUserMeResponse = UserPublic
export type UsersReadUserMeResponse = (UserPublic);
export type UsersDeleteUserMeResponse = Message
export type UsersDeleteUserMeResponse = (Message);
export type UsersUpdateUserMeData = {
requestBody: UserUpdateMe
}
requestBody: UserUpdateMe;
};
export type UsersUpdateUserMeResponse = UserPublic
export type UsersUpdateUserMeResponse = (UserPublic);
export type UsersUpdatePasswordMeData = {
requestBody: UpdatePassword
}
requestBody: UpdatePassword;
};
export type UsersUpdatePasswordMeResponse = Message
export type UsersUpdatePasswordMeResponse = (Message);
export type UsersRegisterUserData = {
requestBody: UserRegister
}
requestBody: UserRegister;
};
export type UsersRegisterUserResponse = UserPublic
export type UsersRegisterUserResponse = (UserPublic);
export type UsersReadUserByIdData = {
userId: string
}
userId: string;
};
export type UsersReadUserByIdResponse = UserPublic
export type UsersReadUserByIdResponse = (UserPublic);
export type UsersUpdateUserData = {
requestBody: UserUpdate
userId: string
}
requestBody: UserUpdate;
userId: string;
};
export type UsersUpdateUserResponse = UserPublic
export type UsersUpdateUserResponse = (UserPublic);
export type UsersDeleteUserData = {
userId: string
}
userId: string;
};
export type UsersDeleteUserResponse = Message
export type UsersDeleteUserResponse = (Message);
export type UtilsTestEmailData = {
emailTo: string
}
emailTo: string;
};
export type UtilsTestEmailResponse = Message
export type UtilsTestEmailResponse = (Message);
export type UtilsHealthCheckResponse = boolean
export type UtilsHealthCheckResponse = (boolean);

View File

@@ -1,10 +1,3 @@
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { Controller, type SubmitHandler, useForm } from "react-hook-form"
import { type UserCreate, UsersService } from "@/client"
import type { ApiError } from "@/client/core/ApiError"
import useCustomToast from "@/hooks/useCustomToast"
import { emailPattern, handleError } from "@/utils"
import {
Button,
DialogActionTrigger,
@@ -14,8 +7,14 @@ import {
Text,
VStack,
} from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { useState } from "react"
import { Controller, type SubmitHandler, useForm } from "react-hook-form"
import { FaPlus } from "react-icons/fa"
import { type UserCreate, UsersService } from "@/client"
import type { ApiError } from "@/client/core/ApiError"
import useCustomToast from "@/hooks/useCustomToast"
import { emailPattern, handleError } from "@/utils"
import { Checkbox } from "../ui/checkbox"
import {
DialogBody,
@@ -106,7 +105,6 @@ const AddUser = () => {
label="Email"
>
<Input
id="email"
{...register("email", {
required: "Email is required",
pattern: emailPattern,
@@ -122,7 +120,6 @@ const AddUser = () => {
label="Full Name"
>
<Input
id="name"
{...register("full_name")}
placeholder="Full name"
type="text"
@@ -136,7 +133,6 @@ const AddUser = () => {
label="Set Password"
>
<Input
id="password"
{...register("password", {
required: "Password is required",
minLength: {
@@ -156,7 +152,6 @@ const AddUser = () => {
label="Confirm Password"
>
<Input
id="confirm_password"
{...register("confirm_password", {
required: "Please confirm your password",
validate: (value) =>

View File

@@ -1,6 +1,3 @@
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { Controller, type SubmitHandler, useForm } from "react-hook-form"
import {
Button,
DialogActionTrigger,
@@ -11,10 +8,12 @@ import {
Text,
VStack,
} from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { useState } from "react"
import { Controller, type SubmitHandler, useForm } from "react-hook-form"
import { FaExchangeAlt } from "react-icons/fa"
import { type UserPublic, type UserUpdate, UsersService } from "@/client"
import { type UserPublic, UsersService, type UserUpdate } from "@/client"
import type { ApiError } from "@/client/core/ApiError"
import useCustomToast from "@/hooks/useCustomToast"
import { emailPattern, handleError } from "@/utils"
@@ -105,7 +104,6 @@ const EditUser = ({ user }: EditUserProps) => {
label="Email"
>
<Input
id="email"
{...register("email", {
required: "Email is required",
pattern: emailPattern,
@@ -121,7 +119,6 @@ const EditUser = ({ user }: EditUserProps) => {
label="Full Name"
>
<Input
id="name"
{...register("full_name")}
placeholder="Full name"
type="text"
@@ -134,7 +131,6 @@ const EditUser = ({ user }: EditUserProps) => {
label="Set Password"
>
<Input
id="password"
{...register("password", {
minLength: {
value: 8,
@@ -152,7 +148,6 @@ const EditUser = ({ user }: EditUserProps) => {
label="Confirm Password"
>
<Input
id="confirm_password"
{...register("confirm_password", {
validate: (value) =>
value === getValues().password ||

View File

@@ -1,10 +1,9 @@
import { IconButton } from "@chakra-ui/react"
import { BsThreeDotsVertical } from "react-icons/bs"
import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu"
import type { ItemPublic } from "@/client"
import DeleteItem from "../Items/DeleteItem"
import EditItem from "../Items/EditItem"
import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu"
interface ItemActionsMenuProps {
item: ItemPublic

View File

@@ -3,54 +3,41 @@ import { Link } from "@tanstack/react-router"
const NotFound = () => {
return (
<>
<Flex
height="100vh"
align="center"
justify="center"
flexDir="column"
data-testid="not-found"
p={4}
>
<Flex alignItems="center" zIndex={1}>
<Flex flexDir="column" ml={4} align="center" justify="center" p={4}>
<Text
fontSize={{ base: "6xl", md: "8xl" }}
fontWeight="bold"
lineHeight="1"
mb={4}
>
404
</Text>
<Text fontSize="2xl" fontWeight="bold" mb={2}>
Oops!
</Text>
</Flex>
<Flex
height="100vh"
align="center"
justify="center"
flexDir="column"
data-testid="not-found"
p={4}
>
<Flex alignItems="center" zIndex={1}>
<Flex flexDir="column" ml={4} align="center" justify="center" p={4}>
<Text
fontSize={{ base: "6xl", md: "8xl" }}
fontWeight="bold"
lineHeight="1"
mb={4}
>
404
</Text>
<Text fontSize="2xl" fontWeight="bold" mb={2}>
Oops!
</Text>
</Flex>
<Text
fontSize="lg"
color="gray.600"
mb={4}
textAlign="center"
zIndex={1}
>
The page you are looking for was not found.
</Text>
<Center zIndex={1}>
<Link to="/">
<Button
variant="solid"
colorScheme="teal"
mt={4}
alignSelf="center"
>
Go Back
</Button>
</Link>
</Center>
</Flex>
</>
<Text fontSize="lg" color="gray.600" mb={4} textAlign="center" zIndex={1}>
The page you are looking for was not found.
</Text>
<Center zIndex={1}>
<Link to="/">
<Button variant="solid" colorScheme="teal" mt={4} alignSelf="center">
Go Back
</Button>
</Link>
</Center>
</Flex>
)
}

View File

@@ -1,10 +1,9 @@
import { IconButton } from "@chakra-ui/react"
import { BsThreeDotsVertical } from "react-icons/bs"
import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu"
import type { UserPublic } from "@/client"
import DeleteUser from "../Admin/DeleteUser"
import EditUser from "../Admin/EditUser"
import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu"
interface UserActionsMenuProps {
user: UserPublic

View File

@@ -1,6 +1,3 @@
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { type SubmitHandler, useForm } from "react-hook-form"
import {
Button,
DialogActionTrigger,
@@ -9,7 +6,9 @@ import {
Text,
VStack,
} from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { useState } from "react"
import { type SubmitHandler, useForm } from "react-hook-form"
import { FaPlus } from "react-icons/fa"
import { type ItemCreate, ItemsService } from "@/client"
@@ -93,7 +92,6 @@ const AddItem = () => {
label="Title"
>
<Input
id="title"
{...register("title", {
required: "Title is required.",
})}
@@ -108,7 +106,6 @@ const AddItem = () => {
label="Description"
>
<Input
id="description"
{...register("description")}
placeholder="Description"
type="text"

View File

@@ -101,7 +101,6 @@ const EditItem = ({ item }: EditItemProps) => {
label="Title"
>
<Input
id="title"
{...register("title", {
required: "Title is required",
})}
@@ -116,7 +115,6 @@ const EditItem = ({ item }: EditItemProps) => {
label="Description"
>
<Input
id="description"
{...register("description")}
placeholder="Description"
type="text"

View File

@@ -7,25 +7,23 @@ const Appearance = () => {
const { theme, setTheme } = useTheme()
return (
<>
<Container maxW="full">
<Heading size="sm" py={4}>
Appearance
</Heading>
<Container maxW="full">
<Heading size="sm" py={4}>
Appearance
</Heading>
<RadioGroup
onValueChange={(e) => setTheme(e.value ?? "system")}
value={theme}
colorPalette="teal"
>
<Stack>
<Radio value="system">System</Radio>
<Radio value="light">Light Mode</Radio>
<Radio value="dark">Dark Mode</Radio>
</Stack>
</RadioGroup>
</Container>
</>
<RadioGroup
onValueChange={(e) => setTheme(e.value ?? "system")}
value={theme}
colorPalette="teal"
>
<Stack>
<Radio value="system">System</Radio>
<Radio value="light">Light Mode</Radio>
<Radio value="dark">Dark Mode</Radio>
</Stack>
</RadioGroup>
</Container>
)
}
export default Appearance

View File

@@ -42,46 +42,39 @@ const ChangePassword = () => {
}
return (
<>
<Container maxW="full">
<Heading size="sm" py={4}>
Change Password
</Heading>
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<VStack gap={4} w={{ base: "100%", md: "sm" }}>
<PasswordInput
type="current_password"
startElement={<FiLock />}
{...register("current_password", passwordRules())}
placeholder="Current Password"
errors={errors}
/>
<PasswordInput
type="new_password"
startElement={<FiLock />}
{...register("new_password", passwordRules())}
placeholder="New Password"
errors={errors}
/>
<PasswordInput
type="confirm_password"
startElement={<FiLock />}
{...register("confirm_password", confirmPasswordRules(getValues))}
placeholder="Confirm Password"
errors={errors}
/>
</VStack>
<Button
variant="solid"
mt={4}
type="submit"
loading={isSubmitting}
>
Save
</Button>
</Box>
</Container>
</>
<Container maxW="full">
<Heading size="sm" py={4}>
Change Password
</Heading>
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<VStack gap={4} w={{ base: "100%", md: "sm" }}>
<PasswordInput
type="current_password"
startElement={<FiLock />}
{...register("current_password", passwordRules())}
placeholder="Current Password"
errors={errors}
/>
<PasswordInput
type="new_password"
startElement={<FiLock />}
{...register("new_password", passwordRules())}
placeholder="New Password"
errors={errors}
/>
<PasswordInput
type="confirm_password"
startElement={<FiLock />}
{...register("confirm_password", confirmPasswordRules(getValues))}
placeholder="Confirm Password"
errors={errors}
/>
</VStack>
<Button variant="solid" mt={4} type="submit" loading={isSubmitting}>
Save
</Button>
</Box>
</Container>
)
}
export default ChangePassword

View File

@@ -49,60 +49,58 @@ const DeleteConfirmation = () => {
}
return (
<>
<DialogRoot
size={{ base: "xs", md: "md" }}
role="alertdialog"
placement="center"
open={isOpen}
onOpenChange={({ open }) => setIsOpen(open)}
>
<DialogTrigger asChild>
<Button variant="solid" colorPalette="red" mt={4}>
Delete
</Button>
</DialogTrigger>
<DialogRoot
size={{ base: "xs", md: "md" }}
role="alertdialog"
placement="center"
open={isOpen}
onOpenChange={({ open }) => setIsOpen(open)}
>
<DialogTrigger asChild>
<Button variant="solid" colorPalette="red" mt={4}>
Delete
</Button>
</DialogTrigger>
<DialogContent>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogCloseTrigger />
<DialogHeader>
<DialogTitle>Confirmation Required</DialogTitle>
</DialogHeader>
<DialogBody>
<Text mb={4}>
All your account data will be{" "}
<strong>permanently deleted.</strong> If you are sure, please
click <strong>"Confirm"</strong> to proceed. This action cannot
be undone.
</Text>
</DialogBody>
<DialogContent>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogCloseTrigger />
<DialogHeader>
<DialogTitle>Confirmation Required</DialogTitle>
</DialogHeader>
<DialogBody>
<Text mb={4}>
All your account data will be{" "}
<strong>permanently deleted.</strong> If you are sure, please
click <strong>"Confirm"</strong> to proceed. This action cannot be
undone.
</Text>
</DialogBody>
<DialogFooter gap={2}>
<ButtonGroup>
<DialogActionTrigger asChild>
<Button
variant="subtle"
colorPalette="gray"
disabled={isSubmitting}
>
Cancel
</Button>
</DialogActionTrigger>
<DialogFooter gap={2}>
<ButtonGroup>
<DialogActionTrigger asChild>
<Button
variant="solid"
colorPalette="red"
type="submit"
loading={isSubmitting}
variant="subtle"
colorPalette="gray"
disabled={isSubmitting}
>
Delete
Cancel
</Button>
</ButtonGroup>
</DialogFooter>
</form>
</DialogContent>
</DialogRoot>
</>
</DialogActionTrigger>
<Button
variant="solid"
colorPalette="red"
type="submit"
loading={isSubmitting}
>
Delete
</Button>
</ButtonGroup>
</DialogFooter>
</form>
</DialogContent>
</DialogRoot>
)
}

View File

@@ -14,8 +14,8 @@ import { type SubmitHandler, useForm } from "react-hook-form"
import {
type ApiError,
type UserPublic,
type UserUpdateMe,
UsersService,
type UserUpdateMe,
} from "@/client"
import useAuth from "@/hooks/useAuth"
import useCustomToast from "@/hooks/useCustomToast"
@@ -70,80 +70,78 @@ const UserInformation = () => {
}
return (
<>
<Container maxW="full">
<Heading size="sm" py={4}>
User Information
</Heading>
<Box
w={{ sm: "full", md: "sm" }}
as="form"
onSubmit={handleSubmit(onSubmit)}
>
<Field label="Full name">
{editMode ? (
<Input
{...register("full_name", { maxLength: 30 })}
type="text"
size="md"
/>
) : (
<Text
fontSize="md"
py={2}
color={!currentUser?.full_name ? "gray" : "inherit"}
truncate
maxW="sm"
>
{currentUser?.full_name || "N/A"}
</Text>
)}
</Field>
<Field
mt={4}
label="Email"
invalid={!!errors.email}
errorText={errors.email?.message}
>
{editMode ? (
<Input
{...register("email", {
required: "Email is required",
pattern: emailPattern,
})}
type="email"
size="md"
/>
) : (
<Text fontSize="md" py={2} truncate maxW="sm">
{currentUser?.email}
</Text>
)}
</Field>
<Flex mt={4} gap={3}>
<Button
variant="solid"
onClick={toggleEditMode}
type={editMode ? "button" : "submit"}
loading={editMode ? isSubmitting : false}
disabled={editMode ? !isDirty || !getValues("email") : false}
<Container maxW="full">
<Heading size="sm" py={4}>
User Information
</Heading>
<Box
w={{ sm: "full", md: "sm" }}
as="form"
onSubmit={handleSubmit(onSubmit)}
>
<Field label="Full name">
{editMode ? (
<Input
{...register("full_name", { maxLength: 30 })}
type="text"
size="md"
/>
) : (
<Text
fontSize="md"
py={2}
color={!currentUser?.full_name ? "gray" : "inherit"}
truncate
maxW="sm"
>
{editMode ? "Save" : "Edit"}
{currentUser?.full_name || "N/A"}
</Text>
)}
</Field>
<Field
mt={4}
label="Email"
invalid={!!errors.email}
errorText={errors.email?.message}
>
{editMode ? (
<Input
{...register("email", {
required: "Email is required",
pattern: emailPattern,
})}
type="email"
size="md"
/>
) : (
<Text fontSize="md" py={2} truncate maxW="sm">
{currentUser?.email}
</Text>
)}
</Field>
<Flex mt={4} gap={3}>
<Button
variant="solid"
onClick={toggleEditMode}
type={editMode ? "button" : "submit"}
loading={editMode ? isSubmitting : false}
disabled={editMode ? !isDirty || !getValues("email") : false}
>
{editMode ? "Save" : "Edit"}
</Button>
{editMode && (
<Button
variant="subtle"
colorPalette="gray"
onClick={onCancel}
disabled={isSubmitting}
>
Cancel
</Button>
{editMode && (
<Button
variant="subtle"
colorPalette="gray"
onClick={onCancel}
disabled={isSubmitting}
>
Cancel
</Button>
)}
</Flex>
</Box>
</Container>
</>
)}
</Flex>
</Box>
</Container>
)
}

View File

@@ -4,13 +4,12 @@ import {
QueryClient,
QueryClientProvider,
} from "@tanstack/react-query"
import { RouterProvider, createRouter } from "@tanstack/react-router"
import { createRouter, RouterProvider } from "@tanstack/react-router"
import { StrictMode } from "react"
import ReactDOM from "react-dom/client"
import { routeTree } from "./routeTree.gen"
import { ApiError, OpenAPI } from "./client"
import { CustomProvider } from "./components/ui/provider"
import { routeTree } from "./routeTree.gen"
OpenAPI.BASE = import.meta.env.VITE_API_URL
OpenAPI.TOKEN = async () => {

View File

@@ -1,4 +1,4 @@
import { Outlet, createRootRoute } from "@tanstack/react-router"
import { createRootRoute, Outlet } from "@tanstack/react-router"
import React, { Suspense } from "react"
import NotFound from "@/components/Common/NotFound"

View File

@@ -1,5 +1,5 @@
import { Flex } from "@chakra-ui/react"
import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"
import { createFileRoute, Outlet, redirect } from "@tanstack/react-router"
import Navbar from "@/components/Common/Navbar"
import Sidebar from "@/components/Common/Sidebar"

View File

@@ -11,15 +11,13 @@ function Dashboard() {
const { user: currentUser } = useAuth()
return (
<>
<Container maxW="full">
<Box pt={12} m={4}>
<Text fontSize="2xl" truncate maxW="sm">
Hi, {currentUser?.full_name || currentUser?.email} 👋🏼
</Text>
<Text>Welcome back, nice to see you again!</Text>
</Box>
</Container>
</>
<Container maxW="full">
<Box pt={12} m={4}>
<Text fontSize="2xl" truncate maxW="sm">
Hi, {currentUser?.full_name || currentUser?.email} 👋🏼
</Text>
<Text>Welcome back, nice to see you again!</Text>
</Box>
</Container>
)
}

View File

@@ -1,7 +1,7 @@
import { Container, Image, Input, Text } from "@chakra-ui/react"
import {
Link as RouterLink,
createFileRoute,
Link as RouterLink,
redirect,
} from "@tanstack/react-router"
import { type SubmitHandler, useForm } from "react-hook-form"
@@ -55,61 +55,58 @@ function Login() {
}
return (
<>
<Container
as="form"
onSubmit={handleSubmit(onSubmit)}
h="100vh"
maxW="sm"
alignItems="stretch"
justifyContent="center"
gap={4}
centerContent
<Container
as="form"
onSubmit={handleSubmit(onSubmit)}
h="100vh"
maxW="sm"
alignItems="stretch"
justifyContent="center"
gap={4}
centerContent
>
<Image
src={Logo}
alt="FastAPI logo"
height="auto"
maxW="2xs"
alignSelf="center"
mb={4}
/>
<Field
invalid={!!errors.username}
errorText={errors.username?.message || !!error}
>
<Image
src={Logo}
alt="FastAPI logo"
height="auto"
maxW="2xs"
alignSelf="center"
mb={4}
/>
<Field
invalid={!!errors.username}
errorText={errors.username?.message || !!error}
>
<InputGroup w="100%" startElement={<FiMail />}>
<Input
id="username"
{...register("username", {
required: "Username is required",
pattern: emailPattern,
})}
placeholder="Email"
type="email"
/>
</InputGroup>
</Field>
<PasswordInput
type="password"
startElement={<FiLock />}
{...register("password", passwordRules())}
placeholder="Password"
errors={errors}
/>
<RouterLink to="/recover-password" className="main-link">
Forgot Password?
<InputGroup w="100%" startElement={<FiMail />}>
<Input
{...register("username", {
required: "Username is required",
pattern: emailPattern,
})}
placeholder="Email"
type="email"
/>
</InputGroup>
</Field>
<PasswordInput
type="password"
startElement={<FiLock />}
{...register("password", passwordRules())}
placeholder="Password"
errors={errors}
/>
<RouterLink to="/recover-password" className="main-link">
Forgot Password?
</RouterLink>
<Button variant="solid" type="submit" loading={isSubmitting} size="md">
Log In
</Button>
<Text>
Don't have an account?{" "}
<RouterLink to="/signup" className="main-link">
Sign Up
</RouterLink>
<Button variant="solid" type="submit" loading={isSubmitting} size="md">
Log In
</Button>
<Text>
Don't have an account?{" "}
<RouterLink to="/signup" className="main-link">
Sign Up
</RouterLink>
</Text>
</Container>
</>
</Text>
</Container>
)
}

View File

@@ -77,7 +77,6 @@ function RecoverPassword() {
<Field invalid={!!errors.email} errorText={errors.email?.message}>
<InputGroup w="100%" startElement={<FiMail />}>
<Input
id="email"
{...register("email", {
required: "Email is required",
pattern: emailPattern,

View File

@@ -1,7 +1,7 @@
import { Container, Flex, Image, Input, Text } from "@chakra-ui/react"
import {
Link as RouterLink,
createFileRoute,
Link as RouterLink,
redirect,
} from "@tanstack/react-router"
import { type SubmitHandler, useForm } from "react-hook-form"
@@ -54,82 +54,78 @@ function SignUp() {
}
return (
<>
<Flex flexDir={{ base: "column", md: "row" }} justify="center" h="100vh">
<Container
as="form"
onSubmit={handleSubmit(onSubmit)}
h="100vh"
maxW="sm"
alignItems="stretch"
justifyContent="center"
gap={4}
centerContent
<Flex flexDir={{ base: "column", md: "row" }} justify="center" h="100vh">
<Container
as="form"
onSubmit={handleSubmit(onSubmit)}
h="100vh"
maxW="sm"
alignItems="stretch"
justifyContent="center"
gap={4}
centerContent
>
<Image
src={Logo}
alt="FastAPI logo"
height="auto"
maxW="2xs"
alignSelf="center"
mb={4}
/>
<Field
invalid={!!errors.full_name}
errorText={errors.full_name?.message}
>
<Image
src={Logo}
alt="FastAPI logo"
height="auto"
maxW="2xs"
alignSelf="center"
mb={4}
/>
<Field
invalid={!!errors.full_name}
errorText={errors.full_name?.message}
>
<InputGroup w="100%" startElement={<FiUser />}>
<Input
id="full_name"
minLength={3}
{...register("full_name", {
required: "Full Name is required",
})}
placeholder="Full Name"
type="text"
/>
</InputGroup>
</Field>
<InputGroup w="100%" startElement={<FiUser />}>
<Input
minLength={3}
{...register("full_name", {
required: "Full Name is required",
})}
placeholder="Full Name"
type="text"
/>
</InputGroup>
</Field>
<Field invalid={!!errors.email} errorText={errors.email?.message}>
<InputGroup w="100%" startElement={<FiUser />}>
<Input
id="email"
{...register("email", {
required: "Email is required",
pattern: emailPattern,
})}
placeholder="Email"
type="email"
/>
</InputGroup>
</Field>
<PasswordInput
type="password"
startElement={<FiLock />}
{...register("password", passwordRules())}
placeholder="Password"
errors={errors}
/>
<PasswordInput
type="confirm_password"
startElement={<FiLock />}
{...register("confirm_password", confirmPasswordRules(getValues))}
placeholder="Confirm Password"
errors={errors}
/>
<Button variant="solid" type="submit" loading={isSubmitting}>
Sign Up
</Button>
<Text>
Already have an account?{" "}
<RouterLink to="/login" className="main-link">
Log In
</RouterLink>
</Text>
</Container>
</Flex>
</>
<Field invalid={!!errors.email} errorText={errors.email?.message}>
<InputGroup w="100%" startElement={<FiUser />}>
<Input
{...register("email", {
required: "Email is required",
pattern: emailPattern,
})}
placeholder="Email"
type="email"
/>
</InputGroup>
</Field>
<PasswordInput
type="password"
startElement={<FiLock />}
{...register("password", passwordRules())}
placeholder="Password"
errors={errors}
/>
<PasswordInput
type="confirm_password"
startElement={<FiLock />}
{...register("confirm_password", confirmPasswordRules(getValues))}
placeholder="Confirm Password"
errors={errors}
/>
<Button variant="solid" type="submit" loading={isSubmitting}>
Sign Up
</Button>
<Text>
Already have an account?{" "}
<RouterLink to="/login" className="main-link">
Log In
</RouterLink>
</Text>
</Container>
</Flex>
)
}