import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import toast from "react-hot-toast"; import { api } from "@/services/api"; import type { RuleEngineListParams } from "@/services/ruleEngine/ruleEngine.service"; import { RULE_ENGINE_SELECT_NONE } from "@/pages/ruleEngine/config/resources"; import type { ApproveRatePayload, RuleEngineRecord, RuleEngineResourceSlug, } from "@/types/rule-engine"; import { QUERY_KEYS } from "@/constants/TANSTACK_QUEY_KEY"; const CARGO_TYPE_PARENT_PAGE_SIZE = 500; const CONTAINER_TYPE_OPTIONS_PAGE_SIZE = 500; const listKey = (resource: RuleEngineResourceSlug) => ["rule-engine", resource] as const; export const useRuleEngineList = ( resource: RuleEngineResourceSlug, params: RuleEngineListParams, ) => useQuery( api.ruleEngine.list.queryOptions({ input: { resource, params }, }), ); export const useCargoTypeParentOptions = (excludeId?: string, enabled = true) => useQuery({ queryKey: api.ruleEngine.list.queryKey({ resource: "cargo-types", params: { page: 1, pageSize: CARGO_TYPE_PARENT_PAGE_SIZE }, }), queryFn: () => api.ruleEngine.list.call({ resource: "cargo-types", params: { page: 1, pageSize: CARGO_TYPE_PARENT_PAGE_SIZE }, }), enabled, select: (result) => { const noneOption = { label: "None", value: RULE_ENGINE_SELECT_NONE }; const parents = (result.data ?? []) .filter((row) => row.id && String(row.id) !== excludeId) .map((row) => { const name = String(row.cargoTypeName ?? "").trim(); const code = String(row.code ?? "").trim(); const label = name && code ? `${name} (${code})` : name || code || String(row.id); return { label, value: String(row.id) }; }); return [noneOption, ...parents]; }, }); export const useContainerTypeOptions = (enabled = true) => useQuery({ queryKey: [ ...QUERY_KEYS.RULE_ENGINE.list("container-types"), "select-options", ], queryFn: () => api.ruleEngine.list.call({ resource: "container-types", params: { page: 1, pageSize: CONTAINER_TYPE_OPTIONS_PAGE_SIZE, }, }), enabled, select: (result) => { const noneOption = { label: "None", value: RULE_ENGINE_SELECT_NONE }; const options = (result.data ?? []).map((row) => { const label = String(row.label ?? "").trim(); const code = String(row.code ?? "").trim(); const size = row.sizeFt ? `${String(row.sizeFt)}ft` : ""; const parts = [label || code || String(row.id), size].filter(Boolean); return { label: parts.join(" - "), value: String(row.id), }; }); return [noneOption, ...options]; }, }); export const useApprovalChain = (enabled: boolean) => useQuery( api.ruleEngine.getApprovalChain.queryOptions({ enabled, }), ); export const useRuleEngineMutations = (resource: RuleEngineResourceSlug) => { const qc = useQueryClient(); const invalidate = () => qc.invalidateQueries({ queryKey: listKey(resource) }); const create = useMutation({ mutationFn: (payload: Record) => api.ruleEngine.create.call({ resource, payload }), onSuccess: () => { toast.success("Created successfully"); invalidate(); }, onError: () => toast.error("Failed to create record"), }); const update = useMutation({ mutationFn: ({ id, payload, }: { id: string; payload: Record; }) => api.ruleEngine.update.call({ resource, id, payload }), onSuccess: () => { toast.success("Updated successfully"); invalidate(); }, onError: () => toast.error("Failed to update record"), }); const remove = useMutation({ mutationFn: (id: string) => api.ruleEngine.remove.call({ resource, id }), onSuccess: () => { toast.success("Deleted successfully"); invalidate(); }, onError: () => toast.error("Failed to delete record"), }); return { create, update, remove }; }; export const useRateWorkflow = () => { const qc = useQueryClient(); const invalidate = () => qc.invalidateQueries({ queryKey: listKey("rates") }); const submit = useMutation({ mutationFn: (id: string) => api.ruleEngine.submitRate.call({ id }), onSuccess: () => { toast.success("Rate submitted for approval"); invalidate(); }, onError: () => toast.error("Failed to submit rate"), }); const approve = useMutation({ mutationFn: ({ id, payload, }: { id: string; payload: ApproveRatePayload; }) => api.ruleEngine.approveRate.call({ id, payload }), onSuccess: () => { toast.success("Rate approved"); invalidate(); }, onError: () => toast.error("Failed to approve rate"), }); return { submit, approve }; };