mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 09:13:11 +00:00
Only the server's TitleRequired rejection is shown on the Document Title field; any other rejected value is reported in a toast. Procedure names and the extra safety note stop at the server's length limits.
85 lines
2.9 KiB
TypeScript
85 lines
2.9 KiB
TypeScript
import {
|
|
useMutation,
|
|
useQueryClient,
|
|
type QueryClient,
|
|
type UseMutationResult,
|
|
} from "@tanstack/react-query";
|
|
import { isHTTPError } from "ky";
|
|
import { toast } from "react-toastify";
|
|
import { completionTemplatesApi } from "@/domain/completion-templates/api/completion-templates-api";
|
|
import { COMPLETION_TEMPLATE_COPY } from "@/domain/completion-templates/constants/completion-template-constants";
|
|
import type {
|
|
CompletionTemplate,
|
|
CompletionTemplateInput,
|
|
} from "@/domain/completion-templates/types/completion-template";
|
|
import { queryKeys } from "@/infra/query-key/query-key";
|
|
|
|
interface UpdateCompletionTemplateVariables {
|
|
template: CompletionTemplate;
|
|
input: CompletionTemplateInput;
|
|
}
|
|
|
|
/** The server's blank-title rejection, which the form shows on the title field instead. */
|
|
export function isTitleRequiredError(error: Error): boolean {
|
|
if (!isHTTPError(error) || error.response.status !== 422) return false;
|
|
const body: unknown = error.data;
|
|
return (
|
|
typeof body === "object" && body !== null && "code" in body && body.code === "TitleRequired"
|
|
);
|
|
}
|
|
|
|
function invalidateTemplates(queryClient: QueryClient) {
|
|
void queryClient.invalidateQueries({ queryKey: queryKeys.completionTemplates.all });
|
|
// The Services registry lists template names and clears links to a deleted template.
|
|
void queryClient.invalidateQueries({ queryKey: queryKeys.services.all });
|
|
}
|
|
|
|
function toastFailure(error: Error, fallback: string) {
|
|
if (isTitleRequiredError(error)) return;
|
|
toast.error(error.message || fallback);
|
|
}
|
|
|
|
export function useCreateCompletionTemplate(): UseMutationResult<
|
|
CompletionTemplate,
|
|
Error,
|
|
CompletionTemplateInput
|
|
> {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: (input: CompletionTemplateInput) => completionTemplatesApi.create(input),
|
|
onSuccess: () => {
|
|
invalidateTemplates(queryClient);
|
|
toast.success(COMPLETION_TEMPLATE_COPY.added);
|
|
},
|
|
onError: (error: Error) => toastFailure(error, "Failed to add template"),
|
|
});
|
|
}
|
|
|
|
export function useUpdateCompletionTemplate(): UseMutationResult<
|
|
CompletionTemplate,
|
|
Error,
|
|
UpdateCompletionTemplateVariables
|
|
> {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: ({ template, input }: UpdateCompletionTemplateVariables) =>
|
|
completionTemplatesApi.update(template, input),
|
|
onSuccess: () => {
|
|
invalidateTemplates(queryClient);
|
|
toast.success(COMPLETION_TEMPLATE_COPY.updated);
|
|
},
|
|
onError: (error: Error) => toastFailure(error, "Failed to update template"),
|
|
});
|
|
}
|
|
|
|
export function useDeleteCompletionTemplate(): UseMutationResult<void, Error, number> {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: (id: number) => completionTemplatesApi.delete(id),
|
|
onSuccess: () => {
|
|
invalidateTemplates(queryClient);
|
|
toast.success(COMPLETION_TEMPLATE_COPY.deleted);
|
|
},
|
|
onError: (error: Error) => toastFailure(error, "Failed to delete template"),
|
|
});
|
|
}
|