From a1af9b2111906fdbc76f1840ec22b9f5e490ada2 Mon Sep 17 00:00:00 2001 From: Rushikesh-Sonawane99 Date: Sun, 2 Jun 2024 02:03:52 +0530 Subject: [PATCH 1/4] PS-645 feat: Developed Custom Date Range Calendar UI --- src/components/CustomRangeModal.tsx | 16 ++- src/components/DateRangePopup.tsx | 145 +++++++++++++++++++++++----- src/components/MonthCalender.tsx | 41 +++++++- 3 files changed, 165 insertions(+), 37 deletions(-) diff --git a/src/components/CustomRangeModal.tsx b/src/components/CustomRangeModal.tsx index 1a390693..10992052 100644 --- a/src/components/CustomRangeModal.tsx +++ b/src/components/CustomRangeModal.tsx @@ -1,8 +1,6 @@ -// components/CustomRangeModal.tsx import * as React from 'react'; import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; import CloseIcon from '@mui/icons-material/Close'; import Modal from '@mui/material/Modal'; import WestIcon from '@mui/icons-material/West'; @@ -27,16 +25,16 @@ const style = { }; const CustomRangeModal: React.FC = () => { - const [open, setOpen] = React.useState(false); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); + const [isCalendarModalOpen, setIsCalenderModalOpen] = React.useState(false); + const toggleCalendarModal = () => setIsCalenderModalOpen(!isCalendarModalOpen); + const { t } = useTranslation(); return (
{/* */} @@ -55,12 +53,12 @@ const CustomRangeModal: React.FC = () => { }} > - + {t('COMMON.CUSTOM_RANGE')} - + diff --git a/src/components/DateRangePopup.tsx b/src/components/DateRangePopup.tsx index b4b80df0..249b0d0b 100644 --- a/src/components/DateRangePopup.tsx +++ b/src/components/DateRangePopup.tsx @@ -15,20 +15,40 @@ import React, { useState } from 'react'; import Check from '@mui/icons-material/Check'; import CloseIcon from '@mui/icons-material/Close'; import ListItemIcon from '@mui/material/ListItemIcon'; +import WestIcon from '@mui/icons-material/West'; import { useTranslation } from 'next-i18next'; +import MonthCalender from './MonthCalender'; const modalStyle = { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', - width: 400, + width: 300, bgcolor: 'background.paper', // border: '2px solid #000', boxShadow: 24, p: 4, }; +const calenderModalStyle = { + width: '300px', // Adjust width as needed + maxWidth: 300, // Maximum width for responsiveness + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + backgroundColor: 'white', + padding: '12px 15px 12px 15px', + borderRadius: '8px', + boxShadow: '0px 4px 10px rgba(0, 0, 0, 0.1)', + + // Responsive styles + '@media (min-width: 768px)': { + width: '70%', // Adjust width for smaller screens + }, +}; + const dividerStyle = { my: 2, }; @@ -47,16 +67,20 @@ const DateRangePopup: React.FC = ({ onDateRangeSelected, }) => { const [isModalOpen, setIsModalOpen] = useState(false); + const [isCalendarModalOpen, setIsCalenderModalOpen] = useState(false); + const [dateRangeArray, setDateRangeArray] = useState([]); const [selectedIndex, setSelectedIndex] = useState(1); - const handleModalOpen = () => setIsModalOpen(true); - const handleModalClose = () => setIsModalOpen(false); + const toggleModal = () => setIsModalOpen(!isModalOpen); + const toggleCalendarModal = () => setIsCalenderModalOpen(!isCalendarModalOpen); const { t } = useTranslation(); const handleMenuItemClick = (index: number, item: string) => { setSelectedIndex(index); setSelectedValue(item); - // handleModalClose(); + if (index === 4) { + toggleCalendarModal(); + } }; const onApply = () => { @@ -65,13 +89,23 @@ const DateRangePopup: React.FC = ({ const { toDate, fromDate } = values; console.log(toDate, fromDate); onDateRangeSelected({ fromDate, toDate }); - handleModalClose(); + toggleModal(); }; const getDateRange = (index: number | null) => { const today = new Date(); - const formatDate = (date: Date) => date.toISOString().split('T')[0]; - let fromDate; + const formatDate = (date: Date) => { + console.log("date", date); + if (typeof date === 'object') { + // return date?.toISOString()?.split('T')[0];} + const localDate = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)); + const year = localDate.getUTCFullYear(); + const month = String(localDate.getUTCMonth() + 1).padStart(2, '0'); // Months are 0-indexed, so add 1 + const day = String(localDate.getUTCDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + + }} + let fromDate: any; let toDate = formatDate(today); switch (index) { @@ -83,37 +117,43 @@ const DateRangePopup: React.FC = ({ fromDate = new Date(today); break; case 2: - { - const dayOfWeek = today.getDay(); - const lastSaturday = new Date(today); - lastSaturday.setDate(today.getDate() - dayOfWeek - 1); - const lastSunday = new Date(lastSaturday); - lastSunday.setDate(lastSaturday.getDate() - 6); - fromDate = lastSunday; - toDate = formatDate(lastSaturday); - } - break; - case 3: fromDate = new Date(today); fromDate.setMonth(today.getMonth() - 1); fromDate.setDate(1); // Start of last month toDate = formatDate(new Date(today.getFullYear(), today.getMonth(), 0)); // End of last month break; - case 4: + case 3: fromDate = new Date(today); fromDate.setMonth(today.getMonth() - 6); fromDate.setDate(1); // Start of the period toDate = formatDate(new Date(today.getFullYear(), today.getMonth(), 0)); // End of last month break; + case 4: + //write here logic to open modal and return fromDate and toDate + if (dateRangeArray) { + fromDate = dateRangeArray[0]; + toDate = formatDate(new Date(dateRangeArray[1])); + } + break; default: fromDate = new Date(today); } return { - fromDate: formatDate(fromDate), + fromDate: formatDate(new Date(fromDate)), toDate, }; }; + const handleCalendarDateChange = (date: Date | [Date, Date] | null) => { + if (Array.isArray(date)) { + setDateRangeArray(date); + // toggleCalendarModal(); + } + }; + + const handleActiveStartDateChange = (date: Date) => { + // setActiveStartDate(date); + }; return ( @@ -124,7 +164,7 @@ const DateRangePopup: React.FC = ({ sx={{ height: '32px', width: '96%', borderRadius: '8px' }} value={selectedValue} displayEmpty - onClick={handleModalOpen} + onClick={toggleModal} inputProps={{ readOnly: true }} > @@ -140,7 +180,7 @@ const DateRangePopup: React.FC = ({ @@ -159,7 +199,7 @@ const DateRangePopup: React.FC = ({ - + @@ -197,6 +237,65 @@ const DateRangePopup: React.FC = ({ + +{/* CustomeCalendarModal */} + + + + + + + + {t('COMMON.CUSTOM_RANGE')} + + + + + + + + {t('COMMON.FROM_TO_DATE')} + + 17 May – 23 May + + + + + + + {t('COMMON.CANCEL')} + {t('COMMON.OK')} + + + + ); }; diff --git a/src/components/MonthCalender.tsx b/src/components/MonthCalender.tsx index 524434a5..35dc4b7f 100644 --- a/src/components/MonthCalender.tsx +++ b/src/components/MonthCalender.tsx @@ -12,7 +12,8 @@ interface CalendarWithAttendanceProps { formattedAttendanceData?: FormattedAttendanceData; learnerAttendanceDate?: learnerAttendanceDate; onChange: (date: Date) => void; - onDateChange: (date: Date) => void; + onDateChange: (date: Date | [Date, Date] | null) => void; + selectionType?: 'single' | 'range'; } type AttendanceData = { @@ -33,8 +34,9 @@ const MonthCalender: React.FC = ({ learnerAttendanceDate, onChange, onDateChange, + selectionType, }) => { - const [date, setDate] = useState(() => new Date()); + const [date, setDate] = useState(() => new Date()); const determinePathColor = useDeterminePathColor(); useEffect(() => { @@ -138,10 +140,38 @@ const MonthCalender: React.FC = ({ onChange(activeStartDate); }; - const handleDateChange: (value: any) => void = (newDate) => { - setDate(newDate); - onDateChange(newDate); + // const handleDateChange: (value: Date | [Date, Date] | null) => void = (newDate) => { + // // Handle the selected date here + // console.log('Selected date:', newDate?.toDateString()); + // setDate(newDate); // Update state with the new selected date if needed + // onDateChange(newDate); + // }; + + const handleDateChange: (value: Date | [Date, Date] | null) => void = (newDate) => { + const formatDate = (date: Date) => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + }; + + if (newDate === null) { + console.log('Selected date: null'); + setDate(null); + onDateChange(null); + } else if (Array.isArray(newDate)) { + const formattedDates = newDate.map(date => formatDate(date)); + console.log('Selected date range:', formattedDates); // Format--->["2024-06-01","2024-06-14"] + setDate(newDate); // Format--->["2024-06-04T18:30:00.000Z","2024-06-13T18:29:59.999Z"] + onDateChange(newDate); + } else { + const formattedDate = formatDate(newDate); + console.log('Selected date:', formattedDate); + setDate(newDate); + onDateChange(newDate); + } }; + return (
@@ -149,6 +179,7 @@ const MonthCalender: React.FC = ({ tileContent({ date, From 5883b427bdc02da718dec173f59f01aa14334daa Mon Sep 17 00:00:00 2001 From: Rushikesh-Sonawane99 Date: Sun, 2 Jun 2024 02:08:25 +0530 Subject: [PATCH 2/4] Issue #PS-627 feat: Integrated API for Attendance overview for all centers --- public/locales/en/common.json | 5 +- public/locales/hi/common.json | 3 +- public/locales/mr/common.json | 3 +- src/components/CohortAttendanceListView.tsx | 53 +++++++++++++++++++ .../LearnerAttendanceStatsListView.tsx | 2 +- src/components/LearnerListHeader.tsx | 14 ++--- src/components/SortingModal.tsx | 4 +- src/pages/dashboard.tsx | 20 ++++--- src/services/AttendanceService.ts | 15 ++++++ src/utils/Interfaces.ts | 18 +++++++ 10 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 src/components/CohortAttendanceListView.tsx diff --git a/public/locales/en/common.json b/public/locales/en/common.json index ef11913a..db16961b 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -109,9 +109,10 @@ "ATTENDANCE_OVERVIEW": "Attendance Overview", "CENTER_ATTENDANCE": "Center Attendance", "LOW_ATTENDANCE_STUDENTS": "Low Attendance Learners", - "N/A": "N/A.", + "N/A": "N/A", "CENTER_NAME": "Center Name", - "ALL_CENTERS": "All Centers" + "ALL_CENTERS": "All Centers", + "NO_LEARNER_WITH_LOW_ATTENDANCE": "No Learner with low attendance" }, "PROFILE": { "EDIT_PROFILE": "Edit Profile", diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index 30b332dc..2a71019c 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -110,7 +110,8 @@ "LOW_ATTENDANCE_STUDENTS": "कम उपस्थिति वाले छात्र", "N/A": "उपलब्ध नहीं", "CENTER_NAME": "केंद्र का नाम", - "ALL_CENTERS": "सभी केंद्र" + "ALL_CENTERS": "सभी केंद्र", + "NO_LEARNER_WITH_LOW_ATTENDANCE": "कम उपस्थिति वाले कोई शिक्षार्थी नहीं" }, "PROFILE": { "EDIT_PROFILE": "प्रोफ़ाइल संपादित करें", diff --git a/public/locales/mr/common.json b/public/locales/mr/common.json index c6ae3245..bb85e89b 100644 --- a/public/locales/mr/common.json +++ b/public/locales/mr/common.json @@ -105,7 +105,8 @@ "LOW_ATTENDANCE_STUDENTS": "कमी उपस्थिती विद्यार्थी", "N/A": "उपलब्ध नाही", "CENTER_NAME": "केंद्राचे नाव", - "ALL_CENTERS": "सर्व केंद्रे" + "ALL_CENTERS": "सर्व केंद्रे", + "NO_LEARNER_WITH_LOW_ATTENDANCE": "कमी उपस्थिती असलेला कोणताही शिकणारा नाही" }, "PROFILE": { "EDIT_PROFILE": "प्रोफाइल संपादित करा", diff --git a/src/components/CohortAttendanceListView.tsx b/src/components/CohortAttendanceListView.tsx new file mode 100644 index 00000000..59b9834d --- /dev/null +++ b/src/components/CohortAttendanceListView.tsx @@ -0,0 +1,53 @@ +import { Box, Grid, Stack, Typography } from '@mui/material'; + +import { CohortAttendanceListViewProps } from '@/utils/Interfaces'; +import React from 'react'; +import { useTheme } from '@mui/material/styles'; +import { useTranslation } from 'next-i18next'; +import { lowLearnerAttendanceLimit } from '../../app.config'; + +const CohortAttendanceListView: React.FC = ({ + cohortName, + attendancePercent, +}) => { + const { t } = useTranslation(); + const theme = useTheme(); + const textColor = attendancePercent > lowLearnerAttendanceLimit ? theme.palette.success.main : theme.palette.error.main; + + return ( + + + + + + {cohortName} + + + + + {attendancePercent}% + + + + + + ); +}; + +export default CohortAttendanceListView; diff --git a/src/components/LearnerAttendanceStatsListView.tsx b/src/components/LearnerAttendanceStatsListView.tsx index fa836d20..6f4baada 100644 --- a/src/components/LearnerAttendanceStatsListView.tsx +++ b/src/components/LearnerAttendanceStatsListView.tsx @@ -125,7 +125,7 @@ const StudentsStatsList: React.FC = ({ = ({ {numberOfColumns == 3 ? ( = ({ ) : ( + borderBottom={`1px solid ${theme.palette.warning['A100']}`} + margin="0" + alignItems={'center'} + bgcolor={'#E6E6E6'} + maxHeight={'auto'} + > void; isModalOpen: boolean; routeName: string; + forAllCenters? : boolean; } const SortingModal: React.FC = ({ @@ -31,6 +32,7 @@ const SortingModal: React.FC = ({ isModalOpen, handleCloseModal, routeName, + forAllCenters }) => { const [sortByName, setSortByName] = React.useState(''); const [sortByAttendance, setSortByAttendance] = React.useState(''); @@ -106,7 +108,7 @@ const SortingModal: React.FC = ({ }} /> - {routeName == '/attendance-overview' ? ( + {(routeName == '/attendance-overview' && !forAllCenters) ? ( <> diff --git a/src/pages/dashboard.tsx b/src/pages/dashboard.tsx index 067f8102..eee17d13 100644 --- a/src/pages/dashboard.tsx +++ b/src/pages/dashboard.tsx @@ -64,6 +64,7 @@ const Dashboard: React.FC = () => { const { t } = useTranslation(); const [open, setOpen] = React.useState(false); const [cohortsData, setCohortsData] = React.useState>([]); + const [manipulatedCohortData, setManipulatedCohortData] = React.useState>(cohortsData); const [classId, setClassId] = React.useState(''); const [showDetails, setShowDetails] = React.useState(false); const [handleSaveHasRun, setHandleSaveHasRun] = React.useState(false); @@ -148,7 +149,10 @@ const Dashboard: React.FC = () => { })) ?.filter(Boolean); setCohortsData(filteredData); - setClassId(filteredData?.[0]?.cohortId); + if(filteredData.length > 0){ + setClassId(filteredData?.[0]?.cohortId); + setManipulatedCohortData(filteredData.concat({ cohortId: 'all', name: 'All Centers' })); + } setLoading(false); } } catch (error) { @@ -164,7 +168,7 @@ const Dashboard: React.FC = () => { const getCohortMemberList = async () => { setLoading(true); try { - if (classId) { + if (classId && classId != "all") { let limit = 300; let page = 0; let filters = { cohortId: classId }; @@ -217,7 +221,7 @@ const Dashboard: React.FC = () => { const studentsWithLowestAttendance = mergedArray.filter( (user) => user.absent && - user.present_percent < lowLearnerAttendanceLimit //TODO: Modify here condition to show low attendance learners + (user.present_percent < lowLearnerAttendanceLimit || user.present_percent === undefined) //TODO: Modify here condition to show low attendance learners ); // Extract names of these students @@ -262,6 +266,8 @@ const Dashboard: React.FC = () => { }; cohortAttendancePercent(); } + }else if (classId && classId === "all"){ + console.log('ALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL CIkCKed') } } catch (error) { console.error('Error fetching cohort list:', error); @@ -439,7 +445,7 @@ const Dashboard: React.FC = () => { onChange={handleCohortSelection} displayEmpty inputProps={{ 'aria-label': 'Without label' }} - disabled={cohortsData?.length == 1 ? true : false} + disabled={cohortsData?.length <= 1 ? true : false} className="SelectLanguages fs-14 fw-500" style={{ borderRadius: '0.5rem', @@ -449,7 +455,7 @@ const Dashboard: React.FC = () => { }} > {cohortsData?.length !== 0 ? ( - cohortsData?.map((cohort) => ( + manipulatedCohortData?.map((cohort) => ( = () => { : lowAttendanceLearnerList.length === 2 ? `${lowAttendanceLearnerList[0]}, ${lowAttendanceLearnerList[1]}` : lowAttendanceLearnerList.length === 1 - ? `${lowAttendanceLearnerList[0]}` - : t('ATTENDANCE.N/A') + ? `${lowAttendanceLearnerList[0]}`: (Array.isArray(lowAttendanceLearnerList) && lowAttendanceLearnerList.length === 0) ? t('ATTENDANCE.NO_LEARNER_WITH_LOW_ATTENDANCE'): + t('ATTENDANCE.N/A') } /> diff --git a/src/services/AttendanceService.ts b/src/services/AttendanceService.ts index ee374212..ff5e3dd4 100644 --- a/src/services/AttendanceService.ts +++ b/src/services/AttendanceService.ts @@ -6,6 +6,7 @@ import { cohortAttendancePercentParam, LearnerAttendanceProps, MarkAttendanceParams, + allCenterAttendancePercentParam, } from '../utils/Interfaces'; export const bulkAttendance = async ({ @@ -114,6 +115,20 @@ export const getCohortAttendance = async ({ }); }; +export const getAllCenterAttendance = async ({ + limit, + page, + filters: {scope, fromDate, toDate, contextId}, + facets, +}: allCenterAttendancePercentParam): Promise => { + return postAttendanceList({ + limit, + page, + filters: {scope, fromDate, toDate, contextId}, + facets, + }) +}; + export const classesMissedAttendancePercentList = async ({ filters, facets, diff --git a/src/utils/Interfaces.ts b/src/utils/Interfaces.ts index 46d3937b..87c3b419 100644 --- a/src/utils/Interfaces.ts +++ b/src/utils/Interfaces.ts @@ -139,6 +139,7 @@ export interface updateCustomField { name?: string; } export interface cohort { + presentPercentage: number; cohortId: string; name: string; value: string; @@ -197,3 +198,20 @@ export interface CustomField { order: number; name: string; } +export interface CohortAttendanceListViewProps{ + cohortName: string; + attendancePercent: number; +} + +export interface allCenterAttendancePercentParam { + limit: number; + page: number; + filters: { + scope: string; + fromDate: Date | string; + toDate: Date | string; + contextId : string; + }; + facets: Array; +} + From 7edb3a8f070866cf959f57c68c26d738aa8e70ed Mon Sep 17 00:00:00 2001 From: Rushikesh-Sonawane99 Date: Sun, 2 Jun 2024 02:10:44 +0530 Subject: [PATCH 3/4] Issue #PS-646 feat: Integrated custom range caleder --- src/pages/attendance-history.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/attendance-history.tsx b/src/pages/attendance-history.tsx index 02844b14..01f5853d 100644 --- a/src/pages/attendance-history.tsx +++ b/src/pages/attendance-history.tsx @@ -304,7 +304,7 @@ const UserAttendanceHistory = () => { useEffect(() => { getCohortMemberList(); - }, [classId, selectedDate]); + }, [classId, selectedDate, handleSaveHasRun]); useEffect(() => { console.log(status); From ea77d9098f2618d15149313a0d238fd7f9e6b0d5 Mon Sep 17 00:00:00 2001 From: Rushikesh-Sonawane99 Date: Sun, 2 Jun 2024 02:11:06 +0530 Subject: [PATCH 4/4] Issue #PS-646 feat: Integrated custom range caleder --- src/pages/attendance-overview.tsx | 490 ++++++++++++++++++------------ 1 file changed, 291 insertions(+), 199 deletions(-) diff --git a/src/pages/attendance-overview.tsx b/src/pages/attendance-overview.tsx index 3816193e..83a216ac 100644 --- a/src/pages/attendance-overview.tsx +++ b/src/pages/attendance-overview.tsx @@ -17,6 +17,7 @@ import { import React, { useEffect, useState } from 'react'; import { classesMissedAttendancePercentList, + getAllCenterAttendance, getCohortAttendance, } from '@/services/AttendanceService'; import { cohort, cohortAttendancePercentParam } from '@/utils/Interfaces'; @@ -42,6 +43,7 @@ import { usePathname } from 'next/navigation'; import { useRouter } from 'next/router'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'next-i18next'; +import CohortAttendanceListView from '@/components/CohortAttendanceListView'; interface AttendanceOverviewProps { // buttonText: string; @@ -52,6 +54,11 @@ const AttendanceOverview: React.FC = () => { const { t } = useTranslation(); const [classId, setClassId] = React.useState(''); const [cohortsData, setCohortsData] = React.useState>([]); + const [manipulatedCohortData, setManipulatedCohortData] = + React.useState>(cohortsData); + const [allCenterAttendanceData, setAllCenterAttendanceData] = + React.useState(cohortsData); + const [loading, setLoading] = React.useState(false); const [searchWord, setSearchWord] = React.useState(''); const [modalOpen, setModalOpen] = React.useState(false); @@ -61,6 +68,7 @@ const AttendanceOverview: React.FC = () => { const [displayStudentList, setDisplayStudentList] = React.useState< Array >([]); + const [userId, setUserId] = React.useState(''); const [selectedValue, setSelectedValue] = React.useState( t('COMMON.AS_OF_TODAY') ); @@ -76,7 +84,6 @@ const AttendanceOverview: React.FC = () => { const menuItems = [ t('COMMON.LAST_SEVEN_DAYS'), t('COMMON.AS_OF_TODAY'), - t('COMMON.AS_OF_LAST_WEEK'), t('COMMON.LAST_MONTH'), t('COMMON.LAST_SIX_MONTHS'), t('COMMON.CUSTOM_RANGE'), @@ -86,6 +93,9 @@ const AttendanceOverview: React.FC = () => { useEffect(() => { const fetchCohortList = async () => { const userId = localStorage.getItem('userId'); + if (userId) { + setUserId(userId); + } setLoading(true); try { if (userId) { @@ -105,6 +115,9 @@ const AttendanceOverview: React.FC = () => { if (filteredData.length > 0) { setClassId(filteredData[0].cohortId); localStorage.setItem('cohortId', filteredData[0]?.cohortId); + setManipulatedCohortData( + filteredData.concat({ cohortId: 'all', name: 'All Centers' }) + ); } } setLoading(false); @@ -126,7 +139,7 @@ const AttendanceOverview: React.FC = () => { const getCohortMemberList = async () => { setLoading(true); try { - if (classId) { + if (classId && classId != 'all') { let limit = 300; let page = 0; let filters = { cohortId: classId }; @@ -184,7 +197,8 @@ const AttendanceOverview: React.FC = () => { const studentsWithLowestAttendance = mergedArray.filter( (user) => user.absent && - user.present_percent < lowLearnerAttendanceLimit //TODO: Modify here condition to show low attendance learners + (user.present_percent < lowLearnerAttendanceLimit || + user.present_percent === undefined) //TODO: Modify here condition to show low attendance learners ); // Extract names of these students @@ -227,6 +241,70 @@ const AttendanceOverview: React.FC = () => { }; cohortAttendancePercent(); } + } + else if (classId && classId === 'all' && cohortsData) { + const cohortIds = cohortsData.map(cohort => cohort.cohortId); + const limit = 300; + const page = 0; + const facets = ['contextId']; + + const fetchAttendanceData = async (cohortIds: any[]) => { + const fetchPromises = cohortIds.map(async (cohortId) => { + const filters = { + fromDate: isFromDate, + toDate: isToDate, + scope: 'student', + contextId: cohortId, + }; + console.log('Filters:', filters); // Log filters to ensure contextId is set + + try { + const response = await getAllCenterAttendance({ + limit, + page, + filters, + facets, + }); + console.log(`Response for cohortId ${cohortId}:`, response); // Log the response + return { cohortId, data: response?.data?.result }; + } catch (error) { + console.error(`Error fetching data for cohortId ${cohortId}:`, error); + return { cohortId, error }; + } + }); + + try { + const results = await Promise.all(fetchPromises); + console.log('Fetched data:', results); + + const nameIDAttendanceArray = results + .filter(result => !result.error && result.data && result.data.contextId) + .map(result => { + const cohortId = result.cohortId; + const contextData = result.data.contextId[cohortId] || {}; + const presentPercentage = contextData.present_percentage || null; + const absentPercentage = contextData.absent_percentage ? 100 - contextData.absent_percentage : null; + const percentage = presentPercentage || absentPercentage; + + const cohortItem = cohortsData.find(cohort => cohort.cohortId === cohortId); + + return { + userId: cohortId, + name: cohortItem ? cohortItem.name : null, + presentPercentage: percentage, + }; + }) + .filter(item => item.presentPercentage !== null); // Filter out items with no valid percentage + + console.log('Filtered and merged data:', nameIDAttendanceArray); + setAllCenterAttendanceData(nameIDAttendanceArray); + + } catch (error) { + console.error('Error fetching attendance data:', error); + } + }; + + fetchAttendanceData(cohortIds); } } catch (error) { console.error('Error fetching cohort list:', error); @@ -362,212 +440,226 @@ const AttendanceOverview: React.FC = () => { {loading && ( )} - - - - - - - {t('ATTENDANCE.ATTENDANCE_OVERVIEW')} - - - - - - - - - - - - - - - - - - - - - ))} - value={ - lowAttendanceLearnerList.length > 2 - ? `${lowAttendanceLearnerList[0]}, ${lowAttendanceLearnerList[1]} ${t('COMMON.AND')} ${lowAttendanceLearnerList.length - 2} ${t('COMMON.MORE')}` - : lowAttendanceLearnerList.length === 2 - ? `${lowAttendanceLearnerList[0]}, ${lowAttendanceLearnerList[1]}` - : lowAttendanceLearnerList.length === 1 - ? `${lowAttendanceLearnerList[0]}` - : t('ATTENDANCE.N/A') - } + + + + - - - + + + {t('ATTENDANCE.ATTENDANCE_OVERVIEW')} + + - - - - - + + + + + - - - {classId !== 'all' ? ( - - ) : ( - - )} - {loading && ( - - )} + {classId !== 'all' ? ( + + + + + + + + ))} + value={ + lowAttendanceLearnerList.length > 2 + ? `${lowAttendanceLearnerList[0]}, ${lowAttendanceLearnerList[1]} ${t('COMMON.AND')} ${lowAttendanceLearnerList.length - 2} ${t('COMMON.MORE')}` + : lowAttendanceLearnerList.length === 2 + ? `${lowAttendanceLearnerList[0]}, ${lowAttendanceLearnerList[1]}` + : lowAttendanceLearnerList.length === 1 + ? `${lowAttendanceLearnerList[0]}` + : Array.isArray(lowAttendanceLearnerList) && + lowAttendanceLearnerList.length === 0 + ? t('ATTENDANCE.NO_LEARNER_WITH_LOW_ATTENDANCE') + : t('ATTENDANCE.N/A') + } + /> + + + + ) : null} + + {learnerData?.length > 0 ? ( - - {displayStudentList?.map((user: any) => ( - + + + + + + + + + + + {searchWord?.length > 0 && ( + + + + )} + + + + + + + + - ))} + + {loading && ( + + )} + {classId !== 'all' ? ( + + + + {displayStudentList?.map((user: any) => ( + + ))} + + + ) : ( + + + {allCenterAttendanceData.map((item: { cohortId: React.Key | null | undefined; name: string; presentPercentage: number; }) => ( + + ))} + + )} ) : (