F: Add global mutation error fallback

This commit is contained in:
Ivan 2025-02-19 19:15:57 +03:00
parent 14276d661c
commit 8c0d5bfca7
53 changed files with 160 additions and 64 deletions

View File

@ -11,6 +11,7 @@ import { GlobalDialogs } from './GlobalDialogs';
import { GlobalLoader } from './GlobalLoader'; import { GlobalLoader } from './GlobalLoader';
import { ToasterThemed } from './GlobalToaster'; import { ToasterThemed } from './GlobalToaster';
import { GlobalTooltips } from './GlobalTooltips'; import { GlobalTooltips } from './GlobalTooltips';
import { MutationErrors } from './MutationErrors';
import { Navigation } from './Navigation'; import { Navigation } from './Navigation';
function ApplicationLayout() { function ApplicationLayout() {
@ -48,6 +49,7 @@ function ApplicationLayout() {
> >
<main className='cc-scroll-y' style={{ overflowY: showScroll ? 'scroll' : 'auto', minHeight: mainHeight }}> <main className='cc-scroll-y' style={{ overflowY: showScroll ? 'scroll' : 'auto', minHeight: mainHeight }}>
<GlobalLoader /> <GlobalLoader />
<MutationErrors />
<Outlet /> <Outlet />
</main> </main>
{!noNavigation && !noFooter ? <Footer /> : null} {!noNavigation && !noFooter ? <Footer /> : null}

View File

@ -0,0 +1,40 @@
import clsx from 'clsx';
import { useMutationErrors } from '@/backend/useMutationErrors';
import { Button } from '@/components/Control';
import { DescribeError } from '@/components/InfoError';
import useEscapeKey from '@/hooks/useEscapeKey';
import { useDialogsStore } from '@/stores/dialogs';
export function MutationErrors() {
const { mutationErrors, resetErrors } = useMutationErrors();
const hideDialog = useDialogsStore(state => state.hideDialog);
useEscapeKey(resetErrors, mutationErrors.length > 0);
if (mutationErrors.length === 0) {
return null;
}
hideDialog();
return (
<div className='fixed top-0 left-0 w-full h-full z-modal cursor-default'>
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'backdrop-blur-[3px] opacity-50')} />
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'bg-prim-0 opacity-25')} />
<div
className={clsx(
'px-10 mb-10 py-3 flex flex-col items-center',
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
'border rounded-xl bg-prim-100'
)}
>
<h1 className='py-2 select-none'>Ошибка при обработке</h1>
<div className={clsx('px-3 flex flex-col', 'text-warn-600 text-sm font-semibold', 'select-text')}>
<DescribeError error={mutationErrors[0]} />
</div>
<Button onClick={resetErrors} className='w-fit' text='Закрыть' />
</div>
</div>
);
}

View File

@ -100,7 +100,6 @@ export function axiosPost<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }
@ -130,7 +129,6 @@ export function axiosDelete<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }
@ -160,7 +158,6 @@ export function axiosPatch<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }

View File

