import jwt from "jsonwebtoken"; import { WorkTrackModel, VAModel, ProjectModel, LoggedModel } from "../../../models/vaModel.js"; // Helper function to get start and end of day function getDayRange(date = new Date()) { const start = new Date(date); start.setHours(0, 0, 0, 0); const end = new Date(date); end.setHours(23, 59, 59, 999); return { start, end }; } function formatHoursToReadable(hours) { const wholeHours = Math.floor(hours); const decimalMinutes = (hours - wholeHours) * 60; const wholeMinutes = Math.round(decimalMinutes); if (wholeHours > 0 && wholeMinutes > 0) { return `${wholeHours}h ${wholeMinutes}m`; } else if (wholeHours > 0) { return `${wholeHours}h`; } else { return `${wholeMinutes}m`; } } // // Helper function to check daily hours and create logout log if needed // async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, currentSessionId = null, additionalTimeMs = 0) { // try { // const today = new Date(); // const { start, end } = getDayRange(today); // // Get today's work entries for this VA and project // // Exclude the current session if it's already in the database // const query = { // vaId, // projectId, // from: { $gte: start, $lte: end } // }; // if (currentSessionId) { // query._id = { $ne: currentSessionId }; // } // const todayWorkEntries = await WorkTrackModel.find(query); // // Calculate total hours worked today // let totalTodayMs = todayWorkEntries.reduce((total, entry) => { // return total + (entry.totalTime || 0); // }, 0); // // Add the additional time from current session if provided // totalTodayMs += additionalTimeMs; // const totalTodayHours = totalTodayMs / (1000 * 60 * 60); // // Check if daily dedicated hours are completed // if (project.dedicatedHours > 0 && totalTodayHours >= project.dedicatedHours) { // // Create automatic logout log // const logoutLog = await LoggedModel.create({ // loggedType: "LOGOUT", // vaId, // vaEmail, // projectId // }); // try { // const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/va-project-log`; // const sfDataSync = { // "_id": logoutLog._id, // "loggedType": "LOGOUT", // "vaId": vaId, // "vaEmail": vaEmail, // "projectId": projectId, // "time": logoutLog.time, // } // const response = await fetch(salesforceUrl, { // method: 'POST', // headers: { // 'Content-Type': 'application/json', // // Add any required headers for Salesforce authentication // // 'Authorization': 'Bearer ' + process.env.SF_ACCESS_TOKEN // }, // body: JSON.stringify(sfDataSync) // }); // if (!response.ok) { // const errorText = await response.text(); // throw new Error(`Salesforce API responded with status ${response.status}: ${errorText}`); // } // const result = await response.json(); // // console.log("✅ Successfully synced VA data to Salesforce:", result); // return { // shouldLogout: true, // totalTodayHours: totalTodayHours, // dedicatedHours: project.dedicatedHours, // logoutLogId: logoutLog._id, // SyncSalesforce: result // }; // } catch (error) { // console.error("Failed to sync with Salesforce:", error.message); // console.log(error) // // Create a custom error to distinguish Salesforce errors // const salesforceError = new Error(`Salesforce sync failed: ${error.message}`); // salesforceError.isSalesforceError = true; // throw salesforceError; // } // } // return { // shouldLogout: false, // totalTodayHours: totalTodayHours, // dedicatedHours: project.dedicatedHours // }; // } catch (error) { // console.error("Error in checkDailyHoursAndLogout:", error); // return { shouldLogout: false, error: error.message }; // } // } // Getting logged hours in a specific project of VA async function va_log_track_work_callback(req, res) { 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 vaEmail = decoded.email; // const vaUser = await VAModel.findOne({ "userDetails.email": vaEmail }); // if (!vaUser) { // return res.status(404).json({ success: false, message: "VA not found" }); // } // const vaId = vaUser._id; const payload = req.body || {}; let { vaId, projectId, logId, logs } = payload; if (!projectId || !logId || !vaId || !Array.isArray(logs)) { return res.status(400).json({ success: false, message: "Missing Props" }); } const vaUser = await VAModel.findById(vaId); if (!vaUser) return res.status(400).json({ success: false, message: "VA not found" }); const project = await ProjectModel.findById(projectId); if (!project) return res.status(400).json({ success: false, message: "Project not found" }); const logEntry = await LoggedModel.findById(logId); if (!logEntry) return res.status(400).json({ success: false, message: "Log entry not found" }); if (logs.length === 0) { return res.status(400).json({ success: false, message: "No logs to track" }); } logs[0].from = logEntry.time; // Ensure the first log's 'from' matches the main log time const firstFromLogTime = new Date(logs[0].from); const firstToLogTime = new Date(logs[0].to); const firstTotalLogTime = Math.abs(firstToLogTime - firstFromLogTime); logs[0].totalTime = firstTotalLogTime; // // Check last log entry for this VA and project // const lastLog = await LoggedModel.findOne({ vaId, projectId }) // .sort({ time: -1 }) // get the most recent log // .lean(); // // If the last log is a LOGOUT, prevent new work tracking // if (lastLog.loggedType === "LOGOUT") { // return res.status(400).json({ // success: false, // message: "User has already logged out from this project", // }); // } // Handle POST → create entry // if (req.method === "POST") { // const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project); // const createdTracks = await Promise.all( // logs.map(async (log) => { // // Calculate total time from timestamps // const fromTime = new Date(log.from); // const toTime = new Date(log.to); // const totalTime = Math.abs(toTime - fromTime); // const createdTrack = await WorkTrackModel.create({ // vaId, // projectId, // logId, // title: log.title, // appName: log.appName, // url: log.url, // from: log.from, // to: log.to, // totalTime: totalTime, // }); // return createdTrack; // }) // ); const fromLogTime = new Date(logs[0].from); const toLogTime = new Date(logs[logs.length -1].to); const totalLogTime = Math.abs(toLogTime - fromLogTime); const createdTrack = await WorkTrackModel.create({ vaId, projectId, logId, from: logs[0].from, to: logs[logs.length -1].to, totalTime: totalLogTime, logs: logs }); return res.status(201).json({ success: true, message: "Work tracking created", data: createdTrack }); // } // // Handle PATCH → update entry (add 'to' and calculate total time) // if (req.method === "PATCH") { // const { id } = payload; // expecting the workTrack record ID to update // if (!id) { // return res.status(400).json({ success: false, message: "Missing workTrack ID" }); // } // const workEntry = await WorkTrackModel.findById(id); // if (!workEntry) { // return res.status(404).json({ success: false, message: "Work entry not found" }); // } // const toTime = new Date(); // const fromTime = new Date(workEntry.from); // const totalTimeMs = toTime - fromTime; // // Optional: store totalTime in minutes or hours instead of raw ms // const hours = Math.floor(totalTimeMs / (1000 * 60 * 60)); // const minutes = Math.floor((totalTimeMs % (1000 * 60 * 60)) / (1000 * 60)); // const seconds = Math.floor((totalTimeMs % (1000 * 60)) / 1000); // const formattedTotalTime = `${hours}h ${minutes}m ${seconds}s`; // // Check if daily dedicated hours are completed after this work session // const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, id, totalTimeMs); // workEntry.to = toTime; // workEntry.totalTime = totalTimeMs; // store as number of minutes // await workEntry.save(); // const response = { // success: true, // message: "Work tracking stopped", // data: { // id: workEntry._id, // from: workEntry.from, // to: workEntry.to, // formattedTotalTime, // totalTimeMs, // sessionHours: totalTimeMs / (1000 * 60 * 60) // }, // dailyHours: { // todayTotal: formatHoursToReadable(dailyCheck.totalTodayHours), // dailyLimit: formatHoursToReadable(dailyCheck.dedicatedHours), // remaining: formatHoursToReadable(Math.max(0, dailyCheck.dedicatedHours - dailyCheck.totalTodayHours)) // } // }; // // If auto-logout was triggered, add that info to response // if (dailyCheck.shouldLogout) { // response.autoLogout = true; // response.message = `Work tracking stopped. Auto-logout created - daily hours completed (${formatHoursToReadable(dailyCheck.totalTodayHours)} / ${formatHoursToReadable(dailyCheck.dedicatedHours)})`; // response.logoutLogId = dailyCheck.logoutLogId; // } // return res.status(200).json(response); // } // Fallback for unsupported methods // return res.status(405).json({ success: false, message: "Method not allowed" }); } catch (error) { return res.status(500).send("Internal Server Error"); } } export { va_log_track_work_callback };