43
resources/client/admin/titles/requests/use-attach-title-tag.ts
Executable file
43
resources/client/admin/titles/requests/use-attach-title-tag.ts
Executable file
@@ -0,0 +1,43 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {TitleTag} from '@app/admin/titles/requests/use-detach-title-tag';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
|
||||
interface Response extends BackendResponse {}
|
||||
|
||||
export interface AttachTitleTagPayload {
|
||||
tag_name: string;
|
||||
}
|
||||
|
||||
export function useAttachTitleTag(
|
||||
form: UseFormReturn<AttachTitleTagPayload>,
|
||||
tagType: TitleTag['model_type'],
|
||||
) {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: AttachTitleTagPayload) =>
|
||||
attachTag(titleId!, tagType, payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['titles', `${titleId}`],
|
||||
});
|
||||
toast(message('Tag attached'));
|
||||
},
|
||||
onError: r => onFormQueryError(r, form),
|
||||
});
|
||||
}
|
||||
|
||||
function attachTag(
|
||||
titleId: number | string,
|
||||
tagType: TitleTag['model_type'],
|
||||
payload: AttachTitleTagPayload,
|
||||
): Promise<Response> {
|
||||
return apiClient
|
||||
.post(`titles/${titleId}/tags/${tagType}`, payload)
|
||||
.then(r => r.data);
|
||||
}
|
||||
33
resources/client/admin/titles/requests/use-create-season.ts
Executable file
33
resources/client/admin/titles/requests/use-create-season.ts
Executable file
@@ -0,0 +1,33 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {titleSeasonsQueryKey} from '@app/titles/requests/use-title-seasons';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {Season} from '@app/titles/models/season';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
season: Season;
|
||||
}
|
||||
|
||||
export function useCreateSeason(titleId: number) {
|
||||
return useMutation({
|
||||
mutationFn: () => createSeason(titleId),
|
||||
onSuccess: async response => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleSeasonsQueryKey(response.season.title_id),
|
||||
});
|
||||
toast(
|
||||
message('Season :number created', {
|
||||
values: {number: response.season.number},
|
||||
}),
|
||||
);
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function createSeason(titleId: number): Promise<Response> {
|
||||
return apiClient.post(`titles/${titleId}/seasons`).then(r => r.data);
|
||||
}
|
||||
53
resources/client/admin/titles/requests/use-create-title-credit.ts
Executable file
53
resources/client/admin/titles/requests/use-create-title-credit.ts
Executable file
@@ -0,0 +1,53 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {titleCreditsQueryKey} from '@app/admin/titles/requests/use-title-credits';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
//
|
||||
}
|
||||
|
||||
export interface CreateTitleCreditPayload {
|
||||
person_id: number;
|
||||
character: string;
|
||||
department: string;
|
||||
job: string;
|
||||
season?: number | string;
|
||||
episode?: number | string;
|
||||
}
|
||||
|
||||
export function useCreateTitleCredit(
|
||||
form: UseFormReturn<CreateTitleCreditPayload>,
|
||||
) {
|
||||
const {titleId, season, episode} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: CreateTitleCreditPayload) =>
|
||||
createCredit(titleId!, season, episode, payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleCreditsQueryKey(titleId!),
|
||||
});
|
||||
toast(message('Credit added'));
|
||||
},
|
||||
onError: r => onFormQueryError(r, form),
|
||||
});
|
||||
}
|
||||
|
||||
function createCredit(
|
||||
titleId: number | string,
|
||||
season: number | string | undefined,
|
||||
episode: number | string | undefined,
|
||||
payload: CreateTitleCreditPayload,
|
||||
): Promise<Response> {
|
||||
payload = {
|
||||
...payload,
|
||||
season,
|
||||
episode,
|
||||
};
|
||||
return apiClient.post(`titles/${titleId}/credits`, payload).then(r => r.data);
|
||||
}
|
||||
45
resources/client/admin/titles/requests/use-create-title.ts
Executable file
45
resources/client/admin/titles/requests/use-create-title.ts
Executable file
@@ -0,0 +1,45 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
import {CreateVideoPayload} from '@app/admin/videos/requests/use-create-video';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
title: Title;
|
||||
}
|
||||
|
||||
export interface CreateTitlePayload {
|
||||
name: string;
|
||||
original_title: string;
|
||||
is_series: boolean;
|
||||
poster: string;
|
||||
backdrop: string;
|
||||
release_date: string;
|
||||
tagline: string;
|
||||
description: string;
|
||||
runtime: number;
|
||||
certification: string;
|
||||
budget: number;
|
||||
revenue: number;
|
||||
language: string;
|
||||
popularity: number;
|
||||
images: {url: string}[];
|
||||
videos: CreateVideoPayload[];
|
||||
}
|
||||
|
||||
export function useCreateTitle(form: UseFormReturn<CreateTitlePayload>) {
|
||||
return useMutation({
|
||||
mutationFn: (payload: CreateTitlePayload) => createTitle(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: ['titles']});
|
||||
},
|
||||
onError: r => (form ? onFormQueryError(r, form) : showHttpErrorToast(r)),
|
||||
});
|
||||
}
|
||||
|
||||
function createTitle(payload: CreateTitlePayload): Promise<Response> {
|
||||
return apiClient.post(`titles`, payload).then(r => r.data);
|
||||
}
|
||||
25
resources/client/admin/titles/requests/use-delete-image.ts
Executable file
25
resources/client/admin/titles/requests/use-delete-image.ts
Executable file
@@ -0,0 +1,25 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {useParams} from 'react-router-dom';
|
||||
|
||||
interface Response extends BackendResponse {}
|
||||
|
||||
export function useDeleteImage(imageId: number | string) {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: () => deleteImage(imageId),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: ['titles', `${titleId}`]});
|
||||
toast(message('Image deleted'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function deleteImage(imageId: number | string): Promise<Response> {
|
||||
return apiClient.delete(`images/${imageId}`).then(r => r.data);
|
||||
}
|
||||
27
resources/client/admin/titles/requests/use-delete-season.ts
Executable file
27
resources/client/admin/titles/requests/use-delete-season.ts
Executable file
@@ -0,0 +1,27 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {titleSeasonsQueryKey} from '@app/titles/requests/use-title-seasons';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
|
||||
interface Response extends BackendResponse {}
|
||||
|
||||
export function useDeleteSeason(title: Title, seasonId: number | string) {
|
||||
return useMutation({
|
||||
mutationFn: () => deleteSeason(seasonId),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleSeasonsQueryKey(title.id),
|
||||
});
|
||||
toast(message('Season deleted'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function deleteSeason(seasonId: number | string): Promise<Response> {
|
||||
return apiClient.delete(`seasons/${seasonId}`).then(r => r.data);
|
||||
}
|
||||
37
resources/client/admin/titles/requests/use-delete-title-credit.ts
Executable file
37
resources/client/admin/titles/requests/use-delete-title-credit.ts
Executable file
@@ -0,0 +1,37 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {titleCreditsQueryKey} from '@app/admin/titles/requests/use-title-credits';
|
||||
|
||||
interface Response extends BackendResponse {}
|
||||
|
||||
export function useDeleteTitleCredit(creditId: number) {
|
||||
const {titleId, season, episode} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: () => deleteCredit(titleId!, season, episode, creditId),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleCreditsQueryKey(titleId!),
|
||||
});
|
||||
toast(message('Credit deleted'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCredit(
|
||||
titleId: number | string,
|
||||
season: string | undefined,
|
||||
episode: string | undefined,
|
||||
creditId: number | string,
|
||||
): Promise<Response> {
|
||||
return apiClient
|
||||
.delete(`titles/${titleId}/credits/${creditId}`, {
|
||||
params: {season, episode},
|
||||
})
|
||||
.then(r => r.data);
|
||||
}
|
||||
32
resources/client/admin/titles/requests/use-detach-title-tag.ts
Executable file
32
resources/client/admin/titles/requests/use-detach-title-tag.ts
Executable file
@@ -0,0 +1,32 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {Keyword} from '@app/titles/models/keyword';
|
||||
import {Genre} from '@app/titles/models/genre';
|
||||
import {ProductionCountry} from '@app/titles/models/production-country';
|
||||
|
||||
interface Response extends BackendResponse {}
|
||||
|
||||
export type TitleTag = Keyword | Genre | ProductionCountry;
|
||||
|
||||
export function useDetachTitleTag(tag: TitleTag) {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: () => detachTag(titleId!, tag),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: ['titles', `${titleId}`]});
|
||||
toast(message('Tag detached'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function detachTag(titleId: number | string, tag: TitleTag): Promise<Response> {
|
||||
return apiClient
|
||||
.delete(`titles/${titleId}/tags/${tag.model_type}/${tag.id}`)
|
||||
.then(r => r.data);
|
||||
}
|
||||
203
resources/client/admin/titles/requests/use-import-multiple-from-tmdb.ts
Executable file
203
resources/client/admin/titles/requests/use-import-multiple-from-tmdb.ts
Executable file
@@ -0,0 +1,203 @@
|
||||
import {useTrans} from '@common/i18n/use-trans';
|
||||
import {ChipValue} from '@common/ui/forms/input-field/chip-field/chip-field';
|
||||
import {useCallback, useRef, useState} from 'react';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
import {DatatableDataQueryKey} from '@common/datatable/requests/paginated-resources';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
titles: Title[];
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
export interface ImportMultipleFromTmdbFormValue {
|
||||
type: 'movie' | 'series';
|
||||
country?: string;
|
||||
language?: string;
|
||||
min_rating?: string;
|
||||
max_rating?: string;
|
||||
genres?: ChipValue[];
|
||||
keywords?: ChipValue[];
|
||||
release_date?: {
|
||||
start?: string;
|
||||
end?: string;
|
||||
};
|
||||
pages_to_import?: number;
|
||||
start_from_page?: number;
|
||||
current_page?: number;
|
||||
}
|
||||
|
||||
interface Payload
|
||||
extends Omit<
|
||||
ImportMultipleFromTmdbFormValue,
|
||||
'genres' | 'keywords' | 'release_date'
|
||||
> {
|
||||
genres?: string;
|
||||
keywords?: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
|
||||
export interface ImportMultipleProgressData {
|
||||
totalItems: number;
|
||||
currentItem: number;
|
||||
progress: number;
|
||||
titleList: string[];
|
||||
}
|
||||
|
||||
interface MutateOptions {
|
||||
onSuccess?: () => void;
|
||||
onProgress?: (data: ImportMultipleProgressData) => void;
|
||||
}
|
||||
|
||||
export function useImportMultipleFromTmdb() {
|
||||
const {trans} = useTrans();
|
||||
const titlesList = useRef<string[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const controller = useRef(new AbortController());
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
controller.current.abort('canceled');
|
||||
}, []);
|
||||
|
||||
const handler = useCallback(
|
||||
async (v: ImportMultipleFromTmdbFormValue, options: MutateOptions) => {
|
||||
let stopped = false;
|
||||
let error = false;
|
||||
let pagesToImport = v.pages_to_import ? +v.pages_to_import : 1;
|
||||
const startFromPage = v.start_from_page ? +v.start_from_page : 1;
|
||||
|
||||
if (pagesToImport + startFromPage > 500) {
|
||||
pagesToImport = 500 - startFromPage;
|
||||
}
|
||||
|
||||
const stopImporting = () => {
|
||||
setIsLoading(false);
|
||||
titlesList.current = [];
|
||||
controller.current = new AbortController();
|
||||
stopped = true;
|
||||
};
|
||||
|
||||
let currentPage = startFromPage;
|
||||
setIsLoading(true);
|
||||
|
||||
controller.current.signal.addEventListener('abort', () =>
|
||||
stopImporting(),
|
||||
);
|
||||
|
||||
let index = 0;
|
||||
while (index <= pagesToImport && !stopped) {
|
||||
// open progress bar instantly, instead of waiting for first response to come back
|
||||
if (index === 0) {
|
||||
options.onProgress?.({
|
||||
totalItems: pagesToImport * 20,
|
||||
currentItem: 0,
|
||||
progress: 0,
|
||||
titleList: [],
|
||||
});
|
||||
}
|
||||
|
||||
index++;
|
||||
currentPage++;
|
||||
|
||||
try {
|
||||
const response = await apiClient
|
||||
.post<Response>(
|
||||
'tmdb/import',
|
||||
formValueToPayload({...v, current_page: currentPage}),
|
||||
{
|
||||
signal: controller.current.signal,
|
||||
},
|
||||
)
|
||||
.then(r => r.data);
|
||||
|
||||
if (response.total_pages < pagesToImport) {
|
||||
pagesToImport = response.total_pages;
|
||||
}
|
||||
|
||||
// limit array to 1000 items
|
||||
if (titlesList.current.length > 1000) {
|
||||
titlesList.current = titlesList.current.slice(0, 1000);
|
||||
}
|
||||
|
||||
titlesList.current.unshift(...response.titles.map(t => t.name));
|
||||
|
||||
const totalItems = pagesToImport * 20;
|
||||
const currentItem = (index - 1) * 20;
|
||||
|
||||
options.onProgress?.({
|
||||
totalItems: totalItems,
|
||||
currentItem: currentItem,
|
||||
progress: Math.round((currentItem / totalItems) * 100),
|
||||
titleList: titlesList.current,
|
||||
});
|
||||
} catch (e) {
|
||||
stopImporting();
|
||||
error = true;
|
||||
if ((e as any).message !== 'canceled') {
|
||||
console.error(e);
|
||||
showHttpErrorToast(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: DatatableDataQueryKey('titles'),
|
||||
});
|
||||
toast(trans(message('Titles imported')));
|
||||
setIsLoading(false);
|
||||
options.onSuccess?.();
|
||||
}
|
||||
},
|
||||
[trans],
|
||||
);
|
||||
|
||||
return {
|
||||
mutate: handler,
|
||||
cancel,
|
||||
isLoading,
|
||||
};
|
||||
}
|
||||
|
||||
function formValueToPayload(values: ImportMultipleFromTmdbFormValue): Payload {
|
||||
const payload: Payload = {
|
||||
type: values.type,
|
||||
pages_to_import: values.pages_to_import,
|
||||
start_from_page: values.start_from_page,
|
||||
current_page: values.current_page,
|
||||
};
|
||||
|
||||
if (values.country) {
|
||||
payload.country = values.country;
|
||||
}
|
||||
|
||||
if (values.language) {
|
||||
payload.language = values.language;
|
||||
}
|
||||
|
||||
if (values.min_rating) {
|
||||
payload.min_rating = values.min_rating;
|
||||
}
|
||||
|
||||
if (values.max_rating) {
|
||||
payload.max_rating = values.max_rating;
|
||||
}
|
||||
|
||||
if (values.genres) {
|
||||
payload.genres = values.genres.map(genre => genre.id).join(',');
|
||||
}
|
||||
if (values.keywords) {
|
||||
payload.keywords = values.keywords.map(keyword => keyword.id).join(',');
|
||||
}
|
||||
if (values.release_date) {
|
||||
payload.start_date = values.release_date.start;
|
||||
payload.end_date = values.release_date.start;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
37
resources/client/admin/titles/requests/use-import-single-from-tmdb.ts
Executable file
37
resources/client/admin/titles/requests/use-import-single-from-tmdb.ts
Executable file
@@ -0,0 +1,37 @@
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {useTrans} from '@common/i18n/use-trans';
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {DatatableDataQueryKey} from '@common/datatable/requests/paginated-resources';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
import {Person} from '@app/titles/models/person';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
mediaItem: Title | Person;
|
||||
}
|
||||
|
||||
export interface ImportMediaItemPayload {
|
||||
tmdb_id: string;
|
||||
media_type: 'movie' | 'series' | 'person';
|
||||
}
|
||||
|
||||
export function useImportSingleFromTmdb() {
|
||||
const {trans} = useTrans();
|
||||
return useMutation({
|
||||
mutationFn: (props: ImportMediaItemPayload) => importMediaItem(props),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: DatatableDataQueryKey('titles'),
|
||||
});
|
||||
toast(trans(message('Item imported')));
|
||||
},
|
||||
onError: err => showHttpErrorToast(err),
|
||||
});
|
||||
}
|
||||
|
||||
function importMediaItem(payload: ImportMediaItemPayload): Promise<Response> {
|
||||
return apiClient.post('media/import', payload).then(r => r.data);
|
||||
}
|
||||
34
resources/client/admin/titles/requests/use-sort-title-credits.ts
Executable file
34
resources/client/admin/titles/requests/use-sort-title-credits.ts
Executable file
@@ -0,0 +1,34 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {titleCreditsQueryKey} from '@app/admin/titles/requests/use-title-credits';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
//
|
||||
}
|
||||
|
||||
interface Payload {
|
||||
ids: number[];
|
||||
}
|
||||
|
||||
export function useSortTitleCredits() {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: Payload) => sortCredits(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleCreditsQueryKey(titleId!),
|
||||
});
|
||||
toast(message('Credit added'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function sortCredits(payload: Payload): Promise<Response> {
|
||||
return apiClient.post(`titles/credits/reorder`, payload).then(r => r.data);
|
||||
}
|
||||
41
resources/client/admin/titles/requests/use-title-credits.ts
Executable file
41
resources/client/admin/titles/requests/use-title-credits.ts
Executable file
@@ -0,0 +1,41 @@
|
||||
import {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';
|
||||
import {TitleCredit} from '@app/titles/models/title';
|
||||
import {useParams} from 'react-router-dom';
|
||||
|
||||
export const titleCreditsQueryKey = (
|
||||
titleId: number | string,
|
||||
season?: number | string,
|
||||
episode?: number | string,
|
||||
params?: any
|
||||
) => {
|
||||
const key = ['titles', `${titleId}`, 'credits'];
|
||||
if (season) {
|
||||
key.push('season', `${season}`);
|
||||
}
|
||||
if (episode) {
|
||||
key.push('episode', `${episode}`);
|
||||
}
|
||||
if (params) {
|
||||
key.push(params);
|
||||
}
|
||||
return key;
|
||||
};
|
||||
|
||||
interface Params {
|
||||
department?: string;
|
||||
crewOnly?: string;
|
||||
}
|
||||
|
||||
export function useTitleCredits(params: Params = {}) {
|
||||
const {titleId, season, episode} = useParams();
|
||||
return useInfiniteData<TitleCredit>({
|
||||
endpoint: `titles/${titleId}/credits`,
|
||||
queryKey: titleCreditsQueryKey(titleId!, season, episode, params),
|
||||
queryParams: {
|
||||
...params,
|
||||
perPage: 30,
|
||||
season: season || '',
|
||||
episode: episode || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
52
resources/client/admin/titles/requests/use-update-title-credit.ts
Executable file
52
resources/client/admin/titles/requests/use-update-title-credit.ts
Executable file
@@ -0,0 +1,52 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {titleCreditsQueryKey} from '@app/admin/titles/requests/use-title-credits';
|
||||
import {CreateTitleCreditPayload} from '@app/admin/titles/requests/use-create-title-credit';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
//
|
||||
}
|
||||
|
||||
export interface UpdateTitleCreditPayload
|
||||
extends Omit<CreateTitleCreditPayload, 'person_id'> {}
|
||||
|
||||
export function useUpdateTitleCredit(
|
||||
form: UseFormReturn<UpdateTitleCreditPayload>,
|
||||
creditId: number,
|
||||
) {
|
||||
const {titleId, season, episode} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: UpdateTitleCreditPayload) =>
|
||||
updateTitle(titleId!, season, episode, creditId, payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: titleCreditsQueryKey(titleId!),
|
||||
});
|
||||
toast(message('Credit updated'));
|
||||
},
|
||||
onError: r => onFormQueryError(r, form),
|
||||
});
|
||||
}
|
||||
|
||||
function updateTitle(
|
||||
titleId: string,
|
||||
season: string | undefined,
|
||||
episode: string | undefined,
|
||||
creditId: number,
|
||||
payload: UpdateTitleCreditPayload,
|
||||
): Promise<Response> {
|
||||
payload = {
|
||||
...payload,
|
||||
season,
|
||||
episode,
|
||||
};
|
||||
return apiClient
|
||||
.put(`titles/${titleId}/credits/${creditId}`, payload)
|
||||
.then(r => r.data);
|
||||
}
|
||||
30
resources/client/admin/titles/requests/use-update-title.ts
Executable file
30
resources/client/admin/titles/requests/use-update-title.ts
Executable file
@@ -0,0 +1,30 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
import {CreateTitlePayload} from '@app/admin/titles/requests/use-create-title';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
title: Title;
|
||||
}
|
||||
|
||||
export function useUpdateTitle(form: UseFormReturn<CreateTitlePayload>) {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: CreateTitlePayload) => updateTitle(titleId!, payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: ['titles']});
|
||||
},
|
||||
onError: r => onFormQueryError(r, form),
|
||||
});
|
||||
}
|
||||
|
||||
function updateTitle(
|
||||
titleId: string,
|
||||
payload: CreateTitlePayload,
|
||||
): Promise<Response> {
|
||||
return apiClient.put(`titles/${titleId}`, payload).then(r => r.data);
|
||||
}
|
||||
36
resources/client/admin/titles/requests/use-upload-image.ts
Executable file
36
resources/client/admin/titles/requests/use-upload-image.ts
Executable file
@@ -0,0 +1,36 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {TitleImage} from '@app/titles/models/title-image';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
import {useParams} from 'react-router-dom';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
image: TitleImage;
|
||||
}
|
||||
|
||||
interface Payload {
|
||||
titleId: number | string;
|
||||
file: File;
|
||||
}
|
||||
|
||||
export function useUploadImage() {
|
||||
const {titleId} = useParams();
|
||||
return useMutation({
|
||||
mutationFn: (payload: Payload) => uploadImage(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: ['titles', `${titleId}`]});
|
||||
toast(message('Image uploaded'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function uploadImage(payload: Payload): Promise<Response> {
|
||||
const formData = new FormData();
|
||||
formData.append('titleId', payload.titleId.toString());
|
||||
formData.append('file', payload.file);
|
||||
return apiClient.post(`images`, formData).then(r => r.data);
|
||||
}
|
||||
Reference in New Issue
Block a user