diff --git a/src/api/calls/calls.ts b/src/api/calls/calls.ts index 65b195d6..10da8082 100644 --- a/src/api/calls/calls.ts +++ b/src/api/calls/calls.ts @@ -14,7 +14,7 @@ const callsApi = createCachedApiEndpoint('/Calls/GetActiveCalls', { const getCallApi = createApiEndpoint('/Calls/GetCall'); const getCallExtraDataApi = createApiEndpoint('/Calls/GetCallExtraData'); const createCallApi = createApiEndpoint('/Calls/SaveCall'); -const updateCallApi = createApiEndpoint('/Calls/UpdateCall'); +const updateCallApi = createApiEndpoint('/Calls/EditCall'); const closeCallApi = createApiEndpoint('/Calls/CloseCall'); export const getCalls = async () => { @@ -96,16 +96,16 @@ const buildDispatchList = (data: { dispatchEveryone?: boolean; dispatchUsers?: s const dispatchEntries: string[] = []; if (data.dispatchUsers) { - dispatchEntries.push(...data.dispatchUsers); + dispatchEntries.push(...data.dispatchUsers.map((user) => `P:${user}`)); } if (data.dispatchGroups) { - dispatchEntries.push(...data.dispatchGroups); + dispatchEntries.push(...data.dispatchGroups.map((group) => `G:${group}`)); } if (data.dispatchRoles) { - dispatchEntries.push(...data.dispatchRoles); + dispatchEntries.push(...data.dispatchRoles.map((role) => `R:${role}`)); } if (data.dispatchUnits) { - dispatchEntries.push(...data.dispatchUnits); + dispatchEntries.push(...data.dispatchUnits.map((unit) => `U:${unit}`)); } return dispatchEntries.join('|'); @@ -147,7 +147,7 @@ export const updateCall = async (callData: UpdateCallRequest) => { const dispatchList = buildDispatchList(callData); const data = { - CallId: callData.callId, + Id: callData.callId, Name: callData.name, Nature: callData.nature, Note: callData.note || '', @@ -163,7 +163,7 @@ export const updateCall = async (callData: UpdateCallRequest) => { DispatchList: dispatchList, }; - const response = await updateCallApi.post(data); + const response = await updateCallApi.put(data); // Invalidate cache after successful mutation try { diff --git a/src/app/call/[id]/edit.tsx b/src/app/call/[id]/edit.tsx index b633d4a3..81fcc84d 100644 --- a/src/app/call/[id]/edit.tsx +++ b/src/app/call/[id]/edit.tsx @@ -88,6 +88,7 @@ export default function EditCall() { const callDataError = useCallsStore((state) => state.error); const fetchCallFormData = useCallsStore((state) => state.fetchCallFormData); const call = useCallDetailStore((state) => state.call); + const callExtraData = useCallDetailStore((state) => state.callExtraData); const callDetailLoading = useCallDetailStore((state) => state.isLoading); const callDetailError = useCallDetailStore((state) => state.error); const fetchCallDetail = useCallDetailStore((state) => state.fetchCallDetail); @@ -158,7 +159,35 @@ export default function EditCall() { useEffect(() => { if (call) { const priority = callPriorities.find((p) => p.Id === call.Priority); - const type = callTypes.find((t) => t.Id === call.Type); + // Call.Type is the type's text, not its id -- matching on Id left the picker blank on every edit. + const type = callTypes.find((t) => t.Name === call.Type); + + // Seed the picker with who the call already went to. Without this the edit posted an empty + // dispatch list, which the API reads as "dispatch the whole department". + const initialDispatch: DispatchSelection = { + everyone: false, + users: [], + groups: [], + roles: [], + units: [], + }; + + if (callExtraData?.Dispatches) { + callExtraData.Dispatches.forEach((dispatch) => { + const dispatchType = (dispatch.Type || '').toLowerCase(); + if (dispatchType === 'personnel' || dispatchType === 'p' || dispatchType === 'user') { + initialDispatch.users.push(dispatch.Id); + } else if (dispatchType === 'group' || dispatchType === 'groups' || dispatchType === 'g') { + initialDispatch.groups.push(dispatch.Id); + } else if (dispatchType === 'role' || dispatchType === 'roles' || dispatchType === 'r') { + initialDispatch.roles.push(dispatch.Id); + } else if (dispatchType === 'unit' || dispatchType === 'units' || dispatchType === 'u') { + initialDispatch.units.push(dispatch.Id); + } + }); + } + + setDispatchSelection(initialDispatch); reset({ name: call.Name || '', @@ -175,13 +204,7 @@ export default function EditCall() { type: type?.Name || '', contactName: call.ContactName || '', contactInfo: call.ContactInfo || '', - dispatchSelection: { - everyone: false, - users: [], - groups: [], - roles: [], - units: [], - }, + dispatchSelection: initialDispatch, }); // Set selected location if coordinates exist @@ -193,7 +216,7 @@ export default function EditCall() { }); } } - }, [call, callPriorities, callTypes, reset]); + }, [call, callExtraData, callPriorities, callTypes, reset]); // Track when edit call view is rendered useEffect(() => { @@ -226,7 +249,8 @@ export default function EditCall() { name: data.name, nature: data.nature, priority: priority?.Id || 0, - type: type?.Id || '', + // The API matches the call type by its text, not its id. + type: type?.Name || '', note: data.note, address: data.address, latitude: data.latitude, diff --git a/src/app/call/new/index.tsx b/src/app/call/new/index.tsx index b65c83dd..ad280a97 100644 --- a/src/app/call/new/index.tsx +++ b/src/app/call/new/index.tsx @@ -280,7 +280,8 @@ export default function NewCall() { name: data.name, nature: data.nature, priority: priority.Id, - type: type.Id, + // The API matches the call type by its text, not its id. + type: type.Name, note: data.note, address: data.address, latitude: data.latitude, diff --git a/src/stores/dispatch/store.ts b/src/stores/dispatch/store.ts index 3de40057..e596d29a 100644 --- a/src/stores/dispatch/store.ts +++ b/src/stores/dispatch/store.ts @@ -75,16 +75,23 @@ export const useDispatchStore = create((set, get) => ({ const categorizedRoles: RecipientsResultData[] = []; const categorizedUnits: RecipientsResultData[] = []; + // The recipients endpoint hands back wire ids ("P:", "R:12"). The selection is keyed on + // bare ids so it lines up with the ids a call's existing dispatches come back as, and the + // prefixes are put back on in the calls API when the dispatch list is built. + const stripPrefix = (id: string) => (id ? id.replace(/^[PGRU]:/, '') : id); + // Categorize recipients based on Type field recipients.Data.forEach((recipient) => { + const entry = { ...recipient, Id: stripPrefix(recipient.Id) }; + if (recipient.Type === 'Personnel') { - categorizedUsers.push(recipient); + categorizedUsers.push(entry); } else if (recipient.Type === 'Groups') { - categorizedGroups.push(recipient); + categorizedGroups.push(entry); } else if (recipient.Type === 'Roles') { - categorizedRoles.push(recipient); + categorizedRoles.push(entry); } else if (recipient.Type === 'Unit') { - categorizedUnits.push(recipient); + categorizedUnits.push(entry); } });