va-tracker-middleware/src/controllers/va/vaProjects/vaProjectReport.controller.js

153 lines
5.3 KiB
JavaScript

import jwt from "jsonwebtoken";
import { LoggedModel, WorkTrackModel, VAModel } from "../../../models/vaModel.js";
function formatHMS(ms) {
const totalSeconds = Math.floor(ms / 1000);
const h = Math.floor(totalSeconds / 3600);
const m = Math.floor((totalSeconds % 3600) / 60);
const s = totalSeconds % 60;
return `${h}h ${m}m ${s}s`;
}
async function va_projects_report_function(req, res) {
try {
const sf_token = req.headers.sf_token;
let vaId;
let vaUser;
let vaEmail;
if(sf_token) {
vaId = req.body.vaId;
vaUser = await VAModel.findById(vaId);
if (!vaUser) {
return res.status(404).json({ success: false, message: "VA not found" });
}
vaEmail = vaUser.userDetails.email
} else {
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" });
}
vaEmail = decoded.email;
vaUser = await VAModel.findOne({ "userDetails.email": vaEmail });
if (!vaUser) {
return res.status(404).json({ success: false, message: "VA not found" });
}
vaId = vaUser._id;
}
const { projectId, from, to } = req.params;
if (!projectId) {
return res.status(400).json({ success: false, message: "Missing projectId" });
}
// Default: current day range
const now = new Date();
const fromDate = from && from !== "undefined" ? new Date(from) : new Date(now.setHours(0, 0, 0, 0));
const toDate = to && to !== "undefined" ? new Date(to) : new Date();
toDate.setHours(23, 59, 59, 999);
// Get all VA login/logout logs for this project in range
const logs = await LoggedModel.find({
projectId,
vaId,
time: { $gte: fromDate, $lte: toDate }
}).sort({ time: 1 }).lean();
if (!logs.length) {
return res.json({ success: true, message: "No logs found for this project", data: [] });
}
// Unique VA IDs
const vaIds = [...new Set(logs.map(log => log.vaId?.toString()))].filter(Boolean);
const vaUsers = await VAModel.find(
{ _id: { $in: vaIds } },
{ "userDetails.firstName": 1, "userDetails.lastName": 1, "userDetails.email": 1 }
).lean();
const projectReport = [];
for (const vaId of vaIds) {
const vaLogList = logs.filter(l => l.vaId.toString() === vaId);
let sessions = [];
let currentLogin = null;
// Pair login → logout
for (const entry of vaLogList) {
if (entry.loggedType === "LOGIN") {
currentLogin = entry;
} else if (entry.loggedType === "LOGOUT" && currentLogin) {
sessions.push({ from: currentLogin.time, to: entry.time });
currentLogin = null;
}
}
// If still logged in, close at end of day
if (currentLogin) {
sessions.push({ from: currentLogin.time, to: toDate });
}
const vaDetails = vaUsers.find(v => v._id.toString() === vaId);
let totalWorkMs = 0;
const sessionDetails = [];
for (const s of sessions) {
const workData = await WorkTrackModel.find({
vaId,
projectId,
from: { $gte: s.from },
to: { $lte: s.to }
}).sort({ from: 1 }).lean();
const tabs = workData.map(t => ({
title: t.title,
appName: t.appName,
from: t.from,
to: t.to,
durationMs: t.totalTime,
durationFormatted: formatHMS(t.totalTime),
}));
const sessionWorkMs = workData.reduce((sum, w) => sum + (w.totalTime || 0), 0);
totalWorkMs += sessionWorkMs;
sessionDetails.push({
from: s.from,
to: s.to,
totalSessionTime: formatHMS(sessionWorkMs),
tabs,
});
}
projectReport.push({
vaId,
vaName: `${vaDetails?.userDetails?.firstName || ""} ${vaDetails?.userDetails?.lastName || ""}`.trim(),
vaEmail: vaDetails?.userDetails?.email,
totalWorkTime: formatHMS(totalWorkMs),
totalWorkMs,
sessions: sessionDetails
});
}
res.json({
success: true,
projectId,
from: fromDate,
to: toDate,
totalVAs: projectReport.length,
data: projectReport,
});
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
}
export { va_projects_report_function };