From baff5fae92c537ec17be197ed0b0c77a7c432c68 Mon Sep 17 00:00:00 2001
From: shebz2023
Date: Wed, 20 Nov 2024 10:50:36 +0200
Subject: [PATCH] user Growth overtime chart
---
src/Chart/TeamChart.tsx | 218 ++++++++++++++++++++++
src/components/AdminDashboardTable.tsx | 10 +
src/components/AdminTeamDetails.tsx | 242 ++++++++++++++++++++++++-
3 files changed, 468 insertions(+), 2 deletions(-)
create mode 100644 src/Chart/TeamChart.tsx
diff --git a/src/Chart/TeamChart.tsx b/src/Chart/TeamChart.tsx
new file mode 100644
index 00000000..56c400f9
--- /dev/null
+++ b/src/Chart/TeamChart.tsx
@@ -0,0 +1,218 @@
+/* eslint-disable no-console */
+/* eslint-disable no-restricted-syntax */
+/* eslint-disable no-plusplus */
+import React from 'react';
+import { Line } from 'react-chartjs-2';
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+} from 'chart.js';
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+);
+
+interface TeamChartProps {
+ timeframe?: 'daily' | 'weekly' | 'monthly';
+ CurrentTeam: any[];
+ loginsbyDate: any[];
+}
+
+function TeamChart({
+ timeframe = 'daily',
+ CurrentTeam,
+ loginsbyDate,
+}: TeamChartProps) {
+ function organizeLoginData(loginData: any) {
+ const currentDate = new Date();
+ const currentYear = currentDate.getFullYear();
+ function getWeekNumber(date: any) {
+ const tempDate: any = new Date(date);
+ tempDate.setUTCDate(
+ tempDate.getUTCDate() + 4 - (tempDate.getUTCDay() || 7),
+ );
+ const yearStart: any = new Date(
+ Date.UTC(tempDate.getUTCFullYear(), 0, 1),
+ );
+ return Math.ceil(((tempDate - yearStart) / 86400000 + 1) / 7);
+ }
+ // Initialize result arrays
+ const weeklyData = Array(54)
+ .fill(0)
+ .map((_, i) => ({ week: i + 1, success: 0, failed: 0 }));
+ const monthlyData = Array(12)
+ .fill(0)
+ .map((_, i) => ({ month: i + 1, success: 0, failed: 0 }));
+ const dailyData = Array(7)
+ .fill(0)
+ .map((_, i) => ({ day: i, success: 0, failed: 0 }));
+ for (const [dateString, { success, failed }] of Object.entries(
+ loginData,
+ ) as any) {
+ const date = new Date(dateString);
+ const isoWeekNumber = getWeekNumber(date);
+ const month = date.getUTCMonth();
+ const dayOfWeek = (date.getUTCDay() + 6) % 7;
+ const weekStart = new Date(currentDate);
+ weekStart.setUTCDate(
+ currentDate.getUTCDate() - currentDate.getUTCDay() + 1,
+ );
+ const weekEnd = new Date(weekStart);
+ weekEnd.setUTCDate(weekStart.getUTCDate() + 6);
+ if (date >= weekStart && date <= weekEnd) {
+ dailyData[dayOfWeek].success += success;
+ dailyData[dayOfWeek].failed += failed;
+ }
+ // Weekly data
+ if (isoWeekNumber <= 54) {
+ weeklyData[isoWeekNumber - 1].success += success;
+ weeklyData[isoWeekNumber - 1].failed += failed;
+ }
+ // Monthly data
+ monthlyData[month].success += success;
+ monthlyData[month].failed += failed;
+ }
+ const weekDays = [
+ 'Monday',
+ 'Tuesday',
+ 'Wednesday',
+ 'Thursday',
+ 'Friday',
+ 'Saturday',
+ 'Sunday',
+ ];
+ const currentWeekData = dailyData.map((data, index) => ({
+ day: weekDays[index],
+ success: data.success,
+ failed: data.failed,
+ }));
+ return {
+ currentWeek: currentWeekData,
+ weekly: weeklyData,
+ monthly: monthlyData.map((data, index) => ({
+ month: new Date(0, index).toLocaleString('en', { month: 'long' }),
+ success: data.success,
+ failed: data.failed,
+ })),
+ };
+ }
+
+ const organizedData = organizeLoginData(loginsbyDate);
+
+ const weeklyDataset = organizedData.weekly
+ .filter((_, index) => index % 3 === 0)
+ .map((item) => item.success);
+
+ const chartData = {
+ daily: {
+ labels: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
+ datasets: [
+ {
+ label: CurrentTeam[0].name,
+ data: organizedData.currentWeek.map((item: any) => item.success),
+ fill: false,
+ borderColor: '#4F46E5',
+ tension: 0.4,
+ },
+ ],
+ },
+ weekly: {
+ labels: [
+ '03',
+ '06',
+ '09',
+ '12',
+ '15',
+ '18',
+ '21',
+ '24',
+ '27',
+ '30',
+ '31',
+ '34',
+ '37',
+ '40',
+ '43',
+ '46',
+ '49',
+ '54',
+ ],
+ datasets: [
+ {
+ label: CurrentTeam[0].name,
+ data: weeklyDataset,
+ fill: false,
+ borderColor: '#4F46E5',
+ tension: 0.4,
+ },
+ ],
+ },
+ monthly: {
+ labels: Array.from({ length: 12 }, (_, i) =>
+ String(i + 1).padStart(2, '0'),
+ ),
+ datasets: [
+ {
+ label: CurrentTeam[0].name,
+ data: organizedData.monthly.map((item: any) => item.success),
+ fill: false,
+ borderColor: '#4F46E5',
+ tension: 0.4,
+ },
+ ],
+ },
+ };
+
+ const options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ position: 'bottom' as const,
+ },
+ tooltip: {
+ mode: 'index' as const,
+ intersect: false,
+ },
+ },
+ scales: {
+ y: {
+ beginAtZero: true,
+ grid: {
+ color: '#D1D5DB',
+ },
+ ticks: {
+ color: '#6B7280',
+ },
+ },
+ x: {
+ grid: {
+ display: false,
+ },
+ ticks: {
+ color: '#6B7280',
+ },
+ },
+ },
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default TeamChart;
diff --git a/src/components/AdminDashboardTable.tsx b/src/components/AdminDashboardTable.tsx
index 33644a6d..7bc3808e 100644
--- a/src/components/AdminDashboardTable.tsx
+++ b/src/components/AdminDashboardTable.tsx
@@ -54,6 +54,16 @@ function DashboardTableDesign() {
columns={organizationColumns}
data={TableData ? (TableData as any[]) : []}
title={t('Teams metrices')}
+<<<<<<< HEAD
+=======
+ loading={loading}
+ />
+ setIsModalOpen(false)}
+ selectedteam={selectedTeam}
+ Teams={TeamsData?.getAllTeams}
+>>>>>>> fdc13ed (user Growth overtime chart)
/>
);
diff --git a/src/components/AdminTeamDetails.tsx b/src/components/AdminTeamDetails.tsx
index dfe5588c..9a19ff07 100644
--- a/src/components/AdminTeamDetails.tsx
+++ b/src/components/AdminTeamDetails.tsx
@@ -1,9 +1,16 @@
import React, { useState } from 'react';
+<<<<<<< HEAD
import { FaAngleDown } from "react-icons/fa6";
+=======
+import { FaAngleDown } from 'react-icons/fa6';
+import TeamChart from '../Chart/TeamChart';
+import ProgressBar from '../Chart/ProgressBar';
+import UsersChart from '../Chart/usersChart';
+>>>>>>> fdc13ed (user Growth overtime chart)
interface TeamData {
ttlName?: string;
- team?: string;
+ teams?: string;
organization?: string;
program?: string;
phase?: string;
@@ -16,9 +23,11 @@ interface TeamData {
interface TeamDetailsModalProps {
isOpen: boolean;
onClose: () => void;
- teamData: TeamData | null;
+ selectedteam: TeamData | null;
+ Teams?: any;
}
+<<<<<<< HEAD
const TeamDetailsModal: React.FC = ({ isOpen, onClose, teamData }) => {
if (!isOpen) return null;
@@ -31,6 +40,112 @@ const TeamDetailsModal: React.FC = ({ isOpen, onClose, te
const handleAttendanceSummaryLeave = () => {
setShowAttendanceSummary(false);
};
+=======
+// Add this near the top of your TeamDetailsModal component
+const loginStats = {
+ daily: {
+ passed: 60,
+ failed: 40,
+ total: '200k',
+ },
+ weekly: {
+ passed: 75,
+ failed: 25,
+ total: '1.2M',
+ },
+ monthly: {
+ passed: 85,
+ failed: 15,
+ total: '5M',
+ },
+};
+
+function TeamDetailsModal({
+ isOpen,
+ onClose,
+ selectedteam,
+ Teams,
+}: TeamDetailsModalProps) {
+ const [activeTab, setActiveTab] = useState<'overview' | 'logins'>('overview');
+ const [timeframe, setTimeframe] = useState<'daily' | 'weekly' | 'monthly'>(
+ 'daily',
+ );
+ const [showAttendanceSummary, setShowAttendanceSummary] = useState(false);
+
+ const handleAttendanceSummaryEnter = () => setShowAttendanceSummary(true);
+ const handleAttendanceSummaryLeave = () => setShowAttendanceSummary(false);
+
+ if (!isOpen) return null;
+
+ const CurrentTeam = Teams?.filter(
+ (items: any) => items?.name === selectedteam?.teams,
+ );
+
+ const average =
+ (parseInt(CurrentTeam[0]?.avgRatings?.quality, 2) +
+ parseInt(CurrentTeam[0]?.avgRatings?.quantity, 2) +
+ parseInt(CurrentTeam[0]?.avgRatings?.professional_Skills, 2)) /
+ 3;
+
+ const activeMembers = CurrentTeam[0]?.members.filter(
+ (item: any) => item.status.status !== 'suspended',
+ );
+ const droppedMembers = CurrentTeam[0]?.members.filter(
+ (item: any) => item.status.status === 'suspended',
+ );
+ function mapLoginsByDate(team: any) {
+ if (!team || !Array.isArray(team[0].members)) {
+ throw new Error('Invalid team object');
+ }
+ const loginCounts: any = {};
+ team[0].members.forEach((member: any) => {
+ const activities = member.profile?.activity;
+
+ if (Array.isArray(activities)) {
+ activities.forEach((activity) => {
+ const rawDate = activity.date;
+ const timestamp = parseInt(rawDate, 10);
+ if (!Number.isNaN(timestamp)) {
+ const loginDate = new Date(timestamp).toISOString().split('T')[0];
+ if (!loginCounts[loginDate]) {
+ loginCounts[loginDate] = { success: 0, failed: 0 };
+ }
+ if (activity.failed === 1) {
+ loginCounts[loginDate].failed += 1;
+ } else {
+ loginCounts[loginDate].success += 1;
+ }
+ }
+ });
+ }
+ });
+ return loginCounts;
+ }
+ const loginsbyDate = mapLoginsByDate(CurrentTeam);
+ const orgName = localStorage.getItem('orgName');
+
+ function calculateLoginPercentages(data: any) {
+ let totalSuccess = 0;
+ let totalFailed = 0;
+
+ // Sum up all successes and failures
+ Object.values(data).forEach(({ success, failed }: any) => {
+ totalSuccess += success;
+ totalFailed += failed;
+ });
+
+ // Calculate percentages
+ const total = totalSuccess + totalFailed;
+ const successPercentage = total > 0 ? (totalSuccess / total) * 100 : 0;
+ const failedPercentage = total > 0 ? (totalFailed / total) * 100 : 0;
+
+ return {
+ successPercentage: successPercentage.toFixed(2),
+ failedPercentage: failedPercentage.toFixed(2),
+ totalLogins: total,
+ };
+ }
+>>>>>>> fdc13ed (user Growth overtime chart)
return (
@@ -103,6 +218,7 @@ const TeamDetailsModal: React.FC
= ({ isOpen, onClose, te
Users
+<<<<<<< HEAD
Active Members
@@ -114,6 +230,95 @@ const TeamDetailsModal: React.FC = ({ isOpen, onClose, te
{teamData?.droppedUsers || '0'}
+=======
+ {[
+ ['TTL Name', CurrentTeam[0]?.ttl?.profile?.name || 'Sostene'],
+ ['Team Name', selectedteam?.teams || 'Team Name'],
+ ['Organization', selectedteam?.organization || orgName],
+ [
+ 'Program',
+ CurrentTeam[0]?.cohort?.program?.name || 'Program Name',
+ ],
+ [
+ 'Phase',
+ CurrentTeam[0]?.cohort?.phase?.name || 'Current Phase',
+ ],
+ ['Cohort', CurrentTeam[0]?.cohort.name || 'Current Cohort'],
+ ].map(([label, value], idx) => (
+ // eslint-disable-next-line react/no-array-index-key
+
+
+
{value}
+
+ ))}
+
+
+
+
+
+
+
+
+ Active Members
+
+
+ {activeMembers?.length || '0'}
+
+
+
+
+ Dropped Members
+
+
+ {droppedMembers?.length || '0'}
+
+
+
+
+
+
+
+ {showAttendanceSummary && (
+
+
+ Quality: {CurrentTeam[0]?.avgRatings?.quality || 0}
+
+
+ Quantity: {CurrentTeam[0]?.avgRatings?.quality || 0}
+
+
+ Professionalism:{' '}
+ {CurrentTeam[0]?.avgRatings?.professional_Skills || 0}
+
+
+ )}
+
+
+
+
+
+
+ {average || '0'} / 5.0
+
+
+>>>>>>> fdc13ed (user Growth overtime chart)
@@ -133,6 +338,7 @@ const TeamDetailsModal: React.FC = ({ isOpen, onClose, te
Quantity: 2.3
Professionalism: 3.1
+<<<<<<< HEAD
)}
@@ -145,6 +351,38 @@ const TeamDetailsModal: React.FC = ({ isOpen, onClose, te
{teamData?.rating || '4.5'} / 5.0
+=======
+
+
+
+ Logins Attempt Status
+
+
+
+
+ Total Logins:{' '}
+
+ {' '}
+ {calculateLoginPercentages(loginsbyDate).totalLogins}
+
+
+
+
+
+>>>>>>> fdc13ed (user Growth overtime chart)