diff --git a/.env b/.env index 9a0bf7db..7cac5892 100644 --- a/.env +++ b/.env @@ -3,7 +3,8 @@ NEXT_PUBLIC_EVENT_BASE_URL=https://event-pratham.tekdinext.com/event-service/eve NEXT_PUBLIC_TELEMETRY_URL=https://qa.prathamteacherapp.tekdinext.com/telemetry NEXT_PUBLIC_MEASUREMENT_ID= G-GNMQZ8Z65Z NEXT_PUBLIC_SHIKSHALOKAM_API_URL=https://dev.elevate-apis.shikshalokam.org/project/v1 -NEXT_PUBLIC_SHIKSHALOKAM_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjoyNjIsIm5hbWUiOiJ0ZWtkaVRlc3RVc2VyIiwic2Vzc2lvbl9pZCI6NjExNiwib3JnYW5pemF0aW9uX2lkIjoxLCJyb2xlcyI6W3siaWQiOjEyLCJ0aXRsZSI6InByb2dyYW1fZGVzaWduZXIiLCJsYWJlbCI6IlByb2dyYW0gRGVzaWduZXIiLCJ1c2VyX3R5cGUiOjAsInN0YXR1cyI6IkFDVElWRSIsIm9yZ2FuaXphdGlvbl9pZCI6MSwidmlzaWJpbGl0eSI6IlBVQkxJQyJ9LHsiaWQiOjIxLCJ0aXRsZSI6ImRpc3RyaWN0X3Jlc291cmNlX3BlcnNvbiIsImxhYmVsIjoiRGlzdHJpY3QgUmVzb3VyY2UgUGVyc29uIiwidXNlcl90eXBlIjowLCJzdGF0dXMiOiJBQ1RJVkUiLCJvcmdhbml6YXRpb25faWQiOjI0LCJ2aXNpYmlsaXR5IjoiUFVCTElDIn1dfSwiaWF0IjoxNzI0ODI1MDM5LCJleHAiOjE3MjQ5MTE0Mzl9.HAK4_MAo-8tqxcVoLNDRuyNj_S_hqM8X5Pya1gKPXKg +NEXT_PUBLIC_SHIKSHALOKAM_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjoxNjIsIm5hbWUiOiJQcml5YW5rYSIsInNlc3Npb25faWQiOjYxNTAsIm9yZ2FuaXphdGlvbl9pZCI6MjQsInJvbGVzIjpbeyJpZCI6MywidGl0bGUiOiJtZW50ZWUiLCJsYWJlbCI6Ik1lbnRlZSIsInVzZXJfdHlwZSI6MCwic3RhdHVzIjoiQUNUSVZFIiwib3JnYW5pemF0aW9uX2lkIjoxLCJ2aXNpYmlsaXR5IjoiUFVCTElDIn0seyJpZCI6NCwidGl0bGUiOiJhZG1pbiIsImxhYmVsIjoiQWRtaW4iLCJ1c2VyX3R5cGUiOjEsInN0YXR1cyI6IkFDVElWRSIsIm9yZ2FuaXphdGlvbl9pZCI6MSwidmlzaWJpbGl0eSI6IlBVQkxJQyJ9LHsiaWQiOjgsInRpdGxlIjoicHVibGljIiwibGFiZWwiOiJQdWJsaWMiLCJ1c2VyX3R5cGUiOjAsInN0YXR1cyI6IkFDVElWRSIsIm9yZ2FuaXphdGlvbl9pZCI6MSwidmlzaWJpbGl0eSI6IlBVQkxJQyJ9LHsiaWQiOjUsInRpdGxlIjoib3JnX2FkbWluIiwibGFiZWwiOiJPcmcgQWRtaW4iLCJ1c2VyX3R5cGUiOjEsInN0YXR1cyI6IkFDVElWRSIsIm9yZ2FuaXphdGlvbl9pZCI6MSwidmlzaWJpbGl0eSI6IlBVQkxJQyJ9LHsiaWQiOjEwLCJ0aXRsZSI6InJldmlld2VyIiwibGFiZWwiOiJSZXZpZXdlciIsInVzZXJfdHlwZSI6MCwic3RhdHVzIjoiQUNUSVZFIiwib3JnYW5pemF0aW9uX2lkIjoxLCJ2aXNpYmlsaXR5IjoiUFVCTElDIn0seyJpZCI6MjAsInRpdGxlIjoiZGlzdHJpY3RfZWR1Y2F0aW9uX29mZmljZXIiLCJsYWJlbCI6IkRpc3RyaWN0IEVkdWNhdGlvbiBPZmZpY2VyIiwidXNlcl90eXBlIjowLCJzdGF0dXMiOiJBQ1RJVkUiLCJvcmdhbml6YXRpb25faWQiOjI0LCJ2aXNpYmlsaXR5IjoiUFVCTElDIn1dfSwiaWF0IjoxNzI0ODM3NzEyLCJleHAiOjE3MjQ5MjQxMTJ9.5rBJlIC0wN-6zpISQfa-cNCLRvSSe6uI87W2JKBt4Yk # NEXT_PUBLIC_BASE_URL=https://backend.prathamdigital.org/user/v1 # NEXT_PUBLIC_NOTIFICATION_BASE_URL=https://notification.prathamdigital.org # NEXT_PUBLIC_TRACKING_API_URL=https://tracking.prathamdigital.org + diff --git a/src/pages/course-planner-detail.tsx b/src/pages/course-planner-detail.tsx index 014f4ec6..cc43999f 100644 --- a/src/pages/course-planner-detail.tsx +++ b/src/pages/course-planner-detail.tsx @@ -21,9 +21,15 @@ 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 { getTargetedSolutions, getUserProjectDetails } from '@/services/CoursePlannerService'; +import { + getSolutionDetails, + getTargetedSolutions, + getUserProjectDetails, + getUserProjectTemplate, +} from '@/services/CoursePlannerService'; import useCourseStore from '@/store/coursePlannerStore'; import dayjs from 'dayjs'; +import { Role } from '@/utils/app.constant'; const CoursePlannerDetail = () => { const theme = useTheme<any>(); @@ -32,14 +38,14 @@ const CoursePlannerDetail = () => { const setResources = useCourseStore((state) => state.setResources); const store = useCourseStore(); - // 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': false, // || example for multiple accordions do this dynamically - // Add more panels if needed + 'panel2-header': true, + 'panel3-header': true, }); const [drawerState, setDrawerState] = React.useState({ bottom: false }); const [isDrawerOpen, setIsDrawerOpen] = useState(false); @@ -48,31 +54,80 @@ const CoursePlannerDetail = () => { const [courseDetails, setCourseDetails] = useState(null); const [userProjectDetails, setUserProjectDetails] = useState([]); - const fetchCourseDetails = useCallback(() => { - getTargetedSolutions({ - subject: "Marathi", - class: "10", - state: "Maharasthra", - board: "NIOS", - type: "foundationCourse", - role: "Teacher", - medium: "English" - }).then((response) => { - const courseId = response.result.data[0]._id; - setCourseDetails(response.result.data); - - return getUserProjectDetails({ id: '66cdb0c86a33880d1f4d60d7' }); - }).then((userProjectDetailsResponse) => { - setUserProjectDetails(userProjectDetailsResponse.result.tasks); - }).catch((error) => { - console.error('Error fetching course planner:', error); + const fetchCourseDetails = useCallback(async () => { + try { + const response = await getTargetedSolutions({ + subject: 'Marathi', + class: '10', + state: 'Assam', + board: 'ASEB', + type: 'mainCourse', + role: 'Teacher', + medium: 'Hindi', }); + + 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); + } }, []); + const fetchCourseIdFromSolution = async (solutionId: string): Promise<string> => { + try { + const solutionResponse = await getSolutionDetails({ + id: solutionId, + role: 'Teacher', + }); + + const externalId = solutionResponse?.result?.externalId; + + const templateResponse = await getUserProjectTemplate({ + templateId: externalId, + solutionId, + role: Role.TEACHER, + }); + + const updatedResponse = await getTargetedSolutions({ + subject: 'Marathi', + class: '10', + state: 'Kerala', + board: 'KSEB', + type: 'mainCourse', + role: 'Teacher', + medium: 'Hindi', + }); + + return updatedResponse.result.data[0]._id; + } catch (error) { + console.error('Error fetching solution details:', error); + throw error; + } + }; + + const fetchAndSetUserProjectDetails = async (courseId: string) => { + try { + const userProjectDetailsResponse = await getUserProjectDetails({ + id: courseId, + }); + setUserProjectDetails(userProjectDetailsResponse.result.tasks); + } catch (error) { + console.error('Error fetching user project details:', error); + } + }; + + + useEffect(() => { fetchCourseDetails(); }, [fetchCourseDetails]); - const handleBackEvent = () => { window.history.back(); @@ -115,8 +170,6 @@ const CoursePlannerDetail = () => { // setModalOpen(true); // }; - - const getAbbreviatedMonth = (dateString: string | number | Date) => { const date = new Date(dateString); const months = Array.from({ length: 12 }, (_, i) => @@ -234,169 +287,175 @@ const CoursePlannerDetail = () => { </Box> </Box> <Box mt={2}> - {userProjectDetails.map((topic:any, index) => ( - <Box key={topic._id} sx={{ borderRadius: '8px', mb: 2 }}> - <Accordion - expanded={expandedPanels[`panel1-header`] || false} - onChange={() => - setExpandedPanels((prev) => ({ - ...prev, - [`panel1-header`]: !prev[`panel1-header`], - })) - } - sx={{ - boxShadow: 'none', - background: '#F1E7D9', - border: 'none', - transition: '0.3s', - }} - > - <AccordionSummary - expandIcon={ - <ArrowDropDownIcon - sx={{ color: theme.palette.warning['300'] }} - /> - } - aria-controls={`panel${index}-content`} - id={`panel${index}-header`} - className="accordion-summary" - sx={{ - px: '16px', - m: 0, - '&.Mui-expanded': { - minHeight: '48px', - }, - }} - > - <Box - sx={{ - display: 'flex', - justifyContent: 'space-between', - width: '100%', - pr: '5px', - alignItems: 'center', - }} - > - <Box - sx={{ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - gap: '5px', - }} - > - <RadioButtonUncheckedIcon sx={{ fontSize: '15px' }} /> - <Typography - fontWeight="500" - fontSize="14px" - color={theme.palette.warning['300']} - > - {`Topic ${index + 1} - ${topic.name}`} - </Typography> - </Box> - <Typography fontWeight="600" fontSize="12px" color="#7C766F"> - {getAbbreviatedMonth(topic?.metaInformation?.startDate)}, {getAbbreviatedMonth(topic?.metaInformation?.endDate)} - </Typography> - </Box> - </AccordionSummary> - <AccordionDetails - sx={{ padding: '0', transition: 'max-height 0.3s ease-out' }} - > - {topic.children.map((subTopic:any) => ( - <Box - key={subTopic._id} + {userProjectDetails.map((topic: any, index) => ( + <Box key={topic._id} sx={{ borderRadius: '8px', mb: 2 }}> + <Accordion + expanded={expandedPanels[`panel${index}-header`] || false} + onChange={() => + setExpandedPanels((prev) => ({ + ...prev, + [`panel${index}-header`]: !prev[`panel${index}-header`], + })) + } sx={{ - borderBottom: `1px solid ${theme.palette.warning['A100']}`, + boxShadow: 'none', + background: '#F1E7D9', + border: 'none', + transition: '0.3s', }} > - <Box + <AccordionSummary + expandIcon={ + <ArrowDropDownIcon + sx={{ color: theme.palette.warning['300'] }} + /> + } + aria-controls={`panel${index}-content`} + id={`panel${index}-header`} + className="accordion-summary" sx={{ - py: '10px', px: '16px', - background: theme.palette.warning['A400'], + m: 0, + '&.Mui-expanded': { + minHeight: '48px', + }, }} > <Box sx={{ display: 'flex', justifyContent: 'space-between', + width: '100%', + pr: '5px', alignItems: 'center', - gap: '20px', }} > <Box sx={{ - fontSize: '16px', - fontWeight: '400', - color: theme.palette.warning['300'], - cursor: 'pointer', - }} - onClick={() => { - setResources(subTopic); - router.push(`/topic-detail-view`); + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + gap: '5px', }} > - {subTopic.name} + <RadioButtonUncheckedIcon sx={{ fontSize: '15px' }} /> + <Typography + fontWeight="500" + fontSize="14px" + color={theme.palette.warning['300']} + > + {`Topic ${index + 1} - ${topic.name}`} + </Typography> </Box> + <Typography fontWeight="600" fontSize="12px" color="#7C766F"> + {getAbbreviatedMonth(topic?.metaInformation?.startDate)},{' '} + {getAbbreviatedMonth(topic?.metaInformation?.endDate)} + </Typography> + </Box> + </AccordionSummary> + <AccordionDetails + sx={{ padding: '0', transition: 'max-height 0.3s ease-out' }} + > + {topic.children.map((subTopic: any) => ( <Box + key={subTopic._id} sx={{ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - gap: '6px', + borderBottom: `1px solid ${theme.palette.warning['A100']}`, }} > <Box sx={{ - padding: '5px', - background: ' #C1D6FF', - fontSize: '12px', - fontWeight: '500', - color: '#4D4639', - borderRadius: '8px', + py: '10px', + px: '16px', + background: theme.palette.warning['A400'], }} > - {getAbbreviatedMonth(subTopic?.metaInformation?.startDate)} + <Box + sx={{ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + gap: '20px', + }} + > + <Box + sx={{ + fontSize: '16px', + fontWeight: '400', + color: theme.palette.warning['300'], + cursor: 'pointer', + }} + onClick={() => { + setResources(subTopic); + router.push(`/topic-detail-view`); + }} + > + {subTopic.name} + </Box> + <Box + sx={{ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + gap: '6px', + }} + > + <Box + sx={{ + padding: '5px', + background: ' #C1D6FF', + fontSize: '12px', + fontWeight: '500', + color: '#4D4639', + borderRadius: '8px', + }} + > + {getAbbreviatedMonth( + subTopic?.metaInformation?.startDate + )} + </Box> + <CheckCircleIcon + onClick={toggleDrawer(true)} + sx={{ + fontSize: '20px', + color: '#7C766F', + cursor: 'pointer', + }} + /> + </Box> + </Box> + <Box + sx={{ + color: theme.palette.secondary.main, + display: 'flex', + alignItems: 'center', + gap: '4px', + mt: 0.8, + cursor: 'pointer', + }} + onClick={() => { + router.push(`/topic-detail-view`); + }} + > + <Box + sx={{ fontSize: '12px', fontWeight: '500' }} + onClick={() => { + setResources(subTopic); + router.push(`/topic-detail-view`); + }} + > + {`${subTopic?.learningResources?.length} ${t('COURSE_PLANNER.RESOURCES')}`} + </Box> + <ArrowForwardIcon sx={{ fontSize: '16px' }} /> + </Box> </Box> - <CheckCircleIcon - onClick={toggleDrawer(true)} - sx={{ - fontSize: '20px', - color: '#7C766F', - cursor: 'pointer', - }} - /> - </Box> - </Box> - <Box - sx={{ - color: theme.palette.secondary.main, - display: 'flex', - alignItems: 'center', - gap: '4px', - mt: 0.8, - cursor: 'pointer', - }} - onClick={() => { - router.push(`/topic-detail-view`); - }} - > - <Box sx={{ fontSize: '12px', fontWeight: '500' }} onClick={() => { - setResources(subTopic); - router.push(`/topic-detail-view`); - }}> - {`${subTopic?.learningResources?.length} ${t('COURSE_PLANNER.RESOURCES')}`} </Box> - <ArrowForwardIcon sx={{ fontSize: '16px' }} /> - </Box> - </Box> - </Box> - ))} - </AccordionDetails> - </Accordion> - </Box> - ))} -</Box> + ))} + </AccordionDetails> + </Accordion> + </Box> + ))} + </Box> <FacilitatorDrawer secondary={'Cancel'} diff --git a/src/services/CoursePlannerService.ts b/src/services/CoursePlannerService.ts index c70a5e32..d219b427 100644 --- a/src/services/CoursePlannerService.ts +++ b/src/services/CoursePlannerService.ts @@ -1,4 +1,4 @@ -import { CoursePlanner, GetTargetedSolutionsParams } from '../utils/Interfaces'; +import { CoursePlanner, GetSolutionDetailsParams, GetTargetedSolutionsParams, GetUserProjectTemplateParams } from '../utils/Interfaces'; import axios from 'axios'; export const getCoursePlanner = (): CoursePlanner[] => { @@ -10,7 +10,7 @@ export const getCoursePlanner = (): CoursePlanner[] => { // { id: 3, subject: 'History', circular: 30 }, // { id: 4, subject: 'Geography', circular: 60 }, // { id: 5, subject: 'Marathi', circular: 90 }, - { id: 6, subject: 'Hindi', circular: 70 }, + { id: 6, subject: 'Marathi', circular: 0 }, // { id: 7, subject: 'Social Science', circular: 80 }, ]; @@ -76,4 +76,51 @@ export const getUserProjectDetails = async ({ id }: GetUserProjectDetailsParams) }; +export const getSolutionDetails = async ({ id, role }: GetSolutionDetailsParams): Promise<any> => { + const apiUrl: string = `${process.env.NEXT_PUBLIC_SHIKSHALOKAM_API_URL}/solutions/details/${id}`; + + const headers = { + 'X-auth-token': process.env.NEXT_PUBLIC_SHIKSHALOKAM_TOKEN, + 'Content-Type': 'application/json', + }; + + const data = { + role, + }; + + try { + const response = await axios.post(apiUrl, data, { headers }); + return response?.data; + } catch (error) { + console.error('Error in getting Solution Details', error); + return error; + } +}; + +export const getUserProjectTemplate = async ({ + templateId, + solutionId, + role, +}: GetUserProjectTemplateParams): Promise<any> => { + const apiUrl: string = `${process.env.NEXT_PUBLIC_SHIKSHALOKAM_API_URL}/userProjects/details?templateId=${templateId}&solutionId=${solutionId}`; + + const headers = { + 'X-auth-token': process.env.NEXT_PUBLIC_SHIKSHALOKAM_TOKEN, + 'Content-Type': 'application/json', + }; + + const data = { + role, + }; + + try { + const response = await axios.post(apiUrl, data, { headers }); + return response?.data; + } catch (error) { + console.error('Error in getting User Project Details', error); + throw error; + } +}; + + diff --git a/src/utils/Interfaces.ts b/src/utils/Interfaces.ts index c4e2712e..6dd0c3b4 100644 --- a/src/utils/Interfaces.ts +++ b/src/utils/Interfaces.ts @@ -641,3 +641,14 @@ export interface IQuestion { score: number; sectionId: string; } + +export interface GetSolutionDetailsParams { + id: string; + role: string; +} + +export interface GetUserProjectTemplateParams { + templateId: string; + solutionId: string; + role: string; +}