mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 12:49:00 +00:00
fix(services): use completion document templates
This commit is contained in:
parent
0b63d882ab
commit
b449df97e6
8 changed files with 68 additions and 7 deletions
|
|
@ -31,6 +31,7 @@ export const API_PATHS = {
|
||||||
boardSearch: "workorders/board/search",
|
boardSearch: "workorders/board/search",
|
||||||
boardPatch: (id: string | number) => `workorders/${id}/board`,
|
boardPatch: (id: string | number) => `workorders/${id}/board`,
|
||||||
boardDetail: (id: string | number) => `workorders/${id}/detail`,
|
boardDetail: (id: string | number) => `workorders/${id}/detail`,
|
||||||
|
completionTemplates: "workorders/completion-templates",
|
||||||
comments: (id: string | number) => `workorders/${id}/comments`,
|
comments: (id: string | number) => `workorders/${id}/comments`,
|
||||||
commentItem: (workOrderId: string | number, commentId: string | number) =>
|
commentItem: (workOrderId: string | number, commentId: string | number) =>
|
||||||
`workorders/${workOrderId}/comments/${commentId}`,
|
`workorders/${workOrderId}/comments/${commentId}`,
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import {
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { Droplets, Hammer, Settings2, Wrench, Zap } from "lucide-react";
|
import { Droplets, Hammer, Settings2, Wrench, Zap } from "lucide-react";
|
||||||
import type { DropdownOption } from "@/domain/settings/dropdown-options/types/dropdown-option";
|
import type { DropdownOption } from "@/domain/settings/dropdown-options/types/dropdown-option";
|
||||||
import type { TaskTemplate } from "@/domain/settings/task-templates/types/task-template";
|
|
||||||
import {
|
import {
|
||||||
SERVICE_WORK_ORDER_TYPES,
|
SERVICE_WORK_ORDER_TYPES,
|
||||||
|
type CompletionDocTemplateOption,
|
||||||
type Service,
|
type Service,
|
||||||
type ServiceWorkOrderType,
|
type ServiceWorkOrderType,
|
||||||
} from "@/domain/services/types/service";
|
} from "@/domain/services/types/service";
|
||||||
|
|
@ -142,7 +142,7 @@ type EditorProps = {
|
||||||
form: ServiceForm;
|
form: ServiceForm;
|
||||||
formError: string;
|
formError: string;
|
||||||
trades: DropdownOption[];
|
trades: DropdownOption[];
|
||||||
templates: TaskTemplate[];
|
templates: CompletionDocTemplateOption[];
|
||||||
isSaving: boolean;
|
isSaving: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSave: () => void;
|
onSave: () => void;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
import { apiGet, apiPost, apiPut } from "@/api/api";
|
import { apiGet, apiPost, apiPut } from "@/api/api";
|
||||||
import { API_PATHS } from "@/api/api-paths";
|
import { API_PATHS } from "@/api/api-paths";
|
||||||
import { handleApiResponse } from "@/api/handle-api-response";
|
import { handleApiResponse } from "@/api/handle-api-response";
|
||||||
import { mapService, mapServices } from "@/domain/services/mappers/service-mapper";
|
import {
|
||||||
import type { Service, ServiceInput } from "@/domain/services/types/service";
|
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 = {
|
const SERVICE_WORK_ORDER_TYPE_API = {
|
||||||
PM: 2,
|
PM: 2,
|
||||||
|
|
@ -27,6 +35,11 @@ export const servicesApi = {
|
||||||
return mapServices(handleApiResponse(data));
|
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> => {
|
create: async (input: ServiceInput): Promise<Service> => {
|
||||||
const data = await apiPost<unknown>(API_PATHS.services.list, toApiInput(input));
|
const data = await apiPost<unknown>(API_PATHS.services.list, toApiInput(input));
|
||||||
return mapService(handleApiResponse(data));
|
return mapService(handleApiResponse(data));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type {
|
import type {
|
||||||
|
CompletionDocTemplateOption,
|
||||||
LinkedServiceTemplate,
|
LinkedServiceTemplate,
|
||||||
Service,
|
Service,
|
||||||
ServiceWorkOrderType,
|
ServiceWorkOrderType,
|
||||||
|
|
@ -87,3 +88,26 @@ export function mapServices(raw: unknown): Service[] {
|
||||||
? payload.map(mapService).filter((service) => service.id !== "")
|
? 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,
|
||||||
|
];
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ export interface LinkedServiceTemplate {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CompletionDocTemplateOption = LinkedServiceTemplate;
|
||||||
|
|
||||||
export interface Service {
|
export interface Service {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ import { useEffect, useMemo, useState } from "react";
|
||||||
import { useAuthContext } from "@/providers/auth-context";
|
import { useAuthContext } from "@/providers/auth-context";
|
||||||
import { getPrimaryUserRole, isAdminUser } from "@/lib/auth/user-utils";
|
import { getPrimaryUserRole, isAdminUser } from "@/lib/auth/user-utils";
|
||||||
import { useDropdownOptionsByCategory } from "@/domain/settings/dropdown-options/use-cases/use-dropdown-options-by-category";
|
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 type { Service, ServiceInput, ServiceWorkOrderType } from "@/domain/services/types/service";
|
||||||
import {
|
import {
|
||||||
useCreateService,
|
useCreateService,
|
||||||
|
useCompletionDocTemplates,
|
||||||
useDeactivateService,
|
useDeactivateService,
|
||||||
useServices,
|
useServices,
|
||||||
useUpdateService,
|
useUpdateService,
|
||||||
|
|
@ -95,7 +95,7 @@ export function useServicesRegistryController() {
|
||||||
const queryStatus = status === "active" ? true : status === "inactive" ? false : undefined;
|
const queryStatus = status === "active" ? true : status === "inactive" ? false : undefined;
|
||||||
const servicesQuery = useServices(queryStatus);
|
const servicesQuery = useServices(queryStatus);
|
||||||
const { data: trades = [] } = useDropdownOptionsByCategory("Trade");
|
const { data: trades = [] } = useDropdownOptionsByCategory("Trade");
|
||||||
const { data: templates = [] } = useTaskTemplates();
|
const { data: templates = [] } = useCompletionDocTemplates();
|
||||||
const createService = useCreateService();
|
const createService = useCreateService();
|
||||||
const updateService = useUpdateService();
|
const updateService = useUpdateService();
|
||||||
const deactivateService = useDeactivateService();
|
const deactivateService = useDeactivateService();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { useMutation, useQuery, useQueryClient, type UseQueryResult } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient, type UseQueryResult } from "@tanstack/react-query";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { servicesApi } from "@/domain/services/api/services-api";
|
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";
|
import { queryKeys } from "@/infra/query-key/query-key";
|
||||||
|
|
||||||
export function useServices(isActive?: boolean): UseQueryResult<Service[], Error> {
|
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() {
|
export function useCreateService() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
|
|
|
||||||
|
|
@ -77,4 +77,13 @@ describe("servicesApi", () => {
|
||||||
supportedWorkOrderTypes: [2],
|
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" }]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue