fix(services): use completion document templates

This commit is contained in:
Codex Review Integration 2026-09-16 19:13:00 -03:00
parent 0b63d882ab
commit b449df97e6
8 changed files with 68 additions and 7 deletions

View file

@ -31,6 +31,7 @@ export const API_PATHS = {
boardSearch: "workorders/board/search",
boardPatch: (id: string | number) => `workorders/${id}/board`,
boardDetail: (id: string | number) => `workorders/${id}/detail`,
completionTemplates: "workorders/completion-templates",
comments: (id: string | number) => `workorders/${id}/comments`,
commentItem: (workOrderId: string | number, commentId: string | number) =>
`workorders/${workOrderId}/comments/${commentId}`,

View file

@ -24,9 +24,9 @@ import {
} from "@mui/material";
import { Droplets, Hammer, Settings2, Wrench, Zap } from "lucide-react";
import type { DropdownOption } from "@/domain/settings/dropdown-options/types/dropdown-option";
import type { TaskTemplate } from "@/domain/settings/task-templates/types/task-template";
import {
SERVICE_WORK_ORDER_TYPES,
type CompletionDocTemplateOption,
type Service,
type ServiceWorkOrderType,
} from "@/domain/services/types/service";
@ -142,7 +142,7 @@ type EditorProps = {
form: ServiceForm;
formError: string;
trades: DropdownOption[];
templates: TaskTemplate[];
templates: CompletionDocTemplateOption[];
isSaving: boolean;
onClose: () => void;
onSave: () => void;

View file

@ -1,8 +1,16 @@
import { apiGet, apiPost, apiPut } from "@/api/api";
import { API_PATHS } from "@/api/api-paths";
import { handleApiResponse } from "@/api/handle-api-response";
import { mapService, mapServices } from "@/domain/services/mappers/service-mapper";
import type { Service, ServiceInput } from "@/domain/services/types/service";
import {
mapCompletionDocTemplates,
mapService,
mapServices,
} from "@/domain/services/mappers/service-mapper";
import type {
CompletionDocTemplateOption,
Service,
ServiceInput,
} from "@/domain/services/types/service";
const SERVICE_WORK_ORDER_TYPE_API = {
PM: 2,
@ -27,6 +35,11 @@ export const servicesApi = {
return mapServices(handleApiResponse(data));
},
getCompletionTemplates: async (): Promise<CompletionDocTemplateOption[]> => {
const data = await apiGet<unknown>(API_PATHS.workOrder.completionTemplates);
return mapCompletionDocTemplates(handleApiResponse(data));
},
create: async (input: ServiceInput): Promise<Service> => {
const data = await apiPost<unknown>(API_PATHS.services.list, toApiInput(input));
return mapService(handleApiResponse(data));

View file

@ -1,4 +1,5 @@
import type {
CompletionDocTemplateOption,
LinkedServiceTemplate,
Service,
ServiceWorkOrderType,
@ -87,3 +88,26 @@ export function mapServices(raw: unknown): Service[] {
? payload.map(mapService).filter((service) => service.id !== "")
: [];
}
export function mapCompletionDocTemplates(raw: unknown): CompletionDocTemplateOption[] {
const payload = Array.isArray(raw)
? raw
: (() => {
const record = asRecord(raw);
return record.items ?? record.Items ?? record.data ?? record.Data;
})();
return Array.isArray(payload)
? payload.flatMap((item) => {
const record = asRecord(item);
const id = readId(record);
return id === ""
? []
: [
{
id,
name: readString(record, "name", "Name"),
} satisfies CompletionDocTemplateOption,
];
})
: [];
}

View file

@ -7,6 +7,8 @@ export interface LinkedServiceTemplate {
name: string;
}
export type CompletionDocTemplateOption = LinkedServiceTemplate;
export interface Service {
id: string | number;
name: string;

View file

@ -2,10 +2,10 @@ import { useEffect, useMemo, useState } from "react";
import { useAuthContext } from "@/providers/auth-context";
import { getPrimaryUserRole, isAdminUser } from "@/lib/auth/user-utils";
import { useDropdownOptionsByCategory } from "@/domain/settings/dropdown-options/use-cases/use-dropdown-options-by-category";
import { useTaskTemplates } from "@/domain/settings/task-templates/use-cases/use-task-templates";
import type { Service, ServiceInput, ServiceWorkOrderType } from "@/domain/services/types/service";
import {
useCreateService,
useCompletionDocTemplates,
useDeactivateService,
useServices,
useUpdateService,
@ -95,7 +95,7 @@ export function useServicesRegistryController() {
const queryStatus = status === "active" ? true : status === "inactive" ? false : undefined;
const servicesQuery = useServices(queryStatus);
const { data: trades = [] } = useDropdownOptionsByCategory("Trade");
const { data: templates = [] } = useTaskTemplates();
const { data: templates = [] } = useCompletionDocTemplates();
const createService = useCreateService();
const updateService = useUpdateService();
const deactivateService = useDeactivateService();

View file

@ -1,7 +1,11 @@
import { useMutation, useQuery, useQueryClient, type UseQueryResult } from "@tanstack/react-query";
import { toast } from "react-toastify";
import { servicesApi } from "@/domain/services/api/services-api";
import type { Service, ServiceInput } from "@/domain/services/types/service";
import type {
CompletionDocTemplateOption,
Service,
ServiceInput,
} from "@/domain/services/types/service";
import { queryKeys } from "@/infra/query-key/query-key";
export function useServices(isActive?: boolean): UseQueryResult<Service[], Error> {
@ -12,6 +16,14 @@ export function useServices(isActive?: boolean): UseQueryResult<Service[], Error
});
}
export function useCompletionDocTemplates(): UseQueryResult<CompletionDocTemplateOption[], Error> {
return useQuery({
queryKey: queryKeys.services.completionTemplates(),
queryFn: servicesApi.getCompletionTemplates,
staleTime: 5 * 60 * 1000,
});
}
export function useCreateService() {
const queryClient = useQueryClient();
return useMutation({

View file

@ -77,4 +77,13 @@ describe("servicesApi", () => {
supportedWorkOrderTypes: [2],
});
});
it("loads active Completion Document Template options from the completion route", async () => {
apiGet.mockResolvedValue([{ Id: 4, Name: "HVAC checklist", IsActive: true }]);
const templates = await servicesApi.getCompletionTemplates();
expect(apiGet).toHaveBeenCalledWith(API_PATHS.workOrder.completionTemplates);
expect(templates).toEqual([{ id: 4, name: "HVAC checklist" }]);
});
});