@ -11,10 +11,12 @@ export const DELAYS = {
/** API keys for local cache. */ /** API keys for local cache. */
export const KEYS = { export const KEYS = {
oss: 'oss', oss: 'oss',
auth: 'auth',
rsform: 'rsform', rsform: 'rsform',
library: 'library', library: 'library',
users: 'users', users: 'users',
cctext: 'cctext', cctext: 'cctext',
global_mutation: 'global_mutation',
composite: { composite: {
libraryList: ['library', 'list'], libraryList: ['library', 'list'],

View File

@ -1,11 +1,12 @@
import { QueryClient } from '@tanstack/react-query'; import { QueryClient } from '@tanstack/react-query';
import { ZodError } from 'zod';
import { AxiosError } from './apiTransport'; import { AxiosError } from './apiTransport';
import { DELAYS } from './configuration'; import { DELAYS } from './configuration';
declare module '@tanstack/react-query' { declare module '@tanstack/react-query' {
interface Register { interface Register {
defaultError: AxiosError; defaultError: AxiosError | ZodError;
} }
} }

View File

@ -0,0 +1,21 @@
import { useState } from 'react';
import { useMutationState, useQueryClient } from '@tanstack/react-query';
import { KEYS } from './configuration';
export const useMutationErrors = () => {
const queryClient = useQueryClient();
const [ignored, setIgnored] = useState<(Error | null)[]>([]);
const mutationErrors = useMutationState({
filters: { mutationKey: [KEYS.global_mutation], status: 'error' },
select: mutation => mutation.state.error
});
console.log(queryClient.getMutationCache().getAll());
function resetErrors() {
setIgnored(mutationErrors);
}
return { mutationErrors: mutationErrors.filter(error => !ignored.includes(error)), resetErrors };
};

View File

@ -12,21 +12,21 @@ interface InfoErrorProps {
error: ErrorData; error: ErrorData;
} }
function DescribeError({ error }: { error: ErrorData }) { export function DescribeError({ error }: { error: ErrorData }) {
if (!error) { if (!error) {
return <p>Ошибки отсутствуют</p>; return <p>Ошибки отсутствуют</p>;
} else if (typeof error === 'string') { } else if (typeof error === 'string') {
return <p>{error}</p>; return <p>{error}</p>;
} else if (error instanceof ZodError) { } else if (error instanceof ZodError) {
return ( return (
<div className='mt-6'> <div>
<p>Ошибка валидации данных</p> <p>Ошибка валидации данных</p>
<PrettyJson data={JSON.parse(error.toString()) as unknown} />; <PrettyJson data={JSON.parse(error.toString()) as unknown} />;
</div> </div>
); );
} else if (!isAxiosError(error)) { } else if (!isAxiosError(error)) {
return ( return (
<div className='mt-6'> <div>
<p> <p>
<b>Error:</b> {error.name} <b>Error:</b> {error.name}
</p> </p>
@ -96,7 +96,7 @@ export function InfoError({ error }: InfoErrorProps) {
'select-text' 'select-text'
)} )}
> >
<div className='font-normal clr-text-default'> <div className='font-normal clr-text-default mb-6'>
<p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p> <p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p>
<br /> <br />
<p>Для продолжения работы перезагрузите страницу</p> <p>Для продолжения работы перезагрузите страницу</p>

View File

@ -1,7 +1,7 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS } from '@/backend/configuration'; import { DELAYS, KEYS } from '@/backend/configuration';
import { infoMsg } from '@/utils/labels'; import { infoMsg } from '@/utils/labels';
import { import {
@ -17,7 +17,7 @@ import {
* Authentication API. * Authentication API.
*/ */
export const authApi = { export const authApi = {
baseKey: 'auth', baseKey: KEYS.auth,
getAuthQueryOptions: () => { getAuthQueryOptions: () => {
return queryOptions({ return queryOptions({

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IChangePasswordDTO } from './types'; import { IChangePasswordDTO } from './types';
export const useChangePassword = () => { export const useChangePassword = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['change-password'], mutationKey: [KEYS.auth, 'change-password'],
mutationFn: authApi.changePassword, mutationFn: authApi.changePassword,
onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }) onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] })
}); });

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IUserLoginDTO } from './types'; import { IUserLoginDTO } from './types';
export const useLogin = () => { export const useLogin = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['login'], mutationKey: [KEYS.auth, 'login'],
mutationFn: authApi.login, mutationFn: authApi.login,
onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }), onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }),
onSuccess: () => client.resetQueries() onSuccess: () => client.resetQueries()

View File

@ -1,11 +1,13 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
export const useLogout = () => { export const useLogout = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['logout'], mutationKey: [KEYS.auth, 'logout'],
mutationFn: authApi.logout, mutationFn: authApi.logout,
onSuccess: () => client.resetQueries() onSuccess: () => client.resetQueries()
}); });

View File

@ -1,11 +1,13 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IRequestPasswordDTO } from './types'; import { IRequestPasswordDTO } from './types';
export const useRequestPasswordReset = () => { export const useRequestPasswordReset = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['request-password-reset'], mutationKey: [KEYS.auth, 'request-password-reset'],
mutationFn: authApi.requestPasswordReset mutationFn: authApi.requestPasswordReset
}); });
return { return {

View File

@ -1,15 +1,17 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IPasswordTokenDTO, IResetPasswordDTO } from './types'; import { IPasswordTokenDTO, IResetPasswordDTO } from './types';
export const useResetPassword = () => { export const useResetPassword = () => {
const validateMutation = useMutation({ const validateMutation = useMutation({
mutationKey: ['validate-token'], mutationKey: [KEYS.auth, 'validate-token'],
mutationFn: authApi.validatePasswordToken mutationFn: authApi.validatePasswordToken
}); });
const resetMutation = useMutation({ const resetMutation = useMutation({
mutationKey: ['reset-password'], mutationKey: [KEYS.auth, 'reset-password'],
mutationFn: authApi.resetPassword mutationFn: authApi.resetPassword
}); });
return { return {

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { libraryApi } from './api'; import { libraryApi } from './api';
import { ICloneLibraryItemDTO } from './types'; import { ICloneLibraryItemDTO } from './types';
export const useCloneItem = () => { export const useCloneItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'clone-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'clone-item'],
mutationFn: libraryApi.cloneItem, mutationFn: libraryApi.cloneItem,
onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }) onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] })
}); });

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { libraryApi } from './api'; import { libraryApi } from './api';
import { ICreateLibraryItemDTO } from './types'; import { ICreateLibraryItemDTO } from './types';
export const useCreateItem = () => { export const useCreateItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'create-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'create-item'],
mutationFn: libraryApi.createItem, mutationFn: libraryApi.createItem,
onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }) onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] })
}); });

