diff --git a/package.json b/package.json index 0d217ddc..4b0a1cbe 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "daisyui": "^3.1.5", "eslint": "8.33.0", "eslint-config-next": "13.1.6", + "express-handlebars": "^7.1.2", "firebase": "9.19.1", "firebase-admin": "^11.10.1", "formidable": "^3.5.0", @@ -35,10 +36,13 @@ "lodash": "^4.17.21", "moment": "^2.29.4", "next": "13.1.6", + "nodemailer": "^6.9.5", + "nodemailer-express-handlebars": "^6.1.0", "primeicons": "^6.0.1", "primereact": "^9.2.3", "react": "18.2.0", "react-chartjs-2": "^5.2.0", + "react-datepicker": "^4.18.0", "react-dom": "18.2.0", "react-firebase-hooks": "^5.1.1", "react-icons": "^4.8.0", @@ -54,6 +58,7 @@ "swr": "^2.1.3", "tailwind-scrollbar-hide": "^1.1.7", "typescript": "4.9.5", + "use-file-picker": "^2.1.0", "uuid": "^9.0.0", "wavesurfer.js": "^6.6.4", "zustand": "^4.3.6" @@ -61,6 +66,9 @@ "devDependencies": { "@types/formidable": "^3.4.0", "@types/lodash": "^4.14.191", + "@types/nodemailer": "^6.4.11", + "@types/nodemailer-express-handlebars": "^4.0.3", + "@types/react-datepicker": "^4.15.1", "@types/uuid": "^9.0.1", "@types/wavesurfer.js": "^6.0.6", "@wixc3/react-board": "^2.2.0", diff --git a/src/components/Low/Button.tsx b/src/components/Low/Button.tsx index b8269589..7b5bef7e 100644 --- a/src/components/Low/Button.tsx +++ b/src/components/Low/Button.tsx @@ -46,7 +46,7 @@ export default function Button({ type={type} onClick={onClick} className={clsx( - "py-4 px-6 rounded-full transition ease-in-out duration-300 disabled:cursor-not-allowed", + "py-4 px-6 rounded-full transition ease-in-out duration-300 disabled:cursor-not-allowed cursor-pointer", className, colorClassNames[color][variant], )} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 3c0abe06..77e9672a 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,6 +1,5 @@ import {User} from "@/interfaces/user"; import Link from "next/link"; -import {Avatar} from "primereact/avatar"; import FocusLayer from "@/components/FocusLayer"; import {preventNavigation} from "@/utils/navigation.disabled"; import {useRouter} from "next/router"; diff --git a/src/constants/userPermissions.ts b/src/constants/userPermissions.ts index 70d9f2cc..ac3ae152 100644 --- a/src/constants/userPermissions.ts +++ b/src/constants/userPermissions.ts @@ -22,4 +22,7 @@ export const PERMISSIONS = { owner: ["developer", "owner"], developer: ["developer"], }, + examManagement: { + delete: ["developer", "owner"], + }, }; diff --git a/src/email/index.ts b/src/email/index.ts new file mode 100644 index 00000000..be8f7e2d --- /dev/null +++ b/src/email/index.ts @@ -0,0 +1,42 @@ +import nodemailer from "nodemailer"; +import hbs from "nodemailer-express-handlebars"; +import path from "path"; + +interface MailOptions { + from: string; + to: string[]; + subject: string; + template: string; + context: object; +} + +export function prepareMailer(): nodemailer.Transporter { + const transport = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + auth: { + user: process.env.MAIL_USER!, + pass: process.env.MAIL_PASS!, + }, + }); + + const handlebarOptions: hbs.NodemailerExpressHandlebarsOptions = { + viewEngine: { + partialsDir: path.resolve("src/email/templates"), + defaultLayout: "src/email/templates/main", + }, + viewPath: path.resolve("src/email/templates"), + }; + + transport.use("compile", hbs(handlebarOptions)); + return transport; +} + +export function prepareMailOptions(context: object, to: string[], subject: string, template: string): MailOptions { + return { + from: process.env.MAIL_USER!, + to, + subject, + template, + context, + }; +} diff --git a/src/email/templates/logo.png b/src/email/templates/logo.png new file mode 100644 index 00000000..d4eaafce Binary files /dev/null and b/src/email/templates/logo.png differ diff --git a/src/email/templates/logo_title.png b/src/email/templates/logo_title.png new file mode 100644 index 00000000..fc5e9d90 Binary files /dev/null and b/src/email/templates/logo_title.png differ diff --git a/src/email/templates/main.handlebars b/src/email/templates/main.handlebars new file mode 100644 index 00000000..4a7bb4d6 --- /dev/null +++ b/src/email/templates/main.handlebars @@ -0,0 +1,33 @@ + + + + + + + + +
+ +
+ Hello future {{type}} of EnCoach,
+ You have been invited to register at EnCoach to + become a + {{type}}!
+ Please use the following code when registering: +
+
+
+ + + {{code}} + + +
+
+
+ Thanks,
Your EnCoach team
+
+
+ + \ No newline at end of file diff --git a/src/email/templates/main.handlebars.json b/src/email/templates/main.handlebars.json new file mode 100644 index 00000000..f99e517c --- /dev/null +++ b/src/email/templates/main.handlebars.json @@ -0,0 +1,4 @@ +{ + "type": "student", + "code": "123a" +} \ No newline at end of file diff --git a/src/exams/Selection.tsx b/src/exams/Selection.tsx index 5b30da2b..c7a3f44f 100644 --- a/src/exams/Selection.tsx +++ b/src/exams/Selection.tsx @@ -19,7 +19,7 @@ interface Props { export default function Selection({user, onStart, disableSelection = false}: Props) { const [selectedModules, setSelectedModules] = useState([]); - const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(false); + const [avoidRepeatedExams, setAvoidRepeatedExams] = useState(true); const {stats} = useStats(user?.id); const toggleModule = (module: Module) => { diff --git a/src/hooks/useExams.tsx b/src/hooks/useExams.tsx index bd645c45..c9e001b5 100644 --- a/src/hooks/useExams.tsx +++ b/src/hooks/useExams.tsx @@ -7,13 +7,15 @@ export default function useExams() { const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); - useEffect(() => { + const getData = () => { setIsLoading(true); axios .get("/api/exam") .then((response) => setExams(response.data)) .finally(() => setIsLoading(false)); - }, []); + }; - return {exams, isLoading, isError}; + useEffect(getData, []); + + return {exams, isLoading, isError, reload: getData}; } diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts index 975c39ee..16a6f22b 100644 --- a/src/interfaces/user.ts +++ b/src/interfaces/user.ts @@ -14,6 +14,7 @@ export interface User { bio: string; isVerified: boolean; demographicInformation?: DemographicInformation; + isDisabled?: boolean; } export interface DemographicInformation { diff --git a/src/pages/(admin)/BatchCodeGenerator.tsx b/src/pages/(admin)/BatchCodeGenerator.tsx new file mode 100644 index 00000000..518aadd9 --- /dev/null +++ b/src/pages/(admin)/BatchCodeGenerator.tsx @@ -0,0 +1,86 @@ +import Button from "@/components/Low/Button"; +import {Type} from "@/interfaces/user"; +import axios from "axios"; +import clsx from "clsx"; +import {capitalize} from "lodash"; +import {useEffect, useState} from "react"; +import {toast} from "react-toastify"; +import ShortUniqueId from "short-unique-id"; +import {useFilePicker} from "use-file-picker"; + +export default function BatchCodeGenerator() { + const [emails, setEmails] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const {openFilePicker, filesContent} = useFilePicker({ + accept: ".txt", + multiple: false, + }); + + useEffect(() => { + if (filesContent.length > 0) { + const file = filesContent[0]; + const emails = file.content + .split("\n") + .filter((x) => new RegExp(/^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$/).test(x)); + + if (emails.length === 0) { + toast.error("Please upload a .txt file containing e-mails, one per line!"); + return; + } + + setEmails(emails); + } + }, [filesContent]); + + const generateCode = (type: Type) => { + const uid = new ShortUniqueId(); + const codes = emails.map(() => uid.randomUUID(6)); + + setIsLoading(true); + axios + .post("/api/code", {type, codes, emails}) + .then(({data, status}) => { + if (data.ok) { + toast.success(`Successfully generated ${capitalize(type)} codes and they have been notified by e-mail!`, {toastId: "success"}); + return; + } + + if (status === 403) { + toast.error(`You do not have permission to generate ${capitalize(type)} codes!`, {toastId: "forbidden"}); + } + }) + .catch(({response: {status}}) => { + if (status === 403) { + toast.error(`You do not have permission to generate ${capitalize(type)} codes!`, {toastId: "forbidden"}); + return; + } + + toast.error(`Something went wrong, please try again later!`, {toastId: "error"}); + }) + .finally(() => setIsLoading(false)); + }; + + return ( +
+ + + +
+ + + + +
+
+ ); +} diff --git a/src/pages/(admin)/CodeGenerator.tsx b/src/pages/(admin)/CodeGenerator.tsx index 749f72ce..b1111c92 100644 --- a/src/pages/(admin)/CodeGenerator.tsx +++ b/src/pages/(admin)/CodeGenerator.tsx @@ -15,7 +15,7 @@ export default function CodeGenerator() { const code = uid.randomUUID(6); axios - .post("/api/code", {type, code}) + .post("/api/code", {type, codes: [code]}) .then(({data, status}) => { if (data.ok) { toast.success(`Successfully generated a ${capitalize(type)} code!`, {toastId: "success"}); diff --git a/src/pages/(admin)/Lists/ExamList.tsx b/src/pages/(admin)/Lists/ExamList.tsx index 9abf19cc..38c75088 100644 --- a/src/pages/(admin)/Lists/ExamList.tsx +++ b/src/pages/(admin)/Lists/ExamList.tsx @@ -1,15 +1,17 @@ +import {PERMISSIONS} from "@/constants/userPermissions"; import useExams from "@/hooks/useExams"; import useUsers from "@/hooks/useUsers"; import {Module} from "@/interfaces"; import {Exam} from "@/interfaces/exam"; -import {Type} from "@/interfaces/user"; +import {Type, User} from "@/interfaces/user"; import useExamStore from "@/stores/examStore"; import {getExamById} from "@/utils/exams"; import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table"; +import axios from "axios"; import clsx from "clsx"; import {capitalize} from "lodash"; import {useRouter} from "next/router"; -import {BsCheck, BsUpload} from "react-icons/bs"; +import {BsCheck, BsTrash, BsUpload} from "react-icons/bs"; import {toast} from "react-toastify"; const CLASSES: {[key in Module]: string} = { @@ -21,8 +23,8 @@ const CLASSES: {[key in Module]: string} = { const columnHelper = createColumnHelper(); -export default function ExamList() { - const {exams} = useExams(); +export default function ExamList({user}: {user: User}) { + const {exams, reload} = useExams(); const setExams = useExamStore((state) => state.setExams); const setSelectedModules = useExamStore((state) => state.setSelectedModules); @@ -45,6 +47,28 @@ export default function ExamList() { router.push("/exercises"); }; + const deleteExam = async (exam: Exam) => { + if (!confirm(`Are you sure you want to delete this ${capitalize(exam.module)} exam?`)) return; + + axios + .delete(`/api/exam/${exam.module}/${exam.id}`) + .then(() => toast.success(`Deleted the "${exam.id}" exam`)) + .catch((reason) => { + if (reason.response.status === 404) { + toast.error("Exam not found!"); + return; + } + + if (reason.response.status === 403) { + toast.error("You do not have permission to delete this exam!"); + return; + } + + toast.error("Something went wrong, please try again later."); + }) + .finally(reload); + }; + const getTotalExercises = (exam: Exam) => { if (exam.module === "reading" || exam.module === "listening") { return exam.parts.flatMap((x) => x.exercises).length; @@ -75,11 +99,18 @@ export default function ExamList() { id: "actions", cell: ({row}: {row: {original: Exam}}) => { return ( -
await loadExam(row.original.module, row.original.id)}> - +
+
await loadExam(row.original.module, row.original.id)}> + +
+ {PERMISSIONS.examManagement.delete.includes(user.type) && ( +
deleteExam(row.original)}> + +
+ )}
); }, diff --git a/src/pages/(admin)/Lists/GroupList.tsx b/src/pages/(admin)/Lists/GroupList.tsx index 93bfb9af..18bf4f00 100644 --- a/src/pages/(admin)/Lists/GroupList.tsx +++ b/src/pages/(admin)/Lists/GroupList.tsx @@ -15,6 +15,7 @@ import {BsCheck, BsDash, BsPencil, BsPlus, BsTrash} from "react-icons/bs"; import {toast} from "react-toastify"; import Select from "react-select"; import {uuidv4} from "@firebase/util"; +import {useFilePicker} from "use-file-picker"; const columnHelper = createColumnHelper(); @@ -29,6 +30,41 @@ const CreatePanel = ({user, users, group, onCreate}: CreateDialogProps) => { const [name, setName] = useState(group?.name || undefined); const [admin, setAdmin] = useState(group?.admin || user.id); const [participants, setParticipants] = useState(group?.participants || []); + const {openFilePicker, filesContent} = useFilePicker({ + accept: ".txt", + multiple: false, + }); + + useEffect(() => { + if (filesContent.length > 0) { + const file = filesContent[0]; + const emails = file.content + .toLowerCase() + .split("\n") + .filter((x) => new RegExp(/^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$/).test(x)); + + if (emails.length === 0) { + toast.error("Please upload a .txt file containing e-mails, one per line!"); + return; + } + + const emailUsers = emails.map((x) => users.find((y) => y.email.toLowerCase() === x)).filter((x) => x !== undefined); + const filteredUsers = emailUsers.filter( + (x) => + ((user.type === "developer" || user.type === "owner" || user.type === "admin") && + (x?.type === "student" || x?.type === "teacher")) || + (user.type === "teacher" && x?.type === "student"), + ); + + setParticipants(filteredUsers.filter((x) => !!x).map((x) => x!.id)); + toast.success( + user.type !== "teacher" + ? "Added all teachers and students found in the file you've provided!" + : "Added all students found in the file you've provided!", + {toastId: "upload-success"}, + ); + } + }, [filesContent, user.type, users]); return (
@@ -36,28 +72,38 @@ const CreatePanel = ({user, users, group, onCreate}: CreateDialogProps) => {
- ({ + value: x, + label: `${users.find((y) => y.id === x)?.email} - ${users.find((y) => y.id === x)?.name}`, + }))} + placeholder="Participants..." + defaultValue={participants.map((x) => ({ + value: x, + label: `${users.find((y) => y.id === x)?.email} - ${users.find((y) => y.id === x)?.name}`, + }))} + options={users + .filter((x) => (user.type === "teacher" ? x.type === "student" : x.type === "student" || x.type === "teacher")) + .map((x) => ({value: x.id, label: `${x.email} - ${x.name}`}))} + onChange={(value) => setParticipants(value.map((x) => x.value))} + isMulti + isSearchable + styles={{ + control: (styles) => ({ + ...styles, + backgroundColor: "white", + borderRadius: "999px", + padding: "1rem 1.5rem", + zIndex: "40", + }), + }} + /> + +
diff --git a/src/pages/stats.tsx b/src/pages/stats.tsx index e5172ddf..23e0ffef 100644 --- a/src/pages/stats.tsx +++ b/src/pages/stats.tsx @@ -1,24 +1,13 @@ /* eslint-disable @next/next/no-img-element */ import Head from "next/head"; -import Navbar from "@/components/Navbar"; -import {BsFileEarmarkText, BsPencil, BsStar, BsBook, BsHeadphones, BsPen, BsMegaphone} from "react-icons/bs"; -import {ArcElement, LinearScale, Chart as ChartJS, CategoryScale, PointElement, LineElement, Legend, Tooltip} from "chart.js"; +import {BsFileEarmarkText, BsPencil, BsStar} from "react-icons/bs"; +import {LinearScale, Chart as ChartJS, CategoryScale, PointElement, LineElement, Legend, Tooltip, LineController} from "chart.js"; import {withIronSessionSsr} from "iron-session/next"; import {sessionOptions} from "@/lib/session"; import {useEffect, useState} from "react"; import useStats from "@/hooks/useStats"; -import { - averageScore, - totalExams, - totalExamsByModule, - groupBySession, - groupByModule, - formatModuleAverageScoreStats, - calculateModuleAverageScoreStats, -} from "@/utils/stats"; +import {averageScore, totalExamsByModule, groupBySession, groupByModule} from "@/utils/stats"; import useUser from "@/hooks/useUser"; -import Sidebar from "@/components/Sidebar"; -import Diagnostic from "@/components/Diagnostic"; import {ToastContainer} from "react-toastify"; import {capitalize} from "lodash"; import {Module} from "@/interfaces"; @@ -27,8 +16,13 @@ import Layout from "@/components/High/Layout"; import {calculateAverageLevel, calculateBandScore} from "@/utils/score"; import {MODULE_ARRAY} from "@/utils/moduleUtils"; import {Chart} from "react-chartjs-2"; +import useUsers from "@/hooks/useUsers"; +import Select from "react-select"; +import useGroups from "@/hooks/useGroups"; +import DatePicker from "react-datepicker"; +import moment from "moment"; -ChartJS.register(LinearScale, CategoryScale, PointElement, LineElement, Legend, Tooltip); +ChartJS.register(LinearScale, CategoryScale, PointElement, LineElement, LineController, Legend, Tooltip); const COLORS = ["#1EB3FF", "#FF790A", "#3D9F11", "#EF5DA8"]; @@ -52,19 +46,30 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => { }, sessionOptions); export default function Stats() { - const {user} = useUser({redirectTo: "/login"}); - const {stats} = useStats(user?.id); + const [statsUserId, setStatsUserId] = useState(); + const [startDate, setStartDate] = useState(null); + const [endDate, setEndDate] = useState(new Date()); - const totalExamsData = { - labels: MODULE_ARRAY.map((x) => capitalize(x)), - datasets: [ - { - label: "Total exams", - data: MODULE_ARRAY.map((x) => totalExamsByModule(stats, x)), - backgroundColor: ["#1EB3FF", "#FF790A", "#3D9F11", "#EF5DA8"], - }, - ], - }; + const {user} = useUser({redirectTo: "/login"}); + const {users} = useUsers(); + const {groups} = useGroups(user?.id); + const {stats} = useStats(statsUserId); + const {stats: userStats} = useStats(user?.id); + + useEffect(() => { + if (user) setStatsUserId(user.id); + }, [user]); + + useEffect(() => { + if (stats && stats.length > 0) { + const sortedStats = stats.sort((a, b) => a.date - b.date); + const firstStat = sortedStats.shift()!; + + setStartDate(moment.unix(firstStat.date).toDate()); + console.log(stats.filter((x) => moment.unix(x.date).isAfter(startDate))); + console.log(stats.filter((x) => moment.unix(x.date).isBefore(endDate))); + } + }, [stats]); const calculateTotalScorePerSession = () => { const groupedBySession = groupBySession(stats); @@ -115,7 +120,7 @@ export default function Stats() { {user && ( - +
{user.name}
@@ -143,7 +148,7 @@ export default function Stats() {
- {Object.keys(groupBySession(stats)).length} + {Object.keys(groupBySession(userStats)).length} Exams
@@ -152,7 +157,7 @@ export default function Stats() {
- {stats.length} + {userStats.length} Exercises
@@ -161,7 +166,7 @@ export default function Stats() {
- {averageScore(stats)}% + {averageScore(userStats)}% Average Score
@@ -170,6 +175,53 @@ export default function Stats() {
{stats.length > 0 && (
+
+ <> + {(user.type === "developer" || user.type === "owner") && ( + groups.flatMap((y) => y.participants).includes(x.id)) + .map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))} + defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}} + onChange={(value) => setStatsUserId(value?.value)} + styles={{ + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> + )} + + !moment(date).isSameOrBefore(moment(startDate))} + onChange={([initialDate, finalDate]) => { + setStartDate(initialDate); + setEndDate(finalDate); + }} + /> +
{/* Exams per module */}
@@ -240,12 +292,86 @@ export default function Stats() {
-
+ {/* Module Score */} +
+ Module Score Bands +
+
+
+ + {user.levels.reading} of{" "} + {user.desiredLevels.reading} + + Reading +
+ +
+
+
+ + {user.levels.listening} of{" "} + {user.desiredLevels.listening} + + Listening +
+ +
+
+
+ + {user.levels.writing} of{" "} + {user.desiredLevels.writing} + + Writing +
+ +
+
+
+ + {user.levels.speaking} of{" "} + {user.desiredLevels.speaking} + + Speaking +
+ +
+
+
+ + {/* Total Score Band per Session */} +
Total Score Band per Session index), + labels: Object.keys( + groupBySession( + stats.filter( + (x) => moment.unix(x.date).isAfter(startDate) && moment.unix(x.date).isBefore(endDate), + ), + ), + ).map((_, index) => index), datasets: [ { type: "line", @@ -262,12 +388,19 @@ export default function Stats() { />
-
+ {/* Module Score Band per Session */} +
Module Score Band per Session index), + labels: Object.keys( + groupBySession( + stats.filter( + (x) => moment.unix(x.date).isAfter(startDate) && moment.unix(x.date).isBefore(endDate), + ), + ), + ).map((_, index) => index), datasets: [ ...MODULE_ARRAY.map((module, index) => ({ type: "line" as const, diff --git a/yarn.lock b/yarn.lock index 1138eab8..37f9da33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41,7 +41,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== -"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3": +"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0": version "7.23.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== @@ -694,6 +694,18 @@ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" @@ -900,6 +912,11 @@ tslib "^2.5.0" webcrypto-core "^1.7.7" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pkgr/utils@^2.3.1": version "2.3.1" resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz" @@ -912,6 +929,11 @@ tiny-glob "^0.2.9" tslib "^2.4.0" +"@popperjs/core@^2.11.8", "@popperjs/core@^2.9.2": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" @@ -1041,6 +1063,11 @@ resolved "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz" integrity sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA== +"@types/express-handlebars@^5": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@types/express-handlebars/-/express-handlebars-5.3.1.tgz#30447330fa4b7d19bb953834c7c26077a906e25e" + integrity sha512-DSzaERLO4gHb8AqnrL58jzSDyT0yDdl6HqDc+bGz1Hf0nrG1FK30nHGzv8NBEGR8QV9eUGB/YaE0Qj3NjF7siw== + "@types/express-serve-static-core@^4.17.33": version "4.17.33" resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz" @@ -1181,6 +1208,21 @@ resolved "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== +"@types/nodemailer-express-handlebars@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/nodemailer-express-handlebars/-/nodemailer-express-handlebars-4.0.3.tgz#c7d52461df7594b75c6c1e5e370f673b3f17fc14" + integrity sha512-YBKOX13L1rpG00WVI0p2Zav+l397ouMyiL7YYz5JdgOSETbYUcpNAt5GRl+y7xLoEFgiAXcxptxzgbJ8c4UWug== + dependencies: + "@types/express-handlebars" "^5" + "@types/nodemailer" "*" + +"@types/nodemailer@*", "@types/nodemailer@^6.4.11": + version "6.4.11" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.11.tgz#98630b15b95f292940d27cf4f314c42c70dfdf19" + integrity sha512-Ld2c0frwpGT4VseuoeboCXQ7UJIkK3X7Lx/4YsZEiUHtHsthWAOCYtf6PAiLhMtfwV0cWJRabLBS3+LD8x6Nrw== + dependencies: + "@types/node" "*" + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -1201,6 +1243,16 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/react-datepicker@^4.15.1": + version "4.15.1" + resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.15.1.tgz#a66fee520f2a31f83b45f4ed7f28af7296e11d0c" + integrity sha512-6/LthK0pTDBKjjVJqA2ygY3jJsHH7uZXIk8WPQcGHUiFOQLOKIv3krOxFZ2mt3BB3guMB6jVTc6ansQAd0r7xQ== + dependencies: + "@popperjs/core" "^2.9.2" + "@types/react" "*" + date-fns "^2.0.1" + react-popper "^2.2.5" + "@types/react-dom@18.0.10": version "18.0.10" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz" @@ -1369,6 +1421,11 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1383,6 +1440,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" @@ -1708,7 +1770,7 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -classnames@^2.3.1: +classnames@^2.2.6, classnames@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== @@ -1831,7 +1893,7 @@ country-flag-icons@^1.5.4: resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.5.7.tgz#f1f2ddf14f3cbf01cba6746374aeba94db35d4b4" integrity sha512-AdvXhMcmSp7nBSkpGfW4qR/luAdRUutJqya9PuwRbsBzuoknThfultbv7Ib6fWsHXC43Es/4QJ8gzQQdBNm75A== -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1874,6 +1936,13 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== +date-fns@^2.0.1, date-fns@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + debug@4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" @@ -2006,6 +2075,11 @@ duplexify@^4.0.0: readable-stream "^3.1.1" stream-shift "^1.0.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" @@ -2416,6 +2490,15 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +express-handlebars@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/express-handlebars/-/express-handlebars-7.1.2.tgz#2471673d11af46f496cba4098a705f0217232fda" + integrity sha512-ss9d3mBChOLTEtyfzXCsxlItUxpgS3i4cb/F70G6Q5ohQzmD12XB4x/Y9U6YboeeYBJZt7WQ5yUNu7ZSQ/EGyQ== + dependencies: + glob "^10.3.3" + graceful-fs "^4.2.11" + handlebars "^4.7.8" + extend@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -2485,6 +2568,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-selector@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" + integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA== + dependencies: + tslib "^2.0.3" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" @@ -2579,6 +2669,14 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" @@ -2763,6 +2861,17 @@ glob@7.1.7, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.3.3: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" @@ -2871,7 +2980,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.9: +graceful-fs@^4.1.9, graceful-fs@^4.2.11: 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== @@ -2895,6 +3004,18 @@ gtoken@^6.1.0: google-p12-pem "^4.0.0" jws "^4.0.0" +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" @@ -3268,6 +3389,15 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jiti@^1.17.2: version "1.18.2" resolved "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz" @@ -3561,7 +3691,7 @@ long@^5.0.0: resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -3575,6 +3705,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +"lru-cache@^9.1.1 || ^10.0.0": + version "10.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" + integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== + lru-cache@~4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" @@ -3678,11 +3813,23 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + minipass@^3.0.0: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" @@ -3695,6 +3842,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -3737,6 +3889,11 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + next@13.1.6: version "13.1.6" resolved "https://registry.npmjs.org/next/-/next-13.1.6.tgz" @@ -3791,6 +3948,16 @@ node-releases@^2.0.8: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== +nodemailer-express-handlebars@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/nodemailer-express-handlebars/-/nodemailer-express-handlebars-6.1.0.tgz#8c7eaec0a695f19ebb4fcf31b86d7b47fbec1b47" + integrity sha512-CWhsoDDa5JbvQmOxTOJhISFuUqDLKW0kvL09whIDBnD71P8ykATCQ+xOjQfltXR5qpK15m0AqwE/kHgbYx/zsQ== + +nodemailer@^6.9.5: + version "6.9.5" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.5.tgz#eaeae949c62ec84ef1e9128df89fc146a1017aca" + integrity sha512-/dmdWo62XjumuLc5+AYQZeiRj+PRR8y8qKtFCOyuOl1k/hckZd8durUUHs/ucKx6/8kN+wFxqKJlQ/LK/qR5FA== + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -3982,6 +4149,14 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" @@ -4230,6 +4405,18 @@ react-chartjs-2@^5.2.0: resolved "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz" integrity sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA== +react-datepicker@^4.18.0: + version "4.18.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.18.0.tgz#d66301acc47833d31fa6f46f98781b084106da0e" + integrity sha512-0MYt3HmLbHVk1sw4v+RCbLAVg5TA3jWP7RyjZbo53PC+SEi+pjdgc92lB53ai/ENZaTOhbXmgni9GzvMrorMAw== + dependencies: + "@popperjs/core" "^2.11.8" + classnames "^2.2.6" + date-fns "^2.30.0" + prop-types "^15.7.2" + react-onclickoutside "^6.13.0" + react-popper "^2.3.0" + react-dom@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" @@ -4271,6 +4458,11 @@ react-media-recorder@1.6.5: resolved "https://registry.npmjs.org/react-media-recorder/-/react-media-recorder-1.6.5.tgz" integrity sha512-YcARNZ498jtmOJ+O7GkaokR0DbMNV+YSXB0msAHMZk9wharBuVSWYCXKiIL5JAnR5cs6ebXaOtkkGsM3uIq7Bw== +react-onclickoutside@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz#e165ea4e5157f3da94f4376a3ab3e22a565f4ffc" + integrity sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A== + react-phone-number-input@^3.3.6: version "3.3.6" resolved "https://registry.yarnpkg.com/react-phone-number-input/-/react-phone-number-input-3.3.6.tgz#5d2a2bbfb2600c4c0428e4cd4a725d69f40fe2dd" @@ -4293,6 +4485,14 @@ react-player@^2.12.0: prop-types "^15.7.2" react-fast-compare "^3.0.1" +react-popper@^2.2.5, react-popper@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" + integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== + dependencies: + react-fast-compare "^3.0.1" + warning "^4.0.2" + react-select@^5.7.5: version "5.7.5" resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.5.tgz#d2d0f29994e0f06000147bfb2adf58324926c2fd" @@ -4558,6 +4758,11 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -4578,7 +4783,7 @@ source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@~0.6.1: +source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -4602,6 +4807,15 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -4611,6 +4825,15 @@ stream-shift@^1.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.matchall@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz" @@ -4650,6 +4873,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -4657,6 +4887,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" @@ -4880,6 +5117,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tslib@^2.0.3: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" @@ -4925,7 +5167,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== -uglify-js@^3.7.7: +uglify-js@^3.1.4, uglify-js@^3.7.7: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== @@ -4960,6 +5202,13 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-file-picker@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/use-file-picker/-/use-file-picker-2.1.0.tgz#ff3239413795740c43ca39eac72736a669e88f83" + integrity sha512-nZDYyB3wagpbuhCVPNH6ceyok9TGytw7waJV8v80eu5ykEj89uBTv3CyrBd0I1N1m2cBJgKCpVNOjZT0GDrb+Q== + dependencies: + file-selector "0.2.4" + use-isomorphic-layout-effect@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" @@ -4985,6 +5234,13 @@ uuid@^9.0.0: resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +warning@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + wavesurfer.js@^6.6.4: version "6.6.4" resolved "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-6.6.4.tgz" @@ -5085,6 +5341,20 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -5094,6 +5364,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"