diff --git a/app.config.ts b/app.config.ts index ee0b16456..898faee76 100644 --- a/app.config.ts +++ b/app.config.ts @@ -69,7 +69,7 @@ export const DaysOfWeek = { Sat: 6, }; -export const Program = 'secondchance'; +export const Program = ['Second Chance','secondchance']; export const tenantId = process.env.NEXT_PUBLIC_TENANT_ID || ''; if (!tenantId) { diff --git a/firebase.js b/firebase.js index 4ba9c4363..3edd3f3ff 100644 --- a/firebase.js +++ b/firebase.js @@ -1,13 +1,15 @@ -import { initializeApp } from "firebase/app"; -import { getMessaging, onMessage, getToken } from "firebase/messaging"; +import { initializeApp } from 'firebase/app'; +import { getMessaging, onMessage, getToken } from 'firebase/messaging'; // import config from './config.json'; import firebaseConfig from './firebaseConfig'; const firebaseApp = initializeApp(firebaseConfig); let messaging; -if (typeof window !== 'undefined') { +if (typeof window !== 'undefined' && 'serviceWorker' in navigator) { messaging = getMessaging(); +} else { + console.warn('Service workers are not supported in this environment.'); } export const requestPermission = async () => { @@ -21,17 +23,17 @@ export const requestPermission = async () => { console.log('Notification token:', token); return token; } else { - console.warn("Notification permission denied"); + console.warn('Notification permission denied'); return null; } -}; +}; export const onMessageListener = () => new Promise((resolve) => { if (messaging) { onMessage(messaging, (payload) => { - console.log("Received foreground message:", payload); + console.log('Received foreground message:', payload); resolve(payload); }); } - }); + }); diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 4f7cf0717..0401b3e0b 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -330,9 +330,12 @@ "STEP_3": "Access the full calendar to track learners' attendance for any month and see who was present or absent each day.", "STEP_4": "Use this button to view a detailed overview of center attendance and see a list of learners categorized by low, average, and good attendance for any custom date range.", "STEP_5": "Update your preferred language anytime from here.", - "STEP_6": "Access your teaching centers and manage tasks like adding, editing, or removing learners, marking dropouts, and reassigning centers or blocks. You can also easily schedule online or offline sessions for your subjects.", - "STEP_7": "Access the full academic year’s course plan for each subject, along with resources like videos and documents for every topic. Track your teaching progress by updating topic completion status.", - "STEP_8": "View detailed scores and summaries of Pre and Post tests for each learner. Track which students have completed, are in progress or yet to start the test.", + "STEP_6": "Access data from the current or past years by selecting a year from this dropdown", + "STEP_7": "Access your teaching centers and manage tasks like adding, editing, or removing learners, marking dropouts, and reassigning centers or blocks. You can also easily schedule online or offline sessions for your subjects.", + "STEP_8": "Fill out surveys for individual learners, facilitators, or centers within their due date", + "STEP_9": "Access the full academic year’s course plan for each subject, along with resources like videos and documents for every topic. Track your teaching progress by updating topic completion status.", + "STEP_10": "View detailed scores and summaries of Pre and Post tests for each learner. Track which students have completed, are in progress or yet to start the test.", + "STEP_11": "Track and update each learner’s board exam enrollment status", "PREVIOUS": "Previous", "NEXT": "Next", "SKIP": "Skip", @@ -442,7 +445,19 @@ "END_TIME_ERROR": "End time cannot be earlier than start time.", "START_DATE_ERROR": "Start date cannot be later than end date.", "END_DATE_ERROR": "End date cannot be earlier than start date.", - "IDENTIFIER_NOT_FOUND": "Identifier not found! Cannot Open Content!" + "IDENTIFIER_NOT_FOUND": "Identifier not found! Cannot Open Content!", + "MEETING_LINK_REQUIRED": "Please Enter Meeting Link!", + "WEEKDAY_ERROR": "Please select at least one weekday for the recurring event.", + "MULTIDAY_EVENT_ERROR": "Recurring events cannot span multiple days.", + "EXTRA_SESSION_DATE_TIME_REQUIRED_ERROR": "Start and end times are required for extra sessions.", + "PLANNED_SESSION_DATE_TIME_REQUIRED_ERROR": "Both start and end date/time are required for planned sessions.", + "EXTRA_SESSION_VALID_DATE_TIME_REQUIRED_ERROR": "Please provide a valid start time for the extra session.", + "PLANNED_SESSION_START_DATE_TIME_REQUIRED_ERROR": "Please provide a valid start date/time for the planned session.", + "EXTRA_SESSION_END_DATE_TIME_REQUIRED_ERROR": "Please provide a valid end time for the extra session.", + "PLANNED_SESSION_END_DATE_TIME_REQUIRED_ERROR": "Please provide a valid end time for the planned session.", + "INVALID_DATE": "Invalid Date", + "INVALID_EVENT_CONFIGURATION": "Invalid event configuration. Please check your inputs.", + "MEETING_URL_ERROR": "Please provide a valid meeting URL." }, "MANAGE_USERS": { "CENTERS_REQUESTED_SUCCESSFULLY": "Center requested successfully", @@ -627,7 +642,7 @@ "DUE_DATE": "Due date", "SURVEY_FORMS": "Survey Forms", "OBSERVATION_STATUS": "Survey Status", - "OBSERVATION_SURVEY_FOR":"Survey for {{entityValue}}", + "OBSERVATION_SURVEY_FOR": "Survey for {{entityValue}}", "OBSERVATION_NOT_STARTED_YET": "Survey not started yet", "EXPIRED": "Expired" } diff --git a/src/assets/images/HTML.svg b/src/assets/images/HTML.svg index 326936861..b5df03019 100644 --- a/src/assets/images/HTML.svg +++ b/src/assets/images/HTML.svg @@ -1,20 +1,9 @@ - - - - - - + + - - + + - - - - - - - - + diff --git a/src/assets/images/Qml.svg b/src/assets/images/Qml.svg index 556e3193b..10a9d5ec4 100644 --- a/src/assets/images/Qml.svg +++ b/src/assets/images/Qml.svg @@ -1,20 +1,9 @@ - - - - - - + + - - + + - - - - - - - - + diff --git a/src/components/AssessmentReport.tsx b/src/components/AssessmentReport.tsx index 08dec2851..b26d8be1e 100644 --- a/src/components/AssessmentReport.tsx +++ b/src/components/AssessmentReport.tsx @@ -10,6 +10,7 @@ import { showToastMessage } from './Toastify'; import AssessmentReportCard from './AssessmentReportCard'; import { AssessmentType, Program } from '../../app.config'; import { useQueryClient } from '@tanstack/react-query'; +import { getCohortDetails } from '@/services/CohortServices'; interface AssessmentReportProp { classId: string; @@ -28,6 +29,7 @@ const AssessmentReport: React.FC = ({ const [postAssessmentList, setPostAssessmentList] = useState([]); const [assessmentData, setAssessmentData] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [board, setBoard] = useState(''); const fetchAssessmentData = async ( type: AssessmentType, @@ -36,8 +38,13 @@ const AssessmentReport: React.FC = ({ const stateName = localStorage.getItem('stateName'); const filters = { - program: [Program], - boards: [stateName], + program: Program, + state: stateName as string, + board: board, + status: ['Live'], + primaryCategory: [ + "Practice Question Set" + ], assessmentType: type, }; @@ -82,8 +89,8 @@ const AssessmentReport: React.FC = ({ try { const options = { userId: [userId], - courseId:assessmentList, // temporary added here assessmentList(contentId)... if assessment is done then need to pass actual course id and unit id here - unitId:assessmentList, + courseId: assessmentList, // temporary added here assessmentList(contentId)... if assessment is done then need to pass actual course id and unit id here + unitId: assessmentList, contentId: assessmentList, // batchId: classId, }; @@ -99,8 +106,8 @@ const AssessmentReport: React.FC = ({ setAssessmentData((prevData) => prevData.some((data) => data.type === type) ? prevData.map((data) => - data.type === type ? newAssessmentData : data - ) + data.type === type ? newAssessmentData : data + ) : [...prevData, newAssessmentData] ); } @@ -110,11 +117,33 @@ const AssessmentReport: React.FC = ({ } }; + const fetchCohortDetails = async (classId: string) => { + try { + + const { cohortData } = await getCohortDetails(classId); + const board = cohortData?.[0]?.customField.filter((item: any) => item.label === "BOARD")?.[0]?.value; + setBoard(board); + } + catch (error) { + console.error('Error fetching cohort details:', error); + showToastMessage(t('COMMON.SOMETHING_WENT_WRONG'), 'error'); + } + } + useEffect(() => { - fetchAssessmentData(AssessmentType.PRE_TEST, setPreAssessmentList); - fetchAssessmentData(AssessmentType.POST_TEST, setPostAssessmentList); + if (classId) { + const cohortDetails = fetchCohortDetails(classId); + } + }, [classId]); + useEffect(() => { + if (board) { + fetchAssessmentData(AssessmentType.PRE_TEST, setPreAssessmentList); + fetchAssessmentData(AssessmentType.POST_TEST, setPostAssessmentList); + } + }, [board]); + useEffect(() => { if (preAssessmentList.length) { fetchAssessmentStatus(preAssessmentList, AssessmentType.PRE_TEST); @@ -157,6 +186,7 @@ const AssessmentReport: React.FC = ({ userId={assessment.userId} classId={classId} assessmentType={assessment.type} + board={board} /> ))} diff --git a/src/components/AssessmentReportCard.tsx b/src/components/AssessmentReportCard.tsx index f8f154ff9..bdc3a48d4 100644 --- a/src/components/AssessmentReportCard.tsx +++ b/src/components/AssessmentReportCard.tsx @@ -3,7 +3,7 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; import RemoveIcon from '@mui/icons-material/Remove'; -import { Box, Grid } from '@mui/material'; +import { Box, Grid, Typography } from '@mui/material'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; @@ -17,6 +17,7 @@ interface AssessmentReportCardProp { userId: string; classId: string; assessmentType?: string; + board?: string; } const AssessmentReportCard: React.FC = ({ @@ -26,6 +27,7 @@ const AssessmentReportCard: React.FC = ({ userId, classId, assessmentType, + board }) => { const theme = useTheme(); const router = useRouter(); @@ -35,12 +37,12 @@ const AssessmentReportCard: React.FC = ({ const handleAssessmentDetails = (userId: string) => { if (router.pathname === '/assessments') { router.push( - `${router.pathname}/user/${userId}?assessmentType=${assessmentType}¢er=${classId}` + `${router.pathname}/user/${userId}?assessmentType=${assessmentType}¢er=${classId}&board=${board}` ); } else { const type = assessmentType === AssessmentType.PRE_TEST ? 'pre' : 'post'; router.push( - `/assessments/user/${userId}?assessmentType=${type}¢er=${classId}` + `/assessments/user/${userId}?assessmentType=${type}¢er=${classId}&board=${board}` ); } }; @@ -139,15 +141,27 @@ const AssessmentReportCard: React.FC = ({ fontSize: '16px', fontWeight: '400', }} + className="one-line-text" > - {cardTitle === 'pre-test' + + {cardTitle === 'pre-test' ? t('PROFILE.PRE_TEST') : cardTitle === 'post-test' ? t('PROFILE.POST_TEST') : cardTitle} + + = ({ name: item?.cohortName || item?.name, typeOfCohort: typeOfCohort || t('ATTENDANCE.UNKNOWN'), status: item?.status, + customField: item?.customField, }; }) ?.filter(Boolean); diff --git a/src/components/ContentCard.tsx b/src/components/ContentCard.tsx index af05e4438..4a5429d47 100644 --- a/src/components/ContentCard.tsx +++ b/src/components/ContentCard.tsx @@ -11,7 +11,7 @@ interface ContentCardProps { appIcon?: string; identifier?: any; resourceType?: string; - subTopic?:string[]; + subTopic?: string[]; } const ContentCard: React.FC = ({ @@ -40,7 +40,7 @@ const ContentCard: React.FC = ({ onClick={() => resourceType === "Course" ? router.push(`/course-hierarchy/${identifier}`) - : router.push(`/play/content/${identifier}`) + : router.push(`/play/content/${identifier?.toLowerCase()}`) } sx={{ backgroundImage: `url(${getBackgroundImage()})`, @@ -49,7 +49,7 @@ const ContentCard: React.FC = ({ borderRadius: '16px', overflow: 'hidden', cursor: 'pointer', - backgroundRepeat:'no-repeat' + backgroundRepeat: 'no-repeat' }} > = ({ textOverflow: 'ellipsis', }} > - {name} || {subTopic?.join(', ')} + {name || subTopic?.join(', ')} @@ -106,7 +106,7 @@ const ContentCard: React.FC = ({ {ContentCardsTypes[mimeType as keyof FileType]?.name} diff --git a/src/components/CoursePlannerCards.tsx b/src/components/CoursePlannerCards.tsx index f04c1add1..cb12d9904 100644 --- a/src/components/CoursePlannerCards.tsx +++ b/src/components/CoursePlannerCards.tsx @@ -5,21 +5,25 @@ import { useTheme } from '@mui/material/styles'; import React from 'react'; import ContentCard from './ContentCard'; - - - const CoursePlannerCards: React.FC = ({ resources, type, }) => { const theme = useTheme(); - + // Filter by type const filteredResources = resources?.filter( (resource: { type?: string }) => (type === ResourcesType.NONE && !resource.type) || resource.type === type ); + // Remove duplicates by identifier + const uniqueResources = filteredResources?.reduce((acc : any, resource :any) => { + if (!acc.some((item : any) => item.identifier === resource.identifier)) { + acc.push(resource); + } + return acc; + }, [] as typeof resources); return ( @@ -28,7 +32,7 @@ const CoursePlannerCards: React.FC = ({ spacing={2} sx={{ px: '16px !important', cursor: 'pointer' }} > - {filteredResources?.map( + {uniqueResources?.map( ( resource: { resourceType: string; @@ -40,14 +44,15 @@ const CoursePlannerCards: React.FC = ({ mimeType: string; // Add this property }, index: number - ) => ( - - - - - + ) )} diff --git a/src/components/CustomRangeModal.tsx b/src/components/CustomRangeModal.tsx index 4f945d8eb..602f514b7 100644 --- a/src/components/CustomRangeModal.tsx +++ b/src/components/CustomRangeModal.tsx @@ -89,8 +89,9 @@ const CustomRangeModal: React.FC = () => { justifyContent: 'end', }} > - {t('COMMON.CANCEL')} - {t('COMMON.OK')} + {t('COMMON.CANCEL')} + {t('COMMON.OK')} diff --git a/src/components/DateRangePopup.tsx b/src/components/DateRangePopup.tsx index 375006b18..fbe84f62d 100644 --- a/src/components/DateRangePopup.tsx +++ b/src/components/DateRangePopup.tsx @@ -433,6 +433,7 @@ const DateRangePopup: React.FC = ({ display: 'flex', gap: '30px', justifyContent: 'end', + cursor: 'pointer' }} > = ({ > {t('COMMON.CANCEL')} - + {t('COMMON.OK')} diff --git a/src/components/LearnerModal.tsx b/src/components/LearnerModal.tsx index 848f1c9da..d335122a0 100644 --- a/src/components/LearnerModal.tsx +++ b/src/components/LearnerModal.tsx @@ -69,7 +69,8 @@ const fieldValueStyles = (theme: any) => ({ const buttonContainerStyles = { padding: '20px', display: 'flex', - justifyContent: 'space-between', + gap:'20px', + justifyContent: 'flex-end', }; const closeButtonStyles = (theme: any) => ({ @@ -162,7 +163,7 @@ const LearnerModal = ({ {t('PROFILE.FULL_NAME')} - + {userName ? toPascalCase(userName) : ''} diff --git a/src/components/LearnersListItem.tsx b/src/components/LearnersListItem.tsx index 14cada565..7b80cea82 100644 --- a/src/components/LearnersListItem.tsx +++ b/src/components/LearnersListItem.tsx @@ -437,7 +437,7 @@ const LearnersListItem: React.FC = ({ ? toggleDrawer('bottom', true)(event) : handleMenuOpen(event); }} - sx={{ fontSize: '32px', color: theme.palette.warning['300'] }} + sx={{ fontSize: '32px', color: theme.palette.warning['300'], cursor:'pointer' }} /> ) : ( diff --git a/src/components/ManageUser.tsx b/src/components/ManageUser.tsx index 7cc80ee52..d75429725 100644 --- a/src/components/ManageUser.tsx +++ b/src/components/ManageUser.tsx @@ -561,6 +561,7 @@ const ManageUser: React.FC = ({ fontSize: '24px', marginTop: '1rem', color: theme.palette.warning['300'], + cursor:'pointer' }} /> ) : ( @@ -696,6 +697,7 @@ const ManageUser: React.FC = ({ fontSize: '24px', marginTop: '1rem', color: theme.palette.warning['300'], + cursor:'pointer' }} /> diff --git a/src/components/MarkBulkAttendance.tsx b/src/components/MarkBulkAttendance.tsx index a97febae7..7dd2c8ffe 100644 --- a/src/components/MarkBulkAttendance.tsx +++ b/src/components/MarkBulkAttendance.tsx @@ -55,6 +55,8 @@ const MarkBulkAttendance: React.FC = ({ const [updateAttendance, setUpdateAttendance] = React.useState(false); const [confirmation, setConfirmation] = React.useState(false); + const [isConfirmation, setIsConfirmation] = React.useState(false); + const [modalOpen, setModalOpen] = React.useState(false); const attendanceUpdate = () => { setUpdateAttendance(true); @@ -91,6 +93,7 @@ const MarkBulkAttendance: React.FC = ({ }; const updateBulkAttendanceStatus = (arr: any[]) => { + setIsConfirmation(true); const isAllPresent = arr.every( (user: any) => user.attendance === 'present' ); @@ -105,6 +108,8 @@ const MarkBulkAttendance: React.FC = ({ status: string, id?: string | undefined ) => { + setIsConfirmation(true); + const updatedAttendanceList = cohortMemberList?.map((user: any) => { if (isBulkAction) { user.attendance = status; @@ -215,7 +220,10 @@ const MarkBulkAttendance: React.FC = ({ // }; const getMessage = () => { - if (updateAttendance) return presentCount == 0 && absentCount == 0 ? t('COMMON.SURE_MARK') : t('COMMON.SURE_UPDATE'); + if (updateAttendance) + return presentCount == 0 && absentCount == 0 + ? t('COMMON.SURE_MARK') + : t('COMMON.SURE_UPDATE'); if (confirmation) return t('COMMON.SURE_CLOSE'); return ''; }; @@ -306,7 +314,7 @@ const MarkBulkAttendance: React.FC = ({ cursor: 'pointer', color: theme.palette.warning['A200'], }} - onClick={confirmationOpen} + onClick={isConfirmation ? confirmationOpen : onClose} /> diff --git a/src/components/MenuDrawer.tsx b/src/components/MenuDrawer.tsx index 0cd8dae6f..dfdafdd00 100644 --- a/src/components/MenuDrawer.tsx +++ b/src/components/MenuDrawer.tsx @@ -245,7 +245,7 @@ const MenuDrawer: React.FC = ({ - +