import React, { useState, useEffect, useRef } from "react"; import { Outlet, NavLink, useNavigate, useLocation, } from "react-router-dom"; import { Bell, Menu, LogOut, User, Settings, Home, FolderKanban, X, CalendarDays, SettingsIcon, TimerIcon, HelpCircleIcon, Pause, ShieldBan, ChevronDown, Play, } from "lucide-react"; interface User { email: string; password: string; } interface Project { id: number; projectName: string; clientName: string; } interface ProjectTrackingData { elapsedTime: number; startTime: Date | null; endTime: Date | null; isTracking: boolean; isPaused: boolean; pauseStartTime: Date | null; totalPausedTime: number; accumulatedTime: number; // ✅ NEW: Stores time from previous sessions } interface TrackingState { selectedProject: Project | null; projectTrackingMap: Map; isTracking: boolean; isPaused: boolean; elapsedTime: number; startTime: Date | null; endTime: Date | null; handleStartTracking: (project: Project) => void; handlePauseResume: () => void; handleStopTracking: () => void; handleProjectSelect: (id: number) => void; projectsData: Project[]; } interface DashboardLayoutProps { user: User | null; setUser: React.Dispatch>; } const DashboardLayout: React.FC = ({ setUser }) => { const [isSidebarOpen, setSidebarOpen] = useState(true); const [isMobile, setIsMobile] = useState(window.innerWidth < 768); const navigate = useNavigate(); const location = useLocation(); // Tracking states const [selectedProject, setSelectedProject] = useState(null); const [isTracking, setIsTracking] = useState(false); const [isPaused, setIsPaused] = useState(false); const [elapsedTime, setElapsedTime] = useState(0); const [startTime, setStartTime] = useState(null); const [endTime, setEndTime] = useState(null); const timerRef = useRef | null>(null); const [projectsData, setProjectsData] = useState([ { id: 1, projectName: "CRM Redesign", clientName: "Salesforce" }, { id: 2, projectName: "AI Assistant", clientName: "OpenAI" }, { id: 3, projectName: "Marketing Dashboard", clientName: "Google" }, ]); const [projectTrackingMap, setProjectTrackingMap] = useState< Map >(new Map()); const handleLogout = async () => { try { const res = await window.electron.logout() if (res && res.success) { localStorage.removeItem("user"); setUser(null); navigate("/login"); } } catch (error) { console.error("Logout error:", error); } }; const toggleSidebar = () => setSidebarOpen(!isSidebarOpen); const closeSidebarOnMobile = () => { if (isMobile) setSidebarOpen(false); }; const menuItems = [ { label: "Dashboard", path: "/dashboard", icon: , exact: true }, { label: "Projects", path: "/dashboard/projects", icon: }, { label: "PTO", path: "/dashboard/leave-adjustments", icon: }, { label: "Timesheet", path: "/dashboard/timesheet", icon: }, { label: "Settings", path: "/dashboard/settings", icon: }, { label: "Help & Support", path: "/dashboard/help-support", icon: }, ]; // ✅ Sync global states with selected project tracking data useEffect(() => { if (selectedProject) { const projectData = projectTrackingMap.get(selectedProject.id); if (projectData) { setIsTracking(projectData.isTracking); setIsPaused(projectData.isPaused); setElapsedTime(projectData.elapsedTime); setStartTime(projectData.startTime); setEndTime(projectData.endTime); } } }, [selectedProject, projectTrackingMap]); // ✅ Timer effect - calculates elapsed time based on timestamps + accumulated time useEffect(() => { if (isTracking && !isPaused && selectedProject) { timerRef.current = setInterval(() => { setProjectTrackingMap((prev) => { const updated = new Map(prev); const current = updated.get(selectedProject.id); if (current && current.isTracking && !current.isPaused && current.startTime) { const now = Date.now(); const startTimestamp = current.startTime.getTime(); const currentSessionTime = Math.floor((now - startTimestamp) / 1000); const totalPausedTime = current.totalPausedTime || 0; // ✅ FIX: Add accumulated time from previous sessions const calculatedElapsed = (current.accumulatedTime || 0) + currentSessionTime - totalPausedTime; current.elapsedTime = calculatedElapsed; updated.set(selectedProject.id, { ...current }); // Update global elapsedTime in sync setElapsedTime(calculatedElapsed); } return updated; }); }, 1000); } else { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } } return () => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; }, [isTracking, isPaused, selectedProject]); // ✅ Start tracking const handleStartTracking = (project: Project) => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } const now = new Date(); setProjectTrackingMap((prev) => { const updated = new Map(prev); const current = updated.get(project.id) || { elapsedTime: 0, startTime: null, endTime: null, isTracking: false, isPaused: false, pauseStartTime: null, totalPausedTime: 0, accumulatedTime: 0, }; // ✅ Keep accumulated time from previous sessions current.startTime = now; current.isTracking = true; current.isPaused = false; current.pauseStartTime = null; current.totalPausedTime = 0; // Reset pause time for new session updated.set(project.id, current); // Update global tracking states setIsTracking(true); setIsPaused(false); setStartTime(now); setElapsedTime(current.accumulatedTime); // Start from accumulated time return updated; }); }; // ✅ Pause/Resume tracking with pause duration tracking const handlePauseResume = () => { if (!selectedProject) return; const currentProjectData = projectTrackingMap.get(selectedProject.id); if (!currentProjectData || !currentProjectData.isTracking) return; const now = new Date(); const newPausedState = !currentProjectData.isPaused; setProjectTrackingMap((prev) => { const updated = new Map(prev); const current = updated.get(selectedProject.id); if (!current) return updated; if (newPausedState) { // Starting pause current.isPaused = true; current.pauseStartTime = now; } else { // Resuming from pause current.isPaused = false; if (current.pauseStartTime) { const pauseDuration = Math.floor( (now.getTime() - current.pauseStartTime.getTime()) / 1000 ); current.totalPausedTime = (current.totalPausedTime || 0) + pauseDuration; current.pauseStartTime = null; } } updated.set(selectedProject.id, { ...current }); setIsPaused(newPausedState); return updated; }); }; // ✅ Stop tracking - PRESERVES elapsed time const handleStopTracking = () => { if (!selectedProject) return; if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } const now = new Date(); setProjectTrackingMap((prev) => { const updated = new Map(prev); const current = updated.get(selectedProject.id); if (!current) return updated; // ✅ FIX: Store current elapsed time as accumulated time current.accumulatedTime = current.elapsedTime; current.isTracking = false; current.isPaused = false; current.endTime = now; current.startTime = null; // Clear startTime for stopped state updated.set(selectedProject.id, { ...current }); // Update global states - keep elapsed time setIsTracking(false); setIsPaused(false); setEndTime(now); setElapsedTime(current.elapsedTime); // ✅ Keep the elapsed time return updated; }); console.log("Tracking stopped. Time preserved:", elapsedTime); }; // Cleanup timer on unmount useEffect(() => { return () => { if (timerRef.current) { clearInterval(timerRef.current); } }; }, []); // ✅ Handle project selection const handleProjectSelect = (id: number) => { if (isTracking) return; const project = projectsData.find((p) => p.id === id); if (project) { setSelectedProject(project); const projectData = projectTrackingMap.get(id); if (projectData) { setElapsedTime(projectData.elapsedTime); setStartTime(projectData.startTime); setEndTime(projectData.endTime); setIsTracking(projectData.isTracking); setIsPaused(projectData.isPaused); } else { setElapsedTime(0); setStartTime(null); setEndTime(null); setIsTracking(false); setIsPaused(false); } } }; const trackingState: TrackingState = { selectedProject, projectTrackingMap, isTracking, isPaused, elapsedTime, startTime, endTime, handleStartTracking, handlePauseResume, handleStopTracking, projectsData, handleProjectSelect, }; const formatTime = (seconds: number) => { const hrs = Math.floor(seconds / 3600); const mins = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return `${hrs}h ${mins}m ${secs}s`; }; return ( <> {/* Header */}
{/* Left Section */}
{selectedProject ? ( isTracking ? ( ) : ( ) ) : ( )} {selectedProject ? ( {selectedProject.projectName} ) : ( No Project Selected )}
{/* Right Section */}
{/* Timer */}
{formatTime(elapsedTime || 0)}
{/* Alert Icon */} {/* Dropdown */}
{/* Layout Body */}
{/* Sidebar - Always visible */} {/* Main Content */}
); }; export default DashboardLayout;