diff --git a/src/components/Class/ClassForm.js b/src/components/Class/ClassForm.js index ba4d4842c..8b18ba22b 100644 --- a/src/components/Class/ClassForm.js +++ b/src/components/Class/ClassForm.js @@ -525,7 +525,7 @@ function ClassForm({ } axios({ method: METHODS.GET, - url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises`, + url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises/v2`, headers: { accept: "application/json", "version-code": versionCode, diff --git a/src/components/Class/index.js b/src/components/Class/index.js index b6027ad3b..3d8999c9c 100644 --- a/src/components/Class/index.js +++ b/src/components/Class/index.js @@ -207,7 +207,7 @@ function Class({ classToEdit, indicator }) { } axios({ method: METHODS.GET, - url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises`, + url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises/v2`, headers: { accept: "application/json", "version-code": versionCode, diff --git a/src/components/Course/redux/api.js b/src/components/Course/redux/api.js index 01c346c56..45fc2cbcf 100644 --- a/src/components/Course/redux/api.js +++ b/src/components/Course/redux/api.js @@ -33,12 +33,13 @@ export const getCourses = () => { export const getCourseContent = (data) => { const { courseId, lang, versionCode, user } = data; return axios({ - url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises?lang=${lang}`, + url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises/v2?lang=${lang}`, method: METHODS.GET, headers: { "version-code": versionCode, accept: "application/json", - Authorization: user?.data?.token ?? localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token ?? localStorage.getItem("studentAuthToken"), }, // headers: HeaderFactory(token), }); diff --git a/src/components/Header/index.js b/src/components/Header/index.js index b656a97aa..c7ea29d5a 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -187,10 +187,7 @@ const PublicMenuOption = ({ leftDrawer, toggleDrawer }) => { borderRadius: "8px", }} > - + Donate @@ -208,10 +205,7 @@ const PublicMenuOption = ({ leftDrawer, toggleDrawer }) => { target="_blank" style={{ textDecoration: "none", color: "black" }} > - + Scratch diff --git a/src/components/Header/styles.js b/src/components/Header/styles.js index 85aef2edf..ff72ea010 100644 --- a/src/components/Header/styles.js +++ b/src/components/Header/styles.js @@ -59,7 +59,7 @@ const useStyles = makeStyles((theme) => ({ backgroundColor: "#E9F5E9", borderRadius: "8px", }, - } + }, })); export default useStyles; diff --git a/src/components/PathwayCourse/index.js b/src/components/PathwayCourse/index.js index dee08fee6..9c1c8fe44 100644 --- a/src/components/PathwayCourse/index.js +++ b/src/components/PathwayCourse/index.js @@ -151,7 +151,8 @@ function PathwayCourse() { url: `${process.env.REACT_APP_MERAKI_URL}/certificate?pathway_code=${certificateCode}`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, }) .then((response) => { @@ -209,7 +210,8 @@ function PathwayCourse() { url: `${process.env.REACT_APP_MERAKI_URL}/teacher/checking`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, }) .then((response) => { @@ -232,7 +234,8 @@ function PathwayCourse() { url: `${process.env.REACT_APP_MERAKI_URL}/pathways/${pathwayId}/completePortion`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, }) .then((response) => { @@ -439,7 +442,7 @@ function PathwayCourse() { <> ) : ( diff --git a/src/components/PathwayExercise/CourseCompletion/LastCoursePage.js b/src/components/PathwayExercise/CourseCompletion/LastCoursePage.js index 87d2c8e2c..a9921fab8 100644 --- a/src/components/PathwayExercise/CourseCompletion/LastCoursePage.js +++ b/src/components/PathwayExercise/CourseCompletion/LastCoursePage.js @@ -10,7 +10,7 @@ function LastCoursePage({ C4CALastPage }) { const isActive = useMediaQuery("(max-width:" + breakpoints.values.sm + "px)"); const history = useHistory(); const params = useParams(); -const studentAuthToken = localStorage.getItem("studentAuthToken"); + const studentAuthToken = localStorage.getItem("studentAuthToken"); return ( <> diff --git a/src/components/PathwayExercise/ExerciseContent/Assessment/AssessmentContent.js b/src/components/PathwayExercise/ExerciseContent/Assessment/AssessmentContent.js index 6f5534abe..dd2535273 100644 --- a/src/components/PathwayExercise/ExerciseContent/Assessment/AssessmentContent.js +++ b/src/components/PathwayExercise/ExerciseContent/Assessment/AssessmentContent.js @@ -2,8 +2,11 @@ import React, { useEffect, useState } from "react"; import { Grid, Typography, Box, Button, Paper, Stack } from "@mui/material"; import useStyles from "../../styles"; import get from "lodash/get"; - +import { Radio, Checkbox, FormControlLabel, RadioGroup } from "@mui/material"; +import CancelIcon from "@mui/icons-material/Cancel"; +import CheckCircleIcon from "@material-ui/icons/CheckCircle"; import DOMPurify from "dompurify"; +// import { fi } from "date-fns/locale"; function UnsafeHTML(props) { const { html, Container, ...otherProps } = props; const sanitizedHTML = DOMPurify.sanitize(html); @@ -44,8 +47,12 @@ const AssessmentContent = ({ setTriedAgain, submitDisable, submitAssessment, + type, + setType, + Partially_ans, + setWrongAnswer, + finalDesicion, }) => { - const classes = useStyles(); if (content.component === "header") { if (triedAgain > 1) { @@ -90,9 +97,21 @@ const AssessmentContent = ({ ); } else { + const Partially_retry = DOMPurify.sanitize(get(Partially_ans, "value")); return ( - - + <> + {submit && finalDesicion && finalDesicion !== "CORRECT" ? ( + + ) : ( + "" + )} + + + {/* + */} + + + - - - - + ); } } @@ -174,51 +194,173 @@ const AssessmentContent = ({ /> ); } - if (content.component === "options") { return ( - {Object.values(content.value).map((item, index) => { - const text = DOMPurify.sanitize(item.value.slice(2)); - return ( - !submitDisable && setAnswer(item.id)} - > - - - {item.value.slice(0, 2)} - - - - - ); - })} + + {Object.values(content.value).map((item, index) => { + const text = DOMPurify.sanitize(item.value); + const isChecked = answer?.includes(item.id); + const isRadioChecked = + answer?.length === 1 && answer?.includes(item.id); + + const isValuePresent = solution?.some( + (sitem) => sitem.value === item.id + ); + return ( + <> + + 1 + ? isValuePresent + ? answer?.includes(item.id) + ? classes.userSelectedCorrect + : classes.correctAnswer + : answer?.includes(item.id) + ? classes.inCorrectAnswer + : "" + : submit && + answer?.includes(item.id) && + classes.greishOption + } + > + + {}} + checkedIcon={} + /> + ) : answer?.includes(item.id) && + triedAgain > 1 ? ( + + ) : ( + { + if (!submit) { + setAnswer([item.id]); + } + }} + /> + ) + ) : ( + { + if (!submit) { + setAnswer([item.id]); + } + }} + /> + ) + ) : submit ? ( + answer?.includes(item.id) && + isValuePresent && + triedAgain > 1 ? ( + {}} //this is for not changing the state + checkedIcon={} + className={ + submit ? classes.cursorA : classes.cursorP + } + /> + ) : answer?.includes(item.id) && triedAgain > 1 ? ( + + ) : ( + { + if (!submit) { + const updatedAnswer = isChecked + ? answer.filter((id) => id !== item.id) + : [...answer, item.id]; + setAnswer(updatedAnswer); + } + }} + className={ + submit ? classes.cursorA : classes.cursorP + } + /> + ) + ) : ( + { + if (!submit) { + const updatedAnswer = isChecked + ? answer.filter((id) => id !== item.id) + : [...answer, item.id]; + setAnswer(updatedAnswer); + } + }} + className={ + submit ? classes.cursorA : classes.cursorP + } + /> + ) + } + label={ + item.option_type !== "image" ? ( + + ) : ( + Your Alt Text + ) + } + /> + + + + + ); + })} + ); } if (content.component === "solution") { - setSolution(content.value); + setSolution(content?.correct_options_value); + setType(content?.type); + setWrongAnswer(); } return ""; }; diff --git a/src/components/PathwayExercise/ExerciseContent/Assessment/index.js b/src/components/PathwayExercise/ExerciseContent/Assessment/index.js index eed49d110..568c58c6a 100644 --- a/src/components/PathwayExercise/ExerciseContent/Assessment/index.js +++ b/src/components/PathwayExercise/ExerciseContent/Assessment/index.js @@ -13,10 +13,12 @@ function Assessment({ setCourseData, setProgressTrackId, res, + triger, + setTriger, }) { const user = useSelector(({ User }) => User); - const [answer, setAnswer] = useState(res?.selected_option); + const [answer, setAnswer] = useState([]); const [correct, setCorrect] = useState(); const [solution, setSolution] = useState(); const [submit, setSubmit] = useState(); @@ -24,9 +26,48 @@ function Assessment({ const [status, setStatus] = useState(); const [triedAgain, setTriedAgain] = useState(res?.attempt_count); const params = useParams(); + const [type, setType] = useState("single"); + const [wrongAnswer, setWrongAnswer] = useState(); // Assessment submit handler - const submitAssessment = () => { + const isValuesCorrect = (value1, value2) => { + if (value1?.length !== value2?.length) { + return false; // Lengths are different, so they are not the same + } + + for (let i = 0; i < value1?.length; i++) { + if (!value2?.includes(value1[i]?.value)) { + return false; // Elements are different, so they are not the same + } + } + + return true; // Length and elements match, so they are the same + }; + + const isCorrect = isValuesCorrect(solution, answer); + + const calculateSelections = () => { + let correctSelections = 0; + let incorrectSelections = 0; + + answer && + answer.forEach((option) => { + const isCorrect = solution?.some( + (correctOption) => correctOption?.value === option + ); + if (isCorrect) { + correctSelections++; + } else { + incorrectSelections++; + } + }); + + return { correctSelections, incorrectSelections }; + }; + + const { correctSelections, incorrectSelections } = calculateSelections(); + + const submitAssessment = (isCorrect) => { setSubmit(true); // Commented this API to test if progress tracking is working fine now @@ -44,22 +85,22 @@ function Assessment({ // exercise_id: courseData.id, // }, // }); - - if (answer == solution) { + if (isCorrect) { setCorrect(true); setStatus("Pass"); setTriedAgain(triedAgain + 2); setSubmitDisable(true); axios({ method: METHODS.POST, - url: `${process.env.REACT_APP_MERAKI_URL}/assessment/student/result`, + url: `${process.env.REACT_APP_MERAKI_URL}/assessment/student/result/v2`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, data: { assessment_id: exerciseId, - selected_option: answer, + selected_multiple_option: answer, status: "Pass", }, }) @@ -74,14 +115,15 @@ function Assessment({ setSubmitDisable(true); axios({ method: METHODS.POST, - url: `${process.env.REACT_APP_MERAKI_URL}/assessment/student/result`, + url: `${process.env.REACT_APP_MERAKI_URL}/assessment/student/result/v2`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, data: { assessment_id: exerciseId, - selected_option: answer, + selected_multiple_option: answer, status: "Fail", }, }) @@ -90,21 +132,31 @@ function Assessment({ }) .catch((err) => {}); } + setTriger(!triger); }; useEffect(() => { // adding a nullish coalescing operator (??), so that the null value can no effect on the assessment. if (res?.assessment_id === (courseData ?? {}).id) { - console.log(res); if (res?.attempt_status === "CORRECT") { - setAnswer(res?.selected_option); + setAnswer(res?.selected_multiple_option); setCorrect(true); setTriedAgain(2); setStatus("pass"); setSubmitDisable(true); setSubmit(true); } else if (res?.attempt_status === "INCORRECT") { - setAnswer(res?.selected_option); + setAnswer(res?.selected_multiple_option); + setTriedAgain(res?.attempt_count); + setSubmitDisable(true); + setSubmit(true); + } else if (res?.attempt_status === "PARTIALLY_CORRECT") { + setAnswer(res?.selected_multiple_option); + setTriedAgain(res?.attempt_count); + setSubmitDisable(true); + setSubmit(true); + } else if (res?.attempt_status === "PARTIALLY_INCORRECT") { + setAnswer(res?.selected_multiple_option); setTriedAgain(res?.attempt_count); setSubmitDisable(true); setSubmit(true); @@ -112,6 +164,18 @@ function Assessment({ } }, [res, triedAgain]); + // const handleOptionClick = (id) => { + // if (!submitDisable) { + // if (answer.includes(id)) { + // // Item is already selected, so remove it + // setAnswer(answer.filter((itemId) => itemId !== id)); + // } else { + // // Item is not selected, so add it + // setAnswer([...answer, id]); + // } + // } + // }; + return ( {data && @@ -131,6 +195,9 @@ function Assessment({ triedAgain={triedAgain} submitAssessment={submitAssessment} params={params} + type={type} + setType={setType} + setWrongAnswer={setWrongAnswer} /> ))} @@ -139,7 +206,7 @@ function Assessment({ variant="contained" sx={{ width: "256px", p: "8px 16px 8px 16px" }} color={answer ? "primary" : "secondary"} - disabled={!answer} + disabled={answer.length === 0 ? true : false} onClick={submitAssessment} > Submit @@ -148,16 +215,32 @@ function Assessment({ {data && submit && - data.map((content) => { - const dataArr = - content.value && correct - ? content.value.correct - : content.value.incorrect; + data?.map((content) => { + let dataArr = []; + if (data[2]?.type === "single") { + dataArr = + content?.value && correct + ? content?.value?.correct + : content?.value?.incorrect; + } else if (data[2]?.type === "multiple") { + dataArr = + content?.value && res?.attempt_status === "PARTIALLY_CORRECT" + ? content?.value?.partially_correct + : content?.value && + res?.attempt_status === "PARTIALLY_INCORRECT" + ? content?.value?.partially_incorrect + : content?.value && res?.attempt_status === "CORRECT" + ? content?.value?.correct + : content?.value?.incorrect; + } + return ( - content.component === "output" && - dataArr.map((content, index) => ( + content?.component === "output" && + dataArr?.map((content, index) => ( )) ); diff --git a/src/components/PathwayExercise/ExerciseContent/index.js b/src/components/PathwayExercise/ExerciseContent/index.js index dc21d4d29..4aaaf3fe9 100644 --- a/src/components/PathwayExercise/ExerciseContent/index.js +++ b/src/components/PathwayExercise/ExerciseContent/index.js @@ -311,6 +311,7 @@ function ExerciseContent({ const [loading, setLoading] = useState(true); const [openMobile, setOpenMobile] = useState(false); const [assessmentResult, setAssessmentResult] = useState(null); + const [triger, setTriger] = useState(false); const dispatch = useDispatch(); useEffect(() => { @@ -344,7 +345,7 @@ function ExerciseContent({ setCourseData(res?.data?.course?.exercises?.[params.exerciseId]); setCashedData(res?.data?.course?.exercises); }); - }, [courseId, lang]); + }, [courseId, lang, triger]); useEffect(() => { setExercise(cashedData?.[params.exerciseId]); @@ -356,18 +357,26 @@ function ExerciseContent({ if (exercise?.content_type === "assessment") { axios({ method: METHODS.GET, - url: `${process.env.REACT_APP_MERAKI_URL}/assessment/${exercise?.id}/student/result`, + url: `${process.env.REACT_APP_MERAKI_URL}/assessment/${exercise?.id}/student/result/v2`, headers: { accept: "application/json", - Authorization: user?.data?.token || localStorage.getItem("studentAuthToken"), + Authorization: + user?.data?.token || localStorage.getItem("studentAuthToken"), }, - }) - .then((res) => { - setAssessmentResult(res.data); - }) - .catch((err) => {}); + }).then((res) => { + const keyToModify = "selected_multiple_option"; + const newValue = res?.data?.selected_multiple_option; + const modifiedObject = { + ...res, + data: { + ...res.data, + [keyToModify]: newValue, + }, + }; + setAssessmentResult(modifiedObject.data); // passing this after parsing the data. + }); } - }, [exerciseId, exercise?.content_type, exercise]); + }, [triger, exerciseId, exercise?.content_type, exercise]); const enrolledBatches = useSelector((state) => { if (state?.Pathways?.enrolledBatches?.data?.length > 0) { @@ -493,6 +502,8 @@ function ExerciseContent({ )} {exercise && exercise.content_type === "assessment" && ( { - if(localStorage.getItem("studentAuth")|| (user && user?.data?.token)){ - return - }else{ + if (localStorage.getItem("studentAuth") || (user && user?.data?.token)) { + return; + } else { history.push(PATHS.LOGIN); } - - },[]) + }, []); useEffect(() => { setExerciseId(parseInt(params.exerciseId)); axios({ method: METHODS.GET, - url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises`, + url: `${process.env.REACT_APP_MERAKI_URL}/courses/${courseId}/exercises/v2`, headers: { "version-code": versionCode, accept: "application/json", - Authorization: user.data?.token || localStorage.getItem("studentAuthToken") || "", + Authorization: + user.data?.token || localStorage.getItem("studentAuthToken") || "", }, }) .then((res) => { @@ -207,7 +207,8 @@ function PathwayExercise() { headers: { "version-code": versionCode, accept: "application/json", - Authorization: user.data?.token || localStorage.getItem("studentAuthToken") || "", + Authorization: + user.data?.token || localStorage.getItem("studentAuthToken") || "", }, }) .then((res) => { @@ -299,7 +300,10 @@ function PathwayExercise() { headers: { "version-code": versionCode, accept: "application/json", - Authorization: user.data?.token || localStorage.getItem("studentAuthToken") || "", + Authorization: + user.data?.token || + localStorage.getItem("studentAuthToken") || + "", }, data: { pathway_id: params.pathwayId, @@ -322,7 +326,10 @@ function PathwayExercise() { headers: { "version-code": versionCode, accept: "application/json", - Authorization: user.data?.token || localStorage.getItem("studentAuthToken") || "", + Authorization: + user.data?.token || + localStorage.getItem("studentAuthToken") || + "", }, data: { pathway_id: params.pathwayId, @@ -356,7 +363,8 @@ function PathwayExercise() { headers: { "version-code": versionCode, accept: "application/json", - Authorization: user.data?.token || localStorage.getItem("studentAuthToken") || "", + Authorization: + user.data?.token || localStorage.getItem("studentAuthToken") || "", }, data: { exerciseId: course[exerciseId].id, diff --git a/src/components/PathwayExercise/styles.js b/src/components/PathwayExercise/styles.js index 33cb52a6e..5d88823d5 100644 --- a/src/components/PathwayExercise/styles.js +++ b/src/components/PathwayExercise/styles.js @@ -61,16 +61,21 @@ const useStyles = makeStyles((theme) => ({ boxShadow: "0px 1px 2px #48A145, 0px 2px 1px #48A145, 0px 1px 5px #48A145 !important", }, - correctAnswer: { - boxShadow: - "0px 1px 2px #48A145, 0px 2px 1px #48A145, 0px 1px 5px #48A145 !important", + userSelectedCorrect: { + border: "2px solid #48A145", background: "#E9F5E9 !important", }, + correctAnswer: { + border: "2px solid #48A145 !important", + }, inCorrectAnswer: { - boxShadow: - "0px 1px 2px #F44336, 0px 2px 1px #F44336, 0px 1px 5px #F44336 !important", + border: "2px solid #F44336 !important", background: "#FFE5E3 !important", }, + greishOption: { + border: "2px solid #F5F5F5 !important", + background: "#F5F5F5 !important", + }, bottomRow: { display: "flex", justifyContent: "space-between", @@ -108,9 +113,6 @@ const useStyles = makeStyles((theme) => ({ "&:focus": { border: "2px solid #48A145 !important", }, - // "&:hover": { - // border: "1px solid #000 !important", - // }, }, mainHeader: { position: "sticky", @@ -123,6 +125,18 @@ const useStyles = makeStyles((theme) => ({ position: "sticky", marginTop: 104, }, + optionImg: { + objectFit: "cover", + width: "100%", + height: "140px", + borderRadius: "8px", + }, + cursorA: { + cursor: "default !important", + }, + cursorP: { + cursor: "pointer !important", + }, })); export default useStyles; diff --git a/src/pages/Home/index.js b/src/pages/Home/index.js index 66f85d422..6eed413b0 100644 --- a/src/pages/Home/index.js +++ b/src/pages/Home/index.js @@ -40,7 +40,6 @@ function Home() { const roles = useSelector(selectRolesData); const history = useHistory(); - useEffect(() => { const urlParams = new URLSearchParams(window.location.search); const studentAuthParam = urlParams.get("studentAuth"); @@ -70,7 +69,6 @@ function Home() { } }, []); - useEffect(() => { dispatch(pathwayActions.getPathways()); }, [dispatch]); diff --git a/src/pages/Login/index.js b/src/pages/Login/index.js index 5a37800c9..6e7542e85 100644 --- a/src/pages/Login/index.js +++ b/src/pages/Login/index.js @@ -114,7 +114,6 @@ function Login(props) { } if (rolesList != false) { - if (!(rolesList.includes("partner") || rolesList.includes("admin"))) { if (utm_medium.includes("amazon")) { return ; diff --git a/src/routing/Routes/OnlyLoggedIn.js b/src/routing/Routes/OnlyLoggedIn.js index 198e04f95..6b88af915 100644 --- a/src/routing/Routes/OnlyLoggedIn.js +++ b/src/routing/Routes/OnlyLoggedIn.js @@ -24,7 +24,6 @@ const OnlyLoggedIn = (passedProps) => { // // Render the Component if the user is not authenticated but studentAuth is present // return // } - } catch (error) { //console.error('Error accessing localStorage:', error); return {};