refactor: sorted hooks

This commit is contained in:
2025-08-23 19:01:21 +04:00
parent 6ad813ea1d
commit 10f50ac254
27 changed files with 28 additions and 28 deletions

View File

@ -0,0 +1,141 @@
import React from "react";
import { useMutation, UseMutationOptions } 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> = {
entities: TEntity[];
setEntities: React.Dispatch<React.SetStateAction<TEntity[]>>;
refetch: () => void;
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,
>({
entities,
setEntities,
refetch,
mutations,
getCreateEntity,
getUpdateEntity,
getDeleteConfirmTitle,
}: UseEntityOperationsProps<TEntity, TUpdate, TCreate>): CrudOperations<
TEntity,
TUpdate
> => {
const onError = (error: AxiosError<HttpValidationError>) => {
console.error(error);
notifications.error({
message: error.response?.data?.detail as string | undefined,
});
refetch();
};
const createMutation = useMutation({
...mutations.create,
onError,
onSuccess: (res: { entity: TEntity }) => {
setEntities([...entities, res.entity]);
},
});
const updateMutation = useMutation({
...mutations.update,
onError,
});
const deleteMutation = useMutation({
...mutations.delete,
onError,
});
const onCreate = (name: string) => {
const entity = getCreateEntity(name);
if (!entity) return;
createMutation.mutate({
body: {
entity,
},
path: undefined,
query: undefined,
});
};
const onUpdate = (id: number, update: TUpdate) => {
updateMutation.mutate({
body: {
entity: update,
},
path: { pk: id },
query: undefined,
});
setEntities(prev => {
const updated = prev.map(entity =>
entity.id === id ? getUpdateEntity(entity, update) : entity
);
if ("lexorank" in update) {
return sortByLexorank(
updated as (TEntity & { lexorank: string })[]
);
}
return updated;
});
};
const onDelete = (entity: TEntity) => {
modals.openConfirmModal({
title: getDeleteConfirmTitle(entity),
children: (
<Text>Вы уверены, что хотите удалить "{entity.name}"?</Text>
),
labels: { confirm: "Да", cancel: "Нет" },
confirmProps: { color: "red" },
onConfirm: () => {
deleteMutation.mutate({ path: { pk: entity.id } } as any);
setEntities(prev => prev.filter(e => e.id !== entity.id));
},
});
};
return { onCreate, onUpdate, onDelete };
};
export default useCrudOperations;