1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-26 22:56:23 -04:00

Add Series with ReactQuery Mutation

This commit is contained in:
Mark McDowall
2025-02-16 14:48:31 -08:00
parent 094df71301
commit 591b569bdd
28 changed files with 812 additions and 388 deletions
+13 -54
View File
@@ -1,45 +1,23 @@
import { UndefinedInitialDataOptions, useQuery } from '@tanstack/react-query';
import { useMemo } from 'react';
import fetchJson, {
ApiError,
apiRoot,
FetchJsonOptions,
} from 'Utilities/Fetch/fetchJson';
interface ApiErrorResponse {
message: string;
details: string;
}
export class ApiError extends Error {
public statusCode: number;
public statusText: string;
public statusBody?: ApiErrorResponse;
public constructor(
path: string,
statusCode: number,
statusText: string,
statusBody?: ApiErrorResponse
) {
super(`Request Error: (${statusCode}) ${path}`);
this.statusCode = statusCode;
this.statusText = statusText;
this.statusBody = statusBody;
Object.setPrototypeOf(this, new.target.prototype);
}
}
interface QueryOptions<T> {
path: string;
headers?: HeadersInit;
interface QueryOptions<T> extends FetchJsonOptions<unknown> {
queryOptions?:
| Omit<UndefinedInitialDataOptions<T, ApiError>, 'queryKey' | 'queryFn'>
| undefined;
}
const apiRoot = '/api/v5'; // window.Sonarr.apiRoot;
function useApiQuery<T>(options: QueryOptions<T>) {
const { path, headers } = useMemo(() => {
const requestOptions = useMemo(() => {
const { queryOptions, ...otherOptions } = options;
return {
...otherOptions,
path: apiRoot + options.path,
headers: {
...options.headers,
@@ -50,28 +28,9 @@ function useApiQuery<T>(options: QueryOptions<T>) {
return useQuery({
...options.queryOptions,
queryKey: [path, headers],
queryFn: async ({ signal }) => {
const response = await fetch(path, {
headers,
signal,
});
if (!response.ok) {
// eslint-disable-next-line init-declarations
let body;
try {
body = (await response.json()) as ApiErrorResponse;
} catch {
throw new ApiError(path, response.status, response.statusText);
}
throw new ApiError(path, response.status, response.statusText, body);
}
return response.json() as T;
},
queryKey: [requestOptions.path],
queryFn: async ({ signal }) =>
fetchJson<T, unknown>({ ...requestOptions, signal }),
});
}