Took care of some warnings

This commit is contained in:
Tiago Ribeiro
2024-08-20 10:07:18 +01:00
parent 75a45108a2
commit 97b533bd3a
5 changed files with 700 additions and 657 deletions

View File

@@ -1,357 +1,371 @@
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
import { Tab } from "@headlessui/react";
import { AiOutlineFileSearch } from "react-icons/ai";
import { MdOutlinePlaylistAddCheckCircle, MdOutlineSelfImprovement } from "react-icons/md";
import { BsChatLeftDots } from "react-icons/bs";
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
import axios from "axios";
import {Tab} from "@headlessui/react";
import {AiOutlineFileSearch} from "react-icons/ai";
import {MdOutlinePlaylistAddCheckCircle, MdOutlineSelfImprovement} from "react-icons/md";
import {BsChatLeftDots} from "react-icons/bs";
import Button from "@/components/Low/Button";
import clsx from "clsx";
import Exercise from "@/training/Exercise";
import TrainingScore from "@/training/TrainingScore";
import { ITrainingContent, ITrainingTip } from "@/training/TrainingInterfaces";
import { Stat, User } from '@/interfaces/user';
import {ITrainingContent, ITrainingTip} from "@/training/TrainingInterfaces";
import {Stat, User} from "@/interfaces/user";
import Head from "next/head";
import Layout from "@/components/High/Layout";
import { ToastContainer } from 'react-toastify';
import { withIronSessionSsr } from "iron-session/next";
import { shouldRedirectHome } from "@/utils/navigation.disabled";
import { sessionOptions } from "@/lib/session";
import qs from 'qs';
import StatsGridItem from '@/components/StatGridItem';
import {ToastContainer} from "react-toastify";
import {withIronSessionSsr} from "iron-session/next";
import {shouldRedirectHome} from "@/utils/navigation.disabled";
import {sessionOptions} from "@/lib/session";
import qs from "qs";
import StatsGridItem from "@/components/StatGridItem";
import useExamStore from "@/stores/examStore";
import { usePDFDownload } from "@/hooks/usePDFDownload";
import useAssignments from '@/hooks/useAssignments';
import useUsers from '@/hooks/useUsers';
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';
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;
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
const user = req.session.user;
if (!user || !user.isVerified) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
if (!user || !user.isVerified) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
if (shouldRedirectHome(user)) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
if (shouldRedirectHome(user)) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: { user: req.session.user },
};
return {
props: {user: req.session.user},
};
}, sessionOptions);
const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
// Record stuff
const setExams = useExamStore((state) => state.setExams);
const setShowSolutions = useExamStore((state) => state.setShowSolutions);
const setUserSolutions = useExamStore((state) => state.setUserSolutions);
const setSelectedModules = useExamStore((state) => state.setSelectedModules);
const setInactivity = useExamStore((state) => state.setInactivity);
const setTimeSpent = useExamStore((state) => state.setTimeSpent);
const renderPdfIcon = usePDFDownload("stats");
const TrainingContent: React.FC<{user: User}> = ({user}) => {
// Record stuff
const setExams = useExamStore((state) => state.setExams);
const setShowSolutions = useExamStore((state) => state.setShowSolutions);
const setUserSolutions = useExamStore((state) => state.setUserSolutions);
const setSelectedModules = useExamStore((state) => state.setSelectedModules);
const setInactivity = useExamStore((state) => state.setInactivity);
const setTimeSpent = useExamStore((state) => state.setTimeSpent);
const renderPdfIcon = usePDFDownload("stats");
const [trainingContent, setTrainingContent] = useState<ITrainingContent | null>(null);
const [loading, setLoading] = useState(true);
const [trainingTips, setTrainingTips] = useState<ITrainingTip[]>([]);
const [currentTipIndex, setCurrentTipIndex] = useState(0);
const { assignments } = useAssignments({});
const { users } = useUsers();
const [trainingContent, setTrainingContent] = useState<ITrainingContent | null>(null);
const [loading, setLoading] = useState(true);
const [trainingTips, setTrainingTips] = useState<ITrainingTip[]>([]);
const [currentTipIndex, setCurrentTipIndex] = useState(0);
const {assignments} = useAssignments({});
const {users} = useUsers();
const router = useRouter();
const { id } = router.query;
const router = useRouter();
const {id} = router.query;
useEffect(() => {
const fetchTrainingContent = async () => {
if (!id || typeof id !== 'string') return;
useEffect(() => {
const fetchTrainingContent = async () => {
if (!id || typeof id !== "string") return;
try {
setLoading(true);
const response = await axios.get<ITrainingContent>(`/api/training/${id}`);
const trainingContent = response.data;
try {
setLoading(true);
const response = await axios.get<ITrainingContent>(`/api/training/${id}`);
const trainingContent = response.data;
const withExamsStats = {
...trainingContent,
exams: await Promise.all(trainingContent.exams.map(async (exam) => {
const stats = await Promise.all(exam.stat_ids.map(async (statId) => {
const statResponse = await axios.get<Stat>(`/api/stats/${statId}`);
return statResponse.data;
}));
return { ...exam, stats };
}))
};
const withExamsStats = {
...trainingContent,
exams: await Promise.all(
trainingContent.exams.map(async (exam) => {
const stats = await Promise.all(
exam.stat_ids.map(async (statId) => {
const statResponse = await axios.get<Stat>(`/api/stats/${statId}`);
return statResponse.data;
}),
);
return {...exam, stats};
}),
),
};
const tips = await axios.get<ITrainingTip[]>('/api/training/walkthrough', {
params: { ids: trainingContent.tip_ids },
paramsSerializer: params => qs.stringify(params, { arrayFormat: 'repeat' })
});
setTrainingTips(tips.data);
setTrainingContent(withExamsStats);
} catch (error) {
router.push('/training');
} finally {
setLoading(false);
}
};
const tips = await axios.get<ITrainingTip[]>("/api/training/walkthrough", {
params: {ids: trainingContent.tip_ids},
paramsSerializer: (params) => qs.stringify(params, {arrayFormat: "repeat"}),
});
setTrainingTips(tips.data);
setTrainingContent(withExamsStats);
} catch (error) {
router.push("/training");
} finally {
setLoading(false);
}
};
fetchTrainingContent();
}, [id]);
fetchTrainingContent();
}, [id, router]);
const handleNext = () => {
setCurrentTipIndex((prevIndex) => (prevIndex + 1));
};
const handleNext = () => {
setCurrentTipIndex((prevIndex) => prevIndex + 1);
};
const handlePrevious = () => {
setCurrentTipIndex((prevIndex) => (prevIndex - 1));
};
const handlePrevious = () => {
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 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];
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");
}
});
}
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>
<title>Training | EnCoach</title>
<meta
name="description"
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<ToastContainer />
return (
<>
<Head>
<title>Training | EnCoach</title>
<meta
name="description"
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<ToastContainer />
<Layout user={user}>
{loading ? (
<div className="absolute left-1/2 top-1/2 flex h-fit w-fit -translate-x-1/2 -translate-y-1/2 animate-pulse flex-col items-center gap-12">
<span className="loading loading-infinity w-32 bg-mti-green-light" />
</div>
) : (trainingContent && (
<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='380px'
height='150px'
examNumber={examIndex + 1}
stats={exam.stats || []}
timestamp={exam.date}
user={user}
assignments={assignments}
users={users}
setExams={setExams}
setShowSolutions={setShowSolutions}
setUserSolutions={setUserSolutions}
setSelectedModules={setSelectedModules}
setInactivity={setInactivity}
setTimeSpent={setTimeSpent}
renderPdfIcon={renderPdfIcon}
/>
))}
</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>
<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>
<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>
</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>
</div>
<Tab.Group>
<div className="flex flex-col gap-4">
<Tab.List>
<div className="flex flex-row gap-6 overflow-x-auto pb-1 training-scrollbar">
{trainingContent.weak_areas.map((x, index) => (
<Tab
key={index}
className={({ selected }) =>
clsx(
'text-[#53B2F9] pb-2 border-b-2',
'focus:outline-none',
selected ? 'border-[#1B78BE]' : 'border-[#1B78BE0F]'
)
}
>
{x.area}
</Tab>
))}
</div>
</Tab.List>
<Tab.Panels>
{trainingContent.weak_areas.map((x, index) => (
<Tab.Panel
key={index}
className="p-3 bg-[#FBFBFB] rounded-lg border border-[#0000000F]"
>
<p>{x.comment}</p>
</Tab.Panel>
))}
</Tab.Panels>
</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>
<Layout user={user}>
{loading ? (
<div className="absolute left-1/2 top-1/2 flex h-fit w-fit -translate-x-1/2 -translate-y-1/2 animate-pulse flex-col items-center gap-12">
<span className="loading loading-infinity w-32 bg-mti-green-light" />
</div>
) : (
trainingContent && (
<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="380px"
height="150px"
examNumber={examIndex + 1}
stats={exam.stats || []}
timestamp={exam.date}
user={user}
assignments={assignments}
users={users}
setExams={setExams}
setShowSolutions={setShowSolutions}
setUserSolutions={setUserSolutions}
setSelectedModules={setSelectedModules}
setInactivity={setInactivity}
setTimeSpent={setTimeSpent}
renderPdfIcon={renderPdfIcon}
/>
))}
</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>
<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>
<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>
</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>
</div>
<Tab.Group>
<div className="flex flex-col gap-4">
<Tab.List>
<div className="flex flex-row gap-6 overflow-x-auto pb-1 training-scrollbar">
{trainingContent.weak_areas.map((x, index) => (
<Tab
key={index}
className={({selected}) =>
clsx(
"text-[#53B2F9] pb-2 border-b-2",
"focus:outline-none",
selected ? "border-[#1B78BE]" : "border-[#1B78BE0F]",
)
}>
{x.area}
</Tab>
))}
</div>
</Tab.List>
<Tab.Panels>
{trainingContent.weak_areas.map((x, index) => (
<Tab.Panel key={index} className="p-3 bg-[#FBFBFB] rounded-lg border border-[#0000000F]">
<p>{x.comment}</p>
</Tab.Panel>
))}
</Tab.Panels>
</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 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 -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]} />
</div>
<div className="self-end flex justify-between w-full gap-8 bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={handlePrevious}
disabled={currentTipIndex == 0}
className="max-w-[200px] self-end w-full">
Previous
</Button>
<Button
color="purple"
disabled={currentTipIndex == (trainingTips.length - 1)}
onClick={handleNext}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
</div>
</div>
</div>
))}
</Layout>
</>
);
}
<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 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 -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]} />
</div>
<div className="self-end flex justify-between w-full gap-8 bottom-8 left-0 px-8">
<Button
color="purple"
variant="outline"
onClick={handlePrevious}
disabled={currentTipIndex == 0}
className="max-w-[200px] self-end w-full">
Previous
</Button>
<Button
color="purple"
disabled={currentTipIndex == trainingTips.length - 1}
onClick={handleNext}
className="max-w-[200px] self-end w-full">
Next
</Button>
</div>
</div>
</div>
</div>
)
)}
</Layout>
</>
);
};
export default TrainingContent;