Fixed the training content view
This commit is contained in:
@@ -24,6 +24,12 @@ import { usePDFDownload } from "@/hooks/usePDFDownload";
|
||||
import useAssignments from '@/hooks/useAssignments';
|
||||
import useUsers from '@/hooks/useUsers';
|
||||
import Dropdown from "@/components/Dropdown";
|
||||
import InfiniteCarousel from '@/components/InfiniteCarousel';
|
||||
import { LuExternalLink } from "react-icons/lu";
|
||||
import { uniqBy } from 'lodash';
|
||||
import { getExamById } from '@/utils/exams';
|
||||
import { convertToUserSolutions } from '@/utils/stats';
|
||||
import { sortByModule } from '@/utils/moduleUtils';
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(({ req, res }) => {
|
||||
const user = req.session.user;
|
||||
@@ -68,12 +74,9 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
const { assignments } = useAssignments({});
|
||||
const { users } = useUsers();
|
||||
|
||||
|
||||
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTrainingContent = async () => {
|
||||
if (!id || typeof id !== 'string') return;
|
||||
@@ -118,6 +121,32 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
setCurrentTipIndex((prevIndex) => (prevIndex - 1));
|
||||
};
|
||||
|
||||
const goToExam = (examNumber: number) => {
|
||||
const stats = trainingContent?.exams[examNumber].stats!;
|
||||
const examPromises = uniqBy(stats, "exam").map((stat) => {
|
||||
return getExamById(stat.module, stat.exam);
|
||||
});
|
||||
|
||||
const { timeSpent, inactivity } = stats[0];
|
||||
|
||||
Promise.all(examPromises).then((exams) => {
|
||||
if (exams.every((x) => !!x)) {
|
||||
if (!!timeSpent) setTimeSpent(timeSpent);
|
||||
if (!!inactivity) setInactivity(inactivity);
|
||||
setUserSolutions(convertToUserSolutions(stats));
|
||||
setShowSolutions(true);
|
||||
setExams(exams.map((x) => x!).sort(sortByModule));
|
||||
setSelectedModules(
|
||||
exams
|
||||
.map((x) => x!)
|
||||
.sort(sortByModule)
|
||||
.map((x) => x!.module),
|
||||
);
|
||||
router.push("/exercises");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -137,13 +166,25 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
<span className="loading loading-infinity w-32 bg-mti-green-light" />
|
||||
</div>
|
||||
) : (trainingContent && (
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="flex h-screen flex-col gap-4">
|
||||
<div className='flex flex-row h-[15%] gap-4'>
|
||||
{/*<Carousel itemsPerFrame={4} itemsPerScroll={4}>*/}
|
||||
<div className="flex flex-col gap-8">
|
||||
<div className="flex flex-row items-center">
|
||||
<span className="bg-gray-200 text-gray-800 px-3 py-0.5 rounded-full font-semibold text-lg mr-2">{trainingContent.exams.length}</span>
|
||||
<span>Exams Selected</span>
|
||||
</div>
|
||||
<div className='h-[15vh] mb-4'>
|
||||
<InfiniteCarousel height="150px"
|
||||
overlay={
|
||||
<LuExternalLink size={20} />
|
||||
}
|
||||
overlayFunc={goToExam}
|
||||
overlayClassName='bottom-6 right-5 cursor-pointer'
|
||||
>
|
||||
{trainingContent.exams.map((exam, examIndex) => (
|
||||
<StatsGridItem
|
||||
key={`exam-${examIndex}`}
|
||||
width='350px'
|
||||
height='150px'
|
||||
examNumber={examIndex + 1}
|
||||
stats={exam.stats || []}
|
||||
timestamp={exam.date}
|
||||
user={user}
|
||||
@@ -158,79 +199,51 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
renderPdfIcon={renderPdfIcon}
|
||||
/>
|
||||
))}
|
||||
{/* </Carousel> */}
|
||||
</div>
|
||||
<div className='flex flex-col h-[75%]' style={{ maxHeight: '85%' }}>
|
||||
<div className='flex flex-row gap-10 -md:flex-col'>
|
||||
<div className="rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full max-h-full">
|
||||
<div className="flex flex-row items-center mb-6 gap-1">
|
||||
<MdOutlinePlaylistAddCheckCircle color={"#40A1EA"} size={26} />
|
||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>General Evaluation</h2>
|
||||
</div>
|
||||
<TrainingScore
|
||||
trainingContent={trainingContent}
|
||||
gridView={false}
|
||||
/>
|
||||
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
||||
<div className="flex flex-row gap-2 items-center mb-6">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_112_168" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_112_168)">
|
||||
<path d="M4 21C3.45 21 2.97917 20.8042 2.5875 20.4125C2.19583 20.0208 2 19.55 2 19V7H4V19H19V21H4ZM8 17C7.45 17 6.97917 16.8042 6.5875 16.4125C6.19583 16.0208 6 15.55 6 15V3H23V15C23 15.55 22.8042 16.0208 22.4125 16.4125C22.0208 16.8042 21.55 17 21 17H8ZM8 15H21V5H8V15ZM10 12H14V7H10V12ZM15 12H19V10H15V12ZM15 9H19V7H15V9Z" fill="#53B2F9" />
|
||||
</g>
|
||||
</svg>
|
||||
<h3 className="text-xl font-semibold text-[#40A1EA]">Performance Breakdown by Exam:</h3>
|
||||
</div>
|
||||
<ul>
|
||||
{trainingContent.exams.flatMap((exam, index) => (
|
||||
<li key={index} className="flex flex-col mb-2 bg-[#22E1B30F] p-4 rounded-xl border">
|
||||
<div className="flex flex-row font-semibold border-b-2 border-[#D9D9D929] text-[#22E1B3] mb-2">
|
||||
<span className="border-r-2 border-[#D9D9D929] pr-2">Exam {index + 1}</span>
|
||||
<span className="pl-2">{exam.score}%</span>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<BsChatLeftDots size={16} />
|
||||
<p className="text-sm">{exam.performance_comment}</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</InfiniteCarousel>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex flex-row gap-10 -md:flex-col h-full'>
|
||||
<div className="flex flex-col rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full max-h-full">
|
||||
<div className="flex flex-row items-center mb-6 gap-1">
|
||||
<MdOutlinePlaylistAddCheckCircle color={"#40A1EA"} size={26} />
|
||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>General Evaluation</h2>
|
||||
</div>
|
||||
<div className="rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full">
|
||||
<div className="flex flex-row items-center mb-4 gap-1">
|
||||
<MdOutlineSelfImprovement color={"#40A1EA"} size={24} />
|
||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>Subjects that Need Improvement</h2>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#FBFBFB] border rounded-xl p-4 max-h-[500px] overflow-y-auto scrollbar-hide">
|
||||
<div className='flex flex-col'>
|
||||
<div className="flex flex-row items-center gap-1 mb-4">
|
||||
<div className="flex items-center justify-center w-[48px] h-[48px]">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_112_445" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_112_445)">
|
||||
<path d="M6 17H11V15H6V17ZM16 17H18V15H16V17ZM6 13H11V11H6V13ZM16 13H18V7H16V13ZM6 9H11V7H6V9ZM4 21C3.45 21 2.97917 20.8042 2.5875 20.4125C2.19583 20.0208 2 19.55 2 19V5C2 4.45 2.19583 3.97917 2.5875 3.5875C2.97917 3.19583 3.45 3 4 3H20C20.55 3 21.0208 3.19583 21.4125 3.5875C21.8042 3.97917 22 4.45 22 5V19C22 19.55 21.8042 20.0208 21.4125 20.4125C21.0208 20.8042 20.55 21 20 21H4ZM4 19H20V5H4V19Z" fill="#1C1B1F" />
|
||||
</g>
|
||||
</svg>
|
||||
<TrainingScore
|
||||
trainingContent={trainingContent}
|
||||
gridView={false}
|
||||
/>
|
||||
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
||||
<div className="flex flex-row gap-2 items-center mb-6">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_112_168" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_112_168)">
|
||||
<path d="M4 21C3.45 21 2.97917 20.8042 2.5875 20.4125C2.19583 20.0208 2 19.55 2 19V7H4V19H19V21H4ZM8 17C7.45 17 6.97917 16.8042 6.5875 16.4125C6.19583 16.0208 6 15.55 6 15V3H23V15C23 15.55 22.8042 16.0208 22.4125 16.4125C22.0208 16.8042 21.55 17 21 17H8ZM8 15H21V5H8V15ZM10 12H14V7H10V12ZM15 12H19V10H15V12ZM15 9H19V7H15V9Z" fill="#53B2F9" />
|
||||
</g>
|
||||
</svg>
|
||||
<h3 className="text-xl font-semibold text-[#40A1EA]">Performance Breakdown by Exam:</h3>
|
||||
</div>
|
||||
<ul className='overflow-auto scrollbar-hide flex-grow'>
|
||||
{trainingContent.exams.flatMap((exam, index) => (
|
||||
<li key={index} className="flex flex-col mb-2 bg-[#22E1B30F] p-4 rounded-xl border">
|
||||
<div className="flex flex-row font-semibold border-b-2 border-[#D9D9D929] text-[#22E1B3] mb-2">
|
||||
<div className='flex items-center border-r-2 border-[#D9D9D929] pr-2'>
|
||||
<span className='mr-1'>Exam</span>
|
||||
<span className="font-semibold bg-gray-200 text-gray-800 px-2 rounded-full text-sm">{index + 1}</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold">Detailed Breakdown</h3>
|
||||
<span className="pl-2">{exam.score}%</span>
|
||||
</div>
|
||||
<ul className="space-y-4 pb-2">
|
||||
{trainingContent.exams.map((exam, index) => (
|
||||
<li key={index} className="border rounded-lg bg-white">
|
||||
<Dropdown title={`Exam ${index + 1}`}>
|
||||
<span>{exam.detailed_summary}</span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<BsChatLeftDots size={16} />
|
||||
<p className="text-sm">{exam.performance_comment}</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex flex-col rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full">
|
||||
<div className='flex flex-col'>
|
||||
<div className="flex flex-row items-center mb-4 gap-1">
|
||||
<AiOutlineFileSearch color="#40A1EA" size={24} />
|
||||
<h3 className="text-xl font-semibold text-[#40A1EA]">Identified Weak Areas</h3>
|
||||
@@ -238,7 +251,7 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
<Tab.Group>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Tab.List>
|
||||
<div className="flex flex-row gap-6">
|
||||
<div className="flex flex-row gap-6 overflow-x-auto pb-1 training-scrollbar">
|
||||
{trainingContent.weak_areas.map((x, index) => (
|
||||
<Tab
|
||||
key={index}
|
||||
@@ -268,10 +281,47 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
</div>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
||||
<div className="flex flex-row items-center mb-4 gap-1">
|
||||
<MdOutlineSelfImprovement color={"#40A1EA"} size={24} />
|
||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>Subjects that Need Improvement</h2>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-grow bg-[#FBFBFB] border rounded-xl p-4">
|
||||
<div className='flex flex-col'>
|
||||
<div className="flex flex-row items-center gap-1 mb-4">
|
||||
<div className="flex items-center justify-center w-[48px] h-[48px]">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_112_445" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_112_445)">
|
||||
<path d="M6 17H11V15H6V17ZM16 17H18V15H16V17ZM6 13H11V11H6V13ZM16 13H18V7H16V13ZM6 9H11V7H6V9ZM4 21C3.45 21 2.97917 20.8042 2.5875 20.4125C2.19583 20.0208 2 19.55 2 19V5C2 4.45 2.19583 3.97917 2.5875 3.5875C2.97917 3.19583 3.45 3 4 3H20C20.55 3 21.0208 3.19583 21.4125 3.5875C21.8042 3.97917 22 4.45 22 5V19C22 19.55 21.8042 20.0208 21.4125 20.4125C21.0208 20.8042 20.55 21 20 21H4ZM4 19H20V5H4V19Z" fill="#1C1B1F" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold">Detailed Breakdown</h3>
|
||||
</div>
|
||||
<ul className="flex flex-col flex-grow space-y-4 pb-2 max-h-[350px] overflow-y-auto scrollbar-hide">
|
||||
{trainingContent.exams.map((exam, index) => (
|
||||
<li key={index} className="border rounded-lg bg-white">
|
||||
<Dropdown title={
|
||||
<div className='flex flex-row items-center'>
|
||||
<span className="mr-1">Exam</span>
|
||||
<span className="font-semibold bg-gray-200 text-gray-800 px-2 rounded-full text-sm mt-0.5">{index + 1}</span>
|
||||
</div>
|
||||
} open={index == 0}>
|
||||
<span>{exam.detailed_summary}</span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<div className="flex -md:hidden">
|
||||
<div className="rounded-3xl p-6 shadow-training-inset w-full">
|
||||
<div className="flex flex-col p-10">
|
||||
<Exercise key={currentTipIndex} {...trainingTips[currentTipIndex]} />
|
||||
@@ -294,6 +344,7 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user