View File

@ -8,7 +8,7 @@ import { libraryApi } from './api';
export const useDeleteItem = () => { export const useDeleteItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'delete-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'delete-item'],
mutationFn: libraryApi.deleteItem, mutationFn: libraryApi.deleteItem,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }).catch(console.error); client.invalidateQueries({ queryKey: libraryApi.libraryListKey }).catch(console.error);

View File

@ -3,8 +3,8 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingLibrary = () => { export const useMutatingLibrary = () => {
const countMutations = useIsMutating({ mutationKey: [KEYS.library] }); const countMutations = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); const countOss = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.oss] });
const countRSForm = useIsMutating({ mutationKey: [KEYS.rsform] }); const countRSForm = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.rsform] });
return countMutations + countOss + countRSForm !== 0; return countMutations + countOss + countRSForm !== 0;
}; };

View File

@ -11,7 +11,7 @@ import { AccessPolicy, ILibraryItem } from './types';
export const useSetAccessPolicy = () => { export const useSetAccessPolicy = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setAccessPolicy, mutationFn: libraryApi.setAccessPolicy,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });

View File

@ -10,7 +10,7 @@ import { libraryApi } from './api';
export const useSetEditors = () => { export const useSetEditors = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setEditors, mutationFn: libraryApi.setEditors,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });

View File

@ -11,7 +11,7 @@ import { ILibraryItem } from './types';
export const useSetLocation = () => { export const useSetLocation = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setLocation, mutationFn: libraryApi.setLocation,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });

View File

@ -11,7 +11,7 @@ import { ILibraryItem } from './types';
export const useSetOwner = () => { export const useSetOwner = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-owner'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-owner'],
mutationFn: libraryApi.setOwner, mutationFn: libraryApi.setOwner,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });

View File

@ -11,7 +11,7 @@ import { ILibraryItem, IUpdateLibraryItemDTO, LibraryItemType } from './types';
export const useUpdateItem = () => { export const useUpdateItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'update-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'update-item'],
mutationFn: libraryApi.updateItem, mutationFn: libraryApi.updateItem,
onSuccess: (data: ILibraryItem) => { onSuccess: (data: ILibraryItem) => {
const itemKey = const itemKey =

View File

@ -10,7 +10,7 @@ export const useVersionCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'create-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'create-version'],
mutationFn: libraryApi.versionCreate, mutationFn: libraryApi.versionCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.schema.id }), data.schema); client.setQueryData(KEYS.composite.rsItem({ itemID: data.schema.id }), data.schema);

View File

@ -9,7 +9,7 @@ import { libraryApi } from './api';
export const useVersionDelete = () => { export const useVersionDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'delete-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'delete-version'],
mutationFn: libraryApi.versionDelete, mutationFn: libraryApi.versionDelete,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) => client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) =>

View File

@ -7,7 +7,7 @@ import { libraryApi } from './api';
export const useVersionRestore = () => { export const useVersionRestore = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'restore-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'restore-version'],
mutationFn: libraryApi.versionRestore, mutationFn: libraryApi.versionRestore,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data);

View File

@ -10,7 +10,7 @@ import { IVersionUpdateDTO } from './types';
export const useVersionUpdate = () => { export const useVersionUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'update-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'update-version'],
mutationFn: libraryApi.versionUpdate, mutationFn: libraryApi.versionUpdate,
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) => client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) =>

View File

