diff --git a/package.json b/package.json index 6bc3943b..526ca5a6 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "daisyui": "^3.1.5", "eslint": "8.33.0", "eslint-config-next": "13.1.6", + "exceljs": "^4.4.0", "express-handlebars": "^7.1.2", "firebase": "9.19.1", "firebase-admin": "^11.10.1", diff --git a/src/dashboards/AssignmentCard.tsx b/src/dashboards/AssignmentCard.tsx index 720708f7..06c68e82 100644 --- a/src/dashboards/AssignmentCard.tsx +++ b/src/dashboards/AssignmentCard.tsx @@ -20,6 +20,7 @@ interface Props { reload?: Function; allowArchive?: boolean; allowUnarchive?: boolean; + allowExcelDownload?: boolean; } export default function AssignmentCard({ @@ -37,9 +38,11 @@ export default function AssignmentCard({ reload, allowArchive, allowUnarchive, + allowExcelDownload, users, }: Assignment & Props) { const renderPdfIcon = usePDFDownload("assignments"); + const renderExcelIcon = usePDFDownload("assignments", "excel"); const renderArchiveIcon = useAssignmentArchive(id, reload); const renderUnarchiveIcon = useAssignmentUnarchive(id, reload); @@ -64,6 +67,7 @@ export default function AssignmentCard({

{name}

{allowDownload && renderPdfIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")} + {allowExcelDownload && renderExcelIcon(id, "text-mti-gray-dim", "text-mti-gray-dim")} {allowArchive && !archived && renderArchiveIcon("text-mti-gray-dim", "text-mti-gray-dim")} {allowUnarchive && archived && renderUnarchiveIcon("text-mti-gray-dim", "text-mti-gray-dim")}
diff --git a/src/dashboards/Corporate.tsx b/src/dashboards/Corporate.tsx index eb6a70d5..1f50539a 100644 --- a/src/dashboards/Corporate.tsx +++ b/src/dashboards/Corporate.tsx @@ -377,6 +377,7 @@ export default function CorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowArchive + allowExcelDownload /> ))} @@ -393,6 +394,7 @@ export default function CorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowUnarchive + allowExcelDownload /> ))} diff --git a/src/dashboards/MasterCorporate.tsx b/src/dashboards/MasterCorporate.tsx index 160f8dea..6c25f391 100644 --- a/src/dashboards/MasterCorporate.tsx +++ b/src/dashboards/MasterCorporate.tsx @@ -4,9 +4,9 @@ import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user"; import UserList from "@/pages/(admin)/Lists/UserList"; -import {dateSorter} from "@/utils"; +import { dateSorter } from "@/utils"; import moment from "moment"; -import {useEffect, useState} from "react"; +import { useEffect, useState } from "react"; import { BsArrowLeft, BsClipboard2Data, @@ -22,6 +22,7 @@ import { BsPlus, BsPersonFillGear, BsFilter, + BsDatabase } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; @@ -33,10 +34,10 @@ import {groupByExam} from "@/utils/stats"; import IconCard from "./IconCard"; import GroupList from "@/pages/(admin)/Lists/GroupList"; import useFilterStore from "@/stores/listFilterStore"; -import {useRouter} from "next/router"; +import { useRouter } from "next/router"; import useCodes from "@/hooks/useCodes"; import useAssignments from "@/hooks/useAssignments"; -import {Assignment} from "@/interfaces/results"; +import { Assignment } from "@/interfaces/results"; import AssignmentView from "./AssignmentView"; import AssignmentCreator from "./AssignmentCreator"; import clsx from "clsx"; @@ -50,9 +51,10 @@ import {groupBy, uniq, uniqBy} from "lodash"; import Select from "@/components/Low/Select"; import {Menu, MenuButton, MenuItem, MenuItems} from "@headlessui/react"; import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover"; +import MasterStatistical from "./MasterStatistical"; interface Props { - user: MasterCorporateUser; + user: MasterCorporateUser; } const activeFilter = (a: Assignment) => @@ -307,17 +309,28 @@ export default function MasterCorporateDashboard({user}: Props) { const {codes} = useCodes(user.id); const {groups} = useGroups({admin: user.id, userType: user.type}); - const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))]; - const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))]; + const masterCorporateUserGroups = [ + ...new Set( + groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants) + ), + ]; - const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id}); + const corporateUserGroups = [ + ...new Set(groups.flatMap((g) => g.participants)), + ]; - const appendUserFilters = useFilterStore((state) => state.appendUserFilter); - const router = useRouter(); + const { + assignments, + isLoading: isAssignmentsLoading, + reload: reloadAssignments, + } = useAssignments({ corporate: user.id }); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); + + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); useEffect(() => { setCorporateAssignments( @@ -332,107 +345,137 @@ export default function MasterCorporateDashboard({user}: Props) { const studentFilter = (user: User) => user.type === "student" && corporateUserGroups.includes(user.id); const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.includes(user.id); - const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); - const UserDisplay = (displayUser: User) => ( -
setSelectedUser(displayUser)} - className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"> - {displayUser.name} -
- {displayUser.name} - {displayUser.email} -
-
- ); + const UserDisplay = (displayUser: User) => ( +
setSelectedUser(displayUser)} + className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300" + > + {displayUser.name} +
+ {displayUser.name} + {displayUser.email} +
+
+ ); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); + const StudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (!!selectedUser + ? corporateUserGroups.includes(x.id) || false + : corporateUserGroups.includes(x.id)); - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Students ({total})

