import React, { useEffect, useRef, useState } from "react"; import { Clock, TrendingUp, Play, Square, ProjectorIcon, Pause, RefreshCw } from "lucide-react"; import { useOutletContext } from "react-router-dom"; import NoData from "./NoData"; import { useDispatch, useSelector } from "react-redux"; import { initializeProjectTracking, setProjectsDataSlice, setProjectSummarySlice, setSelectedProjectSlice, updateProjectTracking } from "../store/projectSlice"; import { setError, setLoading, setProfile } from "../store/profileSlice"; import { getFormattedRemainingTime, isProjectLimitReached } from '../utils/projectLimits'; import { parseTimeStringToSeconds } from "../utils/timeParser"; // Updated Project interface to match JSON structure interface Project { projectId: string; projectName: string; activityStatus: "ACTIVE" | "AWAY"; totalWorkTime: string; totalWorkMs: number; totalLogs: number; status: string; } interface ProjectTrackingData { elapsedTime: number; startTime: Date | null; endTime: Date | null; isTracking: boolean; isPaused: boolean; } 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: (projectId: string) => void; projectsData: Project[]; loadingStart: boolean, loadingStop: boolean, isStopping: boolean } // Helper function 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 `${hrs}h ${mins}m `; }; // Widget Component const Widget: React.FC<{ title: string; value: string | number; subtitle?: string; icon?: React.ReactNode; color?: | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info"; }> = ({ title, value, subtitle, icon, color = "primary" }) => (

{title}

{value}

{icon}
{subtitle &&

{subtitle}

}
); // Dashboard Component const Dashboard: React.FC = () => { const { isTracking, isPaused, elapsedTime, startTime, handleStartTracking, handlePauseResume, handleStopTracking, handleProjectSelect, loadingStart, loadingStop, isStopping } = useOutletContext(); const projectsData = useSelector((state: any) => state.projects.projectsData); const selectedProject = useSelector((state: any) => state.projects.selectedProject); 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) const dispatch = useDispatch(); const fetchProfile = async () => { try { dispatch(setLoading(true)); const res = await window.electron.getProfile(); console.log("Profile", res) if (res.success && res.data) { dispatch(setProfile(res.data)); } else { dispatch(setError("Failed to fetch profile")); } } catch (err: any) { dispatch(setError(err.message)); } finally { dispatch(setLoading(false)); } }; const fetchProjects = async () => { setIsRefreshing(true); try { console.log("📡 Fetching projects...Dashboard"); const res = await window.electron.getProjectList(); console.log("Project list response in dashboard: ", res.data?.[0]); if (res?.success && Array.isArray(res.data)) { // Store data in redux store dispatch(setProjectsDataSlice(res.data)); dispatch( setProjectSummarySlice({ totalProjects: res.totalProjects || 0, activeProjects: res.activeProjects || 0, awayProjects: res.awayProjects || 0, totalWorkTime: res.totalWorkTime || "0h 0m 0s", totalWorkMs: res.totalWorkMs || 0, vaName: res.vaName || "", vaId: res.vaId || "", }) ); // 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; 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; } } // 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); } }; useEffect(() => { fetchProjects(); }, []); const handleRefresh = async () => { // setIsRefreshing(true); await fetchProjects(); // setTimeout(() => setIsRefreshing(false), 500); // Small delay for visual feedback }; const selectedData = selectedProject ? projectTrackingMap[selectedProject.projectId] : null; // FIX: Get the correct time to display const getDisplayTime = () => { if (!selectedProject) return 0; // If tracking is active, use real-time elapsedTime if (selectedData?.isTracking) { return selectedData.elapsedTime || 0; } // If not tracking, use server time from selectedProject return parseTimeStringToSeconds(selectedProject.totalWorkTime); }; const displayTime = getDisplayTime(); const formatWorkTime = (time: string) => { if (!time) return "0h 0m"; // Example input: "0h 2m 29s" const parts = time.split(" "); // Always return first two parts: ["0h", "2m"] return parts.slice(0, 2).join(" "); }; const handleProjectSelectLocal = (projectId: string) => { const project = projectsData.find((p: any) => p.projectId === projectId); if (!project) return; dispatch(setSelectedProjectSlice(project)); const existingData = projectTrackingMap[projectId]; if (!existingData) { const initialElapsed = parseTimeStringToSeconds(project.totalWorkTime); dispatch(initializeProjectTracking({ projectId, initialTime: initialElapsed })); } else { // Restore saved tracking state dispatch(updateProjectTracking({ projectId, data: existingData })); } }; return (
{/* Header */}

Dashboard

{/* Tracking Section */}
{(isStopping || isRefreshing) ? ( // Skeleton loader for tracking section
) : selectedProject ? ( <>
{/* FIX: Use displayTime instead of always using server time */}

{formatTime(displayTime)}

{/*

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

*/}
Project:{" "} {selectedProject.projectName}
{/* Show tracking status */} {selectedData?.isTracking && (
● Live Tracking
)}
{!selectedData?.isTracking ? ( ) : ( )}
) : (

Select a project below to start tracking.

)}
{/* Projects Table */}
{/* 🔹 Sticky Header */}

Projects

{!selectedData?.isTracking && }
{/* 🔹 Table or Empty State or Skeleton */} {(isStopping || isRefreshing) ? ( // Skeleton loader for projects table
{[...Array(3)].map((_, index) => (
))}
) : projectsData.length > 0 ? (
{projectsData.map((project: any, index: any) => { const isCurrentlySelected = selectedProject?.projectId === project.projectId; const isDisabled = isTracking && !isCurrentlySelected; const limitReached = isProjectLimitReached(project); const remainingTime = getFormattedRemainingTime(project); return ( ); })}
# Name Logs Hours Action
{index + 1}
{project.projectName} {limitReached && ( Daily limit reached )}
{formatWorkTime(project.totalWorkTime)}
) : (
)}
); }; export default Dashboard;