From 1045c0ed5574150dd76e58d0e1e4810b780b6fc9 Mon Sep 17 00:00:00 2001 From: upendraTekdi Date: Fri, 31 May 2024 17:58:56 +0530 Subject: [PATCH 1/2] Issue #PS-314 feat:Learner View profile,learner popup ,learner details --- public/locales/en/common.json | 9 +- public/locales/hi/common.json | 9 +- public/locales/mr/common.json | 9 +- src/components/AttendanceStatusListView.tsx | 97 ++- .../LearnerAttendanceStatsListView.tsx | 199 ++++-- src/components/LearnerModal.tsx | 204 ++++++ src/components/ProfileField.tsx | 33 - src/components/learner-details.tsx | 190 ----- src/pages/attendance-overview.tsx | 26 +- src/pages/learner-profile.tsx | 652 ------------------ .../{learner-profile => learner}/[userId].tsx | 394 +++++++---- src/pages/profile.tsx | 12 +- src/services/AssesmentService.ts | 37 +- src/utils/Interfaces.ts | 25 +- 14 files changed, 792 insertions(+), 1104 deletions(-) create mode 100644 src/components/LearnerModal.tsx delete mode 100644 src/components/ProfileField.tsx delete mode 100644 src/components/learner-details.tsx delete mode 100644 src/pages/learner-profile.tsx rename src/pages/{learner-profile => learner}/[userId].tsx (64%) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 874ef496..3a688b7d 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -47,7 +47,8 @@ "DATE_RANGE": "Date Range", "SELECT_AN_OPTION": "Select an option", "AND": "and", - "MORE": "more" + "MORE": "more", + "CLOSE": "Close" }, "LOGIN_PAGE": { "USERNAME": "Username", @@ -81,7 +82,8 @@ "MY_TEACHING_CENTERS": "My Teaching Centers", "UPCOMING_EXTRA_SESSION": "Upcoming Extra Sessions", "BACK_TO_TOP": "Back to Top", - "LAST_SEVEN_DAYS_RANGE": "Last 7 Days {{date_range}})" + "LAST_SEVEN_DAYS_RANGE": "Last 7 Days {{date_range}})", + "LEARNER": "Learners" }, "ATTENDANCE": { "TOTAL_STUDENTS": "Total Number of Learners: {{count}}", @@ -128,6 +130,7 @@ "VIEW_DAY_WISE": "View Day-Wise", "SUBMITTED_ON": "Submitted On", "MARK_OBTAINED": "Mark Obtained", - "TOTAL_QUESTIONS": "Total Questions" + "TOTAL_QUESTIONS": "Total Questions", + "VIEW_FULL_PROFILE": "View Full Profile" } } diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index 3296babe..c70d6d47 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -46,7 +46,8 @@ "DATE_RANGE": "तिथि सीमा", "SELECT_AN_OPTION": "कोई विकल्प चुनें", "AND": "और", - "MORE": "अधिक" + "MORE": "अधिक", + "CLOSE": "बंद करना" }, "LOGIN_PAGE": { "USERNAME": "उपयोगकर्ता नाम", @@ -79,7 +80,8 @@ "MY_TEACHING_CENTERS": "मेरे शिक्षण केंद्र", "UPCOMING_EXTRA_SESSION": "आगामी अतिरिक्त सत्र", "BACK_TO_TOP": "वापस शीर्ष पर", - "LAST_SEVEN_DAYS_RANGE": "पिछले 7 दिन {{date_range}}" + "LAST_SEVEN_DAYS_RANGE": "पिछले 7 दिन {{date_range}}", + "LEARNER": "शिक्षार्थियों" }, "ATTENDANCE": { "TOTAL_STUDENTS": "कुल छात्रों की संख्या: {{count}}", @@ -128,6 +130,7 @@ "VIEW_DAY_WISE": "दिन-वार देखें", "SUBMITTED_ON": "प्रस्तुत किया गया", "MARK_OBTAINED": "प्राप्त अंक", - "TOTAL_QUESTIONS": "कुल प्रश्न" + "TOTAL_QUESTIONS": "कुल प्रश्न", + "VIEW_FULL_PROFILE": "पूरा प्रोफाइल देखें" } } diff --git a/public/locales/mr/common.json b/public/locales/mr/common.json index 0536e292..5e63ca44 100644 --- a/public/locales/mr/common.json +++ b/public/locales/mr/common.json @@ -45,7 +45,8 @@ "DATE_RANGE": "तारीख श्रेणी", "SELECT_AN_OPTION": "एक पर्याय निवडा", "AND": "आणि", - "MORE": "अधिक" + "MORE": "अधिक", + "CLOSE": "बंद" }, "LOGIN_PAGE": { "USERNAME": "वापरकर्ता नाव", @@ -79,7 +80,8 @@ "MY_TEACHING_CENTERS": "माझे शिक्षण केंद्र", "UPCOMING_EXTRA_SESSION": "आगामी अतिरिक्त सत्रे", "BACK_TO_TOP": "परत वर जा", - "LAST_SEVEN_DAYS_RANGE": "शेवटचे 7 दिवस {{date_range}}" + "LAST_SEVEN_DAYS_RANGE": "शेवटचे 7 दिवस {{date_range}}", + "LEARNER": "शिकणारे" }, "ATTENDANCE": { "TOTAL_STUDENTS": "एकूण विद्यार्थी: {{count}}", @@ -123,6 +125,7 @@ "VIEW_DAY_WISE": "दिवस-निहाय पहा", "SUBMITTED_ON": "सादर केलेले", "MARK_OBTAINED": "प्राप्त गुण", - "TOTAL_QUESTIONS": "एकूण प्रश्न" + "TOTAL_QUESTIONS": "एकूण प्रश्न", + "VIEW_FULL_PROFILE": "पूर्ण प्रोफाइल पहा" } } diff --git a/src/components/AttendanceStatusListView.tsx b/src/components/AttendanceStatusListView.tsx index f5a6a581..31de48d8 100644 --- a/src/components/AttendanceStatusListView.tsx +++ b/src/components/AttendanceStatusListView.tsx @@ -1,16 +1,23 @@ import { Box, Typography } from '@mui/material'; import { ATTENDANCE_ENUM } from '../utils/Helper'; -import { AttendanceStatusListViewProps } from '../utils/Interfaces'; +import { + AttendanceStatusListViewProps, + UserData, + updateCustomField, +} from '../utils/Interfaces'; import { BorderBottom } from '@mui/icons-material'; import CancelIcon from '@mui/icons-material/Cancel'; //absent import CheckCircleIcon from '@mui/icons-material/CheckCircle'; //present import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; import HighlightOffIcon from '@mui/icons-material/HighlightOff'; -import React from 'react'; +import React, { useState } from 'react'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'next-i18next'; import Link from 'next/link'; +import LearnerModal from './LearnerModal'; +import { getUserDetails } from '@/services/ProfileService'; +import Loader from './Loader'; const AttendanceStatusListView: React.FC = ({ isDisabled = false, @@ -48,8 +55,83 @@ const AttendanceStatusListView: React.FC = ({ handleBulkAction(isBulkAction, selectedAction, id); } }; + + // -----learner profile details---- + const [usersData, setUsersData] = React.useState(null); + const [customFieldsData, setCustomFieldsData] = React.useState< + updateCustomField[] + >([]); + const [userName, setUserName] = React.useState(''); + const [isModalOpenLearner, setIsModalOpenLearner] = useState(false); + const [loading, setLoading] = useState(false); + // const userId = '12345'; // Replace with the actual user ID you want to pass + + const handleOpenModalLearner = (userId: string) => { + fetchUserDetails(userId); + setIsModalOpenLearner(true); + }; + + const handleCloseModalLearner = () => { + setIsModalOpenLearner(false); + }; + + const fetchUserDetails = async (userId: string) => { + try { + if (userId) { + setLoading(true); + const response = await getUserDetails(userId, true); + console.log('response for popup', response?.result); + if (response?.responseCode === 200) { + const data = response?.result; + if (data) { + const userData = data?.userData; + // setUsersData(userData); + setUserName(userData?.name); + + const customDataFields = userData?.customFields; + if (customDataFields?.length > 0) { + console.log('customDataFields', customDataFields); + setCustomFieldsData(customDataFields); + } + setLoading(false); + } else { + console.log('No data Found'); + } + } else { + console.log('No Response Found'); + } + } + } catch (error) { + console.error('Error fetching user details:', error); + } + }; + const names = [ + 'name', + 'age', + 'gender', + 'student_type', + 'enrollment_number', + 'primary_work', + ]; + + const filteredFields = names + .map((label) => customFieldsData.find((field) => field.name === label)) + .filter(Boolean); + return ( + {loading ? ( + + ) : ( + + )} + = ({ fontWeight: '400', color: '#1F1B13', }} + onClick={() => handleOpenModalLearner(userData?.userId!)} > - {isBulkAction ? t('ATTENDANCE.MARK_ALL') : (showLink ? {userData?.name} : userData?.name)} + {isBulkAction ? ( + t('ATTENDANCE.MARK_ALL') + ) : showLink ? ( + + {userData?.name} + + ) : ( + userData?.name + )} = ({ const theme = useTheme(); const { t } = useTranslation(); const textColor = - presentPercent > lowLearnerAttendanceLimit ? theme.palette.success.main : theme.palette.error.main; + presentPercent > lowLearnerAttendanceLimit + ? theme.palette.success.main + : theme.palette.error.main; // const handleStudentDetails = () => { // router.push(`/student-details/${cohortId}/${userId}`); // }; + const [userData, setUserData] = React.useState(null); + const [customFieldsData, setCustomFieldsData] = React.useState< + updateCustomField[] + >([]); + const [userName, setUserName] = React.useState(''); + const [isModalOpenLearner, setIsModalOpenLearner] = useState(false); + const [loading, setLoading] = useState(false); + // const userId = '12345'; // Replace with the actual user ID you want to pass + + const handleOpenModalLearner = (userId: string) => { + fetchUserDetails(userId); + setIsModalOpenLearner(true); + }; + + const handleCloseModalLearner = () => { + setIsModalOpenLearner(false); + }; + + const fetchUserDetails = async (userId: string) => { + try { + if (userId) { + setLoading(true); + const response = await getUserDetails(userId, true); + console.log('response for popup', response?.result); + if (response?.responseCode === 200) { + const data = response?.result; + if (data) { + const userData = data?.userData; + setUserData(userData); + setUserName(userData?.name); + + const customDataFields = userData?.customFields; + if (customDataFields?.length > 0) { + setCustomFieldsData(customDataFields); + setLoading(false); + } + } else { + console.log('No data Found'); + } + } else { + console.log('No Response Found'); + } + } + } catch (error) { + console.error('Error fetching user details:', error); + } + }; + + // React.useEffect(() => { + // fetchUserDetails(); + // }, [userId]); + + const isDesktop = useMediaQuery(theme.breakpoints.up('md')); + + const labelValueArray = customFieldsData.map(({ label, value }) => ({ + label, + value, + })); + + const names = [ + 'name', + 'age', + 'gender', + 'student_type', + 'enrollment_number', + 'primary_work', + ]; + + const filteredFields = names + .map((label) => customFieldsData.find((field) => field.name === label)) + .filter(Boolean); + return ( - - - + {' '} + {loading ? ( + + ) : ( + + )} + + - - + + + + handleOpenModalLearner(userId!)} + sx={{ + textAlign: 'left', + fontSize: '14px', + fontWeight: '400', + color: theme.palette.secondary.main, + }} + > + {name} + + + + - {name} + {presentPercent}% - - - - - {presentPercent}% - - - - - {classesMissed} - + + + + {classesMissed} + + - - - + + + ); }; diff --git a/src/components/LearnerModal.tsx b/src/components/LearnerModal.tsx new file mode 100644 index 00000000..e223ac2d --- /dev/null +++ b/src/components/LearnerModal.tsx @@ -0,0 +1,204 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { + Box, + Button, + Divider, + Grid, + Modal, + Typography, + useMediaQuery, +} from '@mui/material'; +import CloseSharpIcon from '@mui/icons-material/CloseSharp'; +import { useTheme } from '@mui/material/styles'; + +import ProfileField from './ProfileField'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; + +const LearnerModal = ({ + userId, + open, + onClose, + data, + userName, +}: { + userId?: string; + open: boolean; + data: any; + onClose: () => void; + userName?: string; +}) => { + const { t } = useTranslation(); + + const theme = useTheme(); + const router = useRouter(); + console.log('data', data); + + const handleLearnerFullProfile = () => { + router.push(`/learner/${userId}`); + }; + + return ( + <> + {data && ( + + + + + {t('PROFILE.LEARNER_DETAILS')} + + + + + + + + + + Full Name + + + + {userName} + + + + {data?.map((item: any, index: number) => ( + <> + + + {item.label} + + {/* */} + + {Array.isArray(item.value) + ? item.value.join(', ') + : item.value} + + {/* */} + + + ))} + + + + + + + + + + + )} + + ); +}; + +LearnerModal.propTypes = { + userId: PropTypes.string.isRequired, + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, +}; + +export default LearnerModal; diff --git a/src/components/ProfileField.tsx b/src/components/ProfileField.tsx deleted file mode 100644 index 983c338e..00000000 --- a/src/components/ProfileField.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { Grid, Box, Typography } from '@mui/material'; -import { useTheme, useThemeProps } from '@mui/material/styles'; -interface ProfileFieldProps { - data: { label: string; value: string }[] | any; -} - -const ProfileField: React.FC = ({ data }) => { - const theme = useTheme(); - - return ( - - {data?.map((item: any, index: any) => ( - - - {item.label} - - - - {item.value} - - - - ))} - - ); -}; - -export default ProfileField; diff --git a/src/components/learner-details.tsx b/src/components/learner-details.tsx deleted file mode 100644 index 88b781cb..00000000 --- a/src/components/learner-details.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import React, { useEffect } from 'react'; -import Modal from '@mui/material/Modal'; -import { - Box, - Button, - Divider, - Grid, - IconButton, - Typography, - useMediaQuery, - useTheme, -} from '@mui/material'; -import { useTranslation } from 'next-i18next'; -import CloseIcon from '@mui/icons-material/Close'; -import PlaceOutlinedIcon from '@mui/icons-material/PlaceOutlined'; -import ProfileField from '@/components/ProfileField'; -// import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import { useRouter } from 'next/router'; -import { useParams, usePathname } from 'next/navigation'; -import { getUserDetails } from '@/services/ProfileService'; -import { UserData, updateCustomField } from '@/utils/Interfaces'; -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; - -const LearnerDetails = () => { - // const { t } = useTranslation(); - const pathname = usePathname(); - const router = useRouter(); - const { userId }: any = router.query; - - const [open, setOpen] = React.useState(true); - const [userData, setUserData] = React.useState(null); - const [customFieldsData, setCustomFieldsData] = React.useState< - updateCustomField[] - >([]); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); - - const dummyData = [ - { label: 'Full Name', value: 'Ananya Gupta' }, - { label: 'Age', value: '19' }, - { label: 'Gender', value: 'Female' }, - { label: 'Type Of Learner', value: 'Regular' }, - { label: 'Enrollment Number', value: '1002365362' }, - { label: 'Learner Primary work', value: 'Self Employed' }, - { label: 'contact Number', value: '945454665' }, - ]; - - const fetchUserDetails = async () => { - if (typeof window !== 'undefined' && window.localStorage) { - // const userId = localStorage.getItem('userId'); - - try { - if (userId) { - const response = await getUserDetails(userId, true); - - if (response?.statusCode === 200) { - const data = response?.data; - if (data) { - const userData = data?.userData; - setUserData(userData); - const customDataFields = userData?.customFields; - if (customDataFields?.length > 0) { - setCustomFieldsData(customDataFields); - } - } else { - console.log('No data Found'); - } - } else { - console.log('No Response Found'); - } - } - } catch (error) { - console.error('Error fetching user details:', error); - } - } - }; - - useEffect(() => { - fetchUserDetails(); - }, []); - - const theme = useTheme(); - const isDesktop = useMediaQuery(theme.breakpoints.up('md')); - - const labelValueArray = customFieldsData.map(({ label, value }: any) => ({ - label, - value, - })); - - const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: isDesktop ? 500 : 400, - bgcolor: 'warning.A400', - p: 4, - textAlign: 'center', - height: 'auto', - }; - return ( -
- - - - - Learner Details - {/* {t('PROFILE.LEARNER_DETAILS')} */} - - - - - - - - - - - - - - - - - - -
- ); -}; - -export async function getStaticProps({ locale }: any) { - return { - props: { - ...(await serverSideTranslations(locale, ['common'])), - // Will be passed to the page component as props - }, - }; -} - -export default LearnerDetails; diff --git a/src/pages/attendance-overview.tsx b/src/pages/attendance-overview.tsx index 289ff057..be6afd50 100644 --- a/src/pages/attendance-overview.tsx +++ b/src/pages/attendance-overview.tsx @@ -40,7 +40,7 @@ import { usePathname } from 'next/navigation'; import { useRouter } from 'next/router'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'next-i18next'; -import {lowLearnerAttendanceLimit} from './../../app.config'; +import { lowLearnerAttendanceLimit } from './../../app.config'; interface AttendanceOverviewProps { // buttonText: string; @@ -103,6 +103,7 @@ const AttendanceOverview: React.FC = () => { if (filteredData.length > 0) { setClassId(filteredData[0].cohortId); + localStorage.setItem('cohortId', filteredData[0]?.cohortId); } } setLoading(false); @@ -180,7 +181,9 @@ const AttendanceOverview: React.FC = () => { setDisplayStudentList(mergedArray); const studentsWithLowestAttendance = mergedArray.filter( - (user) => (user.absent && user.present_percent < lowLearnerAttendanceLimit ) //TODO: Modify here condition to show low attendance learners + (user) => + user.absent && + user.present_percent < lowLearnerAttendanceLimit //TODO: Modify here condition to show low attendance learners ); // Extract names of these students @@ -212,15 +215,14 @@ const AttendanceOverview: React.FC = () => { const response = res?.data?.result; const contextData = response?.contextId && response?.contextId[classId]; - if ( contextData?.present_percentage){ - const presentPercentage = (contextData?.present_percentage); - setPresentPercentage(presentPercentage); - }else if(contextData?.absent_percentage){ - setPresentPercentage(0); - }else{ - setPresentPercentage(t('ATTENDANCE.N/A')) - } - + if (contextData?.present_percentage) { + const presentPercentage = contextData?.present_percentage; + setPresentPercentage(presentPercentage); + } else if (contextData?.absent_percentage) { + setPresentPercentage(0); + } else { + setPresentPercentage(t('ATTENDANCE.N/A')); + } }; cohortAttendancePercent(); } @@ -239,6 +241,7 @@ const AttendanceOverview: React.FC = () => { const handleCohortSelection = (event: SelectChangeEvent) => { setClassId(event.target.value as string); + localStorage.setItem('cohortId', event.target.value); }; const handleSearchClear = () => { @@ -344,7 +347,6 @@ const AttendanceOverview: React.FC = () => { }); break; } - setDisplayStudentList(sortedData); }; diff --git a/src/pages/learner-profile.tsx b/src/pages/learner-profile.tsx deleted file mode 100644 index 443f897b..00000000 --- a/src/pages/learner-profile.tsx +++ /dev/null @@ -1,652 +0,0 @@ -import { - ArrowBack as ArrowBackIcon, - Check, - East as EastIcon, -} from '@mui/icons-material'; -// import { Link, useParams } from 'react-router-dom'; -import { - Box, - Button, - Card, - CardContent, - Divider, - FormControl, - Grid, - IconButton, - InputLabel, - List, - ListItemButton, - ListItemIcon, - ListItemText, - MenuItem, - MenuList, - Modal, - Select, - SelectChangeEvent, - Stack, - TextField, - Typography, - useMediaQuery, -} from '@mui/material'; -import React, { useEffect, useState } from 'react'; -import { Theme, useTheme } from '@mui/material/styles'; -import { UserData, updateCustomField } from '../utils/Interfaces'; -import { formatDate, getTodayDate } from '../utils/Helper'; - -import { AssesmentListService } from '@/services/AssesmentService'; -import CloseIcon from '@mui/icons-material/Close'; -import CreateOutlinedIcon from '@mui/icons-material/CreateOutlined'; -import CustomSelect from '@/components/CustomSelect'; -import Header from '../components/Header'; -import MarksObtainedCard from '@/components/MarksObtainedCard'; -import MoreVertIcon from '@mui/icons-material/MoreVert'; -import StudentStatsCard from '@/components/StudentStatsCard'; -import WeekDays from '@/components/WeekDays'; -import { getUserDetails } from '@/services/ProfileService'; -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import { useParams } from 'next/navigation'; -import { useRouter } from 'next/router'; -import { useTranslation } from 'next-i18next'; - -interface QuestionValue { - question: string; - mark_obtained: number; - totalMarks: number; -} -interface QuestionValues { - totalMaxScore: number; - totalScore: number; - length: number; - questions: QuestionValue[]; -} - -const LearnerProfile: React.FC = () => { - const { t } = useTranslation(); - const theme = useTheme(); - - const router = useRouter(); - const { userId } = router.query; // userId is extracted from the URL - - const [userData, setUserData] = useState(null); - const [attendanceReport, setAttendanceReport] = useState(null); - const [limit, setLimit] = useState(10); - const [page, setPage] = useState(1); - const [filter, setFilter] = useState({}); - const [maritalStatus, setMaritalStatus] = useState(''); - const [currentDate, setCurrentDate] = React.useState(getTodayDate); - const [selectedIndex, setSelectedIndex] = useState(null); - const [selectedValue, setSelectedValue] = useState(''); - const [assesmentData, setAssesmentData] = useState([]); - const [questionData, setQuestionData] = useState([]); - const [age, setAge] = React.useState(''); - const [subject, setSubject] = React.useState(''); - const [anchorEl, setAnchorEl] = React.useState(null); - const [openEdit, setOpenEdit] = React.useState(false); - const [customFieldsData, setCustomFieldsData] = useState( - [] - ); - const [submittedOn, setSubmitedOn] = useState(''); - - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - // set""AnchorEl(event.currentTarget); - alert('drawer'); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const handleOpenEdit = () => setOpenEdit(true); - const handleCloseEdit = () => setOpenEdit(false); - - // const handleListItemClick = ( - // event: React.MouseEvent, - // index: number - // ) => { - // setSelectedIndex(index); - // }; - - const [openModal, setOpenModal] = React.useState(true); - const handleOpenModal = () => setOpenModal(true); - const handleCloseModal = () => setOpenModal(false); - - const isDesktop = useMediaQuery(theme.breakpoints.up('md')); - - const dividerStyle = { - width: '100%', // Make the divider full width - marginBottom: '10px', // Optional: Add some spacing below the divider - }; - - const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: isDesktop ? 500 : 400, - bgcolor: 'warning.A400', - p: 4, - textAlign: 'center', - height: 'auto', - }; - - const handleChange = (event: SelectChangeEvent) => { - setAge(event.target.value); - }; - - const handleChangeSubject = (event: SelectChangeEvent) => { - setSubject(event.target.value); - }; - - const handleMenuItemClick = (index: any, value: any) => { - setSelectedIndex(index); - setSelectedValue(value); - console.log('Selected Value:', value); // You can use this value as needed - }; - - const menuItems = [ - 'Last 7 Days(18 - 25 may)', - 'As Of Today, 25 may', - 'Last Month', - 'Last 6 Month', - 'Custom Range', - ]; - - const fetchUserDetails = async () => { - if (typeof window !== 'undefined' && window.localStorage) { - const user: any = userId; - - try { - if (user) { - const response = await getUserDetails(user, true); - - if (response?.statusCode === 200) { - const data = response?.data; - if (data) { - const userData = data?.userData; - setUserData(userData); - const customDataFields = userData?.customFields; - if (customDataFields?.length > 0) { - setCustomFieldsData(customDataFields); - } - } else { - console.log('No data Found'); - } - } else { - console.log('No Response Found'); - } - } - } catch (error) { - console.error('Error fetching user details:', error); - } - } - }; - - const testReportDetails = async () => { - let filters = { - userId: '4bc64b4d-c3c6-4a23-b9f3-15c70ed8ffb6', - }; - let pagination = { - pageSize: 1, - page: 1, - }; - let sort = { - field: 'userId', - order: 'asc', - }; - - const response = await AssesmentListService({ sort, pagination, filters }); - if (response) { - const result = response?.result; - if (result?.length > 0) { - const data = result; - setSubmitedOn(data?.createdOn); - setAssesmentData(data); - console.log('Data', data); - } else { - } - } else { - console.log('No Data Found'); - } - }; - - function getQuestionValues(data: any) { - const questionValues: any = { - totalMaxScore: 0, - totalScore: 0, - length: data.length, - questions: [], - }; - - data.forEach((item: any) => { - item.assessmentSummary?.forEach((summary: any) => { - const parsedData = JSON.parse(summary.data); - let questionNumber = 1; - parsedData.forEach((section: any) => { - section.data.forEach((question: any) => { - const questionValue = { - question: `Q${questionNumber}`, - mark_obtained: question.score, - totalMarks: question.item.maxscore, - }; - questionValues.totalMaxScore += question.item.maxscore; - questionValues.totalScore += question.score; - questionValues.questions.push(questionValue); - questionNumber++; - }); - }); - }); - }); - - return questionValues; - } - - // Usage example - const questionValues = getQuestionValues(assesmentData); - - useEffect(() => { - fetchUserDetails(); - testReportDetails(); - }, []); - - return ( - <> -
- - - - - - - - Ananya Gupta - - - Khapari Dhamu (Chimur , Chandrapur) - - - - - - - - - - - - - - Attendance Overview - - - - View Day-Wise - - - - - - - - - - - - - - - {t('COMMON.OVERALL_ATTENDANCE')} - - {'As of today' + ' ' + formatDate(currentDate)} - - - - - - - - - - - - - - - - - - Learner Details - - - - - {customFieldsData && - customFieldsData?.map((item: any, i: number) => ( - - {/* question */} - - {item?.label} - - - {/* value */} - - {item?.value} - - - ))} - - - - - - - - - {t('COMMON.TEST_REPORT')} - - - - - {' '} - {/* Adjusted minWidth here */} - - Test - - - - - - Subject - - - - - - {/* {assesmentData && assesmentData?.map((item, i) => {})}{' '} */} - - - Submitted On : 2nd Feb , 2024 - - - - - Mark Obtained - - - 60/70 - - - - - Total Questions : 15 - - - - - - - - - - - - - - {t('DATA_RANAGE')} - - - - - - - - - {menuItems.map((item, index) => ( - handleMenuItemClick(index, item)} - sx={{ - display: 'flex', - alignItems: 'center', - paddingLeft: '32px', - }} - > - {selectedIndex === index && ( - - - - )} - {item} - - ))} - - - - - - - ); -}; -export async function getStaticProps({ locale }: any) { - return { - props: { - ...(await serverSideTranslations(locale, ['common'])), - // Will be passed to the page component as props - }, - }; -} - -export default LearnerProfile; diff --git a/src/pages/learner-profile/[userId].tsx b/src/pages/learner/[userId].tsx similarity index 64% rename from src/pages/learner-profile/[userId].tsx rename to src/pages/learner/[userId].tsx index a401611c..0a9cd949 100644 --- a/src/pages/learner-profile/[userId].tsx +++ b/src/pages/learner/[userId].tsx @@ -33,7 +33,10 @@ import { Theme, useTheme } from '@mui/material/styles'; import { UserData, updateCustomField } from '@/utils/Interfaces'; import { formatDate, getTodayDate } from '@/utils/Helper'; -import { AssesmentListService } from '@/services/AssesmentService'; +import { + AssesmentListService, + getDoIdForAssesmentDetails, +} from '@/services/AssesmentService'; import CloseIcon from '@mui/icons-material/Close'; import CreateOutlinedIcon from '@mui/icons-material/CreateOutlined'; import CustomSelect from '@/components/CustomSelect'; @@ -52,6 +55,11 @@ import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; import { classesMissedAttendancePercentList } from '@/services/AttendanceService'; import DateRangePopup from '@/components/DateRangePopup'; +import { styled, alpha } from '@mui/material/styles'; +import Menu, { MenuProps } from '@mui/material/Menu'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; +import PersonOffIcon from '@mui/icons-material/PersonOff'; +import DeleteIcon from '@mui/icons-material/Delete'; // import { UserData, updateCustomField } from '../utils/Interfaces'; @@ -85,7 +93,8 @@ const LearnerProfile: React.FC = () => { const [assesmentData, setAssesmentData] = useState([]); const [questionData, setQuestionData] = useState([]); const [age, setAge] = React.useState(''); - const [subject, setSubject] = React.useState(''); + const [test, setTest] = React.useState('Pre Test'); + const [subject, setSubject] = React.useState('English'); const [anchorEl, setAnchorEl] = React.useState(null); const [openEdit, setOpenEdit] = React.useState(false); const [customFieldsData, setCustomFieldsData] = useState( @@ -107,51 +116,69 @@ const LearnerProfile: React.FC = () => { t('COMMON.AS_OF_TODAY') ); const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - // set""AnchorEl(event.currentTarget); - alert('drawer'); - }; - - const handleClose = () => { - setAnchorEl(null); - }; const handleOpenEdit = () => setOpenEdit(true); const handleCloseEdit = () => setOpenEdit(false); - const [openModal, setOpenModal] = React.useState(false); - const handleOpenModal = () => setOpenModal(true); - const handleCloseModal = () => setOpenModal(false); - - const isDesktop = useMediaQuery(theme.breakpoints.up('md')); - - const dividerStyle = { - width: '100%', // Make the divider full width - marginBottom: '10px', // Optional: Add some spacing below the divider - }; - - const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: isDesktop ? 500 : 400, - bgcolor: 'warning.A400', - p: 4, - textAlign: 'center', - height: 'auto', - }; + const [unitName, setUnitName] = useState(''); + const [blockName, setBlockName] = useState(''); + const [uniqueDoId, setUniqueDoId] = useState(''); + const [anchorElOption, setAnchorElOption] = + React.useState(null); + const openOption = Boolean(anchorElOption); + + const StyledMenu = styled((props: MenuProps) => ( + + ))(({ theme }) => ({ + '& .MuiPaper-root': { + borderRadius: 6, + marginTop: theme.spacing(1), + minWidth: 180, + color: + theme.palette.mode === 'light' + ? 'rgb(55, 65, 81)' + : theme.palette.grey[300], + boxShadow: + 'rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px', + '& .MuiMenu-list': { + padding: '4px 0', + }, + '& .MuiMenuItem-root': { + '& .MuiSvgIcon-root': { + fontSize: 18, + color: theme.palette.text.secondary, + marginRight: theme.spacing(1.5), + }, + '&:active': { + backgroundColor: alpha( + theme.palette.primary.main, + theme.palette.action.selectedOpacity + ), + }, + }, + }, + })); - const handleChange = (event: SelectChangeEvent) => { - setAge(event.target.value); + const handleClickOption = (event: React.MouseEvent) => { + setAnchorElOption(event.currentTarget); }; - const handleChangeSubject = (event: SelectChangeEvent) => { - setSubject(event.target.value); + const handleCloseOption = () => { + setAnchorElOption(null); // Set anchorElOption to null to close the menu }; const handleDateRangeSelected = ({ fromDate, toDate }: any) => { - console.log('Date Range Selected:', { fromDate, toDate }); setIsFromDate(fromDate); setIsToDate(toDate); getAttendaceData(fromDate, toDate); @@ -190,6 +217,13 @@ const LearnerProfile: React.FC = () => { } }; + // find Address + const getFieldValue = (data: any, label: string) => { + const field = data.find((item: any) => item.label === label); + return field ? field.value[0] : null; + }; + + // ger user information const fetchUserDetails = async () => { if (typeof window !== 'undefined' && window.localStorage) { const user: any = userId; @@ -198,16 +232,22 @@ const LearnerProfile: React.FC = () => { if (user) { const response = await getUserDetails(user, true); - if (response?.statusCode === 200) { - const data = response?.data; + console.log('response userId', response); + if (response?.responseCode === 200) { + const data = response?.result; + console.log('data', data); if (data) { const userData = data?.userData; setUserData(userData); - console.log('userData', userData); + const customDataFields = userData?.customFields; if (customDataFields?.length > 0) { setCustomFieldsData(customDataFields); + const unitName = getFieldValue(customDataFields, 'Unit Name'); + setUnitName(unitName); + const blockName = getFieldValue(customDataFields, 'Block Name'); + setBlockName(blockName); } } else { console.log('No data Found'); @@ -222,9 +262,65 @@ const LearnerProfile: React.FC = () => { } }; - const testReportDetails = async () => { + // address find + const address = [unitName, blockName, userData?.district] + ?.filter(Boolean) + ?.join(', '); + + //------ Test Report API Integration------ + + const handleChangeTest = (event: SelectChangeEvent) => { + const test = event.target.value; + setTest(test); + getDoIdForAssesmentReport(test, subject); + }; + + const handleChangeSubject = (event: SelectChangeEvent) => { + const subject = event.target.value; + setSubject(event.target.value); + getDoIdForAssesmentReport(test, subject); + }; + + const getDoIdForAssesmentReport = async (tests: string, subjects: string) => { + const filters = { + program: ['Second chance'], + se_boards: ['Maharashtra'], + subject: [subjects ? subjects : subject], + assessment1: tests ? tests : test, + }; + + try { + const searchResults = await getDoIdForAssesmentDetails({ filters }); + + if (searchResults?.responseCode === 'OK') { + const result = searchResults?.result; + if (result) { + const QuestionSet = result?.QuestionSet?.[0]; + const getUniqueDoId = QuestionSet?.IL_UNIQUE_ID; + setUniqueDoId(getUniqueDoId); + console.log('results:', getUniqueDoId); + testReportDetails(getUniqueDoId); + } else { + console.log('NO Result found from getDoIdForAssesmentDetails '); + } + } else { + console.log('NO Data found from getDoIdForAssesmentDetails '); + } + } catch (error) { + console.error( + 'Error fetching getDoIdForAssesmentDetails results:', + error + ); + } + }; + + const testReportDetails = async (do_Id: string) => { + const cohortId = localStorage.getItem('cohortId'); let filters = { userId: userId, + courseId: do_Id, + batchId: cohortId, // user cohort id + contentId: do_Id, // do_Id }; let pagination = { pageSize: 1, @@ -236,17 +332,23 @@ const LearnerProfile: React.FC = () => { }; const response = await AssesmentListService({ sort, pagination, filters }); - if (response) { - const result = response?.result; - if (result?.length > 0) { - const data = result; - setSubmitedOn(data?.createdOn); - setAssesmentData(data); - console.log('Data', data); + console.log('statusCode', response?.response); + if (response?.response?.status === 200) { + if (response) { + const result = response?.result; + if (result?.length > 0) { + const data = result; + setSubmitedOn(data?.createdOn); + setAssesmentData(data); + console.log('Data', data); + } else { + } } else { + console.log('No Data Found'); } } else { - console.log('No Data Found'); + setUniqueDoId(''); + console.log('AssesmentListService data', response?.response?.statusText); } }; @@ -259,32 +361,30 @@ const LearnerProfile: React.FC = () => { totalQuestions: 0, }; - data.forEach((item: any) => { - item.assessmentSummary?.forEach((summary: any) => { - const parsedData = JSON.parse(summary.data); + data?.forEach((item: any) => { + item?.assessmentSummary?.forEach((summary: any) => { let questionNumber = 1; - parsedData.forEach((section: any) => { - section.data.forEach((question: any, index: any) => { - const questionValue: any = { - question: `Q${questionNumber}`, - mark_obtained: question.score, - totalMarks: question.item.maxscore, - }; - questionValues.totalMaxScore += question.item.maxscore; - questionValues.totalScore += question.score; - questionValues.questions.push(questionValue); - questionNumber++; - }); + summary?.data?.forEach((question: any) => { + const questionValue: any = { + question: `Q${questionNumber}`, + mark_obtained: question.score, + totalMarks: question.item.maxscore, + }; + questionValues.totalMaxScore += question.item.maxscore; + questionValues.totalScore += question.score; + questionValues.questions.push(questionValue); + questionNumber++; }); }); }); + questionValues.totalQuestions = questionValues.questions.length; return questionValues; } - // questionValues const questionValues = getQuestionValues(assesmentData); + // all function call when page render useEffect(() => { const today = new Date(); const formatDate = (date: Date) => date.toISOString().split('T')[0]; @@ -292,24 +392,22 @@ const LearnerProfile: React.FC = () => { getAttendaceData(toDay, toDay); fetchUserDetails(); - testReportDetails(); + // testReportDetails(); + getDoIdForAssesmentReport(test, subject); }, []); - const handleGoBack = () => { - router.push('/attendance-overview'); - }; - return ( <>
- + window.history.back()}> @@ -332,22 +430,52 @@ const LearnerProfile: React.FC = () => { fontSize: '12px', }} > - {userData?.district && userData?.state - ? `${userData.district}, ${userData.state}` - : `${userData?.district || ''}${userData?.state || ''}`} + {address} - + + + + + + {/* */} + + + Mark as Drop Out + + + Remove + + + @@ -408,17 +536,15 @@ const LearnerProfile: React.FC = () => { }} > - {t('COMMON.OVERALL_ATTENDANCE')} - {selectedValue} + Attendance Marked : 3 out of last 7 days { > {t('COMMON.TEST_REPORT')} - - {/* - + Test - */} - {/* + + Subject @@ -584,48 +707,57 @@ const LearnerProfile: React.FC = () => { label="Subject" onChange={handleChangeSubject} > - + {/* Select Value - - English - Marathi - Hindi + */} + English + Math - */} + - - - - {t('PROFILE.SUBMITTED_ON')} : {submittedOn} - - - - - {t('PROFILE.MARK_OBTAINED')} - - - {/* 60/70 */} - - - - - - {t('PROFILE.TOTAL_QUESTIONS')} : - {questionValues?.questions?.length} - + {uniqueDoId ? ( + + + + {t('PROFILE.SUBMITTED_ON')} : {submittedOn} + + + + + {t('PROFILE.MARK_OBTAINED')} + + + {/* 60/70 */} + + + + + + {t('PROFILE.TOTAL_QUESTIONS')} : + {questionValues?.questions?.length} + + + + + + ) : ( - + + {t('COMMON.NO_DATA_FOUND')} + - + )} + {/* { const user_placeholder_img: string = user_placeholder.src; - interface CustomField { - fieldId: string; - label: string; - value: string; - options: Record; - type: string; - order: number; - name: string; - } - const { t } = useTranslation(); const router = useRouter(); const theme = useTheme(); diff --git a/src/services/AssesmentService.ts b/src/services/AssesmentService.ts index b773ed5b..6b352ce7 100644 --- a/src/services/AssesmentService.ts +++ b/src/services/AssesmentService.ts @@ -1,4 +1,7 @@ -import { assesmentListServiceParam } from '@/utils/Interfaces'; +import { + assesmentListServiceParam, + gerDoIdServiceParam, +} from '@/utils/Interfaces'; import { post } from './RestClient'; export const AssesmentListService = async ({ @@ -6,15 +9,41 @@ export const AssesmentListService = async ({ pagination, filters, }: assesmentListServiceParam): Promise => { - // const apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/tracking-assesment/list`; const apiUrl: string = - 'https://tracking-pratham.tekdinext.com/api/v1/tracking-assesment/list'; + 'https://tracking-pratham.tekdinext.com/tracking-assessment/v1/list'; try { - console.log('data', apiUrl, pagination, filters, sort); const response = await post(apiUrl, { pagination, filters, sort }); return response?.data; } catch (error) { console.error('error in getting Assesment List Service list', error); + + return error; + } +}; + +export const getDoIdForAssesmentDetails = async ({ + filters, +}: gerDoIdServiceParam): Promise => { + const apiUrl: string = + 'https://sunbirdsaas.com/api/content/v1/search?orgdetails=orgName%2Cemail&licenseDetails=name%2Cdescription%2Curl'; + + const data = { + request: { + filters: { + program: filters.program, + se_boards: filters.se_boards, + subject: filters.subject, + assessment1: filters.assessment1, + }, + }, + }; + + try { + console.log('Request data', apiUrl, data); + const response = await post(apiUrl, data); + return response?.data; + } catch (error) { + console.error('Error in getDoIdForAssesmentDetails Service', error); return error; } }; diff --git a/src/utils/Interfaces.ts b/src/utils/Interfaces.ts index 309744fe..d3159ce5 100644 --- a/src/utils/Interfaces.ts +++ b/src/utils/Interfaces.ts @@ -68,10 +68,6 @@ export interface cohortMemberList { }; } -interface CustomField { - label: string; - value: string; -} export interface UserData { id: number; name: string; @@ -125,6 +121,7 @@ export interface updateCustomField { type: string; label?: string; values?: string | string[]; + name?: string; } export interface cohort { cohortId: string; @@ -156,7 +153,6 @@ export interface assesmentListServiceParam { }; } - export interface cohortAttendancePercentParam { limit: number; page: number; @@ -164,9 +160,26 @@ export interface cohortAttendancePercentParam { scope: string; fromDate: Date | string; toDate: Date | string; - contextId: string + contextId: string; }; facets: Array; } +export interface gerDoIdServiceParam { + filters: { + program: string[]; + se_boards: string[]; + subject: string[]; + assessment1: string; + }; +} +export interface CustomField { + fieldId: string; + label: string; + value: string; + options: Record; + type: string; + order: number; + name: string; +} From 11703f25fe1dc659956202cd45fd515ca603db02 Mon Sep 17 00:00:00 2001 From: upendraTekdi Date: Fri, 31 May 2024 18:09:20 +0530 Subject: [PATCH 2/2] Issue #PS-314 feat:Learner View profile update --- src/components/LearnerModal.tsx | 1 - src/components/ModalPopup.tsx | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/components/LearnerModal.tsx b/src/components/LearnerModal.tsx index e223ac2d..2129bbe0 100644 --- a/src/components/LearnerModal.tsx +++ b/src/components/LearnerModal.tsx @@ -12,7 +12,6 @@ import { import CloseSharpIcon from '@mui/icons-material/CloseSharp'; import { useTheme } from '@mui/material/styles'; -import ProfileField from './ProfileField'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; diff --git a/src/components/ModalPopup.tsx b/src/components/ModalPopup.tsx index ff0d5508..11c59afc 100644 --- a/src/components/ModalPopup.tsx +++ b/src/components/ModalPopup.tsx @@ -13,12 +13,10 @@ import { import { useTranslation } from 'next-i18next'; import CloseIcon from '@mui/icons-material/Close'; import PlaceOutlinedIcon from '@mui/icons-material/PlaceOutlined'; -import ProfileField from '@/components/ProfileField'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; const ModalComponent = () => { const { t } = useTranslation(); - const [open, setOpen] = React.useState(true); const handleOpen = () => setOpen(true); const handleClose = () => setOpen(false);