@ -8,7 +8,7 @@ import { ITargetOperation } from './types';
export const useInputCreate = () => { export const useInputCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'input-create'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'input-create'],
mutationFn: ossApi.inputCreate, mutationFn: ossApi.inputCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss);

View File

@ -8,7 +8,7 @@ import { IInputUpdateDTO } from './types';
export const useInputUpdate = () => { export const useInputUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'input-update'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'input-update'],
mutationFn: ossApi.inputUpdate, mutationFn: ossApi.inputUpdate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -3,7 +3,7 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingOss = () => { export const useMutatingOss = () => {
const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); const countLibrary = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); const countOss = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.oss] });
return countLibrary + countOss !== 0; return countLibrary + countOss !== 0;
}; };

View File

@ -2,6 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { ossApi } from './api'; import { ossApi } from './api';
import { IOperationCreateDTO } from './types'; import { IOperationCreateDTO } from './types';
@ -9,7 +11,7 @@ export const useOperationCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-create'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-create'],
mutationFn: ossApi.operationCreate, mutationFn: ossApi.operationCreate,
onSuccess: response => { onSuccess: response => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: response.oss.id }).queryKey, response.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: response.oss.id }).queryKey, response.oss);

View File

@ -8,7 +8,7 @@ import { IOperationDeleteDTO } from './types';
export const useOperationDelete = () => { export const useOperationDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-delete'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-delete'],
mutationFn: ossApi.operationDelete, mutationFn: ossApi.operationDelete,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -8,7 +8,7 @@ import { ITargetOperation } from './types';
export const useOperationExecute = () => { export const useOperationExecute = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-execute'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-execute'],
mutationFn: ossApi.operationExecute, mutationFn: ossApi.operationExecute,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -10,7 +10,7 @@ import { IOperationUpdateDTO } from './types';
export const useOperationUpdate = () => { export const useOperationUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-update'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-update'],
mutationFn: ossApi.operationUpdate, mutationFn: ossApi.operationUpdate,
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data);

View File

@ -8,7 +8,7 @@ import { ICstRelocateDTO } from './types';
export const useRelocateConstituents = () => { export const useRelocateConstituents = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'relocate-constituents'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'relocate-constituents'],
mutationFn: ossApi.relocateConstituents, mutationFn: ossApi.relocateConstituents,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -2,13 +2,15 @@ import { useMutation } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { ossApi } from './api'; import { ossApi } from './api';
import { IOperationPosition } from './types'; import { IOperationPosition } from './types';
export const useUpdatePositions = () => { export const useUpdatePositions = () => {
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'update-positions'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-positions'],
mutationFn: ossApi.updatePositions, mutationFn: ossApi.updatePositions,
onSuccess: (_, variables) => updateTimestamp(variables.itemID) onSuccess: (_, variables) => updateTimestamp(variables.itemID)
}); });

View File

@ -1,11 +1,13 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
import { ICheckConstituentaDTO } from './types'; import { ICheckConstituentaDTO } from './types';
export const useCheckConstituenta = () => { export const useCheckConstituenta = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['actions', 'check-constituenta'], mutationKey: [KEYS.global_mutation, 'actions', 'check-constituenta'],
mutationFn: rsformsApi.checkConstituenta mutationFn: rsformsApi.checkConstituenta
}); });
return { return {

View File

@ -11,7 +11,7 @@ export const useCstCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'create-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'create-cst'],
mutationFn: rsformsApi.cstCreate, mutationFn: rsformsApi.cstCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);

View File

@ -11,7 +11,7 @@ export const useCstDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'delete-multiple-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'delete-multiple-cst'],
mutationFn: rsformsApi.cstDelete, mutationFn: rsformsApi.cstDelete,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -2,6 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
import { ICstMoveDTO } from './types'; import { ICstMoveDTO } from './types';
@ -9,7 +11,7 @@ export const useCstMove = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'move-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'move-cst'],
mutationFn: rsformsApi.cstMove, mutationFn: rsformsApi.cstMove,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -11,7 +11,7 @@ export const useCstRename = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'rename-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'rename-cst'],
mutationFn: rsformsApi.cstRename, mutationFn: rsformsApi.cstRename,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);

View File

