Fixed the training content view
This commit is contained in:
643
package-lock.json
generated
643
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@
|
|||||||
"@types/node": "18.13.0",
|
"@types/node": "18.13.0",
|
||||||
"@types/react": "18.0.27",
|
"@types/react": "18.0.27",
|
||||||
"@types/react-dom": "18.0.10",
|
"@types/react-dom": "18.0.10",
|
||||||
|
"@use-gesture/react": "^10.3.1",
|
||||||
"axios": "^1.3.5",
|
"axios": "^1.3.5",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
@@ -67,14 +68,12 @@
|
|||||||
"react-phone-number-input": "^3.3.6",
|
"react-phone-number-input": "^3.3.6",
|
||||||
"react-player": "^2.12.0",
|
"react-player": "^2.12.0",
|
||||||
"react-select": "^5.7.5",
|
"react-select": "^5.7.5",
|
||||||
"react-slick": "^0.30.2",
|
|
||||||
"react-string-replace": "^1.1.0",
|
"react-string-replace": "^1.1.0",
|
||||||
"react-toastify": "^9.1.2",
|
"react-toastify": "^9.1.2",
|
||||||
"react-tooltip": "^5.27.1",
|
"react-tooltip": "^5.27.1",
|
||||||
"react-xarrows": "^2.0.2",
|
"react-xarrows": "^2.0.2",
|
||||||
"read-excel-file": "^5.7.1",
|
"read-excel-file": "^5.7.1",
|
||||||
"short-unique-id": "5.0.2",
|
"short-unique-id": "5.0.2",
|
||||||
"slick-carousel": "^1.8.1",
|
|
||||||
"stripe": "^13.10.0",
|
"stripe": "^13.10.0",
|
||||||
"swr": "^2.1.3",
|
"swr": "^2.1.3",
|
||||||
"tailwind-scrollbar-hide": "^1.1.7",
|
"tailwind-scrollbar-hide": "^1.1.7",
|
||||||
@@ -94,7 +93,6 @@
|
|||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/react-csv": "^1.1.10",
|
"@types/react-csv": "^1.1.10",
|
||||||
"@types/react-datepicker": "^4.15.1",
|
"@types/react-datepicker": "^4.15.1",
|
||||||
"@types/react-slick": "^0.23.13",
|
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.1",
|
||||||
"@types/wavesurfer.js": "^6.0.6",
|
"@types/wavesurfer.js": "^6.0.6",
|
||||||
"@wixc3/react-board": "^2.2.0",
|
"@wixc3/react-board": "^2.2.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, ReactNode, useRef, useEffect } from 'react';
|
|||||||
import { animated, useSpring } from '@react-spring/web';
|
import { animated, useSpring } from '@react-spring/web';
|
||||||
|
|
||||||
interface DropdownProps {
|
interface DropdownProps {
|
||||||
title: string;
|
title: ReactNode;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
contentWrapperClassName?: string;
|
contentWrapperClassName?: string;
|
||||||
@@ -81,4 +81,4 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Dropdown;
|
export default Dropdown;
|
||||||
|
|||||||
168
src/components/InfiniteCarousel.tsx
Normal file
168
src/components/InfiniteCarousel.tsx
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import React, { useRef, useEffect, useState, useCallback, ReactNode } from 'react';
|
||||||
|
import { useSpring, animated } from '@react-spring/web';
|
||||||
|
import { useDrag } from '@use-gesture/react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
interface InfiniteCarouselProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
height: string;
|
||||||
|
speed?: number;
|
||||||
|
gap?: number;
|
||||||
|
overlay?: ReactNode;
|
||||||
|
overlayFunc?: (index: number) => void;
|
||||||
|
overlayClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfiniteCarousel: React.FC<InfiniteCarouselProps> = ({
|
||||||
|
children,
|
||||||
|
height,
|
||||||
|
speed = 20000,
|
||||||
|
gap = 16,
|
||||||
|
overlay = undefined,
|
||||||
|
overlayFunc = undefined,
|
||||||
|
overlayClassName = ""
|
||||||
|
}) => {
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [containerWidth, setContainerWidth] = useState<number>(0);
|
||||||
|
const itemCount = React.Children.count(children);
|
||||||
|
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||||
|
const [itemWidth, setItemWidth] = useState<number>(0);
|
||||||
|
const [isInfinite, setIsInfinite] = useState<boolean>(true);
|
||||||
|
const dragStartX = useRef<number>(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (containerRef.current) {
|
||||||
|
const containerWidth = containerRef.current.clientWidth;
|
||||||
|
setContainerWidth(containerWidth);
|
||||||
|
|
||||||
|
const firstChild = containerRef.current.firstElementChild?.firstElementChild as HTMLElement;
|
||||||
|
if (firstChild) {
|
||||||
|
const childWidth = firstChild.offsetWidth;
|
||||||
|
setItemWidth(childWidth);
|
||||||
|
|
||||||
|
const totalContentWidth = (childWidth + gap) * itemCount - gap;
|
||||||
|
setIsInfinite(totalContentWidth > containerWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
}, [gap, itemCount]);
|
||||||
|
|
||||||
|
const totalWidth = (itemWidth + gap) * itemCount;
|
||||||
|
|
||||||
|
const [{ x }, api] = useSpring(() => ({
|
||||||
|
from: { x: 0 },
|
||||||
|
to: { x: -totalWidth },
|
||||||
|
config: { duration: speed },
|
||||||
|
loop: true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const startAnimation = useCallback(() => {
|
||||||
|
if (isInfinite) {
|
||||||
|
api.start({
|
||||||
|
from: { x: x.get() },
|
||||||
|
to: { x: x.get() - totalWidth },
|
||||||
|
config: { duration: speed },
|
||||||
|
loop: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
api.stop();
|
||||||
|
api.start({ x: 0, immediate: true });
|
||||||
|
}
|
||||||
|
}, [api, x, totalWidth, speed, isInfinite]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (containerWidth > 0 && !isDragging) {
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
}, [containerWidth, isDragging, startAnimation]);
|
||||||
|
|
||||||
|
const bind = useDrag(({ down, movement: [mx], first }) => {
|
||||||
|
if (!isInfinite) return;
|
||||||
|
if (first) {
|
||||||
|
setIsDragging(true);
|
||||||
|
api.stop();
|
||||||
|
dragStartX.current = x.get();
|
||||||
|
}
|
||||||
|
if (down) {
|
||||||
|
let newX = dragStartX.current + mx;
|
||||||
|
newX = ((newX % totalWidth) + totalWidth) % totalWidth;
|
||||||
|
if (newX > 0) newX -= totalWidth;
|
||||||
|
api.start({ x: newX, immediate: true });
|
||||||
|
} else {
|
||||||
|
setIsDragging(false);
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
filterTaps: true,
|
||||||
|
from: () => [x.get(), 0],
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="overflow-hidden relative select-none"
|
||||||
|
style={{ height, touchAction: 'pan-y' }}
|
||||||
|
ref={containerRef}
|
||||||
|
{...(isInfinite ? bind() : {})}
|
||||||
|
>
|
||||||
|
<animated.div
|
||||||
|
className="flex"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
willChange: 'transform',
|
||||||
|
transform: isInfinite
|
||||||
|
? x.to((x) => `translate3d(${x}px, 0, 0)`)
|
||||||
|
: 'none',
|
||||||
|
gap: `${gap}px`,
|
||||||
|
width: 'fit-content',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{React.Children.map(children, (child, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="flex-shrink-0 relative"
|
||||||
|
>
|
||||||
|
{overlay !== undefined && overlayFunc !== undefined && (
|
||||||
|
<div className={clsx('absolute', overlayClassName)} onClick={() => overlayFunc(i)}>
|
||||||
|
{overlay}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className="select-none"
|
||||||
|
style={{ pointerEvents: 'none' }}
|
||||||
|
>
|
||||||
|
{child}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{isInfinite && React.Children.map(children, (child, i) => (
|
||||||
|
<div
|
||||||
|
key={`clone-${i}`}
|
||||||
|
className="flex-shrink-0 relative"
|
||||||
|
>
|
||||||
|
{overlay !== undefined && overlayFunc !== undefined && (
|
||||||
|
<div className={clsx('absolute', overlayClassName)} onClick={() => overlayFunc(i)}>
|
||||||
|
{overlay}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className="select-none"
|
||||||
|
style={{ pointerEvents: 'none' }}
|
||||||
|
>
|
||||||
|
{child}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</animated.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InfiniteCarousel;
|
||||||
@@ -175,6 +175,9 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, u
|
|||||||
{checkAccess(user, getTypesOfUser(["agent"]), "viewRecords") && (
|
{checkAccess(user, getTypesOfUser(["agent"]), "viewRecords") && (
|
||||||
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={true} />
|
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={true} />
|
||||||
)}
|
)}
|
||||||
|
{checkAccess(user, getTypesOfUser(["agent"]), "viewRecords") && (
|
||||||
|
<Nav disabled={disableNavigation} Icon={CiDumbbell} label="Training" path={path} keyPath="/training" isMinimized={true} />
|
||||||
|
)}
|
||||||
{checkAccess(user, getTypesOfUser(["student"])) && (
|
{checkAccess(user, getTypesOfUser(["student"])) && (
|
||||||
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Settings" path={path} keyPath="/settings" isMinimized={true} />
|
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Settings" path={path} keyPath="/settings" isMinimized={true} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { Exam, UserSolution } from '@/interfaces/exam';
|
|||||||
import ModuleBadge from './ModuleBadge';
|
import ModuleBadge from './ModuleBadge';
|
||||||
|
|
||||||
const formatTimestamp = (timestamp: string | number) => {
|
const formatTimestamp = (timestamp: string | number) => {
|
||||||
const time = typeof timestamp === "string" ? parseInt(timestamp) : timestamp;
|
const time = typeof timestamp === "string" ? parseInt(timestamp) : timestamp;
|
||||||
const date = moment(time);
|
const date = moment(time);
|
||||||
const formatter = "YYYY/MM/DD - HH:mm";
|
const formatter = "YYYY/MM/DD - HH:mm";
|
||||||
return date.format(formatter);
|
return date.format(formatter);
|
||||||
@@ -68,6 +68,9 @@ const aggregateScoresByModule = (stats: Stat[]): { module: Module; total: number
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface StatsGridItemProps {
|
interface StatsGridItemProps {
|
||||||
|
width?: string | undefined;
|
||||||
|
height?: string | undefined;
|
||||||
|
examNumber?: number | undefined;
|
||||||
stats: Stat[];
|
stats: Stat[];
|
||||||
timestamp: string | number;
|
timestamp: string | number;
|
||||||
user: User,
|
user: User,
|
||||||
@@ -100,7 +103,10 @@ const StatsGridItem: React.FC<StatsGridItemProps> = ({
|
|||||||
setSelectedModules,
|
setSelectedModules,
|
||||||
setInactivity,
|
setInactivity,
|
||||||
setTimeSpent,
|
setTimeSpent,
|
||||||
renderPdfIcon
|
renderPdfIcon,
|
||||||
|
width = undefined,
|
||||||
|
height = undefined,
|
||||||
|
examNumber = undefined
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const correct = stats.reduce((accumulator, current) => accumulator + current.score.correct, 0);
|
const correct = stats.reduce((accumulator, current) => accumulator + current.score.correct, 0);
|
||||||
@@ -190,15 +196,23 @@ const StatsGridItem: React.FC<StatsGridItemProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
{renderPdfIcon(session, textColor, textColor)}
|
{renderPdfIcon(session, textColor, textColor)}
|
||||||
</div>
|
</div>
|
||||||
{aiUsage >= 50 && user.type !== "student" && (
|
{examNumber === undefined ? (
|
||||||
<div className={clsx(
|
<>
|
||||||
"ml-auto border px-1 rounded w-fit mr-1",
|
{aiUsage >= 50 && user.type !== "student" && (
|
||||||
{
|
<div className={clsx(
|
||||||
'bg-orange-100 border-orange-400 text-orange-700': aiUsage < 80,
|
"ml-auto border px-1 rounded w-fit mr-1",
|
||||||
'bg-red-100 border-red-400 text-red-700': aiUsage >= 80,
|
{
|
||||||
}
|
'bg-orange-100 border-orange-400 text-orange-700': aiUsage < 80,
|
||||||
)}>
|
'bg-red-100 border-red-400 text-red-700': aiUsage >= 80,
|
||||||
<span className="text-xs">AI Usage</span>
|
}
|
||||||
|
)}>
|
||||||
|
<span className="text-xs">AI Usage</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className='flex justify-end'>
|
||||||
|
<span className="font-semibold bg-gray-200 text-gray-800 px-2.5 py-0.5 rounded-full mt-0.5">{examNumber}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -232,7 +246,10 @@ const StatsGridItem: React.FC<StatsGridItemProps> = ({
|
|||||||
correct / total < 0.3 && "hover:border-mti-rose",
|
correct / total < 0.3 && "hover:border-mti-rose",
|
||||||
typeof selectedTrainingExams !== "undefined" && typeof timestamp === "string" && selectedTrainingExams.includes(timestamp) && "border-2 border-slate-600",
|
typeof selectedTrainingExams !== "undefined" && typeof timestamp === "string" && selectedTrainingExams.includes(timestamp) && "border-2 border-slate-600",
|
||||||
)}
|
)}
|
||||||
onClick={selectExam}
|
style={{
|
||||||
|
...(width !== undefined && { width }),
|
||||||
|
...(height !== undefined && { height }),
|
||||||
|
}}
|
||||||
data-tip="This exam is still being evaluated..."
|
data-tip="This exam is still being evaluated..."
|
||||||
role="button">
|
role="button">
|
||||||
{content}
|
{content}
|
||||||
@@ -246,6 +263,10 @@ const StatsGridItem: React.FC<StatsGridItemProps> = ({
|
|||||||
correct / total < 0.3 && "hover:border-mti-rose",
|
correct / total < 0.3 && "hover:border-mti-rose",
|
||||||
)}
|
)}
|
||||||
data-tip="Your screen size is too small to view previous exams."
|
data-tip="Your screen size is too small to view previous exams."
|
||||||
|
style={{
|
||||||
|
...(width !== undefined && { width }),
|
||||||
|
...(height !== undefined && { height }),
|
||||||
|
}}
|
||||||
role="button">
|
role="button">
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const TrainingScore: React.FC<TrainingScoreProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{gridView && (
|
{gridView && (
|
||||||
<div className="flex flex-col items-center justify-center gap-2">
|
<div className="flex flex-col items-center justify-center gap-2 -lg:hidden">
|
||||||
<div className="flex w-14 h-14 bg-[#F5F5F5] items-center justify-center rounded-xl border border-[#DBDBDB]">
|
<div className="flex w-14 h-14 bg-[#F5F5F5] items-center justify-center rounded-xl border border-[#DBDBDB]">
|
||||||
<GiLightBulb color={"#FFCC00"} size={28} />
|
<GiLightBulb color={"#FFCC00"} size={28} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ import { usePDFDownload } from "@/hooks/usePDFDownload";
|
|||||||
import useAssignments from '@/hooks/useAssignments';
|
import useAssignments from '@/hooks/useAssignments';
|
||||||
import useUsers from '@/hooks/useUsers';
|
import useUsers from '@/hooks/useUsers';
|
||||||
import Dropdown from "@/components/Dropdown";
|
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 }) => {
|
export const getServerSideProps = withIronSessionSsr(({ req, res }) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -68,12 +74,9 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
const { assignments } = useAssignments({});
|
const { assignments } = useAssignments({});
|
||||||
const { users } = useUsers();
|
const { users } = useUsers();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { id } = router.query;
|
const { id } = router.query;
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchTrainingContent = async () => {
|
const fetchTrainingContent = async () => {
|
||||||
if (!id || typeof id !== 'string') return;
|
if (!id || typeof id !== 'string') return;
|
||||||
@@ -118,6 +121,32 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
setCurrentTipIndex((prevIndex) => (prevIndex - 1));
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
@@ -137,13 +166,25 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
<span className="loading loading-infinity w-32 bg-mti-green-light" />
|
<span className="loading loading-infinity w-32 bg-mti-green-light" />
|
||||||
</div>
|
</div>
|
||||||
) : (trainingContent && (
|
) : (trainingContent && (
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-8">
|
||||||
<div className="flex h-screen flex-col gap-4">
|
<div className="flex flex-row items-center">
|
||||||
<div className='flex flex-row h-[15%] gap-4'>
|
<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>
|
||||||
{/*<Carousel itemsPerFrame={4} itemsPerScroll={4}>*/}
|
<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) => (
|
{trainingContent.exams.map((exam, examIndex) => (
|
||||||
<StatsGridItem
|
<StatsGridItem
|
||||||
key={`exam-${examIndex}`}
|
key={`exam-${examIndex}`}
|
||||||
|
width='350px'
|
||||||
|
height='150px'
|
||||||
|
examNumber={examIndex + 1}
|
||||||
stats={exam.stats || []}
|
stats={exam.stats || []}
|
||||||
timestamp={exam.date}
|
timestamp={exam.date}
|
||||||
user={user}
|
user={user}
|
||||||
@@ -158,79 +199,51 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
renderPdfIcon={renderPdfIcon}
|
renderPdfIcon={renderPdfIcon}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{/* </Carousel> */}
|
</InfiniteCarousel>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col h-[75%]' style={{ maxHeight: '85%' }}>
|
<div className='flex flex-col'>
|
||||||
<div className='flex flex-row gap-10 -md:flex-col'>
|
<div className='flex flex-row gap-10 -md:flex-col h-full'>
|
||||||
<div className="rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full max-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">
|
<div className="flex flex-row items-center mb-6 gap-1">
|
||||||
<MdOutlinePlaylistAddCheckCircle color={"#40A1EA"} size={26} />
|
<MdOutlinePlaylistAddCheckCircle color={"#40A1EA"} size={26} />
|
||||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>General Evaluation</h2>
|
<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>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full">
|
<TrainingScore
|
||||||
<div className="flex flex-row items-center mb-4 gap-1">
|
trainingContent={trainingContent}
|
||||||
<MdOutlineSelfImprovement color={"#40A1EA"} size={24} />
|
gridView={false}
|
||||||
<h2 className={`text-xl font-semibold text-[#40A1EA]`}>Subjects that Need Improvement</h2>
|
/>
|
||||||
</div>
|
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
||||||
|
<div className="flex flex-row gap-2 items-center mb-6">
|
||||||
<div className="bg-[#FBFBFB] border rounded-xl p-4 max-h-[500px] overflow-y-auto scrollbar-hide">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<div className='flex flex-col'>
|
<mask id="mask0_112_168" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||||
<div className="flex flex-row items-center gap-1 mb-4">
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
<div className="flex items-center justify-center w-[48px] h-[48px]">
|
</mask>
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<g mask="url(#mask0_112_168)">
|
||||||
<mask id="mask0_112_445" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
<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" />
|
||||||
<rect width="24" height="24" fill="#D9D9D9" />
|
</g>
|
||||||
</mask>
|
</svg>
|
||||||
<g mask="url(#mask0_112_445)">
|
<h3 className="text-xl font-semibold text-[#40A1EA]">Performance Breakdown by Exam:</h3>
|
||||||
<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" />
|
</div>
|
||||||
</g>
|
<ul className='overflow-auto scrollbar-hide flex-grow'>
|
||||||
</svg>
|
{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>
|
</div>
|
||||||
<h3 className="text-lg font-semibold">Detailed Breakdown</h3>
|
<span className="pl-2">{exam.score}%</span>
|
||||||
</div>
|
</div>
|
||||||
<ul className="space-y-4 pb-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
{trainingContent.exams.map((exam, index) => (
|
<BsChatLeftDots size={16} />
|
||||||
<li key={index} className="border rounded-lg bg-white">
|
<p className="text-sm">{exam.performance_comment}</p>
|
||||||
<Dropdown title={`Exam ${index + 1}`}>
|
</div>
|
||||||
<span>{exam.detailed_summary}</span>
|
</li>
|
||||||
</Dropdown>
|
))}
|
||||||
</li>
|
</ul>
|
||||||
))}
|
</div>
|
||||||
</ul>
|
<div className="flex flex-col rounded-3xl p-6 w-1/2 shadow-training-inset -md:w-full">
|
||||||
</div>
|
<div className='flex flex-col'>
|
||||||
</div>
|
|
||||||
<div className="w-full h-px bg-[#D9D9D929] my-6"></div>
|
|
||||||
<div className="flex flex-row items-center mb-4 gap-1">
|
<div className="flex flex-row items-center mb-4 gap-1">
|
||||||
<AiOutlineFileSearch color="#40A1EA" size={24} />
|
<AiOutlineFileSearch color="#40A1EA" size={24} />
|
||||||
<h3 className="text-xl font-semibold text-[#40A1EA]">Identified Weak Areas</h3>
|
<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>
|
<Tab.Group>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<Tab.List>
|
<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) => (
|
{trainingContent.weak_areas.map((x, index) => (
|
||||||
<Tab
|
<Tab
|
||||||
key={index}
|
key={index}
|
||||||
@@ -268,10 +281,47 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tab.Group>
|
</Tab.Group>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex -md:hidden">
|
||||||
<div className="rounded-3xl p-6 shadow-training-inset w-full">
|
<div className="rounded-3xl p-6 shadow-training-inset w-full">
|
||||||
<div className="flex flex-col p-10">
|
<div className="flex flex-col p-10">
|
||||||
<Exercise key={currentTipIndex} {...trainingTips[currentTipIndex]} />
|
<Exercise key={currentTipIndex} {...trainingTips[currentTipIndex]} />
|
||||||
@@ -294,6 +344,7 @@ const TrainingContent: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ const Training: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{groupedByTrainingContent && Object.keys(groupedByTrainingContent).length > 0 && (
|
{groupedByTrainingContent && Object.keys(groupedByTrainingContent).length > 0 && (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 w-full gap-4 xl:gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-3 w-full gap-4 xl:gap-6">
|
||||||
{Object.keys(filterTrainingContentByDate(groupedByTrainingContent))
|
{Object.keys(filterTrainingContentByDate(groupedByTrainingContent))
|
||||||
.sort((a, b) => parseInt(b) - parseInt(a))
|
.sort((a, b) => parseInt(b) - parseInt(a))
|
||||||
.map(trainingContentContainer)}
|
.map(trainingContentContainer)}
|
||||||
|
|||||||
@@ -4,14 +4,35 @@
|
|||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.scrollbar-hide {
|
.scrollbar-hide {
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none; /* Firefox */
|
/* IE and Edge */
|
||||||
|
scrollbar-width: none;
|
||||||
|
/* Firefox */
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-hide::-webkit-scrollbar {
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
display: none; /* Chrome, Safari and Opera */
|
display: none;
|
||||||
|
/* Chrome, Safari and Opera */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.training-scrollbar::-webkit-scrollbar {
|
||||||
|
@apply w-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.training-scrollbar::-webkit-scrollbar-track {
|
||||||
|
@apply bg-transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.training-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
@apply bg-gray-400 hover:bg-gray-500 rounded-full transition-colors opacity-50 hover:opacity-75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.training-scrollbar {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--max-width: 1100px;
|
--max-width: 1100px;
|
||||||
--border-radius: 12px;
|
--border-radius: 12px;
|
||||||
@@ -66,4 +87,4 @@ body {
|
|||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
81
yarn.lock
81
yarn.lock
@@ -711,6 +711,13 @@
|
|||||||
node-fetch "2.6.7"
|
node-fetch "2.6.7"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
|
"@firebase/util@^1.9.7":
|
||||||
|
version "1.9.7"
|
||||||
|
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.7.tgz"
|
||||||
|
integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/util@1.9.3":
|
"@firebase/util@1.9.3":
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz"
|
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz"
|
||||||
@@ -718,13 +725,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/util@^1.9.7":
|
|
||||||
version "1.9.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.9.7.tgz#c03b0ae065b3bba22800da0bd5314ef030848038"
|
|
||||||
integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.1.0"
|
|
||||||
|
|
||||||
"@firebase/webchannel-wrapper@0.9.0":
|
"@firebase/webchannel-wrapper@0.9.0":
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz"
|
resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz"
|
||||||
@@ -1591,13 +1591,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react-slick@^0.23.13":
|
|
||||||
version "0.23.13"
|
|
||||||
resolved "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz"
|
|
||||||
integrity sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==
|
|
||||||
dependencies:
|
|
||||||
"@types/react" "*"
|
|
||||||
|
|
||||||
"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.1":
|
"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.1":
|
||||||
version "4.4.5"
|
version "4.4.5"
|
||||||
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz"
|
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz"
|
||||||
@@ -1691,6 +1684,18 @@
|
|||||||
"@typescript-eslint/types" "5.51.0"
|
"@typescript-eslint/types" "5.51.0"
|
||||||
eslint-visitor-keys "^3.3.0"
|
eslint-visitor-keys "^3.3.0"
|
||||||
|
|
||||||
|
"@use-gesture/core@10.3.1":
|
||||||
|
version "10.3.1"
|
||||||
|
resolved "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz"
|
||||||
|
integrity sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==
|
||||||
|
|
||||||
|
"@use-gesture/react@^10.3.1":
|
||||||
|
version "10.3.1"
|
||||||
|
resolved "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz"
|
||||||
|
integrity sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==
|
||||||
|
dependencies:
|
||||||
|
"@use-gesture/core" "10.3.1"
|
||||||
|
|
||||||
"@wixc3/board-core@^2.2.0":
|
"@wixc3/board-core@^2.2.0":
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.npmjs.org/@wixc3/board-core/-/board-core-2.2.0.tgz"
|
resolved "https://registry.npmjs.org/@wixc3/board-core/-/board-core-2.2.0.tgz"
|
||||||
@@ -2165,7 +2170,7 @@ chownr@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz"
|
||||||
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
|
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
|
||||||
|
|
||||||
classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.0, classnames@^2.5.1:
|
classnames@^2.2.6, classnames@^2.3.0, classnames@^2.5.1:
|
||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz"
|
resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz"
|
||||||
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
|
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
|
||||||
@@ -2666,11 +2671,6 @@ enhanced-resolve@^5.10.0:
|
|||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
tapable "^2.2.0"
|
tapable "^2.2.0"
|
||||||
|
|
||||||
enquire.js@^2.1.6:
|
|
||||||
version "2.1.6"
|
|
||||||
resolved "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz"
|
|
||||||
integrity sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw==
|
|
||||||
|
|
||||||
ent@^2.2.0:
|
ent@^2.2.0:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz"
|
resolved "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz"
|
||||||
@@ -4135,13 +4135,6 @@ json-stable-stringify-without-jsonify@^1.0.1:
|
|||||||
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
|
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
|
||||||
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
|
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
|
||||||
|
|
||||||
json2mq@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz"
|
|
||||||
integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==
|
|
||||||
dependencies:
|
|
||||||
string-convert "^0.2.0"
|
|
||||||
|
|
||||||
json5@^1.0.1:
|
json5@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
|
||||||
@@ -4319,11 +4312,6 @@ lodash.clonedeep@^4.5.0:
|
|||||||
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
|
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
|
||||||
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
||||||
|
|
||||||
lodash.debounce@^4.0.8:
|
|
||||||
version "4.0.8"
|
|
||||||
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
|
|
||||||
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
|
|
||||||
|
|
||||||
lodash.includes@^4.3.0:
|
lodash.includes@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"
|
resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"
|
||||||
@@ -5355,17 +5343,6 @@ react-select@^5.7.5:
|
|||||||
react-transition-group "^4.3.0"
|
react-transition-group "^4.3.0"
|
||||||
use-isomorphic-layout-effect "^1.1.2"
|
use-isomorphic-layout-effect "^1.1.2"
|
||||||
|
|
||||||
react-slick@^0.30.2:
|
|
||||||
version "0.30.2"
|
|
||||||
resolved "https://registry.npmjs.org/react-slick/-/react-slick-0.30.2.tgz"
|
|
||||||
integrity sha512-XvQJi7mRHuiU3b9irsqS9SGIgftIfdV5/tNcURTb5LdIokRA5kIIx3l4rlq2XYHfxcSntXapoRg/GxaVOM1yfg==
|
|
||||||
dependencies:
|
|
||||||
classnames "^2.2.5"
|
|
||||||
enquire.js "^2.1.6"
|
|
||||||
json2mq "^0.2.0"
|
|
||||||
lodash.debounce "^4.0.8"
|
|
||||||
resize-observer-polyfill "^1.5.0"
|
|
||||||
|
|
||||||
react-string-replace@^1.1.0:
|
react-string-replace@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmjs.org/react-string-replace/-/react-string-replace-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/react-string-replace/-/react-string-replace-1.1.0.tgz"
|
||||||
@@ -5506,11 +5483,6 @@ requizzle@^0.2.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
|
|
||||||
resize-observer-polyfill@^1.5.0:
|
|
||||||
version "1.5.1"
|
|
||||||
resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz"
|
|
||||||
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
|
|
||||||
|
|
||||||
resolve-from@^4.0.0:
|
resolve-from@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||||
@@ -5720,11 +5692,6 @@ slash@^4.0.0:
|
|||||||
resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"
|
resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"
|
||||||
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
|
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
|
||||||
|
|
||||||
slick-carousel@^1.8.1:
|
|
||||||
version "1.8.1"
|
|
||||||
resolved "https://registry.npmjs.org/slick-carousel/-/slick-carousel-1.8.1.tgz"
|
|
||||||
integrity sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==
|
|
||||||
|
|
||||||
source-map-js@^1.0.2:
|
source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||||
@@ -5773,11 +5740,6 @@ string_decoder@~1.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.1.0"
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
string-convert@^0.2.0:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz"
|
|
||||||
integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==
|
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0":
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
@@ -6369,8 +6331,7 @@ wordwrap@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
|
||||||
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
|
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||||
name wrap-ansi-cjs
|
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
|
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
|||||||
Reference in New Issue
Block a user