/** * api.js - API communication module * * This module handles all communication with the server API endpoints. */ import AppState from './state.js'; import { showLogMessage } from './uiHelpers.js'; import * as DateUtils from './dateUtils.js'; // Import all of DateUtils /** * Load report data from the server (now fetches real_work_hours) * @param {boolean} isAutoRefresh - Whether this is an auto-refresh call * @returns {Promise} - Promise resolving to report data */ export async function loadReportData(isAutoRefresh = false) { const currentPeriod = AppState.getCurrentPeriod(); const user = AppState.getUserFilterText(); let apiUrl = '/api/reports/real_work_hours'; // New endpoint const params = new URLSearchParams(); if (user) { params.append('username', user); } // Add date parameters based on the current period let startDate, endDate; if (currentPeriod === 'daily') { startDate = AppState.getSelectedDate(); endDate = startDate; // For daily, start and end date are the same params.append('start_date', startDate); params.append('end_date', endDate); } else if (currentPeriod === 'weekly') { if (AppState.getSelectedWeekDay()) { startDate = AppState.getSelectedWeekDay(); endDate = startDate; // If a specific day in week is chosen, treat as daily } else { // Get current week's start (Monday) and end (Sunday) // Assuming AppState.getSelectedDate() gives a date within the desired week if not today const refDate = AppState.getSelectedDate() ? new Date(AppState.getSelectedDate()) : new Date(); startDate = DateUtils.getFirstDayOfWeek(refDate); endDate = DateUtils.getLastDayOfWeek(refDate); } params.append('start_date', startDate); params.append('end_date', endDate); } else if (currentPeriod === 'monthly') { // Get current month's start and end dates // Assuming AppState.getSelectedDate() is not used for month context, so always current month startDate = DateUtils.getFirstDayOfCurrentMonth(); endDate = DateUtils.getLastDayOfCurrentMonth(); params.append('start_date', startDate); params.append('end_date', endDate); } // If no specific period logic matched or for a general overview (if API supports it without dates) // we might not append dates, or the API endpoint could have defaults. // For this implementation, daily, weekly, monthly will always have date params. if (params.toString()) { apiUrl += `?${params.toString()}`; } try { const response = await fetch(apiUrl); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.success && result.data) { // Store the data in app state AppState.setReportData(result.data); if (isAutoRefresh) { showLogMessage('Report data refreshed automatically'); } return result.data; } else { throw new Error(result.message || 'Failed to load data.'); } } catch (error) { console.error('Error fetching report data:', error); throw error; } } /** * Fetch current user states from the server * @param {boolean} forceRefresh - Whether to force a refresh even if the cache is valid * @returns {Promise} - Promise resolving to user states object */ export async function fetchUserStates(forceRefresh = false) { // Only update user states if cache expired or force refresh const now = Date.now(); if (!forceRefresh && now - AppState.getUserStatesLastUpdate() < AppState.getStateCacheDuration() && Object.keys(AppState.getUserStates()).length > 0) { return AppState.getUserStates(); } try { const response = await fetch('/api/user-states'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.success && result.data) { const prevStates = {...AppState.getUserStates()}; AppState.setUserStates(result.data); // If forcing a refresh, log the change statistics if (forceRefresh) { const totalUsers = Object.keys(result.data).length; const workingUsers = Object.values(result.data).filter(state => state === 'working').length; const changedStates = countChangedStates(prevStates, result.data); // Only show message if it's a manual refresh or if there were changes // Also check if AppState.isAutoRefreshEnabled is a function before calling const autoRefreshEnabled = (AppState && typeof AppState.isAutoRefreshEnabled === 'function') ? AppState.isAutoRefreshEnabled() : true; if (!autoRefreshEnabled || changedStates > 0) { showLogMessage(`States refreshed: ${totalUsers} users (${workingUsers} working). ${changedStates} state changes detected.`); } } return result.data; } else { // If result.success is false, throw an error with the message from the API throw new Error(result.message || 'Failed to fetch user states: API indicated failure.'); } } catch (error) { console.error('Error fetching user states:', error); // Optionally, clear cached states on error or handle more gracefully // For now, re-throw to let the caller handle it or display a general error. throw error; } } /** * Load user activity data for a specific user * @param {string} username - Username to fetch activity for * @param {string} startDate - Start date in YYYY-MM-DD format * @param {string} endDate - End date in YYYY-MM-DD format * @returns {Promise} - Promise resolving to user activity data */ export async function loadUserActivityData(username, startDate, endDate) { try { const response = await fetch(`/api/user-activity/${encodeURIComponent(username)}?start_date=${startDate}&end_date=${endDate}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.success && result.data) { return result.data.activities; } else { throw new Error(result.message || 'Failed to load activity data'); } } catch (error) { console.error('Error fetching user activity data:', error); throw error; } } /** * Helper function to count changed states between refreshes * @param {Object} prevStates - Previous state object * @param {Object} newStates - New state object * @returns {number} - Number of state changes */ function countChangedStates(prevStates, newStates) { let count = 0; // Check for changes in existing users Object.keys(newStates).forEach(user => { if (prevStates[user] && prevStates[user] !== newStates[user]) { count++; console.log(`State change detected: ${user} changed from ${prevStates[user]} to ${newStates[user]}`); } }); // Check for new users const newUsers = Object.keys(newStates).filter(user => !prevStates[user]); if (newUsers.length > 0) { count += newUsers.length; console.log(`New users detected: ${newUsers.join(', ')}`); } return count; }