import jwt from "jsonwebtoken"; import { VAModel, ProjectModel, LoggedModel, ClientModel } from "../../../models/vaModel.js"; // Helper function to parse date string in DD-MM-YYYY format function parseDate(dateString) { if (!dateString) return null; const parts = dateString.split('-'); if (parts.length !== 3) return null; const day = parseInt(parts[0], 10); const month = parseInt(parts[1], 10) - 1; // Months are 0-indexed in JavaScript const year = parseInt(parts[2], 10); // Validate date components if (isNaN(day) || isNaN(month) || isNaN(year)) return null; if (day < 1 || day > 31 || month < 0 || month > 11 || year < 1900) return null; return new Date(year, month, day); } // Getting logged hours in a specific project of VA async function client_dashboard_va_log(req, res) { console.log(req) try { const accessToken = req.headers.token; if (!accessToken) { return res.status(401).json({ success: false, message: "Missing token" }); } const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_ACCESS_TOKEN); if (!decoded || !decoded.email) { return res.status(401).json({ success: false, message: "Invalid token" }); } const clientEmail = decoded.email; const clientUser = await ClientModel.findOne({ "userDetails.email": clientEmail }); if (!clientUser) { return res.status(404).json({ success: false, message: "Client not found" }); } const clientID = clientUser._id; const clientProjectIds = clientUser.projectIds || []; const payload = req.body || {}; const { vaId } = payload; // const va = await VAModel.findOne({ // _id: vaId, // clientIds: clientID // }); // if (!va) { // return res.status(403).json({ // success: false, // message: "VA not found or not assigned to this client" // }); // } let logs = await LoggedModel.find({ vaId, projectId: { $in: clientProjectIds }, }) .sort({ time: 1 }) .populate("projectId", "name") // attach project name .lean(); if (!logs.length) { return res.status(200).json({ success: true, message: "No logs found in given range", data: [], totalWorkTime: "00:00:00", }); } let totalWorkSeconds = 0; const projectWork = {}; // key: projectId -> seconds // Group logs by date (YYYY-MM-DD format) const logsByDate = {}; logs.forEach(log => { const date = new Date(log.time).toISOString().split('T')[0]; // YYYY-MM-DD if (!logsByDate[date]) { logsByDate[date] = []; } logsByDate[date].push(log); }); // Process each day separately for (const [date, dayLogs] of Object.entries(logsByDate)) { // Check if this day has any adjustment logs const hasAdjustmentLogs = dayLogs.some(log => log.isAdjustment === true); let dayWorkSeconds = 0; let lastLogin = null; let lastProjectId = null; // If day has adjustment logs, only process adjustment logs // If no adjustment logs, process all logs for that day const logsToProcess = hasAdjustmentLogs ? dayLogs.filter(log => log.isAdjustment === true) : dayLogs; // Sort logs by time for proper pairing (already sorted by query, but ensure) logsToProcess.sort((a, b) => new Date(a.time) - new Date(b.time)); // Calculate work duration for this day for (const log of logsToProcess) { const time = new Date(log.time); if (log.loggedType === "LOGIN") { lastLogin = time; lastProjectId = log.projectId?._id?.toString() || null; } else if (log.loggedType === "LOGOUT" && lastLogin) { const diffSec = (time - lastLogin) / 1000; dayWorkSeconds += diffSec; if (lastProjectId) { projectWork[lastProjectId] = (projectWork[lastProjectId] || 0) + diffSec; } // reset after each pair lastLogin = null; lastProjectId = null; } } totalWorkSeconds += dayWorkSeconds; } // 🕓 Convert total seconds to hh:mm:ss const formatTime = (seconds) => { const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const s = Math.floor(seconds % 60); return `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; }; // 🧠 Build project-wise array const projectDetails = await Promise.all( Object.entries(projectWork).map(async ([projectId, sec]) => { const project = await ProjectModel.findById(projectId).lean(); return { projectId, projectName: project?.name || "Unknown Project", totalTime: formatTime(sec), }; }) ); return res.status(200).json({ success: true, totalWorkTime: formatTime(totalWorkSeconds), projects: projectDetails, }); } catch (error) { console.log(error) return res.status(500).send("Internal Server Error"); } } export { client_dashboard_va_log };