Files
hotline-planner/component split/antigravity/hlp asp.net core/wwwroot/js/state.js
2026-02-23 14:02:44 +01:00

144 lines
4.3 KiB
JavaScript

/**
* 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;
}