solve the tracking stop issue and also timmer is run with alert window show changes in dashbpardlayout and useActiveApptracker hooks

This commit is contained in:
JaiPandey425 2025-12-04 17:20:41 +05:30
parent f5f94f016b
commit e4eb851bc1
6 changed files with 281 additions and 209 deletions

View File

@ -13,7 +13,7 @@ const httpsAgent = new https.Agent({
const api: AxiosInstance = axios.create({ const api: AxiosInstance = axios.create({
// https://dreadingly-unfighting-pandora.ngrok-free.dev/ // https://dreadingly-unfighting-pandora.ngrok-free.dev/
baseURL: 'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va', // 🔁 your backend baseURL: 'https://daniela-nonprofessed-boastfully.ngrok-free.app/api/v1/va', // 🔁 your backend
httpsAgent httpsAgent
// timeout: 10000, // timeout: 10000,
}); });
@ -42,7 +42,7 @@ api.interceptors.request.use(
api.interceptors.response.use( api.interceptors.response.use(
(response: AxiosResponse) => response.data, (response: AxiosResponse) => response.data,
async (error) => { async (error) => {
// console.error('[Axios Error]', error.message); console.error('[Axios Error]', error.message);
if (error.response?.status === 401 || 403) { if (error.response?.status === 401 || 403) {
console.warn('Token expired — trigger refresh logic if needed'); console.warn('Token expired — trigger refresh logic if needed');
sendTokenExpired(); sendTokenExpired();

View File

@ -405,11 +405,10 @@ ipcMain.handle("get-payslips", async (event, vaId: string) => {
console.log("get-payslips", vaId) console.log("get-payslips", vaId)
try { try {
const response = await api.get(`/paySlip/${vaId}`); const response = await api.get(`/paySlip/${vaId}`);
console.log(response.data , "Line 409")
return { return {
success: true, success: true,
data: response.data?.data || [], data: response.data || [],
}; };
} catch (error: any) { } catch (error: any) {
let message = "Unknown error occurred"; let message = "Unknown error occurred";

View File

@ -68,7 +68,7 @@ export const handleLogin = async (credentials: { email: string, password: string
try { try {
console.log("➡️ Calling API..."); console.log("➡️ Calling API...");
const response = await axios.post( const response = await axios.post(
'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va/login', 'https://daniela-nonprofessed-boastfully.ngrok-free.app/api/v1/va/login',
{ userDetails: { ...credentials } }, { userDetails: { ...credentials } },
{ headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent } { headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent }
); );

View File

@ -8,14 +8,12 @@ interface DailyHours {
remaining: string; remaining: string;
} }
export const useActiveAppTracker = ( export const useActiveAppTracker = (
isTracking: boolean, isTracking: boolean,
activeProjectLogId: string | null, activeProjectLogId: string | null,
projectId: string | null, projectId: string | null,
projectName: string | null, projectName: string | null,
onLimitExceeded?: () => void // Callback when limit is reached onLimitExceeded?: () => void
) => { ) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const lastActiveRef = useRef<WindowInfo | null>(null); const lastActiveRef = useRef<WindowInfo | null>(null);
@ -24,8 +22,9 @@ export const useActiveAppTracker = (
const intervalIdRef = useRef<number | null>(null); const intervalIdRef = useRef<number | null>(null);
const finalizeTrackingRef = useRef<(() => Promise<void>) | null>(null); const finalizeTrackingRef = useRef<(() => Promise<void>) | null>(null);
const limitCheckedRef = useRef<boolean>(false); const limitCheckedRef = useRef<boolean>(false);
const isStoppingRef = useRef<boolean>(false); // ✅ Flag to prevent new requests
const canSend = !!(activeProjectLogId && projectId); const canSend = !!(activeProjectLogId && projectId && !isStoppingRef.current);
// ✅ Parse time string to minutes // ✅ Parse time string to minutes
const parseTimeToMinutes = (timeStr: string): number => { const parseTimeToMinutes = (timeStr: string): number => {
@ -53,7 +52,6 @@ export const useActiveAppTracker = (
exceeded: remainingMins <= 0 exceeded: remainingMins <= 0
}); });
// If remaining time is 0 or negative, limit is exceeded
if (remainingMins <= 0) { if (remainingMins <= 0) {
return true; return true;
} }
@ -61,6 +59,7 @@ export const useActiveAppTracker = (
return false; return false;
}; };
// ✅ Send activity log (POST for new, PATCH for update)
const sendActivityLog = async ( const sendActivityLog = async (
projectLogId: string, projectLogId: string,
projectId: string, projectId: string,
@ -68,8 +67,14 @@ export const useActiveAppTracker = (
appName: string, appName: string,
isNew: boolean isNew: boolean
) => { ) => {
// ✅ CRITICAL: Block all requests when stopping
if (isStoppingRef.current) {
console.log("🚫 Stopping in progress — blocking activity log");
return null;
}
if (!canSend) { if (!canSend) {
console.log("🚫 Skipping API — missing activeProjectLogId or projectId"); console.log("🚫 Skipping API — missing required IDs");
return null; return null;
} }
@ -99,20 +104,18 @@ export const useActiveAppTracker = (
// Store the log ID for future updates // Store the log ID for future updates
if (isNew && res?.data?._id) { if (isNew && res?.data?._id) {
console.log("res?.data?._id", res?.data?._id)
lastLogIdRef.current = res.data._id; lastLogIdRef.current = res.data._id;
console.log("💾 Stored log ID:", res.data._id);
} }
// ✅ Check daily limit after every API call // ✅ Check daily limit after every API call
if (res?.dailyHours) { if (res?.dailyHours) {
console.log("res?.data?.dailyHours", res?.dailyHours) const limitExceeded = checkDailyLimit(res.dailyHours);
const limitExceeded = checkDailyLimit(res?.dailyHours);
if (limitExceeded && !limitCheckedRef.current) { if (limitExceeded && !limitCheckedRef.current) {
limitCheckedRef.current = true; limitCheckedRef.current = true;
console.warn("🚨 Daily limit exceeded! Stopping tracking..."); console.warn("🚨 Daily limit exceeded!");
// Trigger stop tracking callback
if (onLimitExceeded) { if (onLimitExceeded) {
setTimeout(() => { setTimeout(() => {
onLimitExceeded(); onLimitExceeded();
@ -128,54 +131,69 @@ export const useActiveAppTracker = (
} }
}; };
// ✅ Final PATCH before stopping // ✅ Stop the interval immediately
const stopInterval = useCallback(() => {
console.log("🛑 Stopping activity tracking interval...");
if (intervalIdRef.current) {
clearInterval(intervalIdRef.current);
intervalIdRef.current = null;
console.log("✅ Interval cleared");
}
}, []);
// ✅ Send final PATCH before stopping (called by handleStopTracking)
const sendFinalPatch = useCallback(async () => { const sendFinalPatch = useCallback(async () => {
if (!canSend) { console.log("=".repeat(60));
console.log("🚫 Skipping final PATCH — no active project log ID"); console.log("🛑 FINAL PATCH INITIATED");
console.log("=".repeat(60));
// ✅ STEP 1: Set stopping flag IMMEDIATELY
isStoppingRef.current = true;
console.log("🔒 Stopping flag set — no new requests allowed");
// ✅ STEP 2: Stop the interval IMMEDIATELY
stopInterval();
if (!activeProjectLogId || !projectId) {
console.log("⚠️ Skipping final PATCH — no active project log ID");
return; return;
} }
console.log("=".repeat(60)); // ✅ STEP 3: Send ONE final PATCH for the last active window
console.log("🛑 FINAL PATCH INITIATED - Recording last activity");
console.log("=".repeat(60));
if (lastLogIdRef.current && lastTitleRef.current && lastActiveRef.current) { if (lastLogIdRef.current && lastTitleRef.current && lastActiveRef.current) {
try { try {
console.log("📊 Final Activity Details:"); console.log("📊 Final Activity Details:");
console.log(` • Window Title: ${lastTitleRef.current}`); console.log(` • Window: ${lastTitleRef.current}`);
console.log(` • App Name: ${lastActiveRef.current.owner.name}`); console.log(` • App: ${lastActiveRef.current.owner.name}`);
console.log(` • Log ID: ${lastLogIdRef.current}`); console.log(` • Log ID: ${lastLogIdRef.current}`);
console.log(` • Project ID: ${projectId}`); console.log(` • Project: ${projectId}`);
const result = await sendActivityLog( const result = await sendActivityLog(
activeProjectLogId!, activeProjectLogId,
projectId!, projectId,
lastTitleRef.current, lastTitleRef.current,
lastActiveRef.current.owner.name || "Unknown", lastActiveRef.current.owner.name || "Unknown",
false // This is a PATCH (update), not a POST (new) false // PATCH (update existing log)
); );
console.log("✅ Final PATCH sent successfully!"); console.log("✅ Final PATCH sent successfully!");
if (result?.dailyHours) { if (result?.dailyHours) {
console.log("📈 Final Daily Hours Summary:"); console.log("📈 Final Daily Hours:");
console.log(` • Today Total: ${result.dailyHours.todayTotal}`); console.log(` • Today: ${result.dailyHours.todayTotal}`);
console.log(` • Daily Limit: ${result.dailyHours.dailyLimit}`); console.log(` • Limit: ${result.dailyHours.dailyLimit}`);
console.log(` • Remaining: ${result.dailyHours.remaining}`); console.log(` • Remaining: ${result.dailyHours.remaining}`);
} }
} catch (error) { } catch (error) {
console.error("❌ Final PATCH failed:", error); console.error("❌ Final PATCH failed:", error);
throw error; // Re-throw to let caller handle throw error;
} }
} else { } else {
console.log("ℹ️ No active window to finalize"); console.log("ℹ️ No active window to finalize");
console.log(" • Last Log ID:", lastLogIdRef.current || "None");
console.log(" • Last Title:", lastTitleRef.current || "None");
console.log(" • Last Active Window:", lastActiveRef.current ? "Yes" : "No");
} }
// Clean up all refs // ✅ STEP 4: Clean up all refs
console.log("🧹 Cleaning up tracking references..."); console.log("🧹 Cleaning up tracking references...");
lastActiveRef.current = null; lastActiveRef.current = null;
lastTitleRef.current = null; lastTitleRef.current = null;
@ -183,70 +201,88 @@ export const useActiveAppTracker = (
limitCheckedRef.current = false; limitCheckedRef.current = false;
console.log("✅ Cleanup complete"); console.log("✅ Cleanup complete");
console.log("=".repeat(60)); console.log("=".repeat(60));
}, [activeProjectLogId, projectId, canSend]); }, [activeProjectLogId, projectId, stopInterval]);
// ✅ Update ref whenever sendFinalPatch changes
useEffect(() => { useEffect(() => {
finalizeTrackingRef.current = sendFinalPatch; finalizeTrackingRef.current = sendFinalPatch;
}, [sendFinalPatch]); }, [sendFinalPatch]);
// ✅ Main tracking interval effect
useEffect(() => { useEffect(() => {
// Reset limit check when tracking starts // Reset flags when tracking starts
if (isTracking) { if (isTracking) {
limitCheckedRef.current = false; limitCheckedRef.current = false;
isStoppingRef.current = false;
console.log("🟢 Tracking started — flags reset");
} }
if (!isTracking || !canSend) { if (!isTracking || !canSend) {
console.log("🟡 Tracking inactive or missing IDs — skipping tracker setup"); console.log("🟡 Tracking inactive — cleaning up");
stopInterval();
return; return;
} }
console.log(`🟢 Starting active tracker for: ${projectName}`); console.log(`🟢 Starting active tracker for: ${projectName}`);
const fetchActiveApp = async () => { const fetchActiveApp = async () => {
// ✅ Double-check stopping flag before each fetch
if (isStoppingRef.current) {
console.log("🚫 Stopping in progress — skipping fetch");
return;
}
try { try {
const details = (await window.electron.getActiveAppDetails()) as WindowInfo; const details = (await window.electron.getActiveAppDetails()) as WindowInfo;
if (!details || !details.id) return; if (!details || !details.id) return;
console.log("details" , details)
const title = details.title; const title = details.title;
const appName = details.owner.name; const appName = details.owner.name;
const prevTitle = lastTitleRef.current; const prevTitle = lastTitleRef.current;
const hasChanged = !prevTitle || prevTitle !== title; const hasChanged = !prevTitle || prevTitle !== title;
if (hasChanged) { if (hasChanged) {
// PATCH previous window before creating new log
if (lastLogIdRef.current && prevTitle) { if (lastLogIdRef.current && prevTitle) {
console.log("🔄 Patching previous log:", prevTitle); console.log("🔄 Updating previous window:", prevTitle);
await sendActivityLog(activeProjectLogId!, projectId!, prevTitle, appName, false); await sendActivityLog(activeProjectLogId!, projectId!, prevTitle, appName, false);
} }
console.log("🆕 New title detected → creating POST:", title); // POST new window log
console.log("🆕 New window detected:", title);
await sendActivityLog(activeProjectLogId!, projectId!, title, appName, true); await sendActivityLog(activeProjectLogId!, projectId!, title, appName, true);
// Update refs and Redux
lastActiveRef.current = details; lastActiveRef.current = details;
lastTitleRef.current = title; lastTitleRef.current = title;
dispatch(setActiveWindow({ window: details, projectId, projectName })); dispatch(setActiveWindow({ window: details, projectId, projectName }));
} else { } else {
console.log("⏸ Same window, skipping log"); console.log("⏸️ Same window, skipping");
} }
} catch (error) { } catch (error) {
console.error("Failed to fetch active app:", error); console.error("❌ Failed to fetch active app:", error);
} }
}; };
// Initial fetch
fetchActiveApp(); fetchActiveApp();
// Set up interval (every 5 seconds)
intervalIdRef.current = setInterval(fetchActiveApp, 5000); intervalIdRef.current = setInterval(fetchActiveApp, 5000);
// Cleanup on unmount
return () => { return () => {
console.log("🧹 Cleaning up tracker interval"); console.log("🧹 Cleaning up tracker interval");
if (intervalIdRef.current) { stopInterval();
clearInterval(intervalIdRef.current);
intervalIdRef.current = null;
}
}; };
}, [isTracking, activeProjectLogId]); }, [isTracking, activeProjectLogId, projectId, projectName, dispatch, stopInterval]);
return { return {
finalizeTracking: finalizeTrackingRef.current, finalizeTracking: finalizeTrackingRef.current,
stopInterval,
setIsStopping: (value: boolean) => {
isStoppingRef.current = value;
console.log(`🔒 Stopping flag manually set to: ${value}`);
}
}; };
}; };

View File

@ -135,155 +135,10 @@ const DashboardLayout = () => {
document.documentElement.setAttribute("data-theme", theme); document.documentElement.setAttribute("data-theme", theme);
}, [theme]); }, [theme]);
// Create a ref to store the stop function so it can be called from the hook // Create a ref to store the stop function so it can be called from the hook
const stopTrackingRef = useRef<(() => Promise<void>) | null>(null); const stopTrackingRef = useRef<(() => Promise<void>) | null>(null);
const limitAlertShownRef = useRef(false); const limitAlertShownRef = useRef(false);
// Define handleStopTracking FIRST
const handleStopTracking = useCallback(async () => {
if (loadingStop || loadingStart) return;
if (!selectedProject) {
console.warn("No selected project to stop");
return;
}
// Reset alert flag when stopping
limitAlertShownRef.current = false;
let currentStopTime = new Date().toISOString();
const projectId = selectedProject.projectId;
console.log(" Stop tracking initiated for:", selectedProject.projectName);
console.log(" Current elapsed time:", elapsedTime);
setIsStopping(true);
setLoadingStop(true);
handleSocketDisconnect();
// STEP 1: Clear timer FIRST to prevent further client-side updates
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
console.log("Timer cleared");
}
// STEP 2: Send final PATCH with last active window data
if (stopTrackingRef.current) {
try {
console.log(" Sending final PATCH to record last activity...");
await stopTrackingRef.current();
console.log(" Final tracking data sent successfully");
} catch (error) {
console.error(" Error sending final tracking data:", error);
}
}
// STEP 3: Send LOGOUT to backend
try {
const payload = {
vaId: projectSummary.vaId,
projectId: projectId,
type: "LOGOUT",
time: currentStopTime
};
console.log("📡 Sending LOGOUT request:", payload);
const res = await window.electron.stopProjectTracking(payload);
console.log(" LOGOUT successful:", res);
} catch (error) {
console.error(" Failed to send LOGOUT:", error);
}
// STEP 4: Update Redux tracking state to stop tracking
console.log("🔄 Updating Redux state to stop tracking...");
dispatch(
stopTrackingReducer({
projectId,
})
);
// Allow React to process the state update
await new Promise(resolve => setTimeout(resolve, 50));
// STEP 5: Refresh project list to get updated work hours from server
try {
console.log("🔄 Refreshing project list...");
const projectListRes = await window.electron.getProjectList();
console.log("📊 Updated project list:", projectListRes);
if (projectListRes?.success && Array.isArray(projectListRes.data)) {
// Update projects data
dispatch(setProjectsDataSlice(projectListRes.data));
// Update project summary
dispatch(
setProjectSummarySlice({
totalProjects: projectListRes.totalProjects || 0,
activeProjects: projectListRes.activeProjects || 0,
awayProjects: projectListRes.awayProjects || 0,
totalWorkTime: projectListRes.totalWorkTime || "0h 0m 0s",
totalWorkMs: projectListRes.totalWorkMs || 0,
vaName: projectListRes.vaName || "",
vaId: projectListRes.vaId || "",
})
);
// Update selected project with fresh data
const updatedProject = projectListRes.data.find(
(p: Project) => p.projectId === projectId
);
if (updatedProject) {
dispatch(setSelectedProjectSlice(updatedProject));
// CRITICAL FIX: Use server time instead of client elapsedTime
const serverElapsedTime = parseTimeStringToSeconds(updatedProject.totalWorkTime);
console.log("🔄 Syncing client time with server time:", {
serverTime: updatedProject.totalWorkTime,
serverElapsedSeconds: serverElapsedTime,
previousClientTime: elapsedTime,
difference: serverElapsedTime - elapsedTime
});
// Force update the tracking map with server time
dispatch(
updateProjectTracking({
projectId: updatedProject.projectId,
data: {
elapsedTime: serverElapsedTime,
accumulatedTime: serverElapsedTime,
isTracking: false,
isPaused: false,
startTime: null,
endTime: Date.now(),
pauseStartTime: null,
totalPausedTime: 0
}
})
);
console.log("✅ Selected project updated with server time");
}
}
// STEP 6: Update UI (window restore)
await window.electron.toggleCloseBtn(true);
await window.electron.resizeWindow(500, 600);
toggleWindowSize.current = true;
} catch (error) {
console.error("❌ Error refreshing project list:", error);
} finally {
// Clear loading states
setLoadingStop(false);
setIsStopping(false);
console.log("🎉 TRACKING STOPPED SUCCESSFULLY");
}
}, [selectedProject, projectSummary, elapsedTime, dispatch]);
// NOW define handleLimitExceeded using the defined handleStopTracking // NOW define handleLimitExceeded using the defined handleStopTracking
const handleLimitExceeded = useCallback(async () => { const handleLimitExceeded = useCallback(async () => {
console.log("🚨 LIMIT EXCEEDED - Showing alert (not stopping)"); console.log("🚨 LIMIT EXCEEDED - Showing alert (not stopping)");
@ -316,7 +171,7 @@ const DashboardLayout = () => {
}, [selectedProject]); }, [selectedProject]);
// Initialize useActiveAppTracker and store finalizeTracking in ref // Initialize useActiveAppTracker and store finalizeTracking in ref
const { finalizeTracking } = useActiveAppTracker( const { finalizeTracking, setIsStopping: setIsStoppingInTracker } = useActiveAppTracker(
isTracking, isTracking,
activeProjectLogId, activeProjectLogId,
selectedProject?.projectId ?? null, selectedProject?.projectId ?? null,
@ -324,6 +179,186 @@ const DashboardLayout = () => {
handleLimitExceeded handleLimitExceeded
); );
// Define handleStopTracking FIRST
const handleStopTracking = useCallback(async () => {
if (loadingStop || loadingStart) {
console.log("⏸️ Already processing, skipping...");
return;
}
if (!selectedProject) {
console.warn("⚠️ No selected project to stop");
return;
}
console.log("=".repeat(70));
console.log("🛑 STOP TRACKING INITIATED");
console.log("=".repeat(70));
console.log(`📦 Project: ${selectedProject.projectName}`);
console.log(`⏱️ Elapsed Time: ${elapsedTime}s`);
// Reset alert flag when stopping
limitAlertShownRef.current = false;
const currentStopTime = new Date().toISOString();
const projectId = selectedProject.projectId;
// ✅ CRITICAL: Set stopping flag IMMEDIATELY to block all new tab tracking
console.log("🔒 Setting stopping flag...");
if (setIsStoppingInTracker) {
setIsStoppingInTracker(true);
}
setIsStopping(true);
setLoadingStop(true);
handleSocketDisconnect();
// STEP 1: Clear local timer to prevent further client-side updates
console.log("⏹️ STEP 1: Clearing local timer...");
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
console.log("✅ Timer cleared");
}
// STEP 2: Send final PATCH with last active window data
console.log("📤 STEP 2: Sending final activity tracking...");
if (stopTrackingRef.current) {
try {
await stopTrackingRef.current(); // This calls sendFinalPatch() in the hook
console.log("✅ Final activity tracking completed");
} catch (error) {
console.error("❌ Error during final tracking:", error);
}
} else {
console.log("⚠️ No tracking ref available");
}
// STEP 3: Send LOGOUT to backend
console.log("🚪 STEP 3: Sending LOGOUT request...");
try {
const payload = {
vaId: projectSummary.vaId,
projectId: projectId,
type: "LOGOUT",
time: currentStopTime
};
console.log("📡 Logout payload:", payload);
const res = await window.electron.stopProjectTracking(payload);
console.log("✅ LOGOUT successful:", res);
} catch (error) {
console.error("❌ LOGOUT failed:", error);
}
// STEP 4: Update Redux tracking state
console.log("🔄 STEP 4: Updating Redux state...");
dispatch(
stopTrackingReducer({
projectId,
})
);
// STEP 6: Update UI (restore window)
console.log("🪟 STEP 6: Restoring window...");
await window.electron.toggleCloseBtn(true);
await window.electron.resizeWindow(500, 600);
toggleWindowSize.current = true;
console.log("✅ Window restored");
// Allow React to process the state update
await new Promise(resolve => setTimeout(resolve, 50));
// STEP 5: Refresh project list to get updated work hours from server
console.log("📊 STEP 5: Refreshing project list...");
try {
const projectListRes = await window.electron.getProjectList();
console.log("✅ Project list fetched:", projectListRes);
if (projectListRes?.success && Array.isArray(projectListRes.data)) {
// Update projects data
dispatch(setProjectsDataSlice(projectListRes.data));
// Update project summary
dispatch(
setProjectSummarySlice({
totalProjects: projectListRes.totalProjects || 0,
activeProjects: projectListRes.activeProjects || 0,
awayProjects: projectListRes.awayProjects || 0,
totalWorkTime: projectListRes.totalWorkTime || "0h 0m 0s",
totalWorkMs: projectListRes.totalWorkMs || 0,
vaName: projectListRes.vaName || "",
vaId: projectListRes.vaId || "",
})
);
// Update selected project with fresh data from server
const updatedProject = projectListRes.data.find(
(p: Project) => p.projectId === projectId
);
if (updatedProject) {
dispatch(setSelectedProjectSlice(updatedProject));
// Sync client time with server time
const serverElapsedTime = parseTimeStringToSeconds(updatedProject.totalWorkTime);
console.log("🔄 Syncing with server time:", {
serverTime: updatedProject.totalWorkTime,
serverSeconds: serverElapsedTime,
clientSeconds: elapsedTime,
difference: serverElapsedTime - elapsedTime
});
// Force update the tracking map with server time
dispatch(
updateProjectTracking({
projectId: updatedProject.projectId,
data: {
elapsedTime: serverElapsedTime,
accumulatedTime: serverElapsedTime,
isTracking: false,
isPaused: false,
startTime: null,
endTime: Date.now(),
pauseStartTime: null,
totalPausedTime: 0
}
})
);
console.log("✅ Project synced with server");
}
}
} catch (error) {
console.error("❌ Error refreshing project list:", error);
} finally {
// Clear loading states
setLoadingStop(false);
setIsStopping(false);
// ✅ Reset stopping flag for next session
if (setIsStoppingInTracker) {
setIsStoppingInTracker(false);
}
console.log("=".repeat(70));
console.log("🎉 TRACKING STOPPED SUCCESSFULLY");
console.log("=".repeat(70));
}
}, [
selectedProject,
projectSummary,
elapsedTime,
dispatch,
loadingStop,
loadingStart,
setIsStoppingInTracker
]);
// Update the ref whenever finalizeTracking changes // Update the ref whenever finalizeTracking changes
useEffect(() => { useEffect(() => {
stopTrackingRef.current = finalizeTracking; stopTrackingRef.current = finalizeTracking;
@ -362,7 +397,7 @@ const DashboardLayout = () => {
return () => { return () => {
console.log("🧹 Cleaning token-expired listener"); console.log("🧹 Cleaning token-expired listener");
}; };
}, [isTracking, handleStopTracking]); }, [isTracking]);
const handleLogout = async () => { const handleLogout = async () => {

View File

@ -36,6 +36,8 @@ const PaysSlips = () => {
return; return;
} }
console.log(response , "getPayslips")
// Extract payrolls array from first index // Extract payrolls array from first index
const payrolls = response[0]?.payrolls || []; const payrolls = response[0]?.payrolls || [];