- Replace task-only refresh flow with hydrate/assignment/group events - Add contracts, groups, and activity tabs to the client sidepanel - Introduce server-side CAD store and request handlers
1 line
7.2 KiB
JavaScript
1 line
7.2 KiB
JavaScript
window.cadTasks={contracts:[],groups:[],activity:[],session:{},activeTab:"contracts",statuses:["available","en_route","on_task","holding","danger","refit","offline"],init(){const s=document.getElementById("refreshCadBtn");s&&s.addEventListener("click",()=>this.refresh()),document.querySelectorAll(".cad-tab").forEach(s=>{s.addEventListener("click",()=>{this.setActiveTab(s.dataset.tab||"contracts")})}),window.ForgeBridge.on("cad::hydrate",s=>{this.setHydratePayload(s||{})}),window.ForgeBridge.on("cad::assignment::response",s=>{this.handleServerResponse(!!s.success,s.message||"")}),window.ForgeBridge.on("cad::group::response",s=>{this.handleServerResponse(!!s.success,s.message||"")}),window.ForgeBridge.ready({loaded:!0})},setActiveTab(s){this.activeTab=s||"contracts",document.querySelectorAll(".cad-tab").forEach(s=>{s.classList.toggle("is-active",s.dataset.tab===this.activeTab)}),document.querySelectorAll("[data-panel]").forEach(s=>{s.classList.toggle("is-active",s.dataset.panel===this.activeTab)})},setHydratePayload(s){this.contracts=Array.isArray(s.contracts)?s.contracts:[],this.groups=Array.isArray(s.groups)?s.groups:[],this.activity=Array.isArray(s.activity)?s.activity:[],this.session=s.session&&"object"==typeof s.session?s.session:{};const t=document.getElementById("cadStatusMessage");!t||t.dataset.type&&"info"!==t.dataset.type||this.setStatus("",""),this.render()},setStatus(s,t){const e=document.getElementById("cadStatusMessage");e&&(e.textContent=s||"",e.dataset.type=t||"")},handleServerResponse(s,t){this.setStatus(t||(s?"CAD update succeeded.":"CAD update failed."),s?"success":"error")},refresh(){this.setStatus("Refreshing board...","info"),window.mapUI.sendEvent("cad::refresh",{})},assignTask(s){const t=document.getElementById(`assign-group-${s}`);t&&t.value?(this.setStatus("Submitting assignment...","info"),window.mapUI.sendEvent("cad::tasks::assign",{taskID:s,groupID:t.value,note:""})):this.setStatus("Select a group before assigning a contract.","error")},acknowledgeTask(s){this.setStatus("Acknowledging contract...","info"),window.mapUI.sendEvent("cad::tasks::acknowledge",{taskID:s})},declineTask(s){this.setStatus("Declining contract...","info"),window.mapUI.sendEvent("cad::tasks::decline",{taskID:s})},updateGroupStatus(s,t){this.setStatus("Updating group status...","info"),window.mapUI.sendEvent("cad::groups::status",{groupID:s,status:t})},getPlayerGroupId(){return this.session.groupId||""},canDispatch(){return!!this.session.isDispatcher},isLeader(){return!!this.session.isLeader},renderContracts(){const s=document.getElementById("taskList");if(!s)return;if(!this.contracts.length)return void(s.innerHTML='<div class="placeholder-message"><p>No active contracts are available.</p></div>');const t=this.getPlayerGroupId();s.innerHTML=this.contracts.map(s=>{const e=s.taskId||s.taskID||"",a=Array.isArray(s.position)?s.position:[0,0,0],n=s.assignedGroupId||"",i=s.assignmentState||"unassigned",o=this.groups.find(s=>s.groupId===n),r=this.isLeader()&&n===t,c=this.groups.map(s=>`<option value="${s.groupId}">${s.callsign||s.groupId}</option>`).join("");return`\n <div class="task-card" data-task-id="${e}">\n <div class="task-card-header">\n <strong>${s.title||e}</strong>\n <span class="task-type">${s.type||"task"}</span>\n </div>\n <p class="task-description">${s.description||""}</p>\n <div class="task-meta">\n <span>${"unassigned"===i?"Available":`${i}: ${o?o.callsign:n}`}</span>\n <span>X: ${Math.round(a[0]||0)} Y: ${Math.round(a[1]||0)}</span>\n </div>\n ${this.canDispatch()?`<div class="task-action-stack">\n <select id="assign-group-${e}" class="cad-select">\n <option value="">Assign to group</option>\n ${c}\n </select>\n <button type="button" class="task-accept-btn" onclick="window.cadTasks.assignTask('${e}')">Assign Contract</button>\n </div>`:""}\n ${r&&"assigned"===i?`<div class="task-action-row">\n <button type="button" class="task-accept-btn" onclick="window.cadTasks.acknowledgeTask('${e}')">Acknowledge</button>\n <button type="button" class="task-secondary-btn" onclick="window.cadTasks.declineTask('${e}')">Decline</button>\n </div>`:""}\n </div>\n `}).join("")},renderGroups(){const s=document.getElementById("groupList");if(!s)return;if(!this.groups.length)return void(s.innerHTML='<div class="placeholder-message"><p>No active groups are available.</p></div>');const t=this.getPlayerGroupId();s.innerHTML=this.groups.map(s=>{const e=this.canDispatch()||this.isLeader()&&s.groupId===t,a=this.statuses.map(t=>`<option value="${t}" ${t===s.status?"selected":""}>${t.replaceAll("_"," ")}</option>`).join("");return`\n <div class="task-card" data-group-id="${s.groupId}">\n <div class="task-card-header">\n <strong>${s.callsign||s.groupId}</strong>\n <span class="task-type">${s.role||"group"}</span>\n </div>\n <div class="task-meta">\n <span>Leader: ${s.leaderName||"Unknown"}</span>\n <span>Status: ${s.status||"unknown"}</span>\n </div>\n <div class="task-meta">\n <span>Org: ${s.orgId||"default"}</span>\n <span>Task: ${s.currentTaskId||"None"}</span>\n </div>\n ${e?`<div class="task-action-stack">\n <select id="group-status-${s.groupId}" class="cad-select">\n ${a}\n </select>\n <button type="button" class="task-accept-btn" onclick="window.cadTasks.updateGroupStatus('${s.groupId}', document.getElementById('group-status-${s.groupId}').value)">Update Status</button>\n </div>`:""}\n </div>\n `}).join("")},renderActivity(){const s=document.getElementById("activityList");s&&(this.activity.length?s.innerHTML=this.activity.slice().reverse().slice(0,8).map(s=>`\n <div class="task-card">\n <div class="task-card-header">\n <strong>${s.type||"activity"}</strong>\n <span class="task-type">${Math.round(s.timestamp||0)}s</span>\n </div>\n <p class="task-description">${s.message||""}</p>\n </div>\n `).join(""):s.innerHTML='<div class="placeholder-message"><p>No recent activity.</p></div>')},render(){this.renderContracts(),this.renderGroups(),this.renderActivity(),this.setActiveTab(this.activeTab)}},window.cadTasks.init(); |