From a53339935089a337df3270ceae72612b8652e25d Mon Sep 17 00:00:00 2001 From: suvarnakale Date: Wed, 27 Nov 2024 19:09:15 +0530 Subject: [PATCH 1/3] Issue #PS-2546 bug: Not able to see preview / template image at requisites of topic and subtopic- fix --- src/components/RequisitesAccordion.tsx | 6 ++- src/components/SessionCardFooter.tsx | 42 +++++++++++++++++- src/components/TopicDetails.tsx | 32 +++++++------- src/pages/course-planner-detail-old.tsx | 59 +++++++++++++------------ 4 files changed, 91 insertions(+), 48 deletions(-) diff --git a/src/components/RequisitesAccordion.tsx b/src/components/RequisitesAccordion.tsx index 85446f2e..168a2f47 100644 --- a/src/components/RequisitesAccordion.tsx +++ b/src/components/RequisitesAccordion.tsx @@ -72,7 +72,11 @@ const RequisitesAccordion: React.FC = ({ handlePlayers(item?.identifier)} + sx={{ + backgroundImage: `url(${item?.appIcon ? item.appIcon : '/decorationBg.png'})`, + position: 'relative', + }} + onClick={() => handlePlayers(item?.id)} > = ({ item, @@ -108,7 +110,7 @@ const SessionCardFooter: React.FC = ({ name: resource?.name, link: resource?.link, type: resource?.type || '', - identifier: resource?.identifier || '', + id: resource?.id || '', }) ); return subAcc; @@ -118,7 +120,9 @@ const SessionCardFooter: React.FC = ({ return acc; }, {}); console.log(learningResources); - setLearningResources(learningResources); + const resources: IResource[] = extractResources(learningResources); + const enrichedContent = await fetchLearningResources(resources); + setLearningResources(enrichedContent); } } } catch (error) { @@ -129,6 +133,40 @@ const SessionCardFooter: React.FC = ({ fetchTopicSubtopic(); }, [item]); + const extractResources = (learningResources: any): IResource[] => { + const resources: IResource[] = []; + + Object.values(learningResources).forEach((childTasks: any) => { + Object.values(childTasks).forEach((resourceArray: any) => { + if (Array.isArray(resourceArray)) { + resources.push(...resourceArray); + } + }); + }); + + return resources; + }; + + const fetchLearningResources = async (resources: IResource[]) => { + try { + const identifiers = resources?.map((resource: IResource) => resource?.id); + const response = await fetchBulkContents(identifiers); + + resources = resources.map((resource: IResource) => { + const content = response?.find( + (content: any) => content?.identifier === resource?.id + ); + return { ...resource, ...content, name: resource.name }; + }); + + // setResources(resources); + console.log('response===>', resources); + return resources; + } catch (error) { + console.error('error', error); + } + }; + const handleComponentOpen = () => { setSelectedTopic(''); setSelectedSubtopics([]); diff --git a/src/components/TopicDetails.tsx b/src/components/TopicDetails.tsx index 586e9eae..efa6e2af 100644 --- a/src/components/TopicDetails.tsx +++ b/src/components/TopicDetails.tsx @@ -38,18 +38,18 @@ const TopicDetails: React.FC = ({ const { t } = useTranslation(); const theme = useTheme(); - const content: any = []; - if (learningResources?.[topic]) { - const subTopics = learningResources[topic]; - subTopic?.forEach((currentSubTopic: string) => { - if (subTopics[currentSubTopic]) { - const resources = subTopics[currentSubTopic]; - resources?.forEach((resource: any) => { - content.push(resource); - }); - } - }); - } + // const content: any = []; + // if (learningResources?.[topic]) { + // const subTopics = learningResources[topic]; + // subTopic?.forEach((currentSubTopic: string) => { + // if (subTopics[currentSubTopic]) { + // const resources = subTopics[currentSubTopic]; + // resources?.forEach((resource: any) => { + // content.push(resource); + // }); + // } + // }); + // } const openTopicModal = () => { handleOpen(); @@ -154,13 +154,11 @@ const TopicDetails: React.FC = ({ /> - - = ({ = ({ { setLoading(true); const response = await getTargetedSolutions({ subject: tStore?.taxonomySubject, - class: tStore?.grade, - state: tStore?.state, - board: tStore?.board, + class: tStore?.grade || 'Class 10', + state: tStore?.state || 'Maharashtra', + board: tStore?.board || 'Maharashtra', type: tStore?.type, - medium: tStore?.medium, + medium: tStore?.medium || 'Marathi', }); if (response?.result?.data == '') { @@ -215,7 +218,7 @@ const CoursePlannerDetail = () => { const windowUrl = window.location.pathname; const cleanedUrl = windowUrl.replace(/^\//, ''); - const env = cleanedUrl.split("/")[0]; + const env = cleanedUrl.split('/')[0]; const telemetryInteract = { context: { @@ -231,26 +234,23 @@ const CoursePlannerDetail = () => { }, }; telemetryFactory.interact(telemetryInteract); - - - }; const toggleDrawer = (open: boolean, selectedCount: number = 0) => - (event?: React.KeyboardEvent | React.MouseEvent) => { - if ( - event && - event.type === 'keydown' && - ((event as React.KeyboardEvent).key === 'Tab' || - (event as React.KeyboardEvent).key === 'Shift') - ) { - return; - } - setDrawerState({ ...drawerState, bottom: open }); - setIsDrawerOpen(open); - setSelectedCount(selectedCount); - }; + (event?: React.KeyboardEvent | React.MouseEvent) => { + if ( + event && + event.type === 'keydown' && + ((event as React.KeyboardEvent).key === 'Tab' || + (event as React.KeyboardEvent).key === 'Shift') + ) { + return; + } + setDrawerState({ ...drawerState, bottom: open }); + setIsDrawerOpen(open); + setSelectedCount(selectedCount); + }; const handleCloseModel = () => { setModalOpen(false); @@ -355,7 +355,7 @@ const CoursePlannerDetail = () => { setResources(resources); console.log('response===>', resources); } catch (error) { - console.error("error", error); + console.error('error', error); } }; @@ -610,7 +610,9 @@ const CoursePlannerDetail = () => { cursor: 'pointer', }} onClick={() => { - fetchLearningResources(subTopic?.learningResources); + fetchLearningResources( + subTopic?.learningResources + ); // setResources(subTopic); router.push(`/topic-detail-view`); }} @@ -712,7 +714,9 @@ const CoursePlannerDetail = () => { sx={{ fontSize: '12px', fontWeight: '500' }} onClick={() => { // setResources(subTopic); - fetchLearningResources(subTopic?.learningResources); + fetchLearningResources( + subTopic?.learningResources + ); router.push(`/topic-detail-view`); }} > @@ -759,7 +763,6 @@ const CoursePlannerDetail = () => { selectedCount={selectedCount} /> - {/* Date: Wed, 27 Nov 2024 22:14:52 +0530 Subject: [PATCH 2/3] Issue #PS-2546 bug: hard coded values removed --- src/pages/course-planner-detail-old.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/course-planner-detail-old.tsx b/src/pages/course-planner-detail-old.tsx index 9157ae06..4b291713 100644 --- a/src/pages/course-planner-detail-old.tsx +++ b/src/pages/course-planner-detail-old.tsx @@ -93,11 +93,11 @@ const CoursePlannerDetail = () => { setLoading(true); const response = await getTargetedSolutions({ subject: tStore?.taxonomySubject, - class: tStore?.grade || 'Class 10', - state: tStore?.state || 'Maharashtra', - board: tStore?.board || 'Maharashtra', + class: tStore?.grade, + state: tStore?.state, + board: tStore?.board, type: tStore?.type, - medium: tStore?.medium || 'Marathi', + medium: tStore?.medium, }); if (response?.result?.data == '') { From 81b7933b527a93281a5def691495a8ff23c5eee7 Mon Sep 17 00:00:00 2001 From: suvarnakale Date: Wed, 27 Nov 2024 22:23:59 +0530 Subject: [PATCH 3/3] Issue #PS-2546 bug: deleted old cour planner detail page --- src/components/SessionCardFooter.tsx | 2 +- src/pages/course-planner-detail-old.tsx | 793 ------------------------ 2 files changed, 1 insertion(+), 794 deletions(-) delete mode 100644 src/pages/course-planner-detail-old.tsx diff --git a/src/components/SessionCardFooter.tsx b/src/components/SessionCardFooter.tsx index e6e50d9a..1ef739c0 100644 --- a/src/components/SessionCardFooter.tsx +++ b/src/components/SessionCardFooter.tsx @@ -27,7 +27,7 @@ import { EventStatus } from '@/utils/app.constant'; import { useDirection } from '../hooks/useDirection'; import { useRouter } from 'next/router'; import { fetchBulkContents } from '@/services/PlayerService'; -import { IResource } from '@/pages/course-planner-detail-old'; +import { IResource } from '@/pages/course-planner/center/[cohortId]'; const SessionCardFooter: React.FC = ({ item, diff --git a/src/pages/course-planner-detail-old.tsx b/src/pages/course-planner-detail-old.tsx deleted file mode 100644 index 4b291713..00000000 --- a/src/pages/course-planner-detail-old.tsx +++ /dev/null @@ -1,793 +0,0 @@ -import ConfirmationModal from '@/components/ConfirmationModal'; -import FacilitatorDrawer from '@/components/FacilitatorDrawer'; -import Header from '@/components/Header'; -import { logEvent } from '@/utils/googleAnalytics'; -import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; -import ArrowDropUpIcon from '@mui/icons-material/ArrowDropUp'; -import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import KeyboardBackspaceOutlinedIcon from '@mui/icons-material/KeyboardBackspaceOutlined'; -import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; -import { useRouter } from 'next/router'; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Box, - Typography, -} from '@mui/material'; -import { useTheme } from '@mui/material/styles'; -import { useTranslation } from 'next-i18next'; -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import React, { useState, useEffect, useMemo, useCallback } from 'react'; -import { buildStyles, CircularProgressbar } from 'react-circular-progressbar'; -import { - getSolutionDetails, - getTargetedSolutions, - getUserProjectDetails, - getUserProjectTemplate, - UserStatusDetails, -} from '@/services/CoursePlannerService'; -import useCourseStore from '@/store/coursePlannerStore'; -import dayjs from 'dayjs'; -import { - AssessmentStatus, - Role, - TelemetryEventType, -} from '@/utils/app.constant'; -import Loader from '@/components/Loader'; -import withAccessControl from '@/utils/hoc/withAccessControl'; -import { accessControl } from '../../app.config'; -import taxonomyStore from '@/store/taxonomyStore'; -import useDeterminePathColor from '@/hooks/useDeterminePathColor'; -import { useDirection } from '../hooks/useDirection'; -import { Telemetry } from 'next/dist/telemetry/storage'; -import { telemetryFactory } from '@/utils/telemetry'; -import { fetchBulkContents } from '@/services/PlayerService'; - -export interface IResource { - name: string; - link: string; - app?: string; - type: string; - id: string; -} - -const CoursePlannerDetail = () => { - const theme = useTheme(); - const router = useRouter(); - const { t } = useTranslation(); - const { dir, isRTL } = useDirection(); - const setResources = useCourseStore((state) => state.setResources); - const store = useCourseStore(); - const tStore = taxonomyStore(); - const [loading, setLoading] = useState(false); - const determinePathColor = useDeterminePathColor(); - // Initialize the panels' state, assuming you have a known set of panel IDs - const [expandedPanels, setExpandedPanels] = useState<{ - [key: string]: boolean; - }>({ - 'panel0-header': true, - 'panel1-header': true, - 'panel2-header': true, - 'panel3-header': true, - }); - const [drawerState, setDrawerState] = React.useState({ bottom: false }); - const [isDrawerOpen, setIsDrawerOpen] = useState(false); - const [modalOpen, setModalOpen] = React.useState(false); - const [userProjectDetails, setUserProjectDetails] = useState(); - const [statusData, setStatusData] = useState(); - - const [completionPercentage, setCompletionPercentage] = useState(0); - const [currentSubtopic, setCurrentSubtopic] = useState<{ - topid: any; - subid: any; - } | null>(null); - const [selectedSubtopics, setSelectedSubtopics] = useState< - { topid: string; subid: string }[] - >([]); - const [selectedCount, setSelectedCount] = React.useState(0); - - const fetchCourseDetails = useCallback(async () => { - try { - setLoading(true); - const response = await getTargetedSolutions({ - subject: tStore?.taxonomySubject, - class: tStore?.grade, - state: tStore?.state, - board: tStore?.board, - type: tStore?.type, - medium: tStore?.medium, - }); - - if (response?.result?.data == '') { - setLoading(false); - return; - } - - const courseData = response?.result?.data[0]; - - let courseId = courseData._id; - - if (!courseId) { - courseId = await fetchCourseIdFromSolution(courseData?.solutionId); - } - - await fetchAndSetUserProjectDetails(courseId); - } catch (error) { - console.error('Error fetching course planner:', error); - } - }, [statusData]); - - useEffect(() => { - const calculateProgress = (tasks: any[]) => { - let completionPercentage = 0; - const weightage = Number((100 / tasks.length).toFixed()); - tasks.forEach((task: any) => { - if (task.status === AssessmentStatus.COMPLETED_SMALL) { - completionPercentage += weightage; - } else { - const subtasks = task.children || []; - const subtaskWeightage = Number( - (weightage / subtasks.length).toFixed() - ); - subtasks.forEach((subtask: any) => { - if (subtask.status === AssessmentStatus.COMPLETED_SMALL) { - completionPercentage += subtaskWeightage; - } - }); - } - }); - console.log('completionPercentage:', completionPercentage); - setCompletionPercentage(completionPercentage); - }; - if (userProjectDetails?.tasks?.length) { - calculateProgress(userProjectDetails.tasks); - } - }, [userProjectDetails]); - - const fetchCourseIdFromSolution = async ( - solutionId: string - ): Promise => { - try { - const solutionResponse = await getSolutionDetails({ - id: solutionId, - role: 'Teacher', - }); - - const externalId = solutionResponse?.result?.externalId; - await getUserProjectTemplate({ - templateId: externalId, - solutionId, - role: Role.TEACHER, - }); - - const updatedResponse = await getTargetedSolutions({ - subject: tStore?.taxonomySubject, - class: tStore?.grade, - state: tStore?.state, - board: tStore?.board, - type: tStore?.type, - medium: tStore?.medium, - }); - setLoading(false); - - return updatedResponse?.result?.data[0]?._id; - } catch (error) { - console.error('Error fetching solution details:', error); - throw error; - } - }; - - const fetchAndSetUserProjectDetails = async (courseId: string) => { - try { - setLoading(true); - const userProjectDetailsResponse = await getUserProjectDetails({ - id: courseId, - }); - setUserProjectDetails(userProjectDetailsResponse?.result); - setLoading(false); - } catch (error) { - console.error('Error fetching user project details:', error); - } - }; - - useEffect(() => { - fetchCourseDetails(); - }, [fetchCourseDetails]); - - const handleBackEvent = () => { - window.history.back(); - logEvent({ - action: 'back-button-clicked-attendance-overview', - category: 'Attendance Overview Page', - label: 'Back Button Clicked', - }); - }; - - const handleToggleAll = () => { - const allOpen = Object.values(expandedPanels).every(Boolean); - const newState = Object.keys(expandedPanels).reduce( - (acc, key) => { - acc[key] = !allOpen; - return acc; - }, - {} as { [key: string]: boolean } - ); - setExpandedPanels(newState); - const windowUrl = window.location.pathname; - - const cleanedUrl = windowUrl.replace(/^\//, ''); - const env = cleanedUrl.split('/')[0]; - - const telemetryInteract = { - context: { - env: env, - cdata: [], - }, - edata: { - id: 'change-filter:', - - type: TelemetryEventType.CLICK, - subtype: '', - pageid: cleanedUrl, - }, - }; - telemetryFactory.interact(telemetryInteract); - }; - - const toggleDrawer = - (open: boolean, selectedCount: number = 0) => - (event?: React.KeyboardEvent | React.MouseEvent) => { - if ( - event && - event.type === 'keydown' && - ((event as React.KeyboardEvent).key === 'Tab' || - (event as React.KeyboardEvent).key === 'Shift') - ) { - return; - } - setDrawerState({ ...drawerState, bottom: open }); - setIsDrawerOpen(open); - setSelectedCount(selectedCount); - }; - - const handleCloseModel = () => { - setModalOpen(false); - }; - // const handleOpenModel = () => { - // setModalOpen(true); - // }; - - const getAbbreviatedMonth = (dateString: string | number | Date) => { - const date = new Date(dateString); - const months = Array.from({ length: 12 }, (_, i) => - dayjs().month(i).format('MMM') - ); - return months[date.getMonth()]; - }; - - const markMultipleStatuses = async ( - data: any, - selectedSubtopics: { topid: string; subid: string }[] - ) => { - const updatedData = { ...data }; - - selectedSubtopics.forEach(({ topid, subid }) => { - updatedData.tasks = updatedData.tasks.map( - (task: { status: string; _id: string; children: any[] }) => { - if (task._id === topid) { - task.children = task.children.map((child: { _id: string }) => { - if (child._id === subid) { - return { ...child, status: AssessmentStatus.COMPLETED_SMALL }; - } - return child; - }); - - const allSubtasksCompleted = task.children.every( - (child: { status: string }) => - child.status === AssessmentStatus.COMPLETED_SMALL - ); - - if (allSubtasksCompleted) { - task.status = AssessmentStatus.COMPLETED_SMALL; - } - } - return task; - } - ); - }); - - setStatusData(updatedData); - - try { - const response = await UserStatusDetails({ - data: updatedData, - id: updatedData._id, - lastDownloadedAt: updatedData.lastDownloadedAt, - }); - - setUserProjectDetails(updatedData); - setSelectedSubtopics([]); - toggleDrawer(false)(); - - console.log(response); - } catch (err) { - console.log(err); - } - }; - - const isStatusCompleted = (taskId: any, isSubtask: boolean = true) => { - if (isSubtask) { - const taskWithChildren = userProjectDetails.tasks.find( - (task: { children: any[] }) => - task.children.some((child: { _id: any }) => child._id === taskId) - ); - - if (taskWithChildren) { - const child = taskWithChildren.children.find( - (child: { _id: any }) => child._id === taskId - ); - return child && child.status === AssessmentStatus.COMPLETED_SMALL; - } - } else { - const task = userProjectDetails.tasks.find( - (task: { _id: any }) => task._id === taskId - ); - return task && task.status === AssessmentStatus.COMPLETED_SMALL; - } - - return false; - }; - - const fetchLearningResources = async (resources: IResource[]) => { - try { - const identifiers = resources.map((resource: IResource) => resource?.id); - const response = await fetchBulkContents(identifiers); - - resources = resources.map((resource: IResource) => { - const content = response?.find( - (content: any) => content?.identifier === resource?.id - ); - return { ...resource, ...content }; - }); - - setResources(resources); - console.log('response===>', resources); - } catch (error) { - console.error('error', error); - } - }; - - return ( - -
- - - - - - - - - - - - {completionPercentage}% - - - - - - {tStore?.taxonomySubject} - - - - - - - {Object.values(expandedPanels).every(Boolean) - ? t('COURSE_PLANNER.COLLAPSE_ALL') - : t('COURSE_PLANNER.EXPAND_ALL')} - {Object.values(expandedPanels).every(Boolean) ? ( - - ) : ( - - )} - - - -
- {loading ? ( - - ) : ( - <> - - {userProjectDetails?.tasks?.length > 0 ? ( - userProjectDetails.tasks.map((topic: any, index: number) => ( - - - setExpandedPanels((prev) => ({ - ...prev, - [`panel${index}-header`]: - !prev[`panel${index}-header`], - })) - } - sx={{ - boxShadow: 'none', - background: '#F1E7D9', - border: 'none', - transition: '0.3s', - }} - > - - } - aria-controls={`panel${index}-content`} - id={`panel${index}-header`} - className="accordion-summary" - sx={{ - px: '16px', - m: 0, - '&.Mui-expanded': { - minHeight: '48px', - }, - }} - > - - - {/* Check if the parent task is completed and show a black tick */} - {isStatusCompleted(topic._id, false) ? ( - - ) : ( - - )} - - {`Topic ${index + 1} - ${topic.name}`} - - - - - {getAbbreviatedMonth( - topic?.metaInformation?.startDate - )} - ,{' '} - {getAbbreviatedMonth( - topic?.metaInformation?.endDate - )} - - - - - {topic.children.map((subTopic: any) => ( - - - - { - fetchLearningResources( - subTopic?.learningResources - ); - // setResources(subTopic); - router.push(`/topic-detail-view`); - }} - > - {subTopic.name} - - - - {getAbbreviatedMonth( - subTopic?.metaInformation?.startDate - )} - - { - if (!isStatusCompleted(subTopic._id)) { - const alreadySelected = - selectedSubtopics.find( - (s) => s.subid === subTopic._id - ); - - if (alreadySelected) { - setSelectedSubtopics( - selectedSubtopics.filter( - (s) => s.subid !== subTopic._id - ) - ); - - toggleDrawer( - true, - selectedSubtopics.length - 1 - )(); - } else { - setSelectedSubtopics([ - ...selectedSubtopics, - { - topid: topic._id, - subid: subTopic._id, - }, - ]); - - toggleDrawer( - true, - selectedSubtopics.length + 1 - )(); - } - } - }} - sx={{ - fontSize: '20px', - color: selectedSubtopics.find( - (s) => s.subid === subTopic._id - ) - ? '#FF9800' - : isStatusCompleted(subTopic._id) - ? '#4CAF50' - : '#7C766e', - cursor: isStatusCompleted(subTopic._id) - ? 'default' - : 'pointer', - pointerEvents: isStatusCompleted( - subTopic._id - ) - ? 'none' - : 'auto', - }} - /> - - - { - // // router.push(`/topic-detail-view`); - // }} - > - { - // setResources(subTopic); - fetchLearningResources( - subTopic?.learningResources - ); - router.push(`/topic-detail-view`); - }} - > - {`${subTopic?.learningResources?.length} ${t( - 'COURSE_PLANNER.RESOURCES' - )}`} - - - - - - ))} - - - - )) - ) : ( - - {t('ASSESSMENTS.NO_DATA_FOUND')} - - )} - - - )} -
- { - if (selectedSubtopics.length > 0) { - // Mark all selected subtopics as complete - markMultipleStatuses(userProjectDetails, selectedSubtopics); - toggleDrawer(false)(); - } - }} - onSecondaryClick={() => { - setSelectedSubtopics([]); - toggleDrawer(false)(); - }} - selectedCount={selectedCount} - /> - - {/* */} - - ); -}; - -export async function getStaticProps({ locale }: any) { - return { - props: { - ...(await serverSideTranslations(locale, ['common'])), - // Will be passed to the page component as props - }, - }; -} - -export default withAccessControl( - 'accessCoursePlannerDetails', - accessControl -)(CoursePlannerDetail);