mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 06:53:12 +00:00
Add the Completion Docs page under Data Management: a searchable template table, a read-only detail panel, add and edit with a live document preview, and delete behind a confirmation that counts the open work orders still using the template and links to them. Add, edit and delete are hidden for users whose role lacks the matching template permission. The preview shares the work-order completion document's page frame, header, safety bullets and procedure heading so the two stay identical.
109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useState } from "react";
|
|
import { useForm, useWatch } from "react-hook-form";
|
|
import { COMPLETION_TEMPLATE_COPY } from "@/domain/completion-templates/constants/completion-template-constants";
|
|
import {
|
|
toCompletionTemplateFormValues,
|
|
toCompletionTemplateInput,
|
|
} from "@/domain/completion-templates/mappers/completion-template-mapper";
|
|
import {
|
|
completionTemplateFormSchema,
|
|
type CompletionTemplateFormValues,
|
|
} from "@/domain/completion-templates/schemas/completion-template-schema";
|
|
import type { CompletionTemplate } from "@/domain/completion-templates/types/completion-template";
|
|
import {
|
|
isTitleRequiredError,
|
|
useCreateCompletionTemplate,
|
|
useUpdateCompletionTemplate,
|
|
} from "@/domain/completion-templates/use-cases/use-completion-template-mutations";
|
|
import type { CompletionTemplatePreviewValues } from "./completion-template-preview";
|
|
|
|
export type CompletionTemplateDialogMode = "create" | "view" | "edit";
|
|
|
|
type UseCompletionTemplateDialogOptions = {
|
|
template: CompletionTemplate | null;
|
|
initialMode: CompletionTemplateDialogMode;
|
|
onClose: () => void;
|
|
onSaved: (template: CompletionTemplate) => void;
|
|
};
|
|
|
|
function usePreviewValues(
|
|
control: ReturnType<typeof useForm<CompletionTemplateFormValues>>["control"],
|
|
): CompletionTemplatePreviewValues {
|
|
const watched = useWatch({ control });
|
|
return {
|
|
name: watched.name ?? "",
|
|
extraSafetyNote: watched.extraSafetyNote ?? null,
|
|
procedures: (watched.procedures ?? []).map((procedure) => ({
|
|
name: procedure?.name ?? "",
|
|
description: procedure?.description ?? "",
|
|
})),
|
|
};
|
|
}
|
|
|
|
export function useCompletionTemplateDialog({
|
|
template,
|
|
initialMode,
|
|
onClose,
|
|
onSaved,
|
|
}: UseCompletionTemplateDialogOptions) {
|
|
const [mode, setMode] = useState<CompletionTemplateDialogMode>(
|
|
template === null ? "create" : initialMode,
|
|
);
|
|
const form = useForm<CompletionTemplateFormValues>({
|
|
resolver: zodResolver(completionTemplateFormSchema),
|
|
defaultValues: toCompletionTemplateFormValues(template),
|
|
});
|
|
const previewValues = usePreviewValues(form.control);
|
|
const create = useCreateCompletionTemplate();
|
|
const update = useUpdateCompletionTemplate();
|
|
|
|
function showServerTitleError(error: Error) {
|
|
if (!isTitleRequiredError(error)) return;
|
|
form.setError(
|
|
"name",
|
|
{ message: COMPLETION_TEMPLATE_COPY.titleRequired },
|
|
{ shouldFocus: true },
|
|
);
|
|
}
|
|
|
|
const submit = form.handleSubmit((values) => {
|
|
const input = toCompletionTemplateInput(values);
|
|
if (template === null) {
|
|
create.mutate(input, { onSuccess: onClose, onError: showServerTitleError });
|
|
return;
|
|
}
|
|
update.mutate(
|
|
{ template, input },
|
|
{
|
|
onSuccess: (saved) => {
|
|
form.reset(toCompletionTemplateFormValues(saved));
|
|
setMode("view");
|
|
onSaved(saved);
|
|
},
|
|
onError: showServerTitleError,
|
|
},
|
|
);
|
|
});
|
|
|
|
/** Discards unsaved edits: back to the template as it was, or closed when creating. */
|
|
function cancel() {
|
|
if (template === null) {
|
|
onClose();
|
|
return;
|
|
}
|
|
form.reset(toCompletionTemplateFormValues(template));
|
|
setMode("view");
|
|
}
|
|
|
|
return {
|
|
mode,
|
|
isEditing: mode !== "view",
|
|
form,
|
|
previewValues,
|
|
submit,
|
|
cancel,
|
|
startEditing: () => setMode("edit"),
|
|
isSaving: create.isPending || update.isPending,
|
|
};
|
|
}
|