/** * state.js — Shared reactive state store * Uses Vue.reactive() for global state management. * Replace with Pinia or API integration when backend is ready. */ function createStore() { const today = new Date(); // Start on the most recent Monday const dayOfWeek = today.getDay(); const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; const startDate = new Date(today); startDate.setDate(today.getDate() + mondayOffset); const startDateStr = startDate.toISOString().split('T')[0]; const weekCount = 6; const totalDays = weekCount * 7; const schedule = generateSampleSchedule(AGENTS, startDate, totalDays); const exnetTargets = generateExnetTargets(startDate, totalDays); return Vue.reactive({ // --- Data --- agents: [...AGENTS], shiftTypes: [...SHIFT_TYPES], exnetGroups: [...EXNET_GROUPS], departments: [...DEPARTMENTS], allSkills: [...SKILLS], activeUsers: [...ACTIVE_USERS], versionHistory: [...VERSION_HISTORY], // --- Schedule --- schedule: schedule, exnetTargets: exnetTargets, // --- View State --- startDate: startDateStr, weekCount: weekCount, todayStr: today.toISOString().split('T')[0], // --- Filters --- searchQuery: '', activeSkillFilters: [], activeDepartmentFilter: '', // --- Sidebar --- sidebarOpen: false, sidebarContext: null, // { agentId, dateStr } // --- Cell Editing --- editingCell: null, // { agentId, dateStr } // --- UI --- showVersionHistory: false, }); } /* --- Computed helpers (plain functions operating on store) --- */ function getDateRange(store) { const dates = []; const start = new Date(store.startDate); const total = store.weekCount * 7; for (let i = 0; i < total; i++) { const d = new Date(start); d.setDate(start.getDate() + i); dates.push({ date: d, dateStr: d.toISOString().split('T')[0], dayName: d.toLocaleDateString('en-US', { weekday: 'short' }), dayDate: d.toLocaleDateString('en-US', { day: 'numeric', month: 'short' }), dayOfWeek: d.getDay(), isToday: d.toISOString().split('T')[0] === store.todayStr, isWeekend: d.getDay() === 0 || d.getDay() === 6, }); } return dates; } function getFilteredAgents(store) { let result = store.agents; if (store.searchQuery) { const q = store.searchQuery.toLowerCase(); result = result.filter(a => a.name.toLowerCase().includes(q) || a.email.toLowerCase().includes(q) || a.department.toLowerCase().includes(q) ); } if (store.activeSkillFilters.length > 0) { result = result.filter(a => store.activeSkillFilters.some(skill => a.skills.includes(skill)) ); } if (store.activeDepartmentFilter) { result = result.filter(a => a.department === store.activeDepartmentFilter); } return result; } function getCellData(store, agentId, dateStr) { const key = `${agentId}_${dateStr}`; return store.schedule[key] || { shifts: [], exnet: [], notes: '', locked: null, history: [] }; } function updateCellShifts(store, agentId, dateStr, shifts, exnet) { const key = `${agentId}_${dateStr}`; if (!store.schedule[key]) { store.schedule[key] = { shifts: [], exnet: [], notes: '', locked: null, history: [] }; } store.schedule[key].shifts = [...shifts]; if (exnet !== undefined) { store.schedule[key].exnet = [...exnet]; } // Add history entry store.schedule[key].history.unshift({ user: 'You', action: shifts.length > 0 ? `Set ${shifts.join(', ')}` : 'Cleared shifts', timestamp: new Date().toISOString(), }); } function updateCellNotes(store, agentId, dateStr, notes) { const key = `${agentId}_${dateStr}`; if (!store.schedule[key]) { store.schedule[key] = { shifts: [], exnet: [], notes: '', locked: null, history: [] }; } store.schedule[key].notes = notes; } function openSidebar(store, agentId, dateStr) { store.sidebarContext = { agentId, dateStr }; store.sidebarOpen = true; } function closeSidebar(store) { store.sidebarOpen = false; store.sidebarContext = null; }