@ -11,7 +11,7 @@ export const useCstSubstitute = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'substitute-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'substitute-cst'],
mutationFn: rsformsApi.cstSubstitute, mutationFn: rsformsApi.cstSubstitute,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -11,7 +11,7 @@ export const useCstUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'update-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'update-cst'],
mutationFn: rsformsApi.cstUpdate, mutationFn: rsformsApi.cstUpdate,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
updateTimestamp(variables.itemID); updateTimestamp(variables.itemID);

View File

@ -1,10 +1,12 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
export const useDownloadRSForm = () => { export const useDownloadRSForm = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'download'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'download'],
mutationFn: rsformsApi.download mutationFn: rsformsApi.download
}); });
return { return {

View File

@ -11,7 +11,7 @@ export const useInlineSynthesis = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'inline-synthesis'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'inline-synthesis'],
mutationFn: rsformsApi.inlineSynthesis, mutationFn: rsformsApi.inlineSynthesis,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -3,7 +3,7 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingRSForm = () => { export const useMutatingRSForm = () => {
const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); const countLibrary = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countRsform = useIsMutating({ mutationKey: [KEYS.rsform] }); const countRsform = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.rsform] });
return countLibrary + countRsform !== 0; return countLibrary + countRsform !== 0;
}; };

View File

@ -11,7 +11,7 @@ export const useProduceStructure = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'produce-structure'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'produce-structure'],
mutationFn: rsformsApi.produceStructure, mutationFn: rsformsApi.produceStructure,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);

View File

@ -10,7 +10,7 @@ export const useResetAliases = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'reset-aliases'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'reset-aliases'],
mutationFn: rsformsApi.resetAliases, mutationFn: rsformsApi.resetAliases,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -2,13 +2,15 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
export const useRestoreOrder = () => { export const useRestoreOrder = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'restore-order'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'restore-order'],
mutationFn: rsformsApi.restoreOrder, mutationFn: rsformsApi.restoreOrder,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);

View File

@ -10,7 +10,7 @@ import { IRSFormUploadDTO } from './types';
export const useUploadTRS = () => { export const useUploadTRS = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'load-trs'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'load-trs'],
mutationFn: rsformsApi.upload, mutationFn: rsformsApi.upload,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data);

View File

@ -10,6 +10,7 @@ import { IUpdateProfileDTO, IUserSignupDTO } from './types';
export const usersApi = { export const usersApi = {
baseKey: KEYS.users, baseKey: KEYS.users,
getUsersQueryOptions: () => getUsersQueryOptions: () =>
queryOptions({ queryOptions({
queryKey: [usersApi.baseKey, 'list'], queryKey: [usersApi.baseKey, 'list'],

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { usersApi } from './api'; import { usersApi } from './api';
import { IUserSignupDTO } from './types'; import { IUserSignupDTO } from './types';
export const useSignup = () => { export const useSignup = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['signup'], mutationKey: [KEYS.users, 'signup'],
mutationFn: usersApi.signup, mutationFn: usersApi.signup,
onSuccess: () => client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey }) onSuccess: () => client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey })
}); });

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { usersApi } from './api'; import { usersApi } from './api';
import { IUpdateProfileDTO } from './types'; import { IUpdateProfileDTO } from './types';
export const useUpdateProfile = () => { export const useUpdateProfile = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['update-profile'], mutationKey: [KEYS.users, 'update-profile'],
mutationFn: usersApi.updateProfile, mutationFn: usersApi.updateProfile,
onSuccess: data => { onSuccess: data => {
client.setQueryData(usersApi.getProfileQueryOptions().queryKey, data); client.setQueryData(usersApi.getProfileQueryOptions().queryKey, data);

View File

@ -2,7 +2,7 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
function useEscapeKey(handleClose: () => void) { function useEscapeKey(handleClose: () => void, isEnabled: boolean = true) {
const handleEscKey = useCallback( const handleEscKey = useCallback(
(event: KeyboardEvent) => { (event: KeyboardEvent) => {
if (event.key === 'Escape') { if (event.key === 'Escape') {
@ -13,11 +13,13 @@ function useEscapeKey(handleClose: () => void) {
); );
useEffect(() => { useEffect(() => {
if (isEnabled) {
document.addEventListener('keyup', handleEscKey, false); document.addEventListener('keyup', handleEscKey, false);
return () => { return () => {
document.removeEventListener('keyup', handleEscKey, false); document.removeEventListener('keyup', handleEscKey, false);
}; };
}, [handleEscKey]); }
}, [handleEscKey, isEnabled]);
} }
export default useEscapeKey; export default useEscapeKey;