diff --git a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/activity-modal.tsx b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/activity-modal.tsx
new file mode 100644
index 000000000..86c97485f
--- /dev/null
+++ b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/activity-modal.tsx
@@ -0,0 +1,193 @@
+'use client';
+
+import { Modal, Avatar } from '@/lib/components';
+import { ITimerEmployeeLog } from '@/app/interfaces/timer/ITimerLog';
+import { useState, useMemo } from 'react';
+
+interface ActivityModalProps {
+ employeeLog: ITimerEmployeeLog;
+ isOpen: boolean;
+ closeModal: () => void;
+}
+
+type TabType = 'tracked' | 'activity';
+
+interface CircleProps {
+ color: string;
+ dashArray: string;
+ dashOffset?: string;
+}
+
+const Circle = ({ color, dashArray, dashOffset = '0' }: CircleProps) => (
+
+);
+
+const LegendItem = ({
+ color,
+ label,
+ time,
+ percentage
+}: {
+ color: string;
+ label: string;
+ time: string;
+ percentage: number;
+}) => (
+
+
+
+ {time} ({percentage}%)
+
+
+);
+
+const formatTime = (minutes: number): string => {
+ const hours = Math.floor(minutes / 60);
+ const mins = Math.floor(minutes % 60);
+ return `${hours}h ${mins.toString().padStart(2, '0')}min`;
+};
+
+export const ActivityModal = ({ employeeLog, isOpen, closeModal }: ActivityModalProps) => {
+ const [activeTab, setActiveTab] = useState('activity');
+
+ const timeCalculations = useMemo(() => {
+ const totalTime = employeeLog.sum || 0;
+ return {
+ totalTime,
+ activeTime: totalTime * 0.57,
+ idleTime: totalTime * 0.13,
+ unknownTime: totalTime * 0.3,
+ trackedTime: totalTime * 0.75,
+ manualTime: totalTime * 0.25
+ };
+ }, [employeeLog.sum]);
+
+ const { activeTime, idleTime, unknownTime, trackedTime, manualTime } = timeCalculations;
+
+ const formattedTimes = useMemo(
+ () => ({
+ active: formatTime(activeTime),
+ idle: formatTime(idleTime),
+ unknown: formatTime(unknownTime),
+ tracked: formatTime(trackedTime),
+ manual: formatTime(manualTime)
+ }),
+ [activeTime, idleTime, unknownTime, trackedTime, manualTime]
+ );
+
+ return (
+
+
+
+
+
+
+ {employeeLog.employee.fullName}
+
+
+
+
+
+ {(['tracked', 'activity'] as const).map((tab) => (
+
+ ))}
+
+
+
+ {activeTab === 'tracked' ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
+};
diff --git a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-icon.tsx b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-icon.tsx
new file mode 100644
index 000000000..a658310e9
--- /dev/null
+++ b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-icon.tsx
@@ -0,0 +1,30 @@
+export const ChartIcon = () => {
+ return (
+
+ );
+};
diff --git a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-stats-table.tsx b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-stats-table.tsx
index 0d4609fe7..964957e14 100644
--- a/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-stats-table.tsx
+++ b/apps/web/app/[locale]/dashboard/team-dashboard/[teamId]/components/team-stats-table.tsx
@@ -7,7 +7,10 @@ import { format } from 'date-fns';
import { ITimerLogGrouped } from '@/app/interfaces';
import { Spinner } from '@/components/ui/loaders/spinner';
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
-import { useState } from 'react';
+import { Fragment, useState } from 'react';
+import { ChartIcon } from './team-icon';
+import { ActivityModal } from './activity-modal';
+import { useModal } from '@/app/hooks';
const getProgressColor = (activityLevel: number) => {
if (isNaN(activityLevel) || activityLevel < 0) return 'bg-gray-300';
@@ -33,12 +36,18 @@ const formatPercentage = (value: number) => {
const ITEMS_PER_PAGE = 10;
-export function TeamStatsTable({ rapportDailyActivity, isLoading }: { rapportDailyActivity?: ITimerLogGrouped[], isLoading?: boolean }) {
+export function TeamStatsTable({
+ rapportDailyActivity,
+ isLoading
+}: {
+ rapportDailyActivity?: ITimerLogGrouped[];
+ isLoading?: boolean;
+}) {
const [currentPage, setCurrentPage] = useState(1);
const totalPages = rapportDailyActivity ? Math.ceil(rapportDailyActivity.length / ITEMS_PER_PAGE) : 0;
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
const endIndex = startIndex + ITEMS_PER_PAGE;
-
+ const { openModal, closeModal, isOpen } = useModal();
const paginatedData = rapportDailyActivity?.slice(startIndex, endIndex);
const goToPage = (page: number) => {
@@ -59,103 +68,139 @@ export function TeamStatsTable({ rapportDailyActivity, isLoading }: { rapportDai
}
if (!rapportDailyActivity?.length) {
- return (
-
- No data available
-
- );
+ return No data available
;
}
return (
-
-
-
-
- Member
- Total Time
- Tracked
- Manually Added
- Active Time
- Idle Time
- Unknown Activity
- Activity Level
-
-
-
- {paginatedData?.map((dayData) => (
-
-
-
- {format(new Date(dayData.date), 'EEEE dd MMM yyyy')}
-
-
- {dayData.logs?.map((projectLog) => (
- projectLog.employeeLogs?.map((employeeLog) => (
-
-
-
-
-
-
- {employeeLog.employee?.user?.name?.[0] || 'U'}
-
-
- {employeeLog.employee?.user?.name || 'Unknown User'}
-
-
- {formatDuration(employeeLog.sum || 0)}
- {formatPercentage(employeeLog.activity)}
- {formatPercentage(0)}
- {formatPercentage(100)}
- {formatPercentage(0)}
- {formatPercentage(0)}
-
-
-
-
{(employeeLog.activity || 0).toFixed(1)}%
-
-
-
- )) || []
- )) || []}
-
- ))}
-
-
+
+
+
+
+
+
+
+ Member
+ Total Time
+ Tracked
+ Manually Added
+ Active Time
+ Idle Time
+ Unknown Activity
+ Activity Level
+
+
+
+
+ {paginatedData?.map((dayData) => (
+
+
+
+ {format(new Date(dayData.date), 'EEEE dd MMM yyyy')}
+
+
+ {dayData.logs?.map(
+ (projectLog) =>
+ projectLog.employeeLogs?.map((employeeLog) => (
+
+
+
+
+
+
+ {employeeLog.employee?.user?.name?.[0] ||
+ 'U'}
+
+
+
+ {employeeLog.employee?.user?.name ||
+ 'Unknown User'}
+
+
+
+
+ {formatDuration(employeeLog.sum || 0)}
+
+
+ {formatPercentage(employeeLog.activity)}
+
+
+ {formatPercentage(0)}
+
+
+ {formatPercentage(100)}
+
+
+ {formatPercentage(0)}
+
+
+ {formatPercentage(0)}
+
+
+
+
+
+ {(employeeLog.activity || 0).toFixed(1)}%
+
+
+
+
+ <>
+
+
+ >
+
+
+ )) || []
+ ) || []}
+
+ ))}
+
+
+
+
+
-
-
-
- Showing {startIndex + 1} to {Math.min(endIndex, rapportDailyActivity.length)} of {rapportDailyActivity.length} entries
-
+
+
+ Showing {startIndex + 1} to {Math.min(endIndex, rapportDailyActivity.length)} of{' '}
+ {rapportDailyActivity.length} entries
-