window.cadTasks = { contracts: [], requests: [], groups: [], activity: [], session: {}, mode: "operations", dispatchView: "board", activeTab: "contracts", selectedDispatchGroupId: "", selectedDispatchTaskId: "", selectedDispatchRequestId: "", focusStatusTimer: null, requestModalType: "", statuses: [ "available", "en_route", "on_task", "holding", "danger", "unavailable", ], roles: ["infantry", "recon", "armor", "air", "logistics", "support"], requestTypes: [ { id: "medevac_9line", label: "9-Line MEDEVAC", defaultPriority: "emergency", fields: [ { id: "pickup_location", label: "Line 1 Pickup Location", type: "text", defaultFromGroupPosition: true, }, { id: "radio_freq", label: "Line 2 Radio / Call Sign", type: "text", }, { id: "precedence", label: "Line 3 Precedence", type: "select", options: [ "urgent", "urgent_surgical", "priority", "routine", "convenience", ], }, { id: "special_equipment", label: "Line 4 Special Equipment", type: "select", options: ["none", "hoist", "extraction", "ventilator"], }, { id: "patient_type", label: "Line 5 Patient Type", type: "select", options: ["litter", "ambulatory", "mixed"], }, { id: "security", label: "Line 6 Security", type: "select", options: [ "secure", "possible_enemy", "enemy_in_area", "hot", ], }, { id: "marking", label: "Line 7 Marking", type: "select", options: ["panels", "smoke", "ir", "none", "other"], }, { id: "patient_nationality", label: "Line 8 Patient Nationality", type: "select", options: ["coalition", "civilian", "enemy", "epw", "mixed"], }, { id: "terrain", label: "Line 9 Terrain", type: "select", options: [ "flat", "restricted", "slope", "rooftop", "wooded", ], }, ], }, { id: "ace_lace", label: "ACE/LACE", defaultPriority: "routine", fields: [ { id: "ammo", label: "Ammo", type: "textarea" }, { id: "casualties", label: "Casualties", type: "textarea" }, { id: "equipment", label: "Equipment", type: "textarea" }, { id: "notes", label: "Notes", type: "textarea" }, ], }, { id: "fire_support", label: "Fire Support", defaultPriority: "priority", fields: [ { id: "target_location", label: "Target Location", type: "text", defaultFromGroupPosition: true, }, { id: "target_description", label: "Target Description", type: "textarea", }, { id: "requested_effect", label: "Requested Effect", type: "select", options: [ "suppress", "destroy", "illum", "smoke", "screen", ], }, { id: "ordnance", label: "Requested Ordnance", type: "text" }, { id: "danger_close", label: "Danger Close", type: "select", options: ["no", "yes"], }, { id: "remarks", label: "Remarks", type: "textarea" }, ], }, { id: "air_support", label: "Air Support", defaultPriority: "priority", fields: [ { id: "target_location", label: "Target Location", type: "text", defaultFromGroupPosition: true, }, { id: "target_description", label: "Target Description", type: "textarea", }, { id: "target_marking", label: "Target Marking", type: "select", options: ["smoke", "ir", "laser", "grid", "visual"], }, { id: "requested_effect", label: "Requested Effect", type: "select", options: [ "show_of_force", "escort", "suppress", "destroy", "recon", ], }, { id: "remarks", label: "Remarks", type: "textarea" }, ], }, { id: "logreq", label: "LOGREQ", defaultPriority: "priority", fields: [ { id: "category", label: "Category", type: "select", options: [ "ammo", "medical", "fuel", "repair", "vehicle", "equipment", "weapons", "mixed", ], }, { id: "delivery_method", label: "Delivery Method", type: "select", options: [ "ground", "airdrop", "pickup", "dispatch_discretion", ], }, { id: "delivery_location", label: "Delivery Location", type: "text", defaultFromGroupPosition: true, }, { id: "requested_items", label: "Requested Items", type: "textarea", }, { id: "quantity", label: "Quantity / Package", type: "text", }, { id: "remarks", label: "Remarks", type: "textarea", }, ], }, ], init() { document.querySelectorAll(".cad-tab").forEach((tab) => { tab.addEventListener("click", () => { this.setActiveTab(tab.dataset.tab || "contracts"); }); }); document .getElementById("cadRequestModalCloseBtn") .addEventListener("click", () => { this.closeRequestModal(); }); document .getElementById("cadRequestModalSaveBtn") .addEventListener("click", () => { this.submitSupportRequest(); }); document .querySelector("#cadRequestModal .cad-modal-backdrop") .addEventListener("click", () => { this.closeRequestModal(); }); window.ForgeBridge.on("cad::hydrate", (payload) => { this.setHydratePayload(payload || {}); }); window.ForgeBridge.on("cad::assignment::response", (payload) => { this.handleServerResponse(!!payload.success, payload.message || ""); }); window.ForgeBridge.on("cad::group::response", (payload) => { this.handleServerResponse(!!payload.success, payload.message || ""); }); window.ForgeBridge.on("cad::request::response", (payload) => { this.handleServerResponse(!!payload.success, payload.message || ""); }); window.ForgeBridge.ready({ loaded: true }); }, setActiveTab(tabName) { this.activeTab = tabName || "contracts"; document.querySelectorAll(".cad-tab").forEach((tab) => { tab.classList.toggle( "is-active", tab.dataset.tab === this.activeTab, ); }); document.querySelectorAll("[data-panel]").forEach((panel) => { panel.classList.toggle( "is-active", panel.dataset.panel === this.activeTab, ); }); }, syncLayoutState() { const tabsEl = document.querySelector(".cad-tabs"); const contractsTab = document.getElementById("tabContractsBtn"); const rosterTab = document.getElementById("tabRosterBtn"); const requestsTab = document.getElementById("tabRequestsBtn"); const activityTab = document.getElementById("tabActivityBtn"); const contractsPanel = document.getElementById("contractsPanel"); const rosterPanel = document.getElementById("rosterPanel"); const requestsPanel = document.getElementById("requestsPanel"); const activityPanel = document.getElementById("activityPanel"); const contractsHeader = contractsPanel?.querySelector( ".cad-section-header", ); const rosterHeader = rosterPanel?.querySelector(".cad-section-header"); if (this.isDispatchMapMode()) { if (tabsEl) { tabsEl.style.display = ""; tabsEl.classList.remove("is-two-col"); tabsEl.classList.add("is-three-col"); } if (contractsTab) { contractsTab.style.display = ""; } if (rosterTab) { rosterTab.textContent = "Groups"; } if (activityTab) { activityTab.style.display = "none"; } if (requestsTab) { requestsTab.style.display = ""; } if (activityPanel) { activityPanel.classList.remove("is-active"); activityPanel.style.display = "none"; } if (requestsPanel) { requestsPanel.style.display = ""; } if (rosterPanel) { rosterPanel.style.display = ""; } if (rosterHeader) { rosterHeader.textContent = "Active Groups"; } if (contractsPanel) { contractsPanel.style.display = ""; } if (contractsHeader) { contractsHeader.textContent = "Contracts"; } if (!["contracts", "roster", "requests"].includes(this.activeTab)) { this.activeTab = "contracts"; } return; } if (tabsEl) { tabsEl.style.display = ""; tabsEl.classList.remove("is-three-col"); tabsEl.classList.remove("is-two-col"); } if (contractsTab) { contractsTab.style.display = ""; } if (rosterTab) { rosterTab.textContent = "Roster"; } if (activityTab) { activityTab.style.display = ""; } if (requestsTab) { requestsTab.style.display = ""; } if (contractsPanel) { contractsPanel.style.display = ""; } if (activityPanel) { activityPanel.style.display = ""; } if (requestsPanel) { requestsPanel.style.display = ""; } if (rosterPanel) { rosterPanel.style.display = ""; } if (rosterHeader) { rosterHeader.textContent = "Roster"; } if (contractsHeader) { contractsHeader.textContent = "Contracts"; } }, setHydratePayload(payload) { this.contracts = Array.isArray(payload.contracts) ? payload.contracts : []; this.requests = Array.isArray(payload.requests) ? payload.requests : []; this.groups = Array.isArray(payload.groups) ? payload.groups : []; this.activity = Array.isArray(payload.activity) ? payload.activity : []; this.session = payload.session && typeof payload.session === "object" ? payload.session : {}; this.mode = payload && typeof payload.mode === "string" ? payload.mode : "operations"; this.dispatchView = payload && typeof payload.dispatchView === "string" ? payload.dispatchView : "board"; const statusEl = document.getElementById("cadStatusMessage"); if ( statusEl && (!statusEl.dataset.type || statusEl.dataset.type === "info") ) { this.setStatus("", ""); } if ( this.selectedDispatchGroupId && !this.groups.some( (group) => group.groupId === this.selectedDispatchGroupId, ) ) { this.selectedDispatchGroupId = ""; } if ( this.selectedDispatchTaskId && !this.contracts.some((task) => { const taskId = task.taskId || task.taskID || ""; return taskId === this.selectedDispatchTaskId; }) ) { this.selectedDispatchTaskId = ""; } if ( this.selectedDispatchRequestId && !this.requests.some( (request) => (request.requestId || "") === this.selectedDispatchRequestId, ) ) { this.selectedDispatchRequestId = ""; } if ( this.mode === "dispatch" && this.dispatchView === "map" && !["contracts", "roster", "requests"].includes(this.activeTab) ) { this.activeTab = "contracts"; } this.render(); }, setStatus(message, type) { const statusEl = document.getElementById("cadStatusMessage"); if (!statusEl) { return; } statusEl.textContent = message || ""; statusEl.dataset.type = type || ""; }, getDangerGroups() { return this.groups.filter((group) => (group.status || "") === "danger"); }, getSupportAlertRequests() { return this.requests.filter((request) => ["medevac_9line", "fire_support", "air_support"].includes( request.type || "", ), ); }, buildSupportAlertMessage() { const alertRequests = this.getSupportAlertRequests(); if (!alertRequests.length) { return ""; } const labels = alertRequests.map((request) => { const groupLabel = request.groupCallsign || request.groupId || "Unknown Group"; const typeLabel = this.getRequestTypeLabel( request.type || "request", ); return `${groupLabel} ${typeLabel}`; }); return `Support request alert: ${labels.join(", ")}`; }, getCurrentGroupCoordinates() { const currentGroup = this.getCurrentGroup(); const position = Array.isArray(currentGroup?.position) ? currentGroup.position : [0, 0, 0]; return window.mapUI.formatPosition(position); }, getSortedGroups() { return this.groups.slice().sort((left, right) => { const leftDanger = (left.status || "") === "danger" ? 0 : 1; const rightDanger = (right.status || "") === "danger" ? 0 : 1; if (leftDanger !== rightDanger) { return leftDanger - rightDanger; } const leftCallsign = left.callsign || left.groupId || ""; const rightCallsign = right.callsign || right.groupId || ""; return leftCallsign.localeCompare(rightCallsign); }); }, isDispatchOrder(entry) { return ( !!entry.isDispatchOrder || (entry.type || "") === "dispatch_order" ); }, formatTypeLabel(entry) { const typeLabel = (entry.type || "task").replaceAll("_", " "); return this.isDispatchOrder(entry) ? "dispatch order" : typeLabel; }, getRequestDefinition(typeID) { return this.requestTypes.find((entry) => entry.id === typeID) || null; }, getRequestTypeLabel(typeID) { return this.getRequestDefinition(typeID)?.label || typeID; }, canSubmitSupportRequest() { return this.mode === "operations" && this.isLeader(); }, openRequestModal(typeID) { const definition = this.getRequestDefinition(typeID); if (!definition) { return; } this.requestModalType = typeID; document.getElementById("cadRequestModalTitle").textContent = definition.label; document.getElementById("cadRequestPrioritySelect").value = definition.defaultPriority || "priority"; this.renderRequestFields(definition); document .getElementById("cadRequestModal") .classList.remove("is-hidden"); }, closeRequestModal() { this.requestModalType = ""; document.getElementById("cadRequestFields").innerHTML = ""; document.getElementById("cadRequestModal").classList.add("is-hidden"); }, renderRequestFields(definition) { const container = document.getElementById("cadRequestFields"); if (!container || !definition) { return; } const coords = this.getCurrentGroupCoordinates(); container.innerHTML = definition.fields .map((field) => { const defaultValue = field.defaultFromGroupPosition ? coords : ""; if (field.type === "select") { return ` `; } if (field.type === "textarea") { return ` `; } return ` `; }) .join(""); }, submitSupportRequest() { const definition = this.getRequestDefinition(this.requestModalType); if (!definition) { return; } const fields = {}; definition.fields.forEach((field) => { const input = document.getElementById( `cadRequestField_${field.id}`, ); fields[field.id] = input ? String(input.value || "").trim() : ""; }); const priority = document.getElementById( "cadRequestPrioritySelect", ).value; this.setStatus("Submitting support request...", "info"); window.mapUI.sendEvent("cad::supportRequest::submit", { type: definition.id, fields: fields, priority: priority, }); this.closeRequestModal(); }, closeSupportRequest(requestID) { if (!requestID) { return; } this.setStatus( this.isDispatchMode() ? "Closing support request..." : "Cancelling support request...", "info", ); window.mapUI.sendEvent("cad::supportRequest::close", { requestID: requestID, }); }, renderRequests() { const listEl = document.getElementById("requestList"); if (!listEl) { return; } if (this.isDispatchMapMode()) { const dispatchRequests = this.requests .slice() .sort((left, right) => { const leftTitle = left.title || left.requestId || ""; const rightTitle = right.title || right.requestId || ""; return leftTitle.localeCompare(rightTitle); }); if (!dispatchRequests.length) { listEl.innerHTML = '
'; return; } listEl.innerHTML = dispatchRequests .map((request) => { const requestID = request.requestId || ""; const position = Array.isArray(request.position) ? request.position : [0, 0, 0]; const isSelected = requestID === this.selectedDispatchRequestId; const isWarning = [ "medevac_9line", "fire_support", "air_support", ].includes(request.type || ""); return ` `; }) .join(""); return; } const requestButtons = this.canSubmitSupportRequest() ? `${request.summary || ""}
${ canClose ? `${task.description || ""}
${ isAssignedToLeader && assignmentState === "assigned" ? `${entry.message || ""}