From 6c223f01c9690ad0a66c21e57fe5aa8dcf3b578f Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 10 Dec 2025 16:08:04 +0530 Subject: [PATCH] timesheet session time update --- resources/wireguard/windows/wg0.conf | 4 +- src/electron/api/axiosClient.ts | 7 +- src/electron/api/baseURL.ts | 2 +- src/electron/utils/utilityFunctions.ts | 2 +- src/ui/App.tsx | 4 +- src/ui/pages/Dashboard.tsx | 81 +++++++++++++------ src/ui/pages/HelpSupport/HelpSupport.tsx | 4 +- src/ui/pages/PaySlips/PaysSlips.tsx | 6 +- src/ui/pages/Settings/ChangePasswordModal.tsx | 10 ++- src/ui/pages/Timesheets/ProjectLogsModal.tsx | 28 ++++++- 10 files changed, 101 insertions(+), 47 deletions(-) diff --git a/resources/wireguard/windows/wg0.conf b/resources/wireguard/windows/wg0.conf index 5053efb..69a3e03 100644 --- a/resources/wireguard/windows/wg0.conf +++ b/resources/wireguard/windows/wg0.conf @@ -1,10 +1,10 @@ [Interface] PrivateKey = CEzCd25ufxbOjvRhMqLfkcdP/OziG5i6OkXCfMZrI1I= -Address = 10.0.0.2/24 +Address = 10.0.0.2/32 DNS = 1.1.1.1 [Peer] PublicKey = jG+7H5thEiNjxY1XqI1R9oyMAMTIegLwE3tZkS1Rj2U= Endpoint = 35.95.209.161:51820 -AllowedIPs = 10.0.0.0/24 +AllowedIPs = 10.0.0.0/32 0.0.0.0/0 PersistentKeepalive = 25 diff --git a/src/electron/api/axiosClient.ts b/src/electron/api/axiosClient.ts index ec2d7eb..1ba36c5 100644 --- a/src/electron/api/axiosClient.ts +++ b/src/electron/api/axiosClient.ts @@ -4,7 +4,6 @@ import { getToken } from '../utils/tokenHelper.js'; import chalk from "chalk"; import { sendTokenExpired } from '../ipc/ipcHandler.js'; import https from 'https'; -import { getBaseURL } from './baseURL.js'; const TOKEN_KEY = 'ACCESS_TOKEN'; @@ -13,7 +12,7 @@ const httpsAgent = new https.Agent({ }); const api: AxiosInstance = axios.create({ - baseURL: await getBaseURL(), // 🔁 your backend + baseURL: 'https://quality-friendly-goldfish.ngrok-free.app/api/v1/va', // 🔁 your backend httpsAgent // timeout: 10000, }); @@ -30,7 +29,7 @@ api.interceptors.request.use( if (token) { config.headers['token'] = token; - config.headers['ngrok-skip-browser-warning'] = 'true'; + config.headers['ngrok-skip-browser-warning'] = 'true'; } return config; @@ -55,7 +54,7 @@ api.interceptors.response.use( (response: AxiosResponse) => response.data, async (error) => { - console.log(error, "Line 46") + console.log(error , "Line 46") const status = error?.response?.status; console.error('[Axios Error]', status); diff --git a/src/electron/api/baseURL.ts b/src/electron/api/baseURL.ts index 1982a4a..f380736 100644 --- a/src/electron/api/baseURL.ts +++ b/src/electron/api/baseURL.ts @@ -1,4 +1,4 @@ -let CURRENT_BASE_URL = "https://portal-sf.docva.com"; +let CURRENT_BASE_URL = "https://quality-friendly-goldfish.ngrok-free.app/api/v1/va"; export const getBaseURL = () => CURRENT_BASE_URL; export const setBaseURL = (url: string) => { diff --git a/src/electron/utils/utilityFunctions.ts b/src/electron/utils/utilityFunctions.ts index d8523d5..87e8175 100644 --- a/src/electron/utils/utilityFunctions.ts +++ b/src/electron/utils/utilityFunctions.ts @@ -71,7 +71,7 @@ export const handleLogin = async (credentials: { email: string, password: string try { console.log("➡️ Calling API..."); const response = await axios.post( - `${baseURL}/api/v1/va/login`, + `https://quality-friendly-goldfish.ngrok-free.app/api/v1/va/login`, { userDetails: { ...credentials } }, { headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent } ); diff --git a/src/ui/App.tsx b/src/ui/App.tsx index b55a71b..9852676 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -123,9 +123,9 @@ const App: React.FC = () => { path="/login" element={ - + {/* */} - + {/* */} } /> diff --git a/src/ui/pages/Dashboard.tsx b/src/ui/pages/Dashboard.tsx index ebf8f52..46c89f5 100644 --- a/src/ui/pages/Dashboard.tsx +++ b/src/ui/pages/Dashboard.tsx @@ -130,14 +130,14 @@ const Dashboard: React.FC = () => { }; const fetchProjects = async () => { - setIsRefreshing(true) + setIsRefreshing(true); try { console.log("📡 Fetching projects...Dashboard"); const res = await window.electron.getProjectList(); - console.log(" Project list response in dashboard: ", res.data?.[0]); + console.log("Project list response in dashboard: ", res.data?.[0]); if (res?.success && Array.isArray(res.data)) { - // Store data redux store + // Store data in redux store dispatch(setProjectsDataSlice(res.data)); dispatch( @@ -152,35 +152,67 @@ const Dashboard: React.FC = () => { }) ); - // Auto-select first project - if (res.data.length > 0) { - const firstProject = res.data[0]; + // Check if we already have a selected project that's being tracked + const currentlySelected = selectedProject; + const currentlyTracking = isTracking; + // Find if the currently selected project still exists in the fresh data + let projectToSelect = null; - console.log("Line 158", firstProject) - // Select the project - dispatch(setSelectedProjectSlice(firstProject)); - - const initialElapsed = parseTimeStringToSeconds(firstProject.totalWorkTime); - - // Initialize tracking data for first project - dispatch( - initializeProjectTracking({ - projectId: firstProject.projectId, - initialTime: initialElapsed, - }) + if (currentlySelected && currentlyTracking) { + // We're tracking a project - try to preserve it + const existingProject = res.data.find( + (p: Project) => p.projectId === currentlySelected.projectId ); + + if (existingProject) { + projectToSelect = existingProject; + } } - fetchProfile() + // If no project is selected OR tracked project no longer exists, auto-select first project + if (!projectToSelect && res.data.length > 0) { + projectToSelect = res.data[0]; + } + if (projectToSelect) { + console.log("Line 158", projectToSelect); + // Select the project + dispatch(setSelectedProjectSlice(projectToSelect)); + + // Only initialize tracking if it doesn't exist already + const trackingExists = projectTrackingMap[projectToSelect.projectId]; + if (!trackingExists) { + const initialElapsed = parseTimeStringToSeconds(projectToSelect.totalWorkTime); + dispatch( + initializeProjectTracking({ + projectId: projectToSelect.projectId, + initialTime: initialElapsed, + }) + ); + } else { + // Update project data but preserve tracking state + dispatch( + updateProjectTracking({ + projectId: projectToSelect.projectId, + data: { + ...trackingExists, + // Update elapsed time from server if needed + elapsedTime: parseTimeStringToSeconds(projectToSelect.totalWorkTime), + } + }) + ); + } + } + + fetchProfile(); } else { console.warn("⚠️ Unexpected response:", res); } } catch (err) { console.error("❌ Error fetching projects:", err); } finally { - setIsRefreshing(false) + setIsRefreshing(false); } }; @@ -247,7 +279,7 @@ const Dashboard: React.FC = () => { }; return ( -
+
{/* Header */}

Dashboard

@@ -336,15 +368,16 @@ const Dashboard: React.FC = () => { {/* 🔹 Sticky Header */}

Projects

+ {!selectedData?.isTracking && + }
{/* 🔹 Table or Empty State or Skeleton */} @@ -368,7 +401,7 @@ const Dashboard: React.FC = () => { minHeight: "auto", }} > - +
diff --git a/src/ui/pages/HelpSupport/HelpSupport.tsx b/src/ui/pages/HelpSupport/HelpSupport.tsx index 3d28484..6210087 100644 --- a/src/ui/pages/HelpSupport/HelpSupport.tsx +++ b/src/ui/pages/HelpSupport/HelpSupport.tsx @@ -23,7 +23,7 @@ const HelpSupport: React.FC = () => {

Email

-

support@vatechcorp.com

+

support@docva.com

@@ -31,7 +31,7 @@ const HelpSupport: React.FC = () => {

Phone

-

+91 98765 43210

+

+XXXX XXXXX

diff --git a/src/ui/pages/PaySlips/PaysSlips.tsx b/src/ui/pages/PaySlips/PaysSlips.tsx index d3d9ca5..5c9b931 100644 --- a/src/ui/pages/PaySlips/PaysSlips.tsx +++ b/src/ui/pages/PaySlips/PaysSlips.tsx @@ -84,7 +84,7 @@ const PaysSlips = () => {
- + {/* */} @@ -111,13 +111,13 @@ const PaysSlips = () => { - + */} ))} diff --git a/src/ui/pages/Settings/ChangePasswordModal.tsx b/src/ui/pages/Settings/ChangePasswordModal.tsx index 4d6c5bf..52cbd08 100644 --- a/src/ui/pages/Settings/ChangePasswordModal.tsx +++ b/src/ui/pages/Settings/ChangePasswordModal.tsx @@ -1,6 +1,7 @@ // src/ui/pages/Settings/ChangePasswordModal.tsx import React, { useState } from "react"; import { Eye, EyeOff } from "lucide-react"; +import { useToast } from "../../helper/ToastContext"; interface ChangePasswordModalProps { isOpen: boolean; @@ -19,12 +20,13 @@ const ChangePasswordModal: React.FC = ({ const [showOld, setShowOld] = useState(false); const [showNew, setShowNew] = useState(false); const [showConfirm, setShowConfirm] = useState(false); + const { showToast } = useToast(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (newPassword !== confirmPassword) { - alert("New passwords do not match!"); + showToast("New passwords do not match!" , "error"); return; } @@ -40,17 +42,17 @@ const ChangePasswordModal: React.FC = ({ const response = await window.electron.changePassword(payload); if (response.success) { - alert("Password changed successfully!"); + showToast("Password changed successfully!" , "success"); setOldPassword("") setNewPassword("") setConfirmPassword("") onClose(); } else { - alert(response.message || "Failed to change password."); + showToast((response.message || "Failed to change password.") , "error"); } } catch (error) { console.error("Password change error:", error); - alert("Error changing password."); + showToast("Error changing password." , "error"); } finally { setLoading(false); } diff --git a/src/ui/pages/Timesheets/ProjectLogsModal.tsx b/src/ui/pages/Timesheets/ProjectLogsModal.tsx index 7144932..99855b8 100644 --- a/src/ui/pages/Timesheets/ProjectLogsModal.tsx +++ b/src/ui/pages/Timesheets/ProjectLogsModal.tsx @@ -1,3 +1,4 @@ +import { DateTime } from "luxon"; import React from "react"; interface TabActivity { @@ -27,6 +28,21 @@ interface Props { const ProjectLogsModal: React.FC = ({ isOpen, onClose, projectName, logs, loading }) => { if (!isOpen) return null; + + const getTimeDifference = (from: string, to: string) => { + const start = DateTime.fromISO(from); + const end = DateTime.fromISO(to); + + const diff = end.diff(start, ["hours", "minutes", "seconds"]); + + return { + hours: diff.hours, + minutes: diff.minutes, + seconds: Math.floor(diff.seconds), + formatted: `${diff.hours}h ${diff.minutes}m ${Math.floor(diff.seconds)}s` + }; + }; + return (
@@ -46,7 +62,11 @@ const ProjectLogsModal: React.FC = ({ isOpen, onClose, projectName, logs,
- 🕒 Session {idx + 1} — {session.totalSessionTime} + 🕒 Session {idx + 1} — {getTimeDifference( + new Date(session.from).toISOString(), + new Date(session.to).toISOString() + ).formatted} + {new Date(session.from).toLocaleTimeString()} -{" "} @@ -69,10 +89,10 @@ const ProjectLogsModal: React.FC = ({ isOpen, onClose, projectName, logs,
- + ))}
#Date Total Hours Total PayActionAction
${row.totalPayAmount.toFixed(2)} + {/* -
{tabIdx + 1} - {tab.title}
- {tab.appName} + {tab.title}
+ {tab.appName}
{new Date(tab.from).toLocaleTimeString()}
{new Date(tab.to).toLocaleTimeString()}
{new Date(tab.from).toLocaleTimeString()}
{new Date(tab.to).toLocaleTimeString()}
{tab.durationFormatted}