-
- )} - /> - ); - }; + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Students ({total})

+
+ )} + /> + ); + }; - const TeachersList = () => { - const filter = (x: User) => - x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); + const TeachersList = () => { + const filter = (x: User) => + x.type === "teacher" && + (!!selectedUser + ? corporateUserGroups.includes(x.id) || false + : corporateUserGroups.includes(x.id)); - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Teachers ({total})

-
- )} - /> - ); - }; + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Teachers ({total})

+
+ )} + /> + ); + }; - const corporateUserFilter = (x: User) => - x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id)); + const corporateUserFilter = (x: User) => + x.type === "corporate" && + (!!selectedUser + ? masterCorporateUserGroups.includes(x.id) || false + : masterCorporateUserGroups.includes(x.id)); - const CorporateList = () => { - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Corporates ({total})

-
- )} - /> - ); - }; + const CorporateList = () => { + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Corporates ({total})

+
+ )} + /> + ); + }; - const GroupsList = () => { - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Groups ({groups.length})

-
+ const GroupsList = () => { + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Groups ({groups.length})

+
- - - ); - }; + + + ); + }; + + // const AssignmentsPage = () => { + // const activeFilter = (a: Assignment) => + // moment(a.endDate).isAfter(moment()) && + // moment(a.startDate).isBefore(moment()) && + // a.assignees.length > a.results.length; + // const pastFilter = (a: Assignment) => + // (moment(a.endDate).isBefore(moment()) || + // a.assignees.length === a.results.length) && + // !a.archived; + // const archivedFilter = (a: Assignment) => a.archived; + // const futureFilter = (a: Assignment) => + // moment(a.startDate).isAfter(moment()); const StudentPerformancePage = () => { const students = users @@ -571,6 +614,7 @@ export default function MasterCorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowArchive + allowExcelDownload /> ))} @@ -587,6 +631,7 @@ export default function MasterCorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowUnarchive + allowExcelDownload /> ))} @@ -595,6 +640,33 @@ export default function MasterCorporateDashboard({user}: Props) { ); }; + const MasterStatisticalPage = () => { + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Master Statistical

