diff --git a/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BookingLevelCalendar.tsx b/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BookingLevelCalendar.tsx
index b8a80020..c0b91f81 100644
--- a/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BookingLevelCalendar.tsx
+++ b/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BookingLevelCalendar.tsx
@@ -24,7 +24,7 @@ const BookingLevelCalendar = () => {
const daysInMonth = new Date(year, month + 1, 0).getDate();
const fetchPromises = [];
- for (let day = 1; day <= daysInMonth; day++) {
+ for (let day = 0; day <= daysInMonth + 1; day++) { // Fetch one extra day
const date = new Date(year, month, day);
const formattedDate = date.toISOString().split('T')[0];
fetchPromises.push(
@@ -41,7 +41,15 @@ const BookingLevelCalendar = () => {
try {
const results = await Promise.all(fetchPromises);
const newBookingData = Object.assign({}, ...results);
- setBookingData(newBookingData);
+ // Shift all predictions down by one day
+ const shiftedBookingData = Object.entries(newBookingData).reduce((acc: { [key: string]: BookingData }, [date, data]) => {
+ const shiftedDate = new Date(date);
+ shiftedDate.setDate(shiftedDate.getDate() - 1);
+ const shiftedDateString = shiftedDate.toISOString().split('T')[0];
+ acc[shiftedDateString] = data as BookingData;
+ return acc;
+ }, {});
+ setBookingData(shiftedBookingData);
} catch (error) {
console.error('Error fetching booking data:', error);
}
@@ -53,7 +61,11 @@ const BookingLevelCalendar = () => {
const response = await fetch(`https://date.nager.at/api/v3/PublicHolidays/${year}/ZA`);
const holidays = await response.json();
const holidayMap = holidays.reduce((acc: HolidayData, holiday: { date: string; name: string }) => {
- acc[holiday.date] = holiday.name;
+ // Move the holiday one day back
+ const holidayDate = new Date(holiday.date);
+ holidayDate.setDate(holidayDate.getDate() - 1);
+ const adjustedDate = holidayDate.toISOString().split('T')[0];
+ acc[adjustedDate] = holiday.name;
return acc;
}, {});
setHolidayData(holidayMap);
@@ -103,7 +115,7 @@ const BookingLevelCalendar = () => {
{holiday && (
<>
{holiday}
- Note: AI predictions may be less accurate on holidays.
+ Note: Predictions on Special days may be inaccurate.
>
)}
{dayData ? (
diff --git a/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BuildingTower.tsx b/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BuildingTower.tsx
index 3513cccf..02afd23e 100644
--- a/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BuildingTower.tsx
+++ b/frontend/occupi-web/src/components/aiDashboard/aiDashGraphs/BuildingTower.tsx
@@ -1,4 +1,4 @@
-import { useState, useRef } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Text } from '@react-three/drei';
import { Vector3, Group, Color } from 'three';
@@ -11,20 +11,25 @@ interface FloorProps {
depth: number;
}
-function Floor({ position, occupancy, floorNumber, width, depth }: FloorProps) {
- const [, setHovered] = useState(false)
+interface Room {
+ floorNo: string;
+ maxOccupancy: number;
+}
+
+const Floor: React.FC = ({ position, occupancy, floorNumber, width, depth }) => {
+ const [, setHovered] = useState(false);
- const getColor = (value: number) => {
+ const getColor = (value: number): Vector3 => {
const colors = [
[0.2, 0.8, 0.2], // Green (1)
[0.5, 0.8, 0.2], // Yellow-green (2)
[0.8, 0.8, 0.2], // Yellow (3)
[0.8, 0.5, 0.2], // Orange (4)
- [0.8, 0.2, 0.2] // Red (5)
- ]
- const index = Math.max(0, Math.min(Math.floor(value) - 1, 4))
- return new Vector3(...colors[index])
- }
+ [0.8, 0.2, 0.2] // Red (5)
+ ];
+ const index = Math.max(0, Math.min(Math.floor(value) - 1, 4));
+ return new Vector3(...colors[index]);
+ };
return (
@@ -40,6 +45,8 @@ function Floor({ position, occupancy, floorNumber, width, depth }: FloorProps) {
rotation={[0, -Math.PI / 2, 0]}
fontSize={0.2}
color="black"
+ anchorX="center"
+ anchorY="middle"
>
{`Floor ${floorNumber}`}
@@ -48,6 +55,8 @@ function Floor({ position, occupancy, floorNumber, width, depth }: FloorProps) {
rotation={[0, Math.PI / 2, 0]}
fontSize={0.2}
color="black"
+ anchorX="center"
+ anchorY="middle"
>
{`Occupancy: ${occupancy}/5`}
@@ -56,6 +65,8 @@ function Floor({ position, occupancy, floorNumber, width, depth }: FloorProps) {
rotation={[0, Math.PI, 0]}
fontSize={0.2}
color="black"
+ anchorX="center"
+ anchorY="middle"
>
{`Floor ${floorNumber}`}
@@ -63,34 +74,36 @@ function Floor({ position, occupancy, floorNumber, width, depth }: FloorProps) {
position={[0, 0, -depth / 2 - 0.2]}
fontSize={0.2}
color="black"
+ anchorX="center"
+ anchorY="middle"
>
{`Occupancy: ${occupancy}/5`}
- )
-}
+ );
+};
interface BuildingProps {
floors: number[];
}
-function Building({ floors }: BuildingProps) {
- const groupRef = useRef(null)
- const baseWidth = 4
- const baseDepth = 4
- const shrinkFactor = 0.05
+const Building: React.FC = ({ floors }) => {
+ const groupRef = useRef(null);
+ const baseWidth = 4;
+ const baseDepth = 4;
+ const shrinkFactor = 0.05;
useFrame(() => {
if (groupRef.current) {
- groupRef.current.rotation.y += 0.002
+ groupRef.current.rotation.y += 0.002;
}
- })
+ });
return (
{floors.map((occupancy: number, index: number) => {
- const width = baseWidth - index * shrinkFactor
- const depth = baseDepth - index * shrinkFactor
+ const width = baseWidth - index * shrinkFactor;
+ const depth = baseDepth - index * shrinkFactor;
return (
- )
+ );
})}
- )
-}
+ );
+};
-export default function BuildingTower() {
- const occupancyData = [5, 4, 3, 3, 2, 2, 1]
+const BuildingTower: React.FC = () => {
+ const [occupancyData, setOccupancyData] = useState([]);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ // In a real scenario, you would fetch this data from your API
+ const response = await fetch('/api/view-rooms');
+ const data = await response.json();
+
+ const rooms: Room[] = data.data;
+ const highestFloor = Math.max(...rooms.map(room => parseInt(room.floorNo)));
+
+ // Calculate occupancy for each floor
+ const occupancy = Array(highestFloor + 1).fill(0);
+ rooms.forEach((room: Room) => {
+ const floor = parseInt(room.floorNo);
+ occupancy[floor] = Math.max(occupancy[floor], room.maxOccupancy);
+ });
+
+ // Remove the ground floor (index 0) and reverse the array so the highest floor is first
+ setOccupancyData(occupancy.slice(1).reverse());
+ } catch (error) {
+ console.error('Error fetching room data:', error);
+ }
+ };
+
+ fetchData();
+ }, []);
return (
@@ -118,5 +158,7 @@ export default function BuildingTower() {
- )
-}
\ No newline at end of file
+ );
+};
+
+export default BuildingTower;
\ No newline at end of file
diff --git a/frontend/occupi-web/src/components/workerStats/ActiveEmployeeCard.tsx b/frontend/occupi-web/src/components/workerStats/ActiveEmployeeCard.tsx
index 035a94b7..b48c09c3 100644
--- a/frontend/occupi-web/src/components/workerStats/ActiveEmployeeCard.tsx
+++ b/frontend/occupi-web/src/components/workerStats/ActiveEmployeeCard.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Avatar, Button, Spinner, Progress } from "@nextui-org/react";
+import { Card, CardHeader, CardBody, Avatar, Button, Progress, Skeleton } from "@nextui-org/react";
import { ChevronDown, ChevronUp, Clock, Calendar, TrendingUp } from "lucide-react";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { getMostActiveEmployee, MostActiveEmployeeData } from 'WorkerStatsService';
@@ -36,8 +36,10 @@ const ActiveEmployeeCard = () => {
if (isLoading) {
return (
-
-
+
+
+
+
);
}
diff --git a/frontend/occupi-web/src/components/workerStats/AverageHoursChart.tsx b/frontend/occupi-web/src/components/workerStats/AverageHoursChart.tsx
index 14d11794..b063a487 100644
--- a/frontend/occupi-web/src/components/workerStats/AverageHoursChart.tsx
+++ b/frontend/occupi-web/src/components/workerStats/AverageHoursChart.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Spinner } from "@nextui-org/react";
+import { Card, CardHeader, CardBody, Skeleton } from "@nextui-org/react";
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { getAverageHours } from 'WorkerStatsService';
@@ -29,7 +29,26 @@ const AverageHoursChart = () => {
fetchData();
}, []);
- if (loading) return ;
+ if (loading) {
+ return (
+
+ );
+ }
if (error) return {error}
;
return (
diff --git a/frontend/occupi-web/src/components/workerStats/HoursDashboard.tsx b/frontend/occupi-web/src/components/workerStats/HoursDashboard.tsx
index d947bf55..5e240c5d 100644
--- a/frontend/occupi-web/src/components/workerStats/HoursDashboard.tsx
+++ b/frontend/occupi-web/src/components/workerStats/HoursDashboard.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Spinner } from "@nextui-org/react";
+import { Card, CardHeader, CardBody, Skeleton } from "@nextui-org/react";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { getHours } from 'WorkerStatsService';
@@ -30,9 +30,22 @@ const HoursDashboard = () => {
if (loading) {
return (
-
-
-
+
);
}
diff --git a/frontend/occupi-web/src/components/workerStats/LeastActiveEmployeeCard.tsx b/frontend/occupi-web/src/components/workerStats/LeastActiveEmployeeCard.tsx
index de195ea3..acbe90c5 100644
--- a/frontend/occupi-web/src/components/workerStats/LeastActiveEmployeeCard.tsx
+++ b/frontend/occupi-web/src/components/workerStats/LeastActiveEmployeeCard.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Avatar, Button, Spinner, Progress } from "@nextui-org/react";
+import { Card, CardHeader, CardBody, Avatar, Button, Progress, Skeleton } from "@nextui-org/react";
import { ChevronDown, ChevronUp, Clock, Calendar, TrendingDown } from "lucide-react";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { getLeastActiveEmployee, LeastActiveEmployeeData } from 'WorkerStatsService';
@@ -36,8 +36,11 @@ const LeastActiveEmployeeCard = () => {
if (isLoading) {
return (
-
-
+
+
+
+
+
);
}
diff --git a/frontend/occupi-web/src/components/workerStats/PeakOfficeHoursChart.tsx b/frontend/occupi-web/src/components/workerStats/PeakOfficeHoursChart.tsx
index 877660f8..bd8c8472 100644
--- a/frontend/occupi-web/src/components/workerStats/PeakOfficeHoursChart.tsx
+++ b/frontend/occupi-web/src/components/workerStats/PeakOfficeHoursChart.tsx
@@ -1,6 +1,6 @@
-import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Spinner } from "@nextui-org/react";
-import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
+import React from 'react';
+import { Card, CardBody, Chip, Tooltip, Skeleton } from "@nextui-org/react";
+import { Info } from 'lucide-react'; // Importing the Info icon
import { getPeakOfficeHours } from 'WorkerStatsService';
interface PeakOfficeHoursResponse {
@@ -9,12 +9,12 @@ interface PeakOfficeHoursResponse {
}[];
}
-const PeakOfficeHoursChart = () => {
- const [data, setData] = useState<{ weekday: string; hours: number[] }[]>([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+const PeakOfficeHoursCard = () => {
+ const [data, setData] = React.useState<{ weekday: string; hours: number[] }[]>([]);
+ const [loading, setLoading] = React.useState(true);
+ const [error, setError] = React.useState(null);
- useEffect(() => {
+ React.useEffect(() => {
const fetchData = async () => {
try {
const response = await getPeakOfficeHours({});
@@ -30,30 +30,93 @@ const PeakOfficeHoursChart = () => {
fetchData();
}, []);
- if (loading) return ;
- if (error) return {error}
;
+ if (loading) {
+ return (
+
+ );
+ }
+ if (error) return {error}
;
+
+ const sortedData = [...data].sort((a, b) => {
+ const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+ return days.indexOf(a.weekday) - days.indexOf(b.weekday);
+ });
+
+ const getColorForHour = (hour: number) => {
+ if (hour < 9) return "primary";
+ if (hour < 12) return "success";
+ if (hour < 15) return "warning";
+ return "danger";
+ };
+
+ const colorLegend = [
+ { color: "primary", label: "Early Morning (12 AM - 8 AM)" },
+ { color: "success", label: "Morning (9 AM - 11 AM)" },
+ { color: "warning", label: "Afternoon (12 PM - 2 PM)" },
+ { color: "danger", label: "Late Afternoon & Evening (3 PM - 11 PM)" },
+ ];
return (
-
-
- Peak Office Hours by Weekday
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
Peak Office Hours
+
+ {/* Using Info icon from lucide-react */}
+
+
+
+
+ {sortedData.map((day) => (
+
+
+ {day.weekday}
+
+ {day.hours.map((hour, index) => (
+
+ {hour}:00
+
+ ))}
+
+
+
+ ))}
+
+
+
+
Color Legend
+
+ {colorLegend.map(({ color, label }) => (
+
+
+ {label}
+
+ ))}
+
+
);
};
-export default PeakOfficeHoursChart;
\ No newline at end of file
+export default PeakOfficeHoursCard;
diff --git a/frontend/occupi-web/src/components/workerStats/WorkRatioChart.tsx b/frontend/occupi-web/src/components/workerStats/WorkRatioChart.tsx
index 74dc9d67..f35a7e98 100644
--- a/frontend/occupi-web/src/components/workerStats/WorkRatioChart.tsx
+++ b/frontend/occupi-web/src/components/workerStats/WorkRatioChart.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { Card, CardHeader, CardBody, Spinner } from "@nextui-org/react";
+import { Card, CardHeader, CardBody, Skeleton } from "@nextui-org/react";
import { RadarChart, Radar, PolarGrid, PolarAngleAxis, PolarRadiusAxis, ResponsiveContainer, Tooltip, Legend } from 'recharts';
import { getWorkRatio } from 'WorkerStatsService';
@@ -35,7 +35,15 @@ const WorkRatioChart = () => {
fetchData();
}, []);
- if (loading) return ;
+ if (loading) {
+ return (
+
+
+
+
+
+ );
+ }
if (error) return {error}
;
return (
diff --git a/frontend/occupi-web/src/pages/worker-dash/WorkerDashboard.tsx b/frontend/occupi-web/src/pages/worker-dash/WorkerDashboard.tsx
index 5d01ef23..993d7920 100644
--- a/frontend/occupi-web/src/pages/worker-dash/WorkerDashboard.tsx
+++ b/frontend/occupi-web/src/pages/worker-dash/WorkerDashboard.tsx
@@ -1,5 +1,4 @@
import React, { useState, useEffect } from "react";
-import { Spinner } from "@nextui-org/react";
import { Button } from "@nextui-org/react";
import {
Dropdown,
@@ -7,22 +6,10 @@ import {
DropdownMenu,
DropdownItem,
} from "@nextui-org/dropdown";
-import {
- Clock,
- Users,
- BarChart2,
- Sunrise,
- Sunset,
- User,
- UserMinus,
-} from "lucide-react";
+import { Clock, Users, BarChart2, Sunrise, Sunset } from "lucide-react";
import * as workerStats from "WorkerStatsService";
-import { Responsive, WidthProvider, Layout, Layouts } from "react-grid-layout";
-import "react-grid-layout/css/styles.css";
-import "react-resizable/css/styles.css";
import type { Selection } from "@nextui-org/react";
import {
- AiDashCard,
ActiveEmployeeCard,
LeastActiveEmployeeCard,
WorkRatioChart,
@@ -30,26 +17,75 @@ import {
HoursDashboard,
AverageHoursChart,
TopNav,
+ AiDashCard,
} from "@components/index";
+import { AI_loader } from "@assets/index";
-const ResponsiveGridLayout = WidthProvider(Responsive);
+// New individual AiDashCard components
+const TotalHoursCard: React.FC<{
+ stat: string | null;
+ onRemove: () => void;
+}> = ({ stat, onRemove }) => (
+ }
+ stat={stat || "N/A"}
+ trend={5}
+ onRemove={onRemove}
+ />
+);
-const defaultVisibleCards = [
- "hours",
- "averageHours",
- "workRatio",
- "peakOfficeHours",
-];
+const AverageHoursCard: React.FC<{
+ stat: string | null;
+ onRemove: () => void;
+}> = ({ stat, onRemove }) => (
+ }
+ stat={stat || "N/A"}
+ trend={-2}
+ onRemove={onRemove}
+ />
+);
-const defaultLayouts: Layouts = {
- lg: defaultVisibleCards.map((id, index) => ({
- i: id,
- x: index * 3,
- y: 0,
- w: 3,
- h: 2,
- })),
-};
+const WorkRatioCard: React.FC<{
+ stat: string | null;
+ onRemove: () => void;
+}> = ({ stat, onRemove }) => (
+ }
+ stat={stat || "N/A"}
+ trend={3}
+ onRemove={onRemove}
+ />
+);
+
+const ArrivalDepartureCard: React.FC<{
+ stat: string | null;
+ onRemove: () => void;
+}> = ({ stat, onRemove }) => (
+ }
+ stat={stat || "N/A"}
+ onRemove={onRemove}
+ trend={0}
+ />
+);
+
+const InOfficeRateCard: React.FC<{
+ stat: string | null;
+ onRemove: () => void;
+}> = ({ stat, onRemove }) => (
+ }
+ stat={stat || "N/A"}
+ trend={-1}
+ onRemove={onRemove}
+ />
+);
interface WorkerStats {
hours: string | null;
@@ -74,15 +110,11 @@ const WorkerStatsDashboard: React.FC = () => {
leastActiveEmployee: null,
});
const [loading, setLoading] = useState(true);
- const [layouts, setLayouts] = useState(() => {
- const savedLayouts = localStorage.getItem("workerStatsDashboardLayouts");
- return savedLayouts ? JSON.parse(savedLayouts) : defaultLayouts;
- });
const [visibleCards, setVisibleCards] = useState(() => {
const savedVisibleCards = localStorage.getItem("workerStatsVisibleCards");
return savedVisibleCards
? JSON.parse(savedVisibleCards)
- : defaultVisibleCards;
+ : ["hours", "averageHours"];
});
const [selectedKeys, setSelectedKeys] = React.useState(
new Set(visibleCards)
@@ -103,7 +135,11 @@ const WorkerStatsDashboard: React.FC = () => {
] as const;
const results = await Promise.all(
statNames.map((stat) => {
- const method = workerStats[`get${stat.charAt(0).toUpperCase() + stat.slice(1)}` as keyof typeof workerStats] as unknown as () => Promise<{ data: [string] }>;
+ const method = workerStats[
+ `get${
+ stat.charAt(0).toUpperCase() + stat.slice(1)
+ }` as keyof typeof workerStats
+ ] as unknown as () => Promise<{ data: [string] }>;
return method();
})
);
@@ -126,55 +162,51 @@ const WorkerStatsDashboard: React.FC = () => {
}, []);
useEffect(() => {
- localStorage.setItem(
- "workerStatsDashboardLayouts",
- JSON.stringify(layouts)
- );
localStorage.setItem(
"workerStatsVisibleCards",
JSON.stringify(visibleCards)
);
- }, [layouts, visibleCards]);
+ }, [visibleCards]);
const formatStat = (stat: string, value: unknown): string => {
switch (stat) {
case "hours":
case "averageHours":
- return typeof value === "object" && value !== null && "overallTotal" in value
+ return typeof value === "object" &&
+ value !== null &&
+ "overallTotal" in value
? (value.overallTotal as number).toFixed(2)
: "N/A";
case "workRatio":
- return typeof value === "number" ? `${(value * 100).toFixed(2)}%` : "N/A";
+ return typeof value === "number"
+ ? `${(value * 100).toFixed(2)}%`
+ : "N/A";
case "peakOfficeHours":
- return typeof value === "object" && value !== null && "peakHours" in value
- ? value.peakHours as string
+ return typeof value === "object" &&
+ value !== null &&
+ "peakHours" in value
+ ? (value.peakHours as string)
: "N/A";
case "arrivalDepartureAverage":
- return typeof value === "object" && value !== null &&
- "overallavgArrival" in value && "overallavgDeparture" in value
+ return typeof value === "object" &&
+ value !== null &&
+ "overallavgArrival" in value &&
+ "overallavgDeparture" in value
? `${value.overallavgArrival} - ${value.overallavgDeparture}`
: "N/A";
case "mostActiveEmployee":
case "leastActiveEmployee":
return typeof value === "object" && value !== null && "email" in value
- ? value.email as string
+ ? (value.email as string)
: "N/A";
default:
return "N/A";
}
};
- const onLayoutChange = (_currentLayout: Layout[], allLayouts: Layouts) => {
- setLayouts(allLayouts);
- };
-
const handleAddCard = (cardId: string) => {
if (!visibleCards.includes(cardId)) {
setVisibleCards((prev) => [...prev, cardId]);
- setLayouts((prev) => ({
- ...prev,
- lg: [...prev.lg, { i: cardId, x: 0, y: Infinity, w: 3, h: 2 }],
- }));
}
};
@@ -185,101 +217,54 @@ const WorkerStatsDashboard: React.FC = () => {
newKeys.delete(cardId);
return newKeys;
});
- setLayouts((prev) => ({
- ...prev,
- lg: prev.lg.filter((item) => item.i !== cardId),
- }));
};
if (loading) {
- return Loading stats...;
+ return (
+
+
+
+
Loading Statistics from Occubot...
+
+
+
+
+ );
}
- const cardData = [
- {
- id: "hours",
- title: "Total Hours",
- icon: ,
- stat: stats.hours,
- trend: 5,
- },
- {
- id: "averageHours",
- title: "Average Hours",
- icon: ,
- stat: stats.averageHours,
- trend: -2,
- },
- {
- id: "workRatio",
- title: "Work Ratio",
- icon: ,
- stat: stats.workRatio,
- trend: 3,
- },
- {
- id: "peakOfficeHours",
- title: "Peak Office Hours",
- icon: ,
- stat: stats.peakOfficeHours,
- trend: 0,
- },
- {
- id: "arrivalDepartureAverage",
- title: "Avg Arrival - Departure",
- icon: ,
- stat: stats.arrivalDepartureAverage,
- trend: 1,
- },
- {
- id: "inOfficeRate",
- title: "In-Office Rate",
- icon: ,
- stat: stats.inOfficeRate,
- trend: -1,
- },
- {
- id: "mostActiveEmployee",
- title: "Most Active Employee",
- icon: ,
- stat: stats.mostActiveEmployee,
- trend: 2,
- },
- {
- id: "leastActiveEmployee",
- title: "Least Active Employee",
- icon: ,
- stat: stats.leastActiveEmployee,
- trend: -3,
- },
- ];
-
return (
-
-
- Employee Statistics
-
- See all Your Employee Statistics from Occubot
-
-
} searchQuery={""} onChange={function (): void {
- throw new Error("Function not implemented.");
- } }
+
+
+ Employee Statistics
+
+ See all Your Employee Statistics from Occubot
+
+
+ }
+ searchQuery=""
+ onChange={() => {}}
/>
-
+
{
});
}}
>
- {cardData.map((card) => (
-
- {card.title}
-
- ))}
+ }>
+ Total Hours
+
+ }>
+ Average Hours
+
+ }>
+ Work Ratio
+
+ }
+ >
+ Avg Arrival - Departure
+
+ }>
+ In-Office Rate
+
-
- {cardData.map(
- (card) =>
- visibleCards.includes(card.id) && (
-
-
handleRemoveCard(card.id)}
- />
-
- )
+
+ {visibleCards.includes("workRatio") && (
+
handleRemoveCard("workRatio")}
+ />
+ )}
+ {visibleCards.includes("averageHours") && (
+ handleRemoveCard("averageHours")}
+ />
+ )}
+ {visibleCards.includes("arrivalDepartureAverage") && (
+ handleRemoveCard("arrivalDepartureAverage")}
+ />
+ )}
+ {visibleCards.includes("inOfficeRate") && (
+ handleRemoveCard("inOfficeRate")}
+ />
)}
-
+
-
+
-
-
+
-
-
-
+
+
+
+ {visibleCards.includes("hours") && (
+ handleRemoveCard("hours")}
+ />
+ )}
+
+
+
+
+
+
);
};
-export default WorkerStatsDashboard;
\ No newline at end of file
+export default WorkerStatsDashboard;