This commit is contained in:
Rodrigo Verdiani 2026-03-19 15:53:06 -03:00
parent 82169d76f8
commit b87c2c8b39
13 changed files with 698 additions and 584 deletions

View File

@ -32,6 +32,12 @@ export interface ImportMangaResponseDTO {
id: number;
}
export interface FileImportRequestDTO {
malId?: string;
aniListId?: string;
files?: Blob[];
}
export interface AuthenticationRequestDTO {
email: string;
password: string;
@ -154,30 +160,30 @@ export interface MangaListDTO {
export interface PageMangaListDTO {
totalPages?: number;
totalElements?: number;
pageable?: PageableObject;
first?: boolean;
last?: boolean;
size?: number;
content?: MangaListDTO[];
number?: number;
sort?: SortObject;
pageable?: PageableObject;
numberOfElements?: number;
first?: boolean;
last?: boolean;
sort?: SortObject;
empty?: boolean;
}
export interface PageableObject {
offset?: number;
pageNumber?: number;
pageSize?: number;
paged?: boolean;
unpaged?: boolean;
offset?: number;
sort?: SortObject;
}
export interface SortObject {
empty?: boolean;
sorted?: boolean;
unsorted?: boolean;
empty?: boolean;
}
export interface DefaultResponseDTOMangaDTO {
@ -258,26 +264,19 @@ export interface GenreDTO {
name: string;
}
export type DownloadChapterArchiveParams = {
archiveFileType: DownloadChapterArchiveArchiveFileType;
export type DownloadContentArchiveParams = {
contentArchiveFileType: DownloadContentArchiveContentArchiveFileType;
};
export type DownloadChapterArchiveArchiveFileType = typeof DownloadChapterArchiveArchiveFileType[keyof typeof DownloadChapterArchiveArchiveFileType];
export type DownloadContentArchiveContentArchiveFileType = typeof DownloadContentArchiveContentArchiveFileType[keyof typeof DownloadContentArchiveContentArchiveFileType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const DownloadChapterArchiveArchiveFileType = {
export const DownloadContentArchiveContentArchiveFileType = {
CBZ: 'CBZ',
CBR: 'CBR',
} as const;
export type ImportMultipleFilesBody = {
/** @minLength 1 */
malId: string;
/** List of files to upload */
files: Blob[];
};
export type ResolveMangaIngestReviewParams = {
id: number;
malId: string;

View File

@ -5,16 +5,20 @@
* OpenAPI spec version: v0
*/
import {
useMutation,
useQuery
} from '@tanstack/react-query';
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult
} from '@tanstack/react-query';
@ -23,6 +27,7 @@ import type {
DefaultResponseDTOListGenreDTO,
DefaultResponseDTOMangaDTO,
DefaultResponseDTOPageMangaListDTO,
DefaultResponseDTOVoid,
GetMangasParams
} from '../api.schemas';
@ -34,6 +39,132 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Update a manga's metadata and cover
* @summary Update manga data
*/
export const updateMangas = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/catalog/mangas/${encodeURIComponent(String(mangaId))}/update`, method: 'POST', signal
},
options);
}
export const getUpdateMangasMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof updateMangas>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof updateMangas>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['updateMangas'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof updateMangas>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return updateMangas(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type UpdateMangasMutationResult = NonNullable<Awaited<ReturnType<typeof updateMangas>>>
export type UpdateMangasMutationError = unknown
/**
* @summary Update manga data
*/
export const useUpdateMangas = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof updateMangas>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof updateMangas>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getUpdateMangasMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Update all manga's metadata and cover
* @summary Update all manga data
*/
export const updateMangas1 = (
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/catalog/mangas/update`, method: 'POST', signal
},
options);
}
export const getUpdateMangas1MutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof updateMangas1>>, TError,void, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof updateMangas1>>, TError,void, TContext> => {
const mutationKey = ['updateMangas1'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof updateMangas1>>, void> = () => {
return updateMangas1(requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type UpdateMangas1MutationResult = NonNullable<Awaited<ReturnType<typeof updateMangas1>>>
export type UpdateMangas1MutationError = unknown
/**
* @summary Update all manga data
*/
export const useUpdateMangas1 = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof updateMangas1>>, TError,void, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof updateMangas1>>,
TError,
void,
TContext
> => {
const mutationOptions = getUpdateMangas1MutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Retrieve a list of mangas with their details.
* @summary Get a list of mangas
*/

View File

@ -5,23 +5,30 @@
* OpenAPI spec version: v0
*/
import {
useMutation,
useQuery
} from '@tanstack/react-query';
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseQueryResult,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult
} from '@tanstack/react-query';
import type {
DefaultResponseDTOListMangaContentDTO,
DefaultResponseDTOMangaContentImagesDTO
DefaultResponseDTOMangaContentImagesDTO,
DefaultResponseDTOVoid,
DownloadContentArchiveParams,
FileImportRequestDTO
} from '../api.schemas';
import { customInstance } from '../../api';
@ -32,6 +39,147 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Download content as a compressed file by its ID.
* @summary Download content archive
*/
export const downloadContentArchive = (
mangaContentId: number,
params: DownloadContentArchiveParams,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<Blob>(
{url: `/content/${encodeURIComponent(String(mangaContentId))}/download`, method: 'POST',
params,
responseType: 'blob', signal
},
options);
}
export const getDownloadContentArchiveMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof downloadContentArchive>>, TError,{mangaContentId: number;params: DownloadContentArchiveParams}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof downloadContentArchive>>, TError,{mangaContentId: number;params: DownloadContentArchiveParams}, TContext> => {
const mutationKey = ['downloadContentArchive'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof downloadContentArchive>>, {mangaContentId: number;params: DownloadContentArchiveParams}> = (props) => {
const {mangaContentId,params} = props ?? {};
return downloadContentArchive(mangaContentId,params,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type DownloadContentArchiveMutationResult = NonNullable<Awaited<ReturnType<typeof downloadContentArchive>>>
export type DownloadContentArchiveMutationError = unknown
/**
* @summary Download content archive
*/
export const useDownloadContentArchive = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof downloadContentArchive>>, TError,{mangaContentId: number;params: DownloadContentArchiveParams}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof downloadContentArchive>>,
TError,
{mangaContentId: number;params: DownloadContentArchiveParams},
TContext
> => {
const mutationOptions = getDownloadContentArchiveMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Accepts multiple content files via multipart/form-data and processes them.
* @summary Import multiple files
*/
export const importContentFiles = (
fileImportRequestDTO: FileImportRequestDTO,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
const formData = new FormData();
if(fileImportRequestDTO.malId !== undefined) {
formData.append(`malId`, fileImportRequestDTO.malId)
}
if(fileImportRequestDTO.aniListId !== undefined) {
formData.append(`aniListId`, fileImportRequestDTO.aniListId)
}
if(fileImportRequestDTO.files !== undefined) {
fileImportRequestDTO.files.forEach(value => formData.append(`files`, value));
}
return customInstance<DefaultResponseDTOVoid>(
{url: `/content/import`, method: 'POST',
headers: {'Content-Type': 'multipart/form-data', },
data: formData, signal
},
options);
}
export const getImportContentFilesMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof importContentFiles>>, TError,{data: FileImportRequestDTO}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof importContentFiles>>, TError,{data: FileImportRequestDTO}, TContext> => {
const mutationKey = ['importContentFiles'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof importContentFiles>>, {data: FileImportRequestDTO}> = (props) => {
const {data} = props ?? {};
return importContentFiles(data,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type ImportContentFilesMutationResult = NonNullable<Awaited<ReturnType<typeof importContentFiles>>>
export type ImportContentFilesMutationBody = FileImportRequestDTO
export type ImportContentFilesMutationError = unknown
/**
* @summary Import multiple files
*/
export const useImportContentFiles = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof importContentFiles>>, TError,{data: FileImportRequestDTO}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof importContentFiles>>,
TError,
{data: FileImportRequestDTO},
TContext
> => {
const mutationOptions = getImportContentFilesMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Retrieve the content for a specific manga/content provider combination.
* @summary Get the content for a specific manga/content provider combination
*/

View File

@ -1,154 +0,0 @@
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* OpenAPI definition
* OpenAPI spec version: v0
*/
import {
useMutation
} from '@tanstack/react-query';
import type {
MutationFunction,
QueryClient,
UseMutationOptions,
UseMutationResult
} from '@tanstack/react-query';
import type {
DefaultResponseDTOVoid
} from '../api.schemas';
import { customInstance } from '../../api';
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Remove a manga from favorites for the logged user.
* @summary Unfavorite a manga
*/
export const setUnfavorite = (
id: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/mangas/${encodeURIComponent(String(id))}/unfavorite`, method: 'POST', signal
},
options);
}
export const getSetUnfavoriteMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{id: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{id: number}, TContext> => {
const mutationKey = ['setUnfavorite'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof setUnfavorite>>, {id: number}> = (props) => {
const {id} = props ?? {};
return setUnfavorite(id,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type SetUnfavoriteMutationResult = NonNullable<Awaited<ReturnType<typeof setUnfavorite>>>
export type SetUnfavoriteMutationError = unknown
/**
* @summary Unfavorite a manga
*/
export const useSetUnfavorite = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{id: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof setUnfavorite>>,
TError,
{id: number},
TContext
> => {
const mutationOptions = getSetUnfavoriteMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Set a manga as favorite for the logged user.
* @summary Favorite a manga
*/
export const setFavorite = (
id: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/mangas/${encodeURIComponent(String(id))}/favorite`, method: 'POST', signal
},
options);
}
export const getSetFavoriteMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{id: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{id: number}, TContext> => {
const mutationKey = ['setFavorite'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof setFavorite>>, {id: number}> = (props) => {
const {id} = props ?? {};
return setFavorite(id,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type SetFavoriteMutationResult = NonNullable<Awaited<ReturnType<typeof setFavorite>>>
export type SetFavoriteMutationError = unknown
/**
* @summary Favorite a manga
*/
export const useSetFavorite = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{id: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof setFavorite>>,
TError,
{id: number},
TContext
> => {
const mutationOptions = getSetFavoriteMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}

View File

@ -15,8 +15,7 @@ import type {
} from '@tanstack/react-query';
import type {
DefaultResponseDTOVoid,
DownloadChapterArchiveParams
DefaultResponseDTOVoid
} from '../api.schemas';
import { customInstance } from '../../api';
@ -89,133 +88,4 @@ export const useFetchAllChapters = <TError = unknown,
return useMutation(mutationOptions, queryClient);
}
/**
* Mark a chapter as read by its ID.
* @summary Mark a chapter as read
*/
export const markAsRead = (
chapterId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/mangas/chapters/${encodeURIComponent(String(chapterId))}/mark-as-read`, method: 'POST', signal
},
options);
}
export const getMarkAsReadMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof markAsRead>>, TError,{chapterId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof markAsRead>>, TError,{chapterId: number}, TContext> => {
const mutationKey = ['markAsRead'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof markAsRead>>, {chapterId: number}> = (props) => {
const {chapterId} = props ?? {};
return markAsRead(chapterId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type MarkAsReadMutationResult = NonNullable<Awaited<ReturnType<typeof markAsRead>>>
export type MarkAsReadMutationError = unknown
/**
* @summary Mark a chapter as read
*/
export const useMarkAsRead = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof markAsRead>>, TError,{chapterId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof markAsRead>>,
TError,
{chapterId: number},
TContext
> => {
const mutationOptions = getMarkAsReadMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Download a chapter as a compressed file by its ID.
* @summary Download chapter archive
*/
export const downloadChapterArchive = (
chapterId: number,
params: DownloadChapterArchiveParams,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<Blob>(
{url: `/mangas/chapters/${encodeURIComponent(String(chapterId))}/download`, method: 'POST',
params,
responseType: 'blob', signal
},
options);
}
export const getDownloadChapterArchiveMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof downloadChapterArchive>>, TError,{chapterId: number;params: DownloadChapterArchiveParams}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof downloadChapterArchive>>, TError,{chapterId: number;params: DownloadChapterArchiveParams}, TContext> => {
const mutationKey = ['downloadChapterArchive'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof downloadChapterArchive>>, {chapterId: number;params: DownloadChapterArchiveParams}> = (props) => {
const {chapterId,params} = props ?? {};
return downloadChapterArchive(chapterId,params,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type DownloadChapterArchiveMutationResult = NonNullable<Awaited<ReturnType<typeof downloadChapterArchive>>>
export type DownloadChapterArchiveMutationError = unknown
/**
* @summary Download chapter archive
*/
export const useDownloadChapterArchive = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof downloadChapterArchive>>, TError,{chapterId: number;params: DownloadChapterArchiveParams}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof downloadChapterArchive>>,
TError,
{chapterId: number;params: DownloadChapterArchiveParams},
TContext
> => {
const mutationOptions = getDownloadChapterArchiveMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}

View File

@ -16,8 +16,6 @@ import type {
import type {
DefaultResponseDTOImportMangaResponseDTO,
DefaultResponseDTOVoid,
ImportMultipleFilesBody,
ImportRequestDTO
} from '../api.schemas';
@ -29,74 +27,6 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Accepts multiple files via multipart/form-data and processes them.
* @summary Upload multiple files
*/
export const importMultipleFiles = (
importMultipleFilesBody: ImportMultipleFilesBody,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
const formData = new FormData();
formData.append(`malId`, importMultipleFilesBody.malId)
importMultipleFilesBody.files.forEach(value => formData.append(`files`, value));
return customInstance<DefaultResponseDTOVoid>(
{url: `/manga/import/upload`, method: 'POST',
headers: {'Content-Type': 'multipart/form-data', },
data: formData, signal
},
options);
}
export const getImportMultipleFilesMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof importMultipleFiles>>, TError,{data: ImportMultipleFilesBody}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof importMultipleFiles>>, TError,{data: ImportMultipleFilesBody}, TContext> => {
const mutationKey = ['importMultipleFiles'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof importMultipleFiles>>, {data: ImportMultipleFilesBody}> = (props) => {
const {data} = props ?? {};
return importMultipleFiles(data,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type ImportMultipleFilesMutationResult = NonNullable<Awaited<ReturnType<typeof importMultipleFiles>>>
export type ImportMultipleFilesMutationBody = ImportMultipleFilesBody
export type ImportMultipleFilesMutationError = unknown
/**
* @summary Upload multiple files
*/
export const useImportMultipleFiles = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof importMultipleFiles>>, TError,{data: ImportMultipleFilesBody}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof importMultipleFiles>>,
TError,
{data: ImportMultipleFilesBody},
TContext
> => {
const mutationOptions = getImportMultipleFilesMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Imports manga data from content provider into the local database.
* @summary Import manga from content provider
*/

View File

@ -1,154 +0,0 @@
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* OpenAPI definition
* OpenAPI spec version: v0
*/
import {
useMutation
} from '@tanstack/react-query';
import type {
MutationFunction,
QueryClient,
UseMutationOptions,
UseMutationResult
} from '@tanstack/react-query';
import type {
DefaultResponseDTOVoid
} from '../api.schemas';
import { customInstance } from '../../api';
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Unfollow the manga specified by its ID.
* @summary Unfollow the manga specified by its ID
*/
export const unfollowManga = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/mangas/${encodeURIComponent(String(mangaId))}/unfollowManga`, method: 'POST', signal
},
options);
}
export const getUnfollowMangaMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['unfollowManga'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof unfollowManga>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return unfollowManga(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type UnfollowMangaMutationResult = NonNullable<Awaited<ReturnType<typeof unfollowManga>>>
export type UnfollowMangaMutationError = unknown
/**
* @summary Unfollow the manga specified by its ID
*/
export const useUnfollowManga = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof unfollowManga>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getUnfollowMangaMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Follow the manga specified by its ID.
* @summary Follow the manga specified by its ID
*/
export const followManga = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/mangas/${encodeURIComponent(String(mangaId))}/followManga`, method: 'POST', signal
},
options);
}
export const getFollowMangaMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['followManga'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof followManga>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return followManga(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type FollowMangaMutationResult = NonNullable<Awaited<ReturnType<typeof followManga>>>
export type FollowMangaMutationError = unknown
/**
* @summary Follow the manga specified by its ID
*/
export const useFollowManga = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof followManga>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getFollowMangaMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}

View File

@ -0,0 +1,343 @@
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* OpenAPI definition
* OpenAPI spec version: v0
*/
import {
useMutation
} from '@tanstack/react-query';
import type {
MutationFunction,
QueryClient,
UseMutationOptions,
UseMutationResult
} from '@tanstack/react-query';
import type {
DefaultResponseDTOVoid
} from '../api.schemas';
import { customInstance } from '../../api';
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Unfollow the manga specified by its ID.
* @summary Unfollow the manga specified by its ID
*/
export const unfollowManga = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/user-interaction/manga/${encodeURIComponent(String(mangaId))}/unfollow`, method: 'POST', signal
},
options);
}
export const getUnfollowMangaMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['unfollowManga'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof unfollowManga>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return unfollowManga(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type UnfollowMangaMutationResult = NonNullable<Awaited<ReturnType<typeof unfollowManga>>>
export type UnfollowMangaMutationError = unknown
/**
* @summary Unfollow the manga specified by its ID
*/
export const useUnfollowManga = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof unfollowManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof unfollowManga>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getUnfollowMangaMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Remove a manga from favorites for the logged user.
* @summary Unfavorite a manga
*/
export const setUnfavorite = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/user-interaction/manga/${encodeURIComponent(String(mangaId))}/unfavorite`, method: 'POST', signal
},
options);
}
export const getSetUnfavoriteMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['setUnfavorite'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof setUnfavorite>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return setUnfavorite(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type SetUnfavoriteMutationResult = NonNullable<Awaited<ReturnType<typeof setUnfavorite>>>
export type SetUnfavoriteMutationError = unknown
/**
* @summary Unfavorite a manga
*/
export const useSetUnfavorite = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setUnfavorite>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof setUnfavorite>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getSetUnfavoriteMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Follow the manga specified by its ID.
* @summary Follow the manga specified by its ID
*/
export const followManga = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/user-interaction/manga/${encodeURIComponent(String(mangaId))}/follow`, method: 'POST', signal
},
options);
}
export const getFollowMangaMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['followManga'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof followManga>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return followManga(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type FollowMangaMutationResult = NonNullable<Awaited<ReturnType<typeof followManga>>>
export type FollowMangaMutationError = unknown
/**
* @summary Follow the manga specified by its ID
*/
export const useFollowManga = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof followManga>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof followManga>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getFollowMangaMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Set a manga as favorite for the logged user.
* @summary Favorite a manga
*/
export const setFavorite = (
mangaId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/user-interaction/manga/${encodeURIComponent(String(mangaId))}/favorite`, method: 'POST', signal
},
options);
}
export const getSetFavoriteMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{mangaId: number}, TContext> => {
const mutationKey = ['setFavorite'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof setFavorite>>, {mangaId: number}> = (props) => {
const {mangaId} = props ?? {};
return setFavorite(mangaId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type SetFavoriteMutationResult = NonNullable<Awaited<ReturnType<typeof setFavorite>>>
export type SetFavoriteMutationError = unknown
/**
* @summary Favorite a manga
*/
export const useSetFavorite = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof setFavorite>>, TError,{mangaId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof setFavorite>>,
TError,
{mangaId: number},
TContext
> => {
const mutationOptions = getSetFavoriteMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Mark content as read by its ID.
* @summary Mark content as read
*/
export const markContentAsRead = (
mangaContentId: number,
options?: SecondParameter<typeof customInstance>,signal?: AbortSignal
) => {
return customInstance<DefaultResponseDTOVoid>(
{url: `/user-interaction/content/${encodeURIComponent(String(mangaContentId))}/read`, method: 'POST', signal
},
options);
}
export const getMarkContentAsReadMutationOptions = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof markContentAsRead>>, TError,{mangaContentId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
): UseMutationOptions<Awaited<ReturnType<typeof markContentAsRead>>, TError,{mangaContentId: number}, TContext> => {
const mutationKey = ['markContentAsRead'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof markContentAsRead>>, {mangaContentId: number}> = (props) => {
const {mangaContentId} = props ?? {};
return markContentAsRead(mangaContentId,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type MarkContentAsReadMutationResult = NonNullable<Awaited<ReturnType<typeof markContentAsRead>>>
export type MarkContentAsReadMutationError = unknown
/**
* @summary Mark content as read
*/
export const useMarkContentAsRead = <TError = unknown,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof markContentAsRead>>, TError,{mangaContentId: number}, TContext>, request?: SecondParameter<typeof customInstance>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof markContentAsRead>>,
TError,
{mangaContentId: number},
TContext
> => {
const mutationOptions = getMarkContentAsReadMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}

View File

@ -6,15 +6,12 @@ import type {
MangaListDTO,
PageMangaListDTO,
} from "@/api/generated/api.schemas.ts";
import {
useSetFavorite,
useSetUnfavorite,
} from "@/api/generated/favorite-mangas/favorite-mangas.ts";
import { Badge } from "@/components/ui/badge.tsx";
import { Button } from "@/components/ui/button.tsx";
import { Card, CardContent } from "@/components/ui/card.tsx";
import { useAuth } from "@/contexts/AuthContext.tsx";
import { formatToTwoDigitsDateRange } from "@/utils/dateFormatter.ts";
import {useSetFavorite, useSetUnfavorite} from "@/api/generated/user-interaction/user-interaction.ts";
interface MangaCardProps {
manga: MangaListDTO;
@ -63,18 +60,18 @@ export const MangaCard = ({ manga, queryKey }: MangaCardProps) => {
const isPendingFavoriteChange = isPendingFavorite || isPendingUnfavorite;
const handleFavoriteClick = useCallback(
(isFavorite: boolean) => {
(isFavorite: boolean) =>
isFavorite
? mutateUnfavorite({ id: manga.id })
: mutateFavorite({ id: manga.id });
},
? mutateUnfavorite({ mangaId: manga.id })
: mutateFavorite({ mangaId: manga.id })
,
[mutateUnfavorite, manga.id, mutateFavorite],
);
return (
<Card className="h-full group overflow-hidden border-border bg-card py-0 gap-0 transition-all hover:border-primary/50 hover:shadow-lg hover:shadow-primary/10 cursor-pointer relative">
<CardContent className="p-0">
<div className="relative aspect-[2/3] overflow-hidden bg-muted">
<div className="relative aspect-2/3 overflow-hidden bg-muted">
<Link to={`/manga/${manga.id}`}>
<img
src={

View File

@ -2,7 +2,6 @@ import { FileUp } from "lucide-react";
import type React from "react";
import { useState } from "react";
import { toast } from "sonner";
import { useImportMultipleFiles } from "@/api/generated/manga-import/manga-import.ts";
import { Button } from "@/components/ui/button";
import {
Dialog,
@ -13,6 +12,7 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {useImportContentFiles} from "@/api/generated/content/content.ts";
interface MangaManualImportDialogProps {
fileImportDialogOpen: boolean;
@ -24,10 +24,11 @@ export const MangaManualImportDialog = ({
onFileImportDialogOpenChange,
}: MangaManualImportDialogProps) => {
const [malId, setMalId] = useState("");
const [aniListId, setAniListId] = useState("");
const [dragActive, setDragActive] = useState(false);
const [files, setFiles] = useState<File[] | null>(null);
const { mutate, isPending } = useImportMultipleFiles({
const { mutate, isPending } = useImportContentFiles({
mutation: {
onSuccess: () => {
setFiles(null);
@ -45,27 +46,27 @@ export const MangaManualImportDialog = ({
return;
}
if (!malId.trim()) {
alert("Please enter a MyAnimeList manga ID");
if (!malId.trim() && !aniListId.trim()) {
alert("Please enter either a AniList or a MyAnimeList ID");
return;
}
let id = malId;
// let id = malId;
//
// if (!/^\d+$/.test(malId)) {
// const regex =
// /https?:\/\/(?:www\.)?myanimelist\.net\/(manga)\/(\d+)(?:\/|$)/i;
// const match = malId.match(regex);
//
// if (match) {
// id = match[2];
// } else {
// alert("Invalid MyAnimeList URL or ID");
// return;
// }
// }
if (!/^\d+$/.test(malId)) {
const regex =
/https?:\/\/(?:www\.)?myanimelist\.net\/(manga)\/(\d+)(?:\/|$)/i;
const match = malId.match(regex);
if (match) {
id = match[2];
} else {
alert("Invalid MyAnimeList URL or ID");
return;
}
}
mutate({ data: { malId: id, files } });
mutate({ data: { malId: malId, aniListId: aniListId, files: files } });
};
const handleDrag = (e: React.DragEvent) => {
@ -110,10 +111,21 @@ export const MangaManualImportDialog = ({
<div className="space-y-4">
<div>
<label className="text-sm font-medium">
MyAnimeList Manga URL (or ID)
AniList ID
</label>
<Input
placeholder="e.g., https://myanimelist.net/manga/..."
placeholder="17"
value={aniListId}
onChange={(e) => setAniListId(e.target.value)}
className="mt-2"
/>
</div>
<div>
<label className="text-sm font-medium">
MyAnimeList ID
</label>
<Input
placeholder="20"
value={malId}
onChange={(e) => setMalId(e.target.value)}
className="mt-2"

View File

@ -2,12 +2,9 @@ import { useQueryClient } from "@tanstack/react-query";
import { Check, Database, Download, Eye, Loader2 } from "lucide-react";
import { useCallback, useState } from "react";
import { useNavigate } from "react-router";
import {
useDownloadChapterArchive,
} from "@/api/generated/manga-chapter/manga-chapter.ts";
import { Button } from "@/components/ui/button";
import ReactCountryFlag from "react-country-flag";
import {useGetMangaProviderContent} from "@/api/generated/content/content.ts";
import {useDownloadContentArchive, useGetMangaProviderContent} from "@/api/generated/content/content.ts";
import {useFetchContentProviderContent} from "@/api/generated/ingestion/ingestion.ts";
interface MangaChapterProps {
@ -25,13 +22,13 @@ export const MangaChapter = ({
const queryClient = useQueryClient();
const { mutate: mutateDownloadChapterArchive } = useDownloadChapterArchive({
const { mutate: mutateDownloadChapterArchive } = useDownloadContentArchive({
mutation: {
onSuccess: (data, { chapterId }) => {
onSuccess: (data, { mangaContentId }) => {
const url = window.URL.createObjectURL(data);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", chapterId + ".cbz");
link.setAttribute("download", mangaContentId + ".cbz");
document.body.appendChild(link);
link.click();
link.remove();
@ -129,8 +126,8 @@ export const MangaChapter = ({
variant="outline"
onClick={() =>
mutateDownloadChapterArchive({
chapterId: chapter.id,
params: { archiveFileType: "CBZ" },
mangaContentId: chapter.id,
params: { contentArchiveFileType: "CBZ" },
})
}
className="gap-2"

View File

@ -1,13 +1,11 @@
import { ArrowLeft, ChevronLeft, ChevronRight, Home } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router";
import {
useMarkAsRead,
} from "@/api/generated/manga-chapter/manga-chapter.ts";
import { ThemeToggle } from "@/components/ThemeToggle.tsx";
import { Button } from "@/components/ui/button";
import { useReadingTracker } from "@/features/chapter/hooks/useReadingTracker.ts";
import {useGetMangaContentImages} from "@/api/generated/content/content.ts";
import {useMarkContentAsRead} from "@/api/generated/user-interaction/user-interaction.ts";
const Chapter = () => {
const { setCurrentChapterPage, getCurrentChapterPage } = useReadingTracker();
@ -24,7 +22,7 @@ const Chapter = () => {
const [infiniteScroll, setInfiniteScroll] = useState(true);
const { data, isLoading } = useGetMangaContentImages(chapterNumber);
const { mutate } = useMarkAsRead();
const { mutate } = useMarkContentAsRead();
// For infinite scroll mode
const [visibleCount, setVisibleCount] = useState(1);
@ -35,7 +33,7 @@ const Chapter = () => {
if (!data || isLoading) return;
if (currentPage === data.data?.contentImageKeys.length) {
mutate({ chapterId: chapterNumber });
mutate({ mangaContentId: chapterNumber });
}
}, [data, mutate, currentPage]);

View File

@ -13,15 +13,6 @@ import {
import { useCallback } from "react";
import { useNavigate, useParams } from "react-router";
import { toast } from "sonner";
import {
useSetFavorite,
useSetUnfavorite,
} from "@/api/generated/favorite-mangas/favorite-mangas.ts";
import {
useFollowManga,
useUnfollowManga,
} from "@/api/generated/manga/manga.ts";
// import { useFetchAllChapters } from "@/api/generated/manga-chapter/manga-chapter.ts";
import { ThemeToggle } from "@/components/ThemeToggle.tsx";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@ -38,6 +29,12 @@ import { MangaChapter } from "@/features/manga/MangaChapter.tsx";
import { formatToTwoDigitsDateRange } from "@/utils/dateFormatter.ts";
import {useGetManga} from "@/api/generated/catalog/catalog.ts";
import {useFetchContentProviderContentList} from "@/api/generated/ingestion/ingestion.ts";
import {
useFollowManga,
useSetFavorite,
useSetUnfavorite,
useUnfollowManga
} from "@/api/generated/user-interaction/user-interaction.ts";
const Manga = () => {
const { isAuthenticated } = useAuth();
@ -86,8 +83,8 @@ const Manga = () => {
const handleFavoriteClick = useCallback(
(isFavorite: boolean) =>
isFavorite
? mutateUnfavorite({ id: mangaData?.data?.id ?? -1 })
: mutateFavorite({ id: mangaData?.data?.id ?? -1 }),
? mutateUnfavorite({ mangaId: mangaData?.data?.id ?? -1 })
: mutateFavorite({ mangaId: mangaData?.data?.id ?? -1 }),
[mutateUnfavorite, mutateFavorite, mangaData?.data?.id],
);
@ -146,7 +143,7 @@ const Manga = () => {
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<header className="border-b border-border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60">
<div className="px-8 py-6">
<div className="flex items-center justify-between">
<div className="flex items-center gap-6">
@ -171,7 +168,7 @@ const Manga = () => {
{/* Manga Info Section */}
<div className="grid gap-8 lg:grid-cols-[300px_1fr]">
{/* Cover */}
<div className="relative aspect-[2/3] overflow-hidden rounded-lg border border-border bg-muted lg:sticky lg:top-8 lg:h-fit">
<div className="relative aspect-2/3 overflow-hidden rounded-lg border border-border bg-muted lg:sticky lg:top-8 lg:h-fit">
<img
src={
(mangaData.data?.coverImageKey &&