import React, { useEffect, useRef, useState } from "react"; import { Clock, TrendingUp, Play, Square, ProjectorIcon, Pause } 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); 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)); } }; useEffect(() => { const fetchProjects = async () => { try { console.log("📡 Fetching projects...Dashboard"); const res = await window.electron.getProjectList(); console.log(" Project list response in dashboard:", res); if (res?.success && Array.isArray(res.data)) { // Store data 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 || "", }) ); // Auto-select first project if (res.data.length > 0 && !selectedProject) { const firstProject = res.data[0]; // Select the project dispatch(setSelectedProjectSlice(firstProject)); const initialElapsed = parseTimeStringToSeconds(firstProject.totalWorkTime); // Initialize tracking data for first project dispatch( initializeProjectTracking({ projectId: firstProject.projectId, initialTime: initialElapsed, }) ); } fetchProfile() } else { console.warn("⚠️ Unexpected response:", res); } } catch (err) { console.error("❌ Error fetching projects:", err); } }; fetchProjects(); }, []); 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 ? ( // Skeleton loader for tracking section
) : selectedProject ? ( <>
{/* FIX: Use displayTime instead of always using server time */}

{formatTime(displayTime)}

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

Select a project below to start tracking.

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

Projects

{/* 🔹 Table or Empty State or Skeleton */} {isStopping ? ( // 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;