mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-01 13: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.
103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
import { Controller, useFieldArray, type UseFormReturn } from "react-hook-form";
|
|
import { Text } from "@/components/ui/text";
|
|
import { TextField } from "@/components/ui/text-field";
|
|
import { PROCEDURE_NAME_MAX_LENGTH } from "@/domain/completion-templates/constants/completion-template-constants";
|
|
import type { CompletionTemplateFormValues } from "@/domain/completion-templates/schemas/completion-template-schema";
|
|
import { CompletionTemplateAddLink } from "./completion-template-add-link";
|
|
import { CompletionTemplateRemoveButton } from "./completion-template-remove-button";
|
|
|
|
type ProceduresEditorProps = {
|
|
form: UseFormReturn<CompletionTemplateFormValues>;
|
|
};
|
|
|
|
const DESCRIPTION_PLACEHOLDER =
|
|
"Describe the procedure — steps, sub-items, whatever the source document has. One item per line works well.";
|
|
|
|
function ProcedureFields({ form, index }: ProceduresEditorProps & { index: number }) {
|
|
return (
|
|
<div className="grid gap-2.5">
|
|
<Controller
|
|
control={form.control}
|
|
name={`procedures.${index}.name`}
|
|
render={({ field }) => (
|
|
<TextField
|
|
value={field.value}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
inputRef={field.ref}
|
|
placeholder="Procedure name (e.g. Backflow Procedure)"
|
|
slotProps={{
|
|
htmlInput: {
|
|
"aria-label": `Procedure ${index + 1} name`,
|
|
maxLength: PROCEDURE_NAME_MAX_LENGTH,
|
|
},
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
<Controller
|
|
control={form.control}
|
|
name={`procedures.${index}.description`}
|
|
render={({ field }) => (
|
|
<TextField
|
|
value={field.value}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
inputRef={field.ref}
|
|
multiline
|
|
minRows={5}
|
|
maxRows={8}
|
|
placeholder={DESCRIPTION_PLACEHOLDER}
|
|
slotProps={{ htmlInput: { "aria-label": `Procedure ${index + 1} description` } }}
|
|
sx={{ "& .MuiOutlinedInput-root": { height: "auto" } }}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/** Procedures print in the order they are listed here. */
|
|
export function CompletionTemplateProceduresEditor({ form }: ProceduresEditorProps) {
|
|
const { fields, append, remove } = useFieldArray({ control: form.control, name: "procedures" });
|
|
|
|
return (
|
|
<div className="grid gap-3">
|
|
{fields.map((field, index) => (
|
|
<fieldset
|
|
key={field.id}
|
|
aria-label={`Procedure ${index + 1}`}
|
|
className="m-0 min-w-0"
|
|
style={{
|
|
padding: 12,
|
|
borderRadius: "var(--radius-md)",
|
|
border: "1px solid var(--color-border)",
|
|
}}
|
|
>
|
|
<div className="flex items-center justify-between" style={{ marginBottom: 8 }}>
|
|
<Text
|
|
variant="caption"
|
|
tone="muted"
|
|
sx={{
|
|
fontSize: 12,
|
|
fontWeight: 600,
|
|
textTransform: "uppercase",
|
|
letterSpacing: "0.04em",
|
|
}}
|
|
>
|
|
Procedure {index + 1}
|
|
</Text>
|
|
<CompletionTemplateRemoveButton
|
|
label={`Remove procedure ${index + 1}`}
|
|
onClick={() => remove(index)}
|
|
/>
|
|
</div>
|
|
<ProcedureFields form={form} index={index} />
|
|
</fieldset>
|
|
))}
|
|
<CompletionTemplateAddLink onClick={() => append({ name: "", description: "" })}>
|
|
+ Add procedure
|
|
</CompletionTemplateAddLink>
|
|
</div>
|
|
);
|
|
}
|