import React, { useEffect, useState } from "react"; import { CalendarDays, Clock, FileText, CheckCircle, XCircle, Eye, EyeOff, RefreshCw, Loader2 } from "lucide-react"; import { useSelector } from "react-redux"; import { RootState } from "../../store"; import ProjectLogsModal from "./ProjectLogsModal"; import { TrackingState } from "../../layout/DashboardLayout"; import { useOutletContext } from "react-router-dom"; import { DateTime } from "luxon"; interface TimesheetEntry { id: number; date: string; project: string; hours: number; status: "Approved" | "Pending" | "Rejected"; remarks?: string; } const timesheetData: TimesheetEntry[] = [ { id: 1, date: "2025-10-28", project: "Employee Tracker", hours: 8, status: "Approved", remarks: "Full day" }, { id: 2, date: "2025-10-29", project: "CRM Upgrade", hours: 6, status: "Pending", remarks: "Client call delays" }, { id: 3, date: "2025-10-30", project: "Sales Dashboard", hours: 7, status: "Rejected", remarks: "Missing details" }, { id: 4, date: "2025-10-31", project: "Finance Tracker", hours: 9, status: "Approved", remarks: "Overtime" }, { id: 5, date: "2025-11-01", project: "AI Model Trainer", hours: 8, status: "Approved", remarks: "Normal day" }, ]; interface Project { projectId: string; projectName: string; activityStatus: "ACTIVE" | "AWAY"; totalWorkTime: string; totalWorkMs: number; totalLogs: number; status: string } const Timesheets: React.FC = () => { const { isTracking } = useOutletContext(); const totalHours = timesheetData.reduce((acc, t) => acc + t.hours, 0); const approvedCount = timesheetData.filter((t) => t.status === "Approved").length; 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 [selectedProjectName, setSelectedProjectName] = useState(""); const [modalOpen, setModalOpen] = useState(false); const [loading, setLoading] = useState(false); const [refreshing, setRefreshing] = useState(false); const [lastRefreshed, setLastRefreshed] = useState(null); const [initialLoading, setInitialLoading] = useState(true); const [tick, setTick] = useState(0); const { selectedProject } = useSelector((state: any) => state.projects); const selectedProjectId = selectedProject?.projectId ?? null; const activeProjects = projectsData.filter(p => p.status === "ACTIVE"); useEffect(() => { const interval = setInterval(() => { setTick((t) => t + 1); // force re-render every second }, 1000); return () => clearInterval(interval); }, []); const formatLastRefreshed = () => { if (!lastRefreshed) return "Never"; return DateTime.fromJSDate(lastRefreshed) .toLocal() .toFormat("HH:mm:ss"); // Only time }; const fetchProjects = async () => { setInitialLoading(true); try { console.log("📡 Fetching projects..."); const res = await window.electron.getProjectList(); console.log("✅ Project list response:", res); if (res?.success && Array.isArray(res.data)) { // Store project list setProjectsData(res.data); setLastRefreshed(new Date()); } else { console.warn(" Unexpected response:", res); } } catch (err) { console.error("Error fetching projects:", err); } finally { setInitialLoading(false); setRefreshing(false); } }; useEffect(() => { fetchProjects(); }, []); const handleRefresh = async () => { setRefreshing(true); await fetchProjects(); }; const handleViewLogs = async (projectID: string, projectName: string) => { try { setModalOpen(true); setLoading(true); // setSelectedProject(projectID); setSelectedProjectName(projectName); console.log("projectID", projectID) const res = await window.electron.getProjectLogs(projectID); console.log("📦 Full Logs:", res); if (res?.success && Array.isArray(res.data)) { setLogs(res.data[0].sessions || []); } else { setLogs([]); } } catch (error) { console.error("Error fetching logs:", error); setModalOpen(false) } finally { setLoading(false); } }; 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(" "); }; // Skeleton loader rows const renderSkeletonRows = () => { return Array.from({ length: 5 }).map((_, index) => (
)); }; return (
{/* Header */}

Timesheets

{/* Timesheet Table */}
{initialLoading ? ( // Show skeleton while initially loading renderSkeletonRows() ) : refreshing && projectsData.length === 0 ? ( // Show skeleton while refreshing with empty data renderSkeletonRows() ) : ( // Show actual data projectsData.map((entry, index) => ( )) )} {/* {refreshing && projectsData.length > 0 && ( // Show a single skeleton row at the top while refreshing with existing data )} */}
# Project Hours Logs
{index + 1} {entry.projectName} {formatWorkTime(entry.totalWorkTime)}
Refreshing...
{/* Footer Summary */}
{activeProjects.length} project{activeProjects.length !== 1 ? 's' : ''} shown
{lastRefreshed && (
Last updated: {formatLastRefreshed()}
)}
setModalOpen(false)} projectName={selectedProjectName} logs={logs} loading={loading} />
); }; export default Timesheets;