+
+ { + const user = users.find((u) => u.id === id) as CorporateUser; + if (user) return [...accm, user]; + return accm; + }, + [] + )} + /> + + ); + }; + const DefaultDashboard = () => ( <>
@@ -654,6 +726,13 @@ export default function MasterCorporateDashboard({user}: Props) { color="purple" onClick={() => setPage("studentsPerformance")} /> + setPage("statistical")} + />
-
-
- Latest students -
- {users - .filter(studentFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Latest teachers -
- {users - .filter(teacherFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Highest level students -
- {users - .filter(studentFilter) - .sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels)) - .map((x) => ( - - ))} -
-
-
- Highest exam count students -
- {users - .filter(studentFilter) - .sort( - (a, b) => - Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length, - ) - .map((x) => ( - - ))} -
-
-
- - ); +
+
+ Latest students +
+ {users + .filter(studentFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Latest teachers +
+ {users + .filter(teacherFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Highest level students +
+ {users + .filter(studentFilter) + .sort( + (a, b) => + calculateAverageLevel(b.levels) - + calculateAverageLevel(a.levels) + ) + .map((x) => ( + + ))} +
+
+
+ Highest exam count students +
+ {users + .filter(studentFilter) + .sort( + (a, b) => + Object.keys(groupByExam(getStatsByStudent(b))).length - + Object.keys(groupByExam(getStatsByStudent(a))).length + ) + .map((x) => ( + + ))} +
+
+
+ + ); - return ( - <> - setSelectedUser(undefined)}> - <> - {selectedUser && ( -
- { - setSelectedUser(undefined); - if (shouldReload) reload(); - }} - onViewStudents={ - selectedUser.type === "corporate" || selectedUser.type === "teacher" - ? () => { - appendUserFilters({ - id: "view-students", - filter: (x: User) => x.type === "student", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) - .flatMap((g) => g.participants) - .includes(x.id), - }); + return ( + <> + setSelectedUser(undefined)}> + <> + {selectedUser && ( +
+ { + setSelectedUser(undefined); + if (shouldReload) reload(); + }} + onViewStudents={ + selectedUser.type === "corporate" || + selectedUser.type === "teacher" + ? () => { + appendUserFilters({ + id: "view-students", + filter: (x: User) => x.type === "student", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter( + (g) => + g.admin === selectedUser.id || + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => g.participants) + .includes(x.id), + }); - router.push("/list/users"); - } - : undefined - } - onViewTeachers={ - selectedUser.type === "corporate" || selectedUser.type === "student" - ? () => { - appendUserFilters({ - id: "view-teachers", - filter: (x: User) => x.type === "teacher", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) - .flatMap((g) => g.participants) - .includes(x.id), - }); + router.push("/list/users"); + } + : undefined + } + onViewTeachers={ + selectedUser.type === "corporate" || + selectedUser.type === "student" + ? () => { + appendUserFilters({ + id: "view-teachers", + filter: (x: User) => x.type === "teacher", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter( + (g) => + g.admin === selectedUser.id || + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => g.participants) + .includes(x.id), + }); router.push("/list/users"); } @@ -784,7 +878,8 @@ export default function MasterCorporateDashboard({user}: Props) { {page === "corporate" && } {page === "assignments" && } {page === "studentsPerformance" && } + {page === "statistical" && } {page === "" && } ); -} +} \ No newline at end of file diff --git a/src/dashboards/MasterStatistical.tsx b/src/dashboards/MasterStatistical.tsx new file mode 100644 index 00000000..018039de --- /dev/null +++ b/src/dashboards/MasterStatistical.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { CorporateUser } from "@/interfaces/user"; +import { BsBank, BsPersonFill } from "react-icons/bs"; +import IconCard from "./IconCard"; +import useAssignmentsCorporates from '@/hooks/useAssignmentCorporates'; +interface Props { + users: CorporateUser[]; +} +const MasterStatistical = (props: Props) => { + const { users } = props; + + const usersList = React.useMemo(() => users.map((x) => x.id), [users]); + + const { assignments } = useAssignmentsCorporates({ corporates: usersList }); + + console.log('Assignments', assignments); + return ( +
+ console.log("clicked")} + /> + {users.map((group) => ( + console.log("clicked", group)} + /> + ))} + console.log("clicked")} + Icon={BsPersonFill} + label="Consolidate Highest Student" + color="purple" + /> +
+ ); +}; + +export default MasterStatistical; diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx index 72eb6156..436696d5 100644 --- a/src/dashboards/Teacher.tsx +++ b/src/dashboards/Teacher.tsx @@ -260,6 +260,7 @@ export default function TeacherDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowArchive + allowExcelDownload /> ))}
@@ -276,6 +277,7 @@ export default function TeacherDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowUnarchive + allowExcelDownload /> ))}
diff --git a/src/hooks/useAssignmentCorporates.tsx b/src/hooks/useAssignmentCorporates.tsx new file mode 100644 index 00000000..825a3509 --- /dev/null +++ b/src/hooks/useAssignmentCorporates.tsx @@ -0,0 +1,34 @@ +import { Assignment } from "@/interfaces/results"; +import axios from "axios"; +import { useEffect, useState } from "react"; + +export default function useAssignmentsCorporates({ + corporates, +}: { + corporates: string[]; +}) { + const [assignments, setAssignments] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isError, setIsError] = useState(false); + + const getData = () => { + if (corporates.length === 0) { + setAssignments([]); + return; + } + + setIsLoading(true); + axios + .get( + `/api/assignments/corporate?ids=${corporates.join(",")}` + ) + .then(async (response) => { + setAssignments(response.data); + }) + .finally(() => setIsLoading(false)); + }; + + useEffect(getData, [corporates]); + + return { assignments, isLoading, isError, reload: getData }; +} diff --git a/src/hooks/useAssignments.tsx b/src/hooks/useAssignments.tsx index 2d2f58ef..5a1c30d3 100644 --- a/src/hooks/useAssignments.tsx +++ b/src/hooks/useAssignments.tsx @@ -10,7 +10,7 @@ export default function useAssignments({assigner, assignees, corporate}: {assign const getData = () => { setIsLoading(true); axios - .get(!corporate ? "/api/assignments" : `/api/assignments/corporate?id=${corporate}`) + .get(!corporate ? "/api/assignments" : `/api/assignments/corporate/${corporate}`) .then(async (response) => { if (assigner) { setAssignments(response.data.filter((a) => a.assigner === assigner)); diff --git a/src/hooks/usePDFDownload.tsx b/src/hooks/usePDFDownload.tsx index 54b83884..b7a81a5c 100644 --- a/src/hooks/usePDFDownload.tsx +++ b/src/hooks/usePDFDownload.tsx @@ -1,15 +1,16 @@ import React from "react"; import axios from "axios"; import { toast } from "react-toastify"; -import { BsFilePdf } from "react-icons/bs"; +import { BsFilePdf, BsFileExcel} from "react-icons/bs"; type DownloadingPdf = { [key: string]: boolean; }; type PdfEndpoint = "stats" | "assignments"; +type FileType = "pdf" | "excel"; -export const usePDFDownload = (endpoint: PdfEndpoint) => { +export const usePDFDownload = (endpoint: PdfEndpoint, file: FileType = 'pdf') => { const [downloadingPdf, setDownloadingPdf] = React.useState( {} ); @@ -17,7 +18,7 @@ export const usePDFDownload = (endpoint: PdfEndpoint) => { const triggerDownload = async (id: string) => { try { setDownloadingPdf((prev) => ({ ...prev, [id]: true })); - const res = await axios.post(`/api/${endpoint}/${id}/export`); + const res = await axios.post(`/api/${endpoint}/${id}/export/${file}`); toast.success("Report ready!"); const link = document.createElement("a"); link.href = res.data; @@ -45,8 +46,11 @@ export const usePDFDownload = (endpoint: PdfEndpoint) => { ); } + + const Icon = file === "excel" ? BsFileExcel : BsFilePdf; + return ( - { e.stopPropagation(); diff --git a/src/pages/api/assignments/[id]/[export]/excel.ts b/src/pages/api/assignments/[id]/[export]/excel.ts new file mode 100644 index 00000000..20661676 --- /dev/null +++ b/src/pages/api/assignments/[id]/[export]/excel.ts @@ -0,0 +1,334 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { app, storage } from "@/firebase"; +import { + getFirestore, + doc, + getDoc, + updateDoc, + getDocs, + query, + collection, + where, + documentId, +} from "firebase/firestore"; +import { withIronSessionApiRoute } from "iron-session/next"; +import { sessionOptions } from "@/lib/session"; +import ReactPDF from "@react-pdf/renderer"; +import GroupTestReport from "@/exams/pdf/group.test.report"; +import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; +import { Stat, CorporateUser } from "@/interfaces/user"; +import { User, DemographicInformation } from "@/interfaces/user"; +import { Module } from "@/interfaces"; +import { ModuleScore, StudentData } from "@/interfaces/module.scores"; +import { SkillExamDetails } from "@/exams/pdf/details/skill.exam"; +import { LevelExamDetails } from "@/exams/pdf/details/level.exam"; +import { calculateBandScore, getLevelScore } from "@/utils/score"; +import { + generateQRCode, + getRadialProgressPNG, + streamToBuffer, +} from "@/utils/pdf"; +import { Group } from "@/interfaces/user"; +import moment from "moment-timezone"; +import ExcelJS from "exceljs"; + +interface GroupScoreSummaryHelper { + score: [number, number]; + label: string; + sessions: string[]; +} +const db = getFirestore(app); + +export default withIronSessionApiRoute(handler, sessionOptions); + +async function handler(req: NextApiRequest, res: NextApiResponse) { + // if (req.method === "GET") return get(req, res); + if (req.method === "POST") return await post(req, res); +} + +function logWorksheetData(worksheet: any) { + worksheet.eachRow((row: any, rowNumber: number) => { + console.log(`Row ${rowNumber}:`); + row.eachCell((cell: any, colNumber: number) => { + console.log(` Cell ${colNumber}: ${cell.value}`); + }); + }); +} + +async function post(req: NextApiRequest, res: NextApiResponse) { + // verify if it's a logged user that is trying to export + if (req.session.user) { + const { id } = req.query as { id: string }; + + const docSnap = await getDoc(doc(db, "assignments", id)); + const data = docSnap.data() as { + assigner: string; + assignees: string[]; + results: any; + exams: { module: Module }[]; + startDate: string; + excel: { + path: string; + version: string; + }; + name: string; + }; + if (!data) { + res.status(400).end(); + return; + } + + // if ( + // data.excel && + // data.excel.path && + // data.excel.version === process.env.EXCEL_VERSION + // ) { + // // if it does, return the excel url + // const fileRef = ref(storage, data.excel.path); + // const url = await getDownloadURL(fileRef); + // res.status(200).end(url); + // return; + // } + + const docsSnap = await getDocs( + query(collection(db, "users"), where(documentId(), "in", data.assignees)) + ); + const users = docsSnap.docs.map((d) => ({ + ...d.data(), + id: d.id, + })) as User[]; + + const docUser = await getDoc(doc(db, "users", req.session.user.id)); + if (docUser.exists()) { + // we'll need the user in order to get the user data (name, email, focus, etc); + const user = docUser.data() as CorporateUser; + + const allStats = data.results.flatMap((r: any) => r.stats); + + const uniqueExercises = [ + ...new Set(allStats.map((s: any) => s.exercise)), + ]; + + const assigneesData = data.assignees + .map((assignee: string) => { + const userStats = allStats.filter((s: any) => s.user === assignee); + return { + userId: assignee, + user: users.find((u) => u.id === assignee), + ...userStats.reduce( + (acc: any, curr: any) => { + return { + ...acc, + correct: acc.correct + curr.score.correct, + missing: acc.missing + curr.score.missing, + total: acc.total + curr.score.total, + }; + }, + { correct: 0, missing: 0, total: 0 } + ), + stats: userStats, + }; + }) + .sort((a, b) => b.correct - a.correct); + + const results = assigneesData.map((r: any) => r.correct); + const highestScore = Math.max(...results); + const lowestScore = Math.min(...results); + const averageScore = results.reduce((a, b) => a + b, 0) / results.length; + + const dates = assigneesData + .flatMap((r: any) => r.stats) + .map((r: any) => r.date) + .map((d: number) => moment(d)); + const firstDate = moment.min(dates); + const lastDate = moment.max(dates); + + const firstSectionData = [ + { + label: "Corporate Name :", + value: user.corporateInformation?.companyInformation?.name || "", + }, + { + label: "Report Download date :", + value: moment().format("DD/MM/YYYY"), + }, + { label: "Test Information :", value: data.name}, + { + label: "Date of Test :", + value: moment(data.startDate).format("DD/MM/YYYY"), + }, + { label: "Number of Candidates :", value: data.assignees.length }, + { label: "Highest score :", value: highestScore }, + { label: "Lowest score :", value: lowestScore }, + { label: "Average score :", value: averageScore }, + { label: "", value: "" }, + { + label: "Date and time of First submission :", + value: firstDate.format("DD/MM/YYYY"), + }, + { + label: "Date and time of Last submission :", + value: lastDate.format("DD/MM/YYYY"), + }, + ]; + + // Create a new workbook and add a worksheet + const workbook = new ExcelJS.Workbook(); + const worksheet = workbook.addWorksheet("Report Data"); + + // Populate the worksheet with the data + firstSectionData.forEach(({ label, value }, index) => { + worksheet.getCell(`A${index + 1}`).value = label; // First column (labels) + worksheet.getCell(`B${index + 1}`).value = value; // Second column (values) + }); + + // Define the static part of the headers (before "Test Sections") + const staticHeaders = [ + "Sr N", + "Candidate ID", + "First and Last Name", + "Passport/ID", + "Email ID", + "Gender", + ]; + + // Define additional headers after "Test Sections" + const additionalHeaders = ["Time Spent", "Score"]; + + // Calculate the dynamic columns based on the testSectionsArray + const testSectionHeaders = uniqueExercises.map( + (section, index) => `Part ${index + 1}` + ); + + const tableColumnHeadersFirstPart = [ + ...staticHeaders, + ...uniqueExercises.map((a) => "Test Sections"), + ]; + // Add the main header row, merging static columns and "Test Sections" + const tableColumnHeaders = [ + ...tableColumnHeadersFirstPart, + ...additionalHeaders, + ]; + worksheet.addRow(tableColumnHeaders); + + // 1 headers rows + const startIndexTable = firstSectionData.length + 1; + + // // Merge "Test Sections" over dynamic number of columns + // const tableColumns = staticHeaders.length + numberOfTestSections; + worksheet.mergeCells( + 1, + staticHeaders.length + 1, + 1, + tableColumnHeadersFirstPart.length + ); + + + // Add the dynamic second and third header rows for test sections and sub-columns + worksheet.addRow([ + ...Array(staticHeaders.length).fill(""), + ...testSectionHeaders, + "", + "", + ]); + worksheet.addRow([ + ...Array(staticHeaders.length).fill(""), + ...uniqueExercises.map(() => "Grammar & Vocabulary"), + "", + "", + ]); + worksheet.addRow([ + ...Array(staticHeaders.length).fill(""), + ...uniqueExercises.map( + (exercise) => allStats.find((s: any) => s.exercise === exercise).type + ), + "", + "", + ]); + + // Merging static headers and "Test Sections" over dynamic columns + worksheet.mergeCells(`A${startIndexTable}:A${startIndexTable + 3}`); // "Sr N" + worksheet.mergeCells(`B${startIndexTable}:B${startIndexTable + 3}`); // "Candidate ID" + worksheet.mergeCells(`C${startIndexTable}:C${startIndexTable + 3}`); // "First and Last Name" + worksheet.mergeCells(`D${startIndexTable}:D${startIndexTable + 3}`); // "Passport/ID" + worksheet.mergeCells(`E${startIndexTable}:E${startIndexTable + 3}`); // "Email ID" + worksheet.mergeCells(`F${startIndexTable}:F${startIndexTable + 3}`); // "Gender" + + assigneesData.forEach((data, index) => { + worksheet.addRow([ + index + 1, + data.userId, + data.user.name, + data.user.demographicInformation?.passportId, + data.user.email, + data.user.demographicInformation?.gender, + ...uniqueExercises.map((exercise) => { + const score = data.stats.find( + (s: any) => s.exercise === exercise && s.user === data.userId + ).score; + return `${score.correct}/${score.total}`; + }), + `${ + Math.ceil(data.stats.reduce( + (acc: number, curr: any) => acc + curr.timeSpent, + 0 + ) / 60) + } minutes`, + data.correct, + ]); + }); + + worksheet.addRow([""]); + worksheet.addRow([""]); + + for (let i = 0; i < tableColumnHeaders.length; i++) { + worksheet.getColumn(i + 1).width = 30; + } + + // Apply styles to the headers + [startIndexTable].forEach((rowNumber) => { + worksheet.getRow(rowNumber).eachCell((cell) => { + if (cell.value) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "FFBFBFBF" }, // Grey color for headers + }; + cell.font = { bold: true }; + cell.alignment = { vertical: "middle", horizontal: "center" }; + } + }); + }); + + worksheet.addRow(["Printed by: Confidential Information"]); + worksheet.addRow(["info@encoach.com"]); + + // Convert workbook to Buffer (Node.js) or Blob (Browser) + const buffer = await workbook.xlsx.writeBuffer(); + // generate the file ref for storage + const fileName = `${Date.now().toString()}.xlsx`; + const refName = `assignment_report/${fileName}`; + const fileRef = ref(storage, refName); + + // upload the pdf to storage + const snapshot = await uploadBytes(fileRef, buffer, { + contentType: + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + // update the stats entries with the pdf url to prevent duplication + await updateDoc(docSnap.ref, { + excel: { + path: refName, + version: process.env.EXCEL_VERSION, + }, + }); + const url = await getDownloadURL(fileRef); + res.status(200).end(url); + + return; + } + } + + res.status(401).json({ message: "Unauthorized" }); +} diff --git a/src/pages/api/assignments/[id]/export.tsx b/src/pages/api/assignments/[id]/[export]/pdf.tsx similarity index 100% rename from src/pages/api/assignments/[id]/export.tsx rename to src/pages/api/assignments/[id]/[export]/pdf.tsx diff --git a/src/pages/api/assignments/corporate.ts b/src/pages/api/assignments/corporate/[id].ts similarity index 100% rename from src/pages/api/assignments/corporate.ts rename to src/pages/api/assignments/corporate/[id].ts diff --git a/src/pages/api/assignments/corporate/index.ts b/src/pages/api/assignments/corporate/index.ts new file mode 100644 index 00000000..d70197ae --- /dev/null +++ b/src/pages/api/assignments/corporate/index.ts @@ -0,0 +1,34 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; +import { withIronSessionApiRoute } from "iron-session/next"; +import { sessionOptions } from "@/lib/session"; +import { getAllAssignersByCorporate } from "@/utils/groups.be"; +import { getAssignmentsByAssigners } from "@/utils/assignments.be"; + + +export default withIronSessionApiRoute(handler, sessionOptions); + +async function handler(req: NextApiRequest, res: NextApiResponse) { + if (!req.session.user) { + res.status(401).json({ ok: false }); + return; + } + + if (req.method === "GET") return await GET(req, res); + + res.status(404).json({ ok: false }); +} + +async function GET(req: NextApiRequest, res: NextApiResponse) { + const { ids } = req.query as { ids: string }; + try { + const idsList = ids.split(","); + + const assigners = await Promise.all(idsList.map(getAllAssignersByCorporate)); + const assignmentList = [...assigners.flat(), ...idsList]; + const assignments = await getAssignmentsByAssigners(assignmentList); + res.status(200).json(assignments); + } catch (err: any) { + res.status(500).json({ error: err.message }); + } +} diff --git a/src/pages/api/stats/[id]/export.tsx b/src/pages/api/stats/[id]/[export]/pdf.tsx similarity index 100% rename from src/pages/api/stats/[id]/export.tsx rename to src/pages/api/stats/[id]/[export]/pdf.tsx diff --git a/src/utils/assignments.be.ts b/src/utils/assignments.be.ts index 96725e67..d7b42bc9 100644 --- a/src/utils/assignments.be.ts +++ b/src/utils/assignments.be.ts @@ -9,6 +9,11 @@ export const getAssignmentsByAssigner = async (id: string) => { return docs.map((x) => ({...x.data(), id: x.id})) as Assignment[]; }; +export const getAssignmentsByAssignerBetweenDates = async (id: string, startDate: Date, endDate: Date) => { + const {docs} = await getDocs(query(collection(db, "assignments"), where("assigner", "==", id), )); + return docs.map((x) => ({...x.data(), id: x.id})) as Assignment[]; +}; + export const getAssignmentsByAssigners = async (ids: string[]) => { return (await Promise.all(ids.map(getAssignmentsByAssigner))).flat(); }; diff --git a/yarn.lock b/yarn.lock index 2887738b..c5a73193 100644 --- a/yarn.lock +++ b/yarn.lock @@ -305,6 +305,31 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@fast-csv/format@4.3.5": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" + integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.isboolean "^3.0.3" + lodash.isequal "^4.5.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + +"@fast-csv/parse@4.3.6": + version "4.3.6" + resolved "https://registry.yarnpkg.com/@fast-csv/parse/-/parse-4.3.6.tgz#ee47d0640ca0291034c7aa94039a744cfb019264" + integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.groupby "^4.6.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + lodash.isundefined "^3.0.1" + lodash.uniq "^4.5.0" + "@fastify/busboy@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-1.2.1.tgz#9c6db24a55f8b803b5222753b24fe3aea2ba9ca3" @@ -1775,6 +1800,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== +"@types/node@^14.0.1": + version "14.18.63" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" + integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== + "@types/node@^17.0.41": version "17.0.45" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" @@ -2062,6 +2092,51 @@ anymatch@~3.1.2: resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver-utils@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-3.0.4.tgz#a0d201f1cf8fce7af3b5a05aea0a337329e96ec7" + integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== + dependencies: + glob "^7.2.3" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +archiver@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.2.tgz#99991d5957e53bd0303a392979276ac4ddccf3b0" + integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.4" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.1.2" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + are-we-there-yet@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" @@ -2219,6 +2294,11 @@ async-retry@^1.3.3: dependencies: retry "0.13.1" +async@^3.2.4: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2328,6 +2408,11 @@ bidi-js@^1.0.2: dependencies: require-from-string "^2.0.2" +big-integer@^1.6.17: + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + bignumber.js@^9.0.0: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" @@ -2338,11 +2423,33 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + bluebird@^3.7.2, bluebird@~3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2389,11 +2496,29 @@ browserslist@^4.23.3: node-releases "^2.0.18" update-browserslist-db "^1.1.0" +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== +buffer-indexof-polyfill@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" + integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@^6: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -2402,6 +2527,11 @@ buffer@^6: base64-js "^1.3.1" ieee754 "^1.2.1" +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== + busboy@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -2447,6 +2577,13 @@ catharsis@^0.9.0: dependencies: lodash "^4.17.15" +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ== + dependencies: + traverse ">=0.3.0 <0.4" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2609,6 +2746,16 @@ commander@^4.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +compress-commons@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.2.tgz#6542e59cb63e1f46a8b21b0e06f9a32e4c8b06df" + integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + compressible@^2.0.12: version "2.0.18" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" @@ -2678,6 +2825,19 @@ country-flag-icons@^1.5.11: resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.5.13.tgz#963596b7fca6602b4b389a4e7b711ef3f33cc0b1" integrity sha512-4JwHNqaKZ19doQoNcBjsoYA+I7NqCH/mC/6f5cBWvdKzcK5TMmzLpq3Z/syVHMHJuDGFwJ+rPpGizvrqJybJow== +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.3.tgz#85dd677eb78fa7cad1ba17cc506a597d41fc6f33" + integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + create-emotion@^10.0.14, create-emotion@^10.0.27: version "10.0.27" resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503" @@ -2798,6 +2958,11 @@ date-fns@^2.0.1, date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" +dayjs@^1.8.34: + version "1.11.12" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.12.tgz#5245226cc7f40a15bf52e0b99fd2a04669ccac1d" + integrity sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg== + debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.6" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" @@ -3456,6 +3621,21 @@ events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +exceljs@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/exceljs/-/exceljs-4.4.0.tgz#cfb1cb8dcc82c760a9fc9faa9e52dadab66b0156" + integrity sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg== + dependencies: + archiver "^5.0.0" + dayjs "^1.8.34" + fast-csv "^4.3.1" + jszip "^3.10.1" + readable-stream "^3.6.0" + saxes "^5.0.1" + tmp "^0.2.0" + unzipper "^0.10.11" + uuid "^8.3.0" + express-handlebars@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/express-handlebars/-/express-handlebars-7.1.3.tgz#48de4fff6617af9574a6d63031f34fe95e255dd2" @@ -3470,6 +3650,14 @@ extend@^3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +fast-csv@^4.3.1: + version "4.3.6" + resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-4.3.6.tgz#70349bdd8fe4d66b1130d8c91820b64a21bc4a63" + integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== + dependencies: + "@fast-csv/format" "4.3.5" + "@fast-csv/parse" "4.3.6" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -3716,6 +3904,11 @@ framer-motion@^9.0.2: optionalDependencies: "@emotion/is-prop-valid" "^0.8.2" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^11.2.0: version "11.2.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" @@ -3742,6 +3935,16 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" @@ -3875,7 +4078,7 @@ glob@^10.3.10, glob@^10.4.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3980,7 +4183,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4133,7 +4336,7 @@ idb@7.0.1: resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.1.tgz#d2875b3a2f205d854ee307f6d196f246fea590a7" integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg== -ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -4143,6 +4346,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -4164,7 +4372,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4598,6 +4806,16 @@ jsonwebtoken@^9.0.0: object.assign "^4.1.4" object.values "^1.1.6" +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + jwa@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -4670,6 +4888,13 @@ language-tags@^1.0.9: dependencies: language-subtag-registry "^0.3.20" +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -4691,6 +4916,13 @@ libphonenumber-js@^1.11.5: resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz#efe4fcf816e1982925e9c800d0013b0ee99b8283" integrity sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A== +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -4718,6 +4950,11 @@ linkify-it@^5.0.0: dependencies: uc.micro "^2.0.0" +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ== + load-script@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" @@ -4747,6 +4984,31 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== + +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + +lodash.groupby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -4757,11 +5019,26 @@ lodash.isboolean@^3.0.3: resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.isfunction@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + lodash.isinteger@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== +lodash.isnil@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" + integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== + lodash.isnumber@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" @@ -4777,6 +5054,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.isundefined@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" + integrity sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -4787,6 +5069,16 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -4920,7 +5212,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== @@ -4964,6 +5256,13 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +"mkdirp@>=0.5 0": + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -5270,7 +5569,7 @@ pako@^0.2.5: resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== -pako@~1.0.5: +pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -5851,7 +6150,7 @@ read-excel-file@^5.7.1: fflate "^0.7.3" unzipper "^0.12.2" -readable-stream@^2.0.2: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -5864,7 +6163,7 @@ readable-stream@^2.0.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.6.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -5873,6 +6172,13 @@ readable-stream@^3.1.1, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== + dependencies: + minimatch "^5.1.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -5986,6 +6292,13 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -6029,6 +6342,13 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + scheduler@^0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe" @@ -6091,6 +6411,11 @@ set-function-name@^2.0.1, set-function-name@^2.0.2: functions-have-names "^1.2.3" has-property-descriptors "^1.0.2" +setimmediate@^1.0.5, setimmediate@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -6437,6 +6762,17 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar@^6.1.11: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" @@ -6489,7 +6825,7 @@ tiny-inflate@^1.0.0, tiny-inflate@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== -tmp@^0.2.1: +tmp@^0.2.0, tmp@^0.2.1: version "0.2.3" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== @@ -6511,6 +6847,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" @@ -6662,6 +7003,22 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== +unzipper@^0.10.11: + version "0.10.14" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1" + integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "^1.0.12" + graceful-fs "^4.2.2" + listenercount "~1.0.1" + readable-stream "~2.3.6" + setimmediate "~1.0.4" + unzipper@^0.12.2: version "0.12.3" resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.12.3.tgz#31958f5eed7368ed8f57deae547e5a673e984f87" @@ -6725,7 +7082,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^8.0.0: +uuid@^8.0.0, uuid@^8.3.0: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -6912,6 +7269,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xmlcreate@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.4.tgz#0c5ab0f99cdd02a81065fa9cd8f8ae87624889be" @@ -7013,6 +7375,15 @@ yoga-layout@^2.0.1: resolved "https://registry.yarnpkg.com/yoga-layout/-/yoga-layout-2.0.1.tgz#4bc686abe2464f977866650ddccc1dbcf9f0d03c" integrity sha512-tT/oChyDXelLo2A+UVnlW9GU7CsvFMaEnd9kVFsaiCQonFAXd3xrHhkLYu+suwwosrAEQ746xBU+HvYtm1Zs2Q== +zip-stream@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.1.tgz#1337fe974dbaffd2fa9a1ba09662a66932bd7135" + integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== + dependencies: + archiver-utils "^3.0.4" + compress-commons "^4.1.2" + readable-stream "^3.6.0" + zustand@^4.3.6: version "4.5.5" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.5.tgz#f8c713041543715ec81a2adda0610e1dc82d4ad1"