From 1cc863d3c9502a10fea16f93c4a0b361206e0f51 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Mon, 8 Dec 2025 16:50:08 +0530 Subject: [PATCH 1/3] isLimit end then change the color working but comment --- .env | 0 src/electron/api/axiosClient.ts | 2 +- src/electron/api/regionCheck.ts | 57 +++++++++++++ src/electron/ipc/ipcHandler.ts | 8 ++ src/electron/preload.cts | 2 + src/ui/App.tsx | 19 +++-- src/ui/layout/DashboardLayout.tsx | 2 + src/ui/pages/Dashboard.tsx | 8 +- .../tabs/AdjustmentTab.tsx | 5 +- src/ui/pages/Vpn/VpnGuard.tsx | 82 ++++++++++--------- types.d.ts | 11 +++ 11 files changed, 146 insertions(+), 50 deletions(-) create mode 100644 .env create mode 100644 src/electron/api/regionCheck.ts diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/src/electron/api/axiosClient.ts b/src/electron/api/axiosClient.ts index 53b5896..cc0acd5 100644 --- a/src/electron/api/axiosClient.ts +++ b/src/electron/api/axiosClient.ts @@ -71,4 +71,4 @@ api.interceptors.response.use( } ); -export default api; +export default api; \ No newline at end of file diff --git a/src/electron/api/regionCheck.ts b/src/electron/api/regionCheck.ts new file mode 100644 index 0000000..e4d1c45 --- /dev/null +++ b/src/electron/api/regionCheck.ts @@ -0,0 +1,57 @@ + +import axios from "axios"; +import https from "https"; + +const httpsAgent = new https.Agent({ rejectUnauthorized: false }); + +export const checkRegion = async () => { + const baseURL = "https://daniela-nonprofessed-boastfully.ngrok-free.app"; + + try { + + const res = await axios.get(`${baseURL}/health`, { + headers: { "ngrok-skip-browser-warning": "true" }, + httpsAgent + }); + + return { + success: true, + status: res.status, + data: res.data + }; + + } catch (error: any) { + const status = error?.response?.status || 500; + + console.log("Region Check Error:", status); + + // 🔁 Auto retry if 403 — server blocked first try + if (status === 403) { + try { + const retry = await axios.get(`${baseURL}/api`, { + headers: { "ngrok-skip-browser-warning": "true" }, + httpsAgent + }); + + return { + success: true, + status: retry.status, + data: retry.data, + retry: true + }; + } catch (retryErr: any) { + return { + success: false, + status: retryErr?.response?.status || 500, + message: "403 Retry failed" + }; + } + } + + return { + success: false, + status, + message: "Region check failed" + }; + } +}; diff --git a/src/electron/ipc/ipcHandler.ts b/src/electron/ipc/ipcHandler.ts index edaa1df..8465665 100644 --- a/src/electron/ipc/ipcHandler.ts +++ b/src/electron/ipc/ipcHandler.ts @@ -3,6 +3,7 @@ import { getToken, saveToken, clearToken } from "../utils/tokenHelper.js"; import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling, getRunningAppsList, captureSpecificApp } from "../utils/utilityFunctions.js"; import api from "../api/axiosClient.js"; import { getMainWindow } from '../main.js'; +import { checkRegion } from "../api/regionCheck.js"; @@ -10,6 +11,8 @@ import { getMainWindow } from '../main.js'; export const registerIPCHandlers = (mainWindow: BrowserWindow) => { console.log("⚙️ Registering IPC Handlers..."); + + ipcMain.handle("get-token", async (_, key: "ACCESS_TOKEN" | "REFRESH_TOKEN") => { return await getToken(key); }); @@ -534,6 +537,11 @@ ipcMain.handle("update-payment", async (event, data: Record) => { +ipcMain.handle("check-region", async () => { + return await checkRegion(); +}); + + export const sendTokenExpired = () => { console.log("⚠️ Sending token-expired event to renderer"); diff --git a/src/electron/preload.cts b/src/electron/preload.cts index 870cf71..171a4ef 100644 --- a/src/electron/preload.cts +++ b/src/electron/preload.cts @@ -65,6 +65,8 @@ contextBridge.exposeInMainWorld('electron', { getLeaveList: () => ipcRenderer.invoke("get-leave-list"), getAdjustmentsList:(vaId: string) => ipcRenderer.invoke("get-adjustments-list",vaId), + checkRegion: () => ipcRenderer.invoke("check-region") + } satisfies Window['electron']); // function ipcInvoke( diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 7de1c12..b55a71b 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -97,22 +97,23 @@ import Vpn from "./pages/Vpn/Vpn"; import Schedule from "./pages/Schedule/Schedule"; import PaysSlips from "./pages/PaySlips/PaysSlips"; import ApplyLeaveAndAdjustmentsTime from "./pages/LeaveAndAdjustments/ApplyLeaveAndAdjustmentsTime"; +import VpnGuard from "./pages/Vpn/VpnGuard"; const App: React.FC = () => { - + const dispatch = useDispatch(); // ✅ Get user directly from Redux const user = useSelector((state: RootState) => state.user.user); - + useEffect(() => { dispatch(loadUserFromStorage()); }, [dispatch]); - console.log("App.tsx → user:", user); + console.log("App.tsx → user:", user); return ( @@ -122,7 +123,9 @@ const App: React.FC = () => { path="/login" element={ - + + + } /> @@ -132,20 +135,22 @@ const App: React.FC = () => { path="/dashboard" element={ + {/* */} + {/* */} } > } /> } /> } /> - } /> + } /> } /> } /> } /> } /> - } /> - } /> + } /> + } /> {/* Default Redirect */} diff --git a/src/ui/layout/DashboardLayout.tsx b/src/ui/layout/DashboardLayout.tsx index 46d39d8..c24749b 100644 --- a/src/ui/layout/DashboardLayout.tsx +++ b/src/ui/layout/DashboardLayout.tsx @@ -167,6 +167,8 @@ const DashboardLayout = () => { `Timer will continue running. Please stop manually when ready.` ); + + console.log("✅ Alert shown, timer continues running"); }, [selectedProject]); diff --git a/src/ui/pages/Dashboard.tsx b/src/ui/pages/Dashboard.tsx index 8130cbe..ebf8f52 100644 --- a/src/ui/pages/Dashboard.tsx +++ b/src/ui/pages/Dashboard.tsx @@ -106,6 +106,7 @@ const Dashboard: React.FC = () => { const projectSummary = useSelector((state: any) => state.projects.projectSummary); const projectTrackingMap = useSelector((state: any) => state.projects.projectTrackingMap); const [isRefreshing, setIsRefreshing] = useState(false); + const isLimitReached = selectedProject ? isProjectLimitReached(selectedProject) : false; console.log("Line 111", projectsData, selectedProject, projectTrackingMap) @@ -156,7 +157,7 @@ const Dashboard: React.FC = () => { const firstProject = res.data[0]; - console.log("Line 158" , firstProject) + console.log("Line 158", firstProject) // Select the project dispatch(setSelectedProjectSlice(firstProject)); @@ -272,6 +273,11 @@ const Dashboard: React.FC = () => {

{formatTime(displayTime)}

+ + {/*

+ {formatTime(displayTime)} + {isLimitReached && " ⚠️"} +

*/}
Project:{" "} diff --git a/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx b/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx index 7e99b90..bd9c521 100644 --- a/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx +++ b/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx @@ -464,7 +464,7 @@ const AdjustmentTab: React.FC = ({ projects }) => { console.log("Timesheet Created Successfully"); resetForm(); // Show success toast instead of alert - showToast("PTO Request submitted successfully!", "success"); + showToast("Timesheet Request submitted successfully!", "success"); // Navigate after a small delay setTimeout(() => { @@ -680,4 +680,5 @@ const AdjustmentTab: React.FC = ({ projects }) => { ); }; -export default AdjustmentTab; \ No newline at end of file +export default AdjustmentTab; + diff --git a/src/ui/pages/Vpn/VpnGuard.tsx b/src/ui/pages/Vpn/VpnGuard.tsx index 5032cb9..f4bea63 100644 --- a/src/ui/pages/Vpn/VpnGuard.tsx +++ b/src/ui/pages/Vpn/VpnGuard.tsx @@ -1,54 +1,58 @@ import React, { useEffect, useState } from "react"; interface Props { - children: React.ReactNode; + children: React.ReactNode; } const VpnGuard: React.FC = ({ children }) => { - const [checking, setChecking] = useState(true); - const [vpnConnected, setVpnConnected] = useState(true); + const [checking, setChecking] = useState(true); + const [vpnConnected, setVpnConnected] = useState(true); -// const checkVPN = async () => { -// try { -// const res = await window.electron.checkVpnConnection(); -// setVpnConnected(res?.success); -// } catch { -// setVpnConnected(false); -// } finally { -// setChecking(false); -// } -// }; + const checkVPN = async () => { + setChecking(true) + try { + const res = await window.electron.checkRegion(); + console.log("VpnGuard", res) + if (res.success) { + setVpnConnected(true); + } + } catch { + setVpnConnected(false); + } finally { + setChecking(false); + } + }; - useEffect(() => { - // checkVPN(); - }, []); + useEffect(() => { + checkVPN(); + }, []); - if (checking) { - return ( -
- - Checking VPN... -
- ); - } + if (checking) { + return ( +
+ + Checking VPN... +
+ ); + } - if (!vpnConnected) { - return ( -
-
-

VPN Required

-

Please connect to your company VPN to continue.

+ if (!vpnConnected) { + return ( +
+
+

VPN Required

+

Please connect to your company VPN to continue.

- -
-
- ); - } + +
+
+ ); + } - return <>{children}; + return <>{children}; }; export default VpnGuard; diff --git a/types.d.ts b/types.d.ts index 8f20363..70f38ce 100644 --- a/types.d.ts +++ b/types.d.ts @@ -133,6 +133,15 @@ interface PayslipResponse { } +interface RegionResponse { + success: boolean; + status: number; + data?: any; + retry?: boolean; + message?: string; +} + + interface Window { electron: { login: (credentials: { email: string; password: string }) => Promise; @@ -241,6 +250,8 @@ interface Window { success: boolean; data?: any; }>; + + checkRegion: () => Promise; }; } From 6c223f01c9690ad0a66c21e57fe5aa8dcf3b578f Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 10 Dec 2025 16:08:04 +0530 Subject: [PATCH 2/3] 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,
- + ))} From 882f4acad859b4adf276e762052eda86a6b12628 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 10 Dec 2025 18:46:57 +0530 Subject: [PATCH 3/3] timesheet --- src/ui/pages/Timesheets/Timesheets.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ui/pages/Timesheets/Timesheets.tsx b/src/ui/pages/Timesheets/Timesheets.tsx index b6cc269..8ca6afc 100644 --- a/src/ui/pages/Timesheets/Timesheets.tsx +++ b/src/ui/pages/Timesheets/Timesheets.tsx @@ -52,10 +52,11 @@ const Timesheets: React.FC = () => { const { windowLogs } = useSelector((state: RootState) => state.window); + console.log(" Timesheet in component:", windowLogs); const [projectsData, setProjectsData] = useState([]); const [logs, setLogs] = useState([]); - const [selectedProject, setSelectedProject] = useState(null); + // const [selectedProject, setSelectedProject] = useState(null); const [selectedProjectName, setSelectedProjectName] = useState(""); const [modalOpen, setModalOpen] = useState(false); const [loading, setLoading] = useState(false); @@ -63,9 +64,13 @@ const Timesheets: React.FC = () => { const [lastRefreshed, setLastRefreshed] = useState(null); const [initialLoading, setInitialLoading] = useState(true); const [tick, setTick] = useState(0); + const { selectedProject } = + useSelector((state: any) => state.projects); const activeProjects = projectsData.filter(p => p.status === "ACTIVE"); + console.log("selectedProject", selectedProject.projectId) + useEffect(() => { const interval = setInterval(() => { @@ -84,7 +89,6 @@ const Timesheets: React.FC = () => { }; - const fetchProjects = async () => { setInitialLoading(true); try { @@ -120,7 +124,7 @@ const Timesheets: React.FC = () => { try { setModalOpen(true); setLoading(true); - setSelectedProject(projectID); + // setSelectedProject(projectID); setSelectedProjectName(projectName); console.log("projectID", projectID) @@ -154,10 +158,6 @@ const Timesheets: React.FC = () => { return parts.slice(0, 2).join(" "); }; - - - - // Skeleton loader rows const renderSkeletonRows = () => { return Array.from({ length: 5 }).map((_, index) => ( @@ -225,13 +225,13 @@ const Timesheets: React.FC = () => {
#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}
{formatWorkTime(entry.totalWorkTime)}