2025-05-16 17:55:30 +04:00

191 lines
7.6 KiB
JavaScript

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