Files
Crm-Frontend/src/hooks/cruds/baseCrud/useCrudOperations.tsx

188 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import {
useMutation,
UseMutationOptions,
useQueryClient,
} from "@tanstack/react-query";
import { AxiosError } from "axios";
import { Text } from "@mantine/core";
import { modals } from "@mantine/modals";
import { HttpValidationError } from "@/lib/client";
import { notifications } from "@/lib/notifications";
import { sortByLexorank } from "@/utils/lexorank";
import {
BaseEntity,
CreateMutationOptions,
DeleteMutationOptions,
UpdateMutationOptions,
} from "./types";
type CrudOperations<TEntity, TUpdate> = {
onCreate: (name: string) => void;
onUpdate: (id: number, update: TUpdate) => void;
onDelete: (entity: TEntity) => void;
};
type UseEntityOperationsProps<TEntity extends BaseEntity, TUpdate, TCreate> = {
key: string;
queryKey: any[];
mutations: {
create: UseMutationOptions<
any,
AxiosError<HttpValidationError>,
CreateMutationOptions
>;
update: UseMutationOptions<
any,
AxiosError<HttpValidationError>,
UpdateMutationOptions
>;
delete: UseMutationOptions<
any,
AxiosError<HttpValidationError>,
DeleteMutationOptions
>;
};
getCreateEntity: (name: string) => TCreate | null;
getUpdateEntity: (oldEntity: TEntity, update: TUpdate) => TEntity;
getDeleteConfirmTitle: (entity: TEntity) => string;
};
const useCrudOperations = <
TEntity extends BaseEntity,
TUpdate extends object,
TCreate extends object,
>({
key,
queryKey,
mutations,
getCreateEntity,
getUpdateEntity,
getDeleteConfirmTitle,
}: UseEntityOperationsProps<TEntity, TUpdate, TCreate>): CrudOperations<
TEntity,
TUpdate
> => {
const queryClient = useQueryClient();
const onError = (
error: AxiosError<HttpValidationError>,
_: any,
context: any
) => {
console.error(error);
notifications.error({
message: error.response?.data?.detail as string | undefined,
});
if (context?.previous) {
queryClient.setQueryData(queryKey, context.previous);
}
};
const onSettled = () => {
queryClient.invalidateQueries({
predicate: (query: { queryKey: any }) =>
query.queryKey[0]?._id === key,
});
};
const createMutation = useMutation({
...mutations.create,
onError,
onSettled,
});
const updateMutation = useMutation({
...mutations.update,
onError,
onSettled,
onMutate: async ({ body: { entity: update } }) => {
await queryClient.cancelQueries({ queryKey: [key] });
const previous = queryClient.getQueryData(queryKey);
queryClient.setQueryData(queryKey, (old: { items: TEntity[] }) => {
let updated = old.items.map((entity: TEntity) =>
entity.id === update.id
? getUpdateEntity(entity, update)
: entity
);
if ("lexorank" in update) {
updated = sortByLexorank(
updated as (TEntity & { lexorank: string })[]
);
}
return {
...old,
items: updated,
};
});
return { previous };
},
});
const deleteMutation = useMutation({
...mutations.delete,
onError,
onSettled,
onMutate: async ({ path: { pk } }) => {
await queryClient.cancelQueries({ queryKey: [key] });
const previous = queryClient.getQueryData(queryKey);
queryClient.setQueryData(queryKey, (old: { items: TEntity[] }) => {
const filtered = old.items.filter(e => e.id !== pk);
return {
...old,
items: filtered,
};
});
return { previous };
},
});
const onCreate = (name: string) => {
const entity = getCreateEntity(name);
if (!entity) return;
createMutation.mutate({
body: {
entity,
},
path: undefined,
query: undefined,
});
};
const onUpdate = async (id: number, update: TUpdate) => {
updateMutation.mutate({
body: {
entity: update,
},
path: { pk: id },
query: undefined,
});
};
const onDelete = (entity: TEntity, onSuccess?: () => void) => {
modals.openConfirmModal({
title: getDeleteConfirmTitle(entity),
children: (
<Text>Вы уверены, что хотите удалить "{entity.name}"?</Text>
),
confirmProps: { color: "red" },
onConfirm: () => {
deleteMutation.mutate({ path: { pk: entity.id } } as any);
onSuccess && onSuccess();
},
});
};
return { onCreate, onUpdate, onDelete };
};
export default useCrudOperations;