This commit is contained in:
=bhagwanSingh 2025-12-10 20:24:38 +05:30
parent 140b669bdb
commit 6fd3da0837
5 changed files with 136 additions and 130 deletions

View File

@ -8,45 +8,48 @@ const vaClientService = new VaClientService(new VaClientRepository());
async function va_register_client(req, res) { async function va_register_client(req, res) {
logger.info("ClientController - Register Client Hit ..."); logger.info("ClientController - Register Client Hit ...");
try { try {
const payload = req.body || {}; const payload = req.body || {};
const { userDetails } = payload; const { userDetails } = payload;
if (!userDetails || !userDetails.email || !userDetails.name) { if (!userDetails || !userDetails.email || !userDetails.name) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: "Missing required fields: name and email are required" message: "Missing required fields: name and email are required"
}); });
} }
const created = await vaClientService.registerClient(payload); const created = await vaClientService.registerClient(payload);
logger.info(`ClientController - Client registered successfully: ${userDetails.email}`); logger.info(`ClientController - Client registered successfully: ${userDetails.email}`);
return res.status(201).json({ await passwordResetService.requestPasswordReset(userDetails.email, 'client');
success: true, logger.info(`Client password reset requested for: ${email}`);
return res.status(201).json({
success: true,
data: created, data: created,
message: "Client registered successfully" message: "Client registered successfully"
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Register error: ${error.message}`); logger.error(`ClientController - Register error: ${error.message}`);
if (error.message === "User already exists with this email") { if (error.message === "User already exists with this email") {
return res.status(409).json({ return res.status(409).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
if (error.message.includes("Salesforce API is unreachable")) { if (error.message.includes("Salesforce API is unreachable")) {
return res.status(503).json({ return res.status(503).json({
success: false, success: false,
message: "Salesforce service is currently unavailable. Please try again later." message: "Salesforce service is currently unavailable. Please try again later."
}); });
} }
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "Internal Server Error" message: "Internal Server Error"
}); });
} }
} }
@ -56,52 +59,52 @@ async function get_client_profile(req, res) {
try { try {
const email = req.body.clientEmail; const email = req.body.clientEmail;
const client = await vaClientService.getClientByEmail(email); const client = await vaClientService.getClientByEmail(email);
if (!client) { if (!client) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: "Client not found" message: "Client not found"
}); });
} }
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
data: client data: client
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Get client error: ${error.message}`); logger.error(`ClientController - Get client error: ${error.message}`);
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "Internal Server Error" message: "Internal Server Error"
}); });
} }
} }
async function delete_client(req, res) { async function delete_client(req, res) {
logger.info("ClientController - Delete Client Hit ..."); logger.info("ClientController - Delete Client Hit ...");
try { try {
const { clientId } = req.params; const { clientId } = req.params;
if (!clientId) { if (!clientId) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: "Client ID is required" message: "Client ID is required"
}); });
} }
const deletedClient = await vaClientService.deleteClient(clientId); const deletedClient = await vaClientService.deleteClient(clientId);
if (!deletedClient) { if (!deletedClient) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: "Client not found" message: "Client not found"
}); });
} }
logger.info(`ClientController - Client deleted successfully: ${clientId}`); logger.info(`ClientController - Client deleted successfully: ${clientId}`);
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Client deleted successfully", message: "Client deleted successfully",
data: { data: {
clientId: clientId, clientId: clientId,
@ -111,79 +114,79 @@ async function delete_client(req, res) {
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Delete error: ${error.message}`); logger.error(`ClientController - Delete error: ${error.message}`);
if (error.message === "Client not found") { if (error.message === "Client not found") {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "Internal Server Error" message: "Internal Server Error"
}); });
} }
} }
async function update_client(req, res) { async function update_client(req, res) {
logger.info("ClientController - Update Client Hit ..."); logger.info("ClientController - Update Client Hit ...");
try { try {
const { clientId } = req.params; const { clientId } = req.params;
const payload = req.body || {}; const payload = req.body || {};
const { userDetails } = payload; const { userDetails } = payload;
if (!clientId) { if (!clientId) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: "Client ID is required" message: "Client ID is required"
}); });
} }
if (!userDetails) { if (!userDetails) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: "Missing userDetails in request body" message: "Missing userDetails in request body"
}); });
} }
const updatedClient = await vaClientService.updateClient(clientId, payload); const updatedClient = await vaClientService.updateClient(clientId, payload);
logger.info(`ClientController - Client updated successfully: ${clientId}`); logger.info(`ClientController - Client updated successfully: ${clientId}`);
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Client updated successfully", message: "Client updated successfully",
data: updatedClient data: updatedClient
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Update error: ${error.message}`); logger.error(`ClientController - Update error: ${error.message}`);
if (error.message === "Client not found") { if (error.message === "Client not found") {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
if (error.message.includes("Email already exists")) { if (error.message.includes("Email already exists")) {
return res.status(409).json({ return res.status(409).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
} }
async function get_client_dashboard_profile(req, res) { async function get_client_dashboard_profile(req, res) {
try { try {
const accessToken = req.headers.token; const accessToken = req.headers.token;
if (!accessToken) { if (!accessToken) {
return res.status(401).json({ success: false, message: "Missing token" }); return res.status(401).json({ success: false, message: "Missing token" });
} }
@ -195,14 +198,14 @@ async function get_client_dashboard_profile(req, res) {
} }
const clientEmail = decoded.email; const clientEmail = decoded.email;
// Use the new method that returns only necessary fields // Use the new method that returns only necessary fields
const client = await vaClientService.getClientProfileByEmail(clientEmail); const client = await vaClientService.getClientProfileByEmail(clientEmail);
if (!client) { if (!client) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: "Client not found" message: "Client not found"
}); });
} }
@ -217,15 +220,15 @@ async function get_client_dashboard_profile(req, res) {
position: client.userDetails?.position || '' position: client.userDetails?.position || ''
}; };
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
data: profileData data: profileData
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Get dashboard profile error: ${error.message}`); logger.error(`ClientController - Get dashboard profile error: ${error.message}`);
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "Internal Server Error" message: "Internal Server Error"
}); });
} }
} }
@ -234,8 +237,8 @@ async function update_client_password(req, res) {
logger.info("ClientController - Update Client Password Hit ..."); logger.info("ClientController - Update Client Password Hit ...");
console.log("Update Client Password - Request Body:", req.body); console.log("Update Client Password - Request Body:", req.body);
try { try {
const accessToken = req.headers.token; const accessToken = req.headers.token;
if (!accessToken) { if (!accessToken) {
return res.status(401).json({ success: false, message: "Missing token" }); return res.status(401).json({ success: false, message: "Missing token" });
} }
@ -249,14 +252,14 @@ async function update_client_password(req, res) {
const clientEmail = decoded.email; const clientEmail = decoded.email;
const payload = req.body || {}; const payload = req.body || {};
const { userDetails } = payload; const { userDetails } = payload;
// Get client by email to get the ID // Get client by email to get the ID
const client = await vaClientService.getClientByEmail(clientEmail); const client = await vaClientService.getClientByEmail(clientEmail);
if (!client) { if (!client) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: "Client not found" message: "Client not found"
}); });
} }
@ -266,41 +269,41 @@ async function update_client_password(req, res) {
const result = await vaClientService.updateClientPassword(clientId, userDetails); const result = await vaClientService.updateClientPassword(clientId, userDetails);
logger.info(`ClientController - Client password updated successfully: ${clientEmail}`); logger.info(`ClientController - Client password updated successfully: ${clientEmail}`);
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
message: "Password updated successfully", message: "Password updated successfully",
data: result data: result
}); });
} catch (error) { } catch (error) {
logger.error(`ClientController - Update password error: ${error.message}`); logger.error(`ClientController - Update password error: ${error.message}`);
if (error.message === "Client not found") { if (error.message === "Client not found") {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
if (error.message.includes("Current password is incorrect") || if (error.message.includes("Current password is incorrect") ||
error.message.includes("New passwords do not match") || error.message.includes("New passwords do not match") ||
error.message.includes("All password fields are required")) { error.message.includes("All password fields are required")) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: error.message message: error.message
}); });
} }
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "Internal Server Error" message: "Internal Server Error"
}); });
} }
} }
export { export {
va_register_client, va_register_client,
get_client_profile, get_client_profile,
delete_client, delete_client,
update_client, update_client,

View File

@ -5,10 +5,10 @@ import { WorkTrackModel, VAModel, ProjectModel, LoggedModel } from "../../../mod
function getDayRange(date = new Date()) { function getDayRange(date = new Date()) {
const start = new Date(date); const start = new Date(date);
start.setHours(0, 0, 0, 0); start.setHours(0, 0, 0, 0);
const end = new Date(date); const end = new Date(date);
end.setHours(23, 59, 59, 999); end.setHours(23, 59, 59, 999);
return { start, end }; return { start, end };
} }
@ -16,7 +16,7 @@ function formatHoursToReadable(hours) {
const wholeHours = Math.floor(hours); const wholeHours = Math.floor(hours);
const decimalMinutes = (hours - wholeHours) * 60; const decimalMinutes = (hours - wholeHours) * 60;
const wholeMinutes = Math.round(decimalMinutes); const wholeMinutes = Math.round(decimalMinutes);
if (wholeHours > 0 && wholeMinutes > 0) { if (wholeHours > 0 && wholeMinutes > 0) {
return `${wholeHours}h ${wholeMinutes}m`; return `${wholeHours}h ${wholeMinutes}m`;
} else if (wholeHours > 0) { } else if (wholeHours > 0) {
@ -31,7 +31,7 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
try { try {
const today = new Date(); const today = new Date();
const { start, end } = getDayRange(today); const { start, end } = getDayRange(today);
// Get today's work entries for this VA and project // Get today's work entries for this VA and project
// Exclude the current session if it's already in the database // Exclude the current session if it's already in the database
const query = { const query = {
@ -39,23 +39,23 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
projectId, projectId,
from: { $gte: start, $lte: end } from: { $gte: start, $lte: end }
}; };
if (currentSessionId) { if (currentSessionId) {
query._id = { $ne: currentSessionId }; query._id = { $ne: currentSessionId };
} }
const todayWorkEntries = await WorkTrackModel.find(query); const todayWorkEntries = await WorkTrackModel.find(query);
// Calculate total hours worked today // Calculate total hours worked today
let totalTodayMs = todayWorkEntries.reduce((total, entry) => { let totalTodayMs = todayWorkEntries.reduce((total, entry) => {
return total + (entry.totalTime || 0); return total + (entry.totalTime || 0);
}, 0); }, 0);
// Add the additional time from current session if provided // Add the additional time from current session if provided
totalTodayMs += additionalTimeMs; totalTodayMs += additionalTimeMs;
const totalTodayHours = totalTodayMs / (1000 * 60 * 60); const totalTodayHours = totalTodayMs / (1000 * 60 * 60);
// Check if daily dedicated hours are completed // Check if daily dedicated hours are completed
if (project.dedicatedHours > 0 && totalTodayHours >= project.dedicatedHours) { if (project.dedicatedHours > 0 && totalTodayHours >= project.dedicatedHours) {
// Create automatic logout log // Create automatic logout log
@ -69,13 +69,13 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
try { try {
const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/va-project-log`; const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/va-project-log`;
const sfDataSync = { const sfDataSync = {
"_id": logoutLog._id, "_id": logoutLog._id,
"loggedType": "LOGOUT", "loggedType": "LOGOUT",
"vaId": vaId, "vaId": vaId,
"vaEmail": vaEmail, "vaEmail": vaEmail,
"projectId": projectId, "projectId": projectId,
"time": logoutLog.time, "time": logoutLog.time,
} }
const response = await fetch(salesforceUrl, { const response = await fetch(salesforceUrl, {
method: 'POST', method: 'POST',
@ -86,7 +86,7 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
}, },
body: JSON.stringify(sfDataSync) body: JSON.stringify(sfDataSync)
}); });
if (!response.ok) { if (!response.ok) {
const errorText = await response.text(); const errorText = await response.text();
throw new Error(`Salesforce API responded with status ${response.status}: ${errorText}`); throw new Error(`Salesforce API responded with status ${response.status}: ${errorText}`);
@ -94,7 +94,7 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
const result = await response.json(); const result = await response.json();
// console.log("✅ Successfully synced VA data to Salesforce:", result); // console.log("✅ Successfully synced VA data to Salesforce:", result);
return { return {
shouldLogout: true, shouldLogout: true,
totalTodayHours: totalTodayHours, totalTodayHours: totalTodayHours,
@ -105,14 +105,14 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
} catch (error) { } catch (error) {
console.error("Failed to sync with Salesforce:", error.message); console.error("Failed to sync with Salesforce:", error.message);
console.log(error) console.log(error)
// Create a custom error to distinguish Salesforce errors // Create a custom error to distinguish Salesforce errors
const salesforceError = new Error(`Salesforce sync failed: ${error.message}`); const salesforceError = new Error(`Salesforce sync failed: ${error.message}`);
salesforceError.isSalesforceError = true; salesforceError.isSalesforceError = true;
throw salesforceError; throw salesforceError;
} }
} }
return { return {
shouldLogout: false, shouldLogout: false,
totalTodayHours: totalTodayHours, totalTodayHours: totalTodayHours,
@ -128,7 +128,7 @@ async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, curre
// Getting logged hours in a specific project of VA // Getting logged hours in a specific project of VA
async function va_log_track_work_callback(req, res) { async function va_log_track_work_callback(req, res) {
try { try {
const accessToken = req.headers.token; const accessToken = req.headers.token;
if (!accessToken) { if (!accessToken) {
return res.status(401).json({ success: false, message: "Missing token" }); return res.status(401).json({ success: false, message: "Missing token" });
} }
@ -147,9 +147,14 @@ async function va_log_track_work_callback(req, res) {
const vaId = vaUser._id; const vaId = vaUser._id;
const payload = req.body || {}; const payload = req.body || {};
const { projectId, logId, title, appName, url = null } = payload;
const project = await ProjectModel.findById(projectId); let { projectId, logId, title, appName, url = null } = payload;
if (title === "") {
title = ""
}
const project = await ProjectModel.findById(projectId);
if (!project) return res.status(400).json({ success: false, message: "Project not found" }); if (!project) return res.status(400).json({ success: false, message: "Project not found" });
const logEntry = await LoggedModel.findById(logId); const logEntry = await LoggedModel.findById(logId);
@ -175,7 +180,7 @@ async function va_log_track_work_callback(req, res) {
// Handle POST → create entry // Handle POST → create entry
if (req.method === "POST") { if (req.method === "POST") {
const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project); const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project);
if (dailyCheck.shouldLogout) { if (dailyCheck.shouldLogout) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,

View File

@ -31,8 +31,6 @@ clientRoutes.delete("/tips/:tipId", clientAuthValidator, va_tips_delete);
// clientRoutes.get("/:clientID?", va_clients_callback); // VA Clients Callback for getting all VA's or specific client by ID (NC) // clientRoutes.get("/:clientID?", va_clients_callback); // VA Clients Callback for getting all VA's or specific client by ID (NC)
clientRoutes.get("/:clientId/projects/:projectId", va_clients_projects_callback); // VA Clients Projects Callback (NC) clientRoutes.get("/:clientId/projects/:projectId", va_clients_projects_callback); // VA Clients Projects Callback (NC)
// dashboard API's // dashboard API's
clientRoutes.get("/dashboard", clientAuthValidator, client_dashboard); // VA Clients Projects Callback clientRoutes.get("/dashboard", clientAuthValidator, client_dashboard); // VA Clients Projects Callback
clientRoutes.post("/dashboard/va-report", clientAuthValidator, client_dashboard_va_log); // VA details clientRoutes.post("/dashboard/va-report", clientAuthValidator, client_dashboard_va_log); // VA details

View File

@ -11,14 +11,14 @@
<style> <style>
.void-btn-a { .void-btn-a {
background: #394059; background: tomato;
text-decoration: none; text-decoration: none;
color: #2b8efc !important; color: #ffffff !important;
border: none; border: none;
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
border-radius: 5px; border-radius: 5px;
font-weight: bold; font-weight: bold;
text-decoration: underline; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
</style> </style>

View File

@ -224,7 +224,7 @@
<input type="password" name="password" placeholder="Enter your password *" required /> <input type="password" name="password" placeholder="Enter your password *" required />
<a href="/forgot-password" class="forgot">Forgot password?</a> <a href="/forgot-password" class="forgot">Forgot password?</a>
<button type="submit" class="btn btn-primary">Log in using password</button> <button type="submit" class="btn btn-primary">Log in using</button>
<!-- <div class="divider">OR</div> <!-- <div class="divider">OR</div>