Add locale support (#228)

This commit is contained in:
Luke Vella 2022-07-21 12:12:35 +01:00 committed by GitHub
parent 800af20132
commit 416a17c5b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 967 additions and 467 deletions

View file

@ -93,6 +93,10 @@ yarn start
If you would like to contribute to the development of the project please reach out first before spending significant time on it. If you would like to contribute to the development of the project please reach out first before spending significant time on it.
### Translators 🇫🇷 🇩🇪 🇮🇹 🇪🇸
If you'd like to volunteer to translate Rallly to another language, check out our [guide for translators](https://github.com/lukevella/rallly/wiki/Guide-for-translators).
## 👮‍♂️ License ## 👮‍♂️ License
Rallly is open-source under the GNU Affero General Public License Version 3 (AGPLv3) or any later version. See [LICENSE](LICENSE) for more detail. Rallly is open-source under the GNU Affero General Public License Version 3 (AGPLv3) or any later version. See [LICENSE](LICENSE) for more detail.

View file

@ -1,11 +1,13 @@
import "react-i18next"; import "react-i18next";
import app from "~/public/locales/en/app.json"; import app from "~/public/locales/en/app.json";
import common from "~/public/locales/en/common.json";
import homepage from "~/public/locales/en/homepage.json"; import homepage from "~/public/locales/en/homepage.json";
declare module "next-i18next" { declare module "next-i18next" {
interface Resources { interface Resources {
homepage: typeof homepage; homepage: typeof homepage;
app: typeof app; app: typeof app;
common: typeof common;
} }
} }

View file

@ -3,7 +3,7 @@ const path = require("path");
module.exports = { module.exports = {
i18n: { i18n: {
defaultLocale: "en", defaultLocale: "en",
locales: ["en"], locales: ["en", "de"],
localePath: path.resolve("./public/locales"), localePath: path.resolve("./public/locales"),
reloadOnPrerender: process.env.NODE_ENV === "development", reloadOnPrerender: process.env.NODE_ENV === "development",
}, },

View file

@ -35,7 +35,7 @@
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"nanoid": "^3.1.30", "nanoid": "^3.1.30",
"next": "^12.1.4", "next": "^12.2.2",
"next-i18next": "^10.5.0", "next-i18next": "^10.5.0",
"next-plausible": "^3.1.9", "next-plausible": "^3.1.9",
"nodemailer": "^6.7.2", "nodemailer": "^6.7.2",
@ -43,7 +43,6 @@
"react": "17.0.2", "react": "17.0.2",
"react-big-calendar": "^0.38.9", "react-big-calendar": "^0.38.9",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-github-btn": "^1.2.2",
"react-hook-form": "^7.31.3", "react-hook-form": "^7.31.3",
"react-hot-toast": "^2.2.0", "react-hot-toast": "^2.2.0",
"react-i18next": "^11.16.9", "react-i18next": "^11.16.9",
@ -70,7 +69,7 @@
"@typescript-eslint/parser": "^5.21.0", "@typescript-eslint/parser": "^5.21.0",
"autoprefixer": "^10.4.2", "autoprefixer": "^10.4.2",
"eslint": "^7.26.0", "eslint": "^7.26.0",
"eslint-config-next": "12.1.0", "eslint-config-next": "^12.2.2",
"eslint-import-resolver-typescript": "^2.7.0", "eslint-import-resolver-typescript": "^2.7.0",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-react": "^7.23.2", "eslint-plugin-react": "^7.23.2",

129
public/locales/de/app.json Normal file
View file

@ -0,0 +1,129 @@
{
"12h": "12 Stunden",
"24h": "24 Stunden",
"addTimeOption": "Uhrzeit hinzufügen",
"applyToAllDates": "Auf alle Termine anwenden",
"areYouSure": "Bist du sicher?",
"back": "Zurück",
"blog": "Blog",
"calendarHelp": "Du kannst keine Umfrage ohne Optionen erstellen. Füge mindestens eine Option hinzu, um fortzufahren.",
"calendarHelpTitle": "Irgendwas vergessen?",
"cancel": "Abbrechen",
"comment": "Kommentieren",
"commentPlaceholder": "Kommentar zu dieser Umfrage hinterlassen (für jeden sichtbar)",
"comments": "Kommentare",
"continue": "Weiter",
"copied": "Kopiert",
"copyLink": "Link kopieren",
"createdBy": "von <b>{{name}}</b>",
"createPoll": "Umfrage erstellen",
"creatingDemo": "Demo-Umfrage wird erstellt…",
"delete": "Löschen",
"deleteComment": "Kommentar löschen",
"deleteDate": "Tag löschen",
"deletedPoll": "Umfrage gelöscht",
"deletedPollInfo": "Diese Umfrage existiert nicht mehr.",
"deletePoll": "Umfrage löschen",
"deletePollDescription": "Alle Daten zu dieser Umfrage werden gelöscht. Zur Bestätigung geben Sie bitte <s>“{{confirmText}}”</s> in das folgende Feld ein:",
"deletingOptionsWarning": "Du löschst Optionen, für die bereits Teilnehmer gestimmt haben. Ihre Stimmen werden ebenfalls gelöscht.",
"demoPollNotice": "Demo-Umfragen werden automatisch nach einem Tag gelöscht",
"description": "Beschreibung",
"descriptionPlaceholder": "Hallo ihr, bitte wählt alle Termine aus, die für euch passen!",
"discussions": "Diskussion",
"donate": "Spenden",
"editDetails": "Details bearbeiten",
"editOptions": "Optionen bearbeiten",
"email": "E-Mail",
"emailPlaceholder": "Max.Mustermann@mail.de",
"endingGuestSessionNotice": "Sobald eine Gastsitzung beendet ist, kann sie nicht fortgesetzt werden. Du kannst weder Auswahl noch Kommentare bearbeiten, die Du mit dieser Sitzung gemacht hast.",
"endSession": "Sitzung beenden",
"errorCreate": "Oh oh! Es gab ein Problem beim Erstellen deiner Umfrage. Der Fehler wurde protokolliert und wir werden versuchen, ihn zu beheben.",
"exportToCsv": "CSV exportieren",
"finish": "Fertigstellen",
"forgetMe": "Vergiss mich",
"goToAdmin": "Zur Admin Oberfläche",
"guest": "Gast",
"guestSessionNotice": "Du benutzt eine Gastsitzung, so können wir dich erkennen, wenn du später wiederkommst, damit du deine Angaben bearbeiten kannst.",
"guestSessionReadMore": "Mehr über Gastsitzungen.",
"hide": "Ausblenden",
"ifNeedBe": "Falls erforderlich",
"linkHasExpired": "Der Link ist abgelaufen oder ungültig",
"loading": "Wird geladen…",
"loadingParticipants": "Teilnehmerliste wird geladen…",
"location": "Ort",
"locationPlaceholder": "Joe's Café",
"lockPoll": "Umfragen sperren",
"login": "Login",
"loginCheckInbox": "Bitte überprüfe deinen Posteingang.",
"loginMagicLinkSent": "Ein magischer Link wurde geschickt an:",
"loginSendMagicLink": "Schicke mir einen magischen Link",
"loginViaMagicLink": "Anmeldung über magischen Link",
"loginViaMagicLinkDescription": "Wir senden dir eine E-Mail mit einem magischen Link, mit dem du dich anmelden kannst.",
"loginWithValidEmail": "Bitte gib eine gültige E-Mail-Adresse ein",
"logout": "Logout",
"manage": "Verwalten",
"menu": "Menü",
"mixedOptionsDescription": "Du kannst keine Zeit- und Datumsoptionen in der gleichen Umfrage haben. Welche möchtest Du beibehalten?",
"mixedOptionsKeepDates": "Datumsoptionen beibehalten",
"mixedOptionsKeepTimes": "Zeitoptionen beibehalten",
"mixedOptionsTitle": "Warte einen Moment…🤔",
"monday": "Montag",
"monthView": "Monatsansicht",
"name": "Name",
"namePlaceholder": "Max Mustermann",
"newPoll": "Neue Umfrage",
"next": "Weiter",
"nextMonth": "Nächster Monat",
"no": "Nein",
"noDatesSelected": "Kein Datum ausgewählt",
"notificationsDisabled": "Benachrichtigungen wurden deaktiviert",
"notificationsOff": "Benachrichtigungen sind deaktiviert",
"notificationsOn": "Benachrichtigungen sind aktiv",
"notificationsOnDescription": "Wenn diese Umfrage bearbeitet wird, wird eine E-Mail an <b>{{email}}</b> gesendet.",
"notificationsVerifyEmail": "Du musst deine E-Mail-Adresse bestätigen, um Benachrichtigungen zu aktivieren",
"ok": "Ok",
"options": "Optionen",
"participant": "Teilnehmer",
"addParticipant": "Add participant",
"alreadyVoted": "You have already voted",
"participantCount_other": "{{count}} Teilnehmer",
"participantCount": "{{count}} Teilnehmer",
"pollHasBeenLocked": "Diese Umfrage wurde gesperrt",
"pollHasBeenVerified": "Deine Umfrage wurde verifiziert",
"pollOwnerNotice": "Hallo {{name}}, sieht so aus, als ob du der Besitzer dieser Umfrage bist.",
"pollsEmpty": "Keine Umfragen erstellt",
"possibleAnswers": "Mögliche Antworten",
"preferences": "Einstellungen",
"previousMonth": "Vorheriger Monat",
"profileLogin": "Profil - Login",
"profileUser": "Profil - {{username}}",
"requiredNameError": "Bitte gib einen Namen an",
"save": "Speichern",
"saveInstruction": "Select your availability and click <b>{{save}}</b>",
"share": "Teilen",
"shareDescription": "Gib diesen Link deinen <b>Teilnehmern</b> damit sie an deiner Umfrage teilnehmen können.",
"shareLink": "Über Link teilen",
"specifyTimes": "Uhrzeiten angeben",
"specifyTimesDescription": "Start- und Endzeit für jede Option angeben",
"stepSummary": "Schritt {{current}} von {{total}}",
"sunday": "Sonntag",
"support": "Hilfe",
"timeAndDate": "Datum & Uhrzeit",
"timeFormat": "Uhrzeitformat:",
"timeZone": "Zeitzone:",
"title": "Titel",
"titlePlaceholder": "Monatliches Meeting",
"unlockPoll": "Umfrage entsperren",
"unverifiedMessage": "Ein Link zur Bestätigung der E-Mail-Adresse wurde an <b>{{email}}</b> versendet.",
"user": "Benutzer",
"vote": "Abstimmen",
"voteCount_other": "{{count}} Stimmen",
"voteCount": "{{count}} Stimme",
"weekStartsOn": "Woche beginnt am",
"weekView": "Wochenansicht",
"whatsThis": "Was ist das?",
"yes": "Ja",
"yourDetails": "Persönliche Angaben",
"yourName": "Your name…",
"yourPolls": "Deine Umfragen"
}

View file

@ -0,0 +1,13 @@
{
"language": "Sprache",
"english": "Englisch",
"german": "Deutsch",
"home": "Home",
"blog": "Blog",
"support": "Support",
"donate": "Donate",
"volunteerTranslator": "Help translate this site",
"starOnGithub": "Star us on Github",
"footerCredit": "Made by <a>@imlukevella</a>",
"footerSponsor": "This project is user-funded. Please consider supporting it by <a>donating</a>."
}

View file

@ -0,0 +1,44 @@
{
"3Ls": "Ja mit 3 <e>L</e>s",
"adFree": "Ohne Werbung",
"adFreeDescription": "Gönn deinem Adblocker eine Pause - du brauchst ihn hier nicht.",
"blog": "Blog",
"comments": "Kommentare",
"commentsDescription": "Teilnehmer können deine Umfrage kommentieren, die Kommentare sind für alle sichtbar.",
"discussions": "Diskussion",
"features": "Funktionen",
"featuresSubheading": "Terminfindung leicht gemacht",
"follow": "Folgen",
"getStarted": "Los geht's",
"heroSubText": "Finde ohne Hin-und Her den richtigen Termin",
"heroText": "Plane<br/><s>Besprechungen</s><br />ganz einfach",
"links": "Links",
"liveDemo": "Live Demo",
"metaDescription": "Erstelle Umfragen und stimme ab, um den besten Tag oder die beste Zeit zu finden. Eine kostenlose Alternative zu Doodle.",
"metaTitle": "Rallly - Gruppenmeetings planen",
"mobileFriendly": "Für Mobilgeräte optimiert",
"mobileFriendlyDescription": "Funktioniert hervorragend auf mobilen Geräten, so dass Teilnehmer auf Umfragen antworten können, wo immer sie sich befinden.",
"new": "Neu",
"noLoginRequired": "Keine Anmeldung benötigt",
"noLoginRequiredDescription": "Du musst dich nicht einloggen, um eine Umfrage zu erstellen oder an ihr teilzunehmen",
"notifications": "Benachrichtigungen",
"notificationsDescription": "Behalte den Überblick darüber, wer geantwortet hat. Werde benachrichtigt, wenn Teilnehmer abstimmen oder deine Umfrage kommentieren.",
"openSource": "Open Source",
"openSourceDescription": "Die Codebase ist vollständig Open-Source und <a>auf GitHub</a> verfügbar.",
"participant": "Teilnehmer",
"participantCount_other": "{{count}} Teilnehmer",
"social": "Social",
"participantCount": "{{count}} Teilnehmer",
"perfect": "Perfekt!",
"poweredBy": "Unterstützt von",
"principles": "Grundsätze",
"principlesSubheading": "Wir sind nicht wie die anderen",
"privacyPolicy": "Datenschutzrichtlinie",
"selfHostable": "Selfhosting möglich",
"selfHostableDescription": "Betreibe es auf deinem eigenen Server, um die volle Kontrolle über deine Daten zu haben",
"sponsorThisProject": "Dieses Projekt unterstützen",
"star": "Star",
"support": "Hilfe",
"timeSlots": "Zeitfenster",
"timeSlotsDescription": "Wähle individuelle Start- und Endzeiten für jede Option in deiner Umfrage. Die Zeiten können automatisch an die Zeitzone jedes Teilnehmers angepasst werden oder so eingestellt werden, dass Zeitzonen komplett ignoriert werden."
}

View file

@ -2,7 +2,6 @@
"12h": "12-hour", "12h": "12-hour",
"24h": "24-hour", "24h": "24-hour",
"addTimeOption": "Add time option", "addTimeOption": "Add time option",
"admin": "Admin",
"applyToAllDates": "Apply to all dates", "applyToAllDates": "Apply to all dates",
"areYouSure": "Are you sure?", "areYouSure": "Are you sure?",
"back": "Back", "back": "Back",
@ -23,7 +22,7 @@
"deleteComment": "Delete comment", "deleteComment": "Delete comment",
"deleteDate": "Delete date", "deleteDate": "Delete date",
"deletedPoll": "Deleted poll", "deletedPoll": "Deleted poll",
"deletedPollInfo": "this poll doesn't exist anymore.", "deletedPollInfo": "This poll doesn't exist anymore.",
"deletePoll": "Delete poll", "deletePoll": "Delete poll",
"deletePollDescription": "All data related to this poll will be deleted. To confirm, please type <s>“{{confirmText}}”</s> in to the input below:", "deletePollDescription": "All data related to this poll will be deleted. To confirm, please type <s>“{{confirmText}}”</s> in to the input below:",
"deletingOptionsWarning": "You are deleting options that participants have voted for. Their votes will be also be deleted.", "deletingOptionsWarning": "You are deleting options that participants have voted for. Their votes will be also be deleted.",
@ -85,6 +84,8 @@
"ok": "Ok", "ok": "Ok",
"options": "Options", "options": "Options",
"participant": "Participant", "participant": "Participant",
"addParticipant": "Add participant",
"alreadyVoted": "You have already voted",
"participantCount_other": "{{count}} participants", "participantCount_other": "{{count}} participants",
"participantCount": "{{count}} participant", "participantCount": "{{count}} participant",
"pollHasBeenLocked": "This poll has been locked", "pollHasBeenLocked": "This poll has been locked",
@ -96,9 +97,9 @@
"previousMonth": "Previous month", "previousMonth": "Previous month",
"profileLogin": "Profile - Login", "profileLogin": "Profile - Login",
"profileUser": "Profile - {{username}}", "profileUser": "Profile - {{username}}",
"remove": "Remove",
"requiredNameError": "Name is required", "requiredNameError": "Name is required",
"save": "Save", "save": "Save",
"saveInstruction": "Select your availability and click <b>{{save}}</b>",
"share": "Share", "share": "Share",
"shareDescription": "Give this link to your <b>participants</b> to allow them to vote on your poll.", "shareDescription": "Give this link to your <b>participants</b> to allow them to vote on your poll.",
"shareLink": "Share via link", "shareLink": "Share via link",
@ -123,5 +124,6 @@
"whatsThis": "What's this?", "whatsThis": "What's this?",
"yes": "Yes", "yes": "Yes",
"yourDetails": "Your details", "yourDetails": "Your details",
"yourName": "Your name…",
"yourPolls": "Your polls" "yourPolls": "Your polls"
} }

View file

@ -1,3 +1,13 @@
{ {
"appName": "Rallly" "language": "Language",
"english": "English",
"german": "German",
"home": "Home",
"blog": "Blog",
"support": "Support",
"donate": "Donate",
"volunteerTranslator": "Help translate this site",
"starOnGithub": "Star us on Github",
"footerCredit": "Made by <a>@imlukevella</a>",
"footerSponsor": "This project is user-funded. Please consider supporting it by <a>donating</a>."
} }

View file

@ -9,7 +9,6 @@
"features": "Features", "features": "Features",
"featuresSubheading": "Scheduling, the smart way", "featuresSubheading": "Scheduling, the smart way",
"follow": "Follow", "follow": "Follow",
"footerCredit": "Self-funded and built by <a>@imlukevella</a>",
"getStarted": "Get started", "getStarted": "Get started",
"heroSubText": "Find the right date without the back and forth", "heroSubText": "Find the right date without the back and forth",
"heroText": "Schedule<br/><s>group meetings</s><br />with ease", "heroText": "Schedule<br/><s>group meetings</s><br />with ease",
@ -28,6 +27,7 @@
"openSourceDescription": "The codebase is fully open-source and <a>available on GitHub</a>.", "openSourceDescription": "The codebase is fully open-source and <a>available on GitHub</a>.",
"participant": "Participant", "participant": "Participant",
"participantCount_other": "{{count}} participants", "participantCount_other": "{{count}} participants",
"social": "Social",
"participantCount": "{{count}} participant", "participantCount": "{{count}} participant",
"perfect": "Perfect!", "perfect": "Perfect!",
"poweredBy": "Powered by", "poweredBy": "Powered by",
@ -38,7 +38,7 @@
"selfHostableDescription": "Run it on your own server to take full control of your data", "selfHostableDescription": "Run it on your own server to take full control of your data",
"sponsorThisProject": "Sponsor this project", "sponsorThisProject": "Sponsor this project",
"star": "Star", "star": "Star",
"support": "support", "support": "Support",
"timeSlots": "Time slots", "timeSlots": "Time slots",
"timeSlotsDescription": "Set individual start and end times for each option in your poll. Times can be automatically adjusted to each participant's timezone or they can be set to ignore timezones completely." "timeSlotsDescription": "Set individual start and end times for each option in your poll. Times can be automatically adjusted to each participant's timezone or they can be set to ignore timezones completely."
} }

View file

@ -156,7 +156,7 @@ const Page: NextPage<CreatePollPageProps> = ({
<div className="max-w-full py-4 md:px-3 lg:px-6"> <div className="max-w-full py-4 md:px-3 lg:px-6">
<div className="mx-auto w-fit max-w-full lg:mx-0"> <div className="mx-auto w-fit max-w-full lg:mx-0">
<div className="mb-4 flex items-center justify-center space-x-4 px-4 lg:justify-start"> <div className="mb-4 flex items-center justify-center space-x-4 px-4 lg:justify-start">
<h1 className="m-0">New Poll</h1> <h1 className="m-0">{t("newPoll")}</h1>
<Steps current={currentStepIndex} total={steps.length} /> <Steps current={currentStepIndex} total={steps.length} />
</div> </div>
<div className="overflow-hidden border-t border-b bg-white shadow-sm md:rounded-lg md:border"> <div className="overflow-hidden border-t border-b bg-white shadow-sm md:rounded-lg md:border">

View file

@ -66,7 +66,7 @@ const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
); );
}} }}
components={{ components={{
toolbar: (props) => { toolbar: function Toolbar(props) {
return ( return (
<DateNavigationToolbar <DateNavigationToolbar
year={props.date.getFullYear()} year={props.date.getFullYear()}
@ -83,7 +83,7 @@ const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
/> />
); );
}, },
eventWrapper: (props) => { eventWrapper: function EventWraper(props) {
const start = dayjs(props.event.start); const start = dayjs(props.event.start);
const end = dayjs(props.event.end); const end = dayjs(props.event.end);
return ( return (
@ -105,7 +105,7 @@ const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
}, },
week: { week: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
header: ({ date }: any) => { header: function Header({ date }: any) {
const dateString = formatDateWithoutTime(date); const dateString = formatDateWithoutTime(date);
const selectedOption = options.find((option) => { const selectedOption = options.find((option) => {
return option.type === "date" && option.date === dateString; return option.type === "date" && option.date === dateString;
@ -143,7 +143,7 @@ const WeekCalendar: React.VoidFunctionComponent<DateTimePickerProps> = ({
); );
}, },
}, },
timeSlotWrapper: ({ children }) => { timeSlotWrapper: function TimeSlotWrapper({ children }) {
return <div className="h-8 text-xs text-gray-500">{children}</div>; return <div className="h-8 text-xs text-gray-500">{children}</div>;
}, },
}} }}

View file

@ -10,7 +10,7 @@ import Ban from "./ban-ads.svg";
const Bonus: React.VoidFunctionComponent = () => { const Bonus: React.VoidFunctionComponent = () => {
const { t } = useTranslation("homepage"); const { t } = useTranslation("homepage");
return ( return (
<div className="mx-auto max-w-7xl px-8 pt-8 pb-24"> <div className="mx-auto max-w-7xl px-8 py-8">
<h2 className="heading">{t("principles")}</h2> <h2 className="heading">{t("principles")}</h2>
<p className="subheading">{t("principlesSubheading")}</p> <p className="subheading">{t("principlesSubheading")}</p>
<div className="grid grid-cols-4 gap-16"> <div className="grid grid-cols-4 gap-16">

View file

@ -26,12 +26,12 @@ const Hero: React.VoidFunctionComponent = () => {
</h1> </h1>
<div className="mb-12 text-xl text-gray-400">{t("heroSubText")}</div> <div className="mb-12 text-xl text-gray-400">{t("heroSubText")}</div>
<div className="space-x-3"> <div className="space-x-3">
<Link href="/new"> <Link href="/new" locale={false}>
<a className="rounded-lg bg-primary-500 px-5 py-3 font-semibold text-white shadow-sm transition-all hover:bg-primary-500/90 hover:text-white hover:no-underline hover:shadow-md focus:ring-2 focus:ring-primary-200 active:bg-primary-600/90"> <a className="rounded-lg bg-primary-500 px-5 py-3 font-semibold text-white shadow-sm transition-all hover:bg-primary-500/90 hover:text-white hover:no-underline hover:shadow-md focus:ring-2 focus:ring-primary-200 active:bg-primary-600/90">
{t("getStarted")} {t("getStarted")}
</a> </a>
</Link> </Link>
<Link href="/demo"> <Link href="/demo" locale={false}>
<a <a
className="rounded-lg bg-slate-500 px-5 py-3 font-semibold text-white shadow-sm transition-all hover:bg-slate-500/90 hover:text-white hover:no-underline hover:shadow-md focus:ring-2 focus:ring-primary-200 active:bg-slate-600/90" className="rounded-lg bg-slate-500 px-5 py-3 font-semibold text-white shadow-sm transition-all hover:bg-slate-500/90 hover:text-white hover:no-underline hover:shadow-md focus:ring-2 focus:ring-primary-200 active:bg-slate-600/90"
rel="nofollow" rel="nofollow"

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path fill-rule="evenodd" d="M14.06 3.44a1.5 1.5 0 0 1 0 2.12l-7 7a1.5 1.5 0 0 1-2.12 0l-3-3a1.5 1.5 0 1 1 2.12-2.12L6 9.378l5.94-5.94a1.5 1.5 0 0 1 2.12 0Z" clip-rule="evenodd" /> <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 211 B

Before After
Before After

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.317 4.537a19.596 19.596 0 0 0-4.885-1.536.074.074 0 0 0-.079.038c-.21.38-.444.877-.608 1.267-1.845-.28-3.68-.28-5.487 0a12.891 12.891 0 0 0-.617-1.267A.077.077 0 0 0 8.562 3c-1.714.3-3.354.824-4.885 1.536a.07.07 0 0 0-.032.028C.533 9.278-.32 13.875.099 18.414a.084.084 0 0 0 .031.057 19.797 19.797 0 0 0 5.993 3.071.077.077 0 0 0 .084-.028c.462-.639.874-1.313 1.226-2.022a.078.078 0 0 0-.041-.107 13.021 13.021 0 0 1-1.872-.904.079.079 0 0 1-.008-.13c.126-.095.252-.195.372-.295a.073.073 0 0 1 .078-.01c3.927 1.817 8.18 1.817 12.061 0a.073.073 0 0 1 .079.009c.12.1.245.2.372.296a.079.079 0 0 1-.006.13 12.23 12.23 0 0 1-1.873.903.078.078 0 0 0-.041.108c.36.708.772 1.382 1.225 2.021a.076.076 0 0 0 .084.03 19.731 19.731 0 0 0 6.002-3.072.078.078 0 0 0 .032-.056c.5-5.248-.838-9.807-3.549-13.849a.061.061 0 0 0-.031-.029ZM8.02 15.65c-1.182 0-2.157-1.1-2.157-2.452 0-1.352.956-2.453 2.157-2.453 1.21 0 2.176 1.11 2.157 2.453 0 1.351-.956 2.452-2.157 2.452Zm7.975 0c-1.183 0-2.157-1.1-2.157-2.452 0-1.352.955-2.453 2.157-2.453 1.21 0 2.176 1.11 2.157 2.453 0 1.351-.946 2.452-2.157 2.452Z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 540 B

Before After
Before After

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129" />
</svg>

After

Width:  |  Height:  |  Size: 314 B

View file

@ -1,4 +1,5 @@
import clsx from "clsx"; import clsx from "clsx";
import { useTranslation } from "next-i18next";
import * as React from "react"; import * as React from "react";
import UserAvatar from "./poll/user-avatar"; import UserAvatar from "./poll/user-avatar";
@ -16,6 +17,7 @@ const NameInput: React.ForwardRefRenderFunction<
HTMLInputElement, HTMLInputElement,
NameInputProps NameInputProps
> = ({ value, defaultValue, className, ...forwardProps }, ref) => { > = ({ value, defaultValue, className, ...forwardProps }, ref) => {
const { t } = useTranslation("app");
return ( return (
<div className="relative flex items-center"> <div className="relative flex items-center">
<UserAvatar <UserAvatar
@ -25,7 +27,7 @@ const NameInput: React.ForwardRefRenderFunction<
<input <input
ref={ref} ref={ref}
className={clsx("input pl-[35px]", className)} className={clsx("input pl-[35px]", className)}
placeholder="Your name…" placeholder={t("yourName")}
value={value} value={value}
{...forwardProps} {...forwardProps}
/> />

View file

@ -1,6 +1,5 @@
import clsx from "clsx"; import clsx from "clsx";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { Trans, useTranslation } from "next-i18next"; import { Trans, useTranslation } from "next-i18next";
@ -24,6 +23,7 @@ const Menu: React.VoidFunctionComponent<{ className: string }> = ({
className, className,
}) => { }) => {
const { pathname } = useRouter(); const { pathname } = useRouter();
const { t } = useTranslation("common");
return ( return (
<nav className={className}> <nav className={className}>
<Link href="/"> <Link href="/">
@ -36,7 +36,7 @@ const Menu: React.VoidFunctionComponent<{ className: string }> = ({
}, },
)} )}
> >
Home {t("home")}
</a> </a>
</Link> </Link>
<Link href="https://blog.rallly.co"> <Link href="https://blog.rallly.co">
@ -45,14 +45,14 @@ const Menu: React.VoidFunctionComponent<{ className: string }> = ({
"text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2", "text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2",
)} )}
> >
Blog {t("blog")}
</a> </a>
</Link> </Link>
<a <a
href="https://support.rallly.co" href="https://support.rallly.co"
className="text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2" className="text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2"
> >
Support {t("support")}
</a> </a>
<Link href="https://github.com/lukevella/rallly"> <Link href="https://github.com/lukevella/rallly">
<a className="text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2"> <a className="text-gray-400 transition-colors hover:text-primary-500 hover:no-underline hover:underline-offset-2">
@ -70,9 +70,6 @@ const PageLayout: React.VoidFunctionComponent<PageLayoutProps> = ({
const { t } = useTranslation("homepage"); const { t } = useTranslation("homepage");
return ( return (
<div className="bg-pattern min-h-full overflow-x-hidden"> <div className="bg-pattern min-h-full overflow-x-hidden">
<Head>
<title>Rallly - Support</title>
</Head>
<div className="mx-auto flex max-w-7xl items-center py-8 px-8"> <div className="mx-auto flex max-w-7xl items-center py-8 px-8">
<div className="grow"> <div className="grow">
<div className="relative inline-block"> <div className="relative inline-block">

View file

@ -1,115 +1,151 @@
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router";
import { Trans, useTranslation } from "next-i18next"; import { Trans, useTranslation } from "next-i18next";
import * as React from "react"; import * as React from "react";
import GitHubButton from "react-github-btn";
import Discord from "@/components/icons/discord.svg";
import Star from "@/components/icons/star.svg";
import Translate from "@/components/icons/translate.svg";
import Twitter from "@/components/icons/twitter.svg";
import DigitalOcean from "~/public/digitalocean.svg";
import Logo from "~/public/logo.svg"; import Logo from "~/public/logo.svg";
import Sentry from "~/public/sentry.svg";
import Vercel from "~/public/vercel-logotype-dark.svg"; import Vercel from "~/public/vercel-logotype-dark.svg";
import { LanguageSelect } from "../poll/language-selector";
const Footer: React.VoidFunctionComponent = () => { const Footer: React.VoidFunctionComponent = () => {
const { t } = useTranslation("homepage"); const { t } = useTranslation(["common", "homepage"]);
const router = useRouter();
return ( return (
<div className="mt-16 bg-slate-50/70"> <div className="mt-16 bg-slate-50/70">
<div className="mx-auto grid max-w-7xl grid-cols-10 gap-8 py-20 px-8"> <div className="mx-auto max-w-7xl space-y-8 p-8 lg:grid lg:grid-cols-12 lg:gap-16 lg:space-y-0">
<div className="col-span-12 md:col-span-4"> <div className=" lg:col-span-4">
<Logo className="mb-4 w-32 text-gray-400" /> <Logo className="w-32 text-slate-400" />
<p className="text-sm text-gray-400"> <div className="mb-8 mt-4 text-slate-400">
<p>
<Trans <Trans
t={t} t={t}
i18nKey="footerCredit" i18nKey="common:footerSponsor"
components={{ components={{
a: ( a: (
<a <a
className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline" className="font-normal leading-loose text-slate-400 underline hover:text-slate-800 hover:underline"
href="https://twitter.com/imlukevella" href="https://www.paypal.com/donate/?hosted_button_id=7QXP2CUBLY88E"
/> />
), ),
}} }}
/> />
</p> </p>
<div className="flex space-x-3"> <div>
<GitHubButton <Trans
t={t}
i18nKey="common:footerCredit"
components={{
a: (
<a
className="font-normal leading-loose text-slate-400 underline hover:text-slate-800 hover:underline"
href="https://twitter.com/imlukevella"
/>
),
}}
/>
</div>
</div>
<div className="mb-8 flex items-center space-x-6">
<a
href="https://twitter.com/ralllyco"
className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"
>
<Twitter className="h-5 w-5" />
</a>
<a
href="https://discord.gg/m5UFXavc2C"
className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"
>
<Discord className="h-5 w-5" />
</a>
<a
href="https://github.com/lukevella/rallly" href="https://github.com/lukevella/rallly"
data-icon="octicon-star" className="inline-flex h-8 items-center rounded-full bg-slate-100 pl-2 pr-3 text-sm text-slate-400 transition-colors hover:bg-primary-500 hover:text-white hover:no-underline focus:ring-2 focus:ring-primary-500 focus:ring-offset-1 active:bg-primary-600"
aria-label="Star lukevella/rallly on GitHub"
data-show-count={true}
> >
{t("star")} <Star className="mr-2 inline-block w-5" />
</GitHubButton> <span>{t("common:starOnGithub")}</span>
<GitHubButton </a>
href="https://github.com/sponsors/lukevella"
data-icon="octicon-heart"
aria-label="Sponsor @lukevella on GitHub"
>
{t("sponsorThisProject")}
</GitHubButton>
</div> </div>
</div> </div>
<div className="col-span-6 md:col-span-2"> <div className="lg:col-span-2">
<div className="mb-4 font-medium">{t("links")}</div> <div className="mb-4 font-medium">{t("homepage:links")}</div>
<ul> <ul>
<li> <li>
<a <a
className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline" className="font-normal leading-loose text-slate-400 hover:text-slate-800 hover:no-underline"
href="https://github.com/lukevella/rallly/discussions" href="https://github.com/lukevella/rallly/discussions"
> >
{t("discussions")} {t("homepage:discussions")}
</a> </a>
</li> </li>
<li> <li>
<Link href="https://blog.rallly.co"> <Link href="https://blog.rallly.co">
<a className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline"> <a className="font-normal leading-loose text-slate-400 hover:text-slate-800 hover:no-underline">
{t("blog")} {t("homepage:blog")}
</a> </a>
</Link> </Link>
</li> </li>
<li> <li>
<a <a
href="https://support.rallly.co" href="https://support.rallly.co"
className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline" className="font-normal leading-loose text-slate-400 hover:text-slate-800 hover:no-underline"
> >
{t("support")} {t("homepage:support")}
</a> </a>
</li> </li>
<li> <li>
<Link href="/privacy-policy"> <Link href="/privacy-policy">
<a className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline"> <a className="font-normal leading-loose text-slate-400 hover:text-slate-800 hover:no-underline">
{t("privacyPolicy")} {t("homepage:privacyPolicy")}
</a> </a>
</Link> </Link>
</li> </li>
</ul> </ul>
</div> </div>
<div className="col-span-6 md:col-span-2"> <div className="lg:col-span-3">
<div className="mb-4 font-medium">{t("follow")}</div> <div className="mb-4 font-medium">{t("homepage:poweredBy")}</div>
<ul> <div className="block space-y-4">
<li> <div>
<a
className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline"
href="https://github.com/lukevella/rallly"
>
Github
</a>
</li>
<li>
<a
className="font-normal leading-loose text-gray-400 hover:text-gray-800 hover:no-underline"
href="https://twitter.com/ralllyco"
>
Twitter
</a>
</li>
</ul>
</div>
<div className="col-span-12 md:col-span-2">
<a <a
href="https://vercel.com?utm_source=rallly&utm_campaign=oss" href="https://vercel.com?utm_source=rallly&utm_campaign=oss"
className="inline-block text-white" className="inline-block text-white"
> >
<span className="mb-1 inline-block w-full text-right text-xs italic text-gray-400"> <Vercel className="h-5" />
{t("poweredBy")} </a>
</span> </div>
<Vercel className="w-24" /> <div>
<a className="inline-block" href="https://m.do.co/c/f91efc9c9e50">
<DigitalOcean className="h-7" />
</a>
</div>
<div>
<a className="inline-block" href="https://sentry.io">
<Sentry className="h-6" />
</a>
</div>
</div>
</div>
<div className="lg:col-span-3">
<div className="mb-4 font-medium">{t("common:language")}</div>
<LanguageSelect
className="mb-4 w-full"
onChange={(locale) => {
router.push(router.asPath, router.asPath, { locale });
}}
/>
<a
href="https://github.com/lukevella/rallly/wiki/Guide-for-translators"
className="inline-flex items-center rounded-md border px-3 py-2 text-xs text-slate-500"
>
<Translate className="mr-2 h-5 w-5" />
{t("common:volunteerTranslator")} &rarr;
</a> </a>
</div> </div>
</div> </div>

View file

@ -174,13 +174,6 @@ const PollPage: NextPage = () => {
<Sharing <Sharing
onHide={() => { onHide={() => {
setSharingVisible(false); setSharingVisible(false);
router.replace(
`/admin/${router.query.urlId}`,
undefined,
{
shallow: true,
},
);
}} }}
/> />
</motion.div> </motion.div>

View file

@ -1,12 +1,14 @@
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { useTranslation } from "next-i18next"; import { Trans, useTranslation } from "next-i18next";
import * as React from "react"; import * as React from "react";
import { useMeasure } from "react-use"; import { useMeasure } from "react-use";
import smoothscroll from "smoothscroll-polyfill";
import ArrowLeft from "@/components/icons/arrow-left.svg";
import ArrowRight from "@/components/icons/arrow-right.svg";
import Check from "@/components/icons/check.svg";
import Plus from "@/components/icons/plus-sm.svg";
import { Button } from "../button"; import { Button } from "../button";
import ArrowLeft from "../icons/arrow-left.svg";
import ArrowRight from "../icons/arrow-right.svg";
import { useParticipants } from "../participants-provider"; import { useParticipants } from "../participants-provider";
import { usePoll } from "../poll-context"; import { usePoll } from "../poll-context";
import TimeZonePicker from "../time-zone-picker"; import TimeZonePicker from "../time-zone-picker";
@ -14,11 +16,10 @@ import ParticipantRow from "./desktop-poll/participant-row";
import ParticipantRowForm from "./desktop-poll/participant-row-form"; import ParticipantRowForm from "./desktop-poll/participant-row-form";
import { PollContext } from "./desktop-poll/poll-context"; import { PollContext } from "./desktop-poll/poll-context";
import PollHeader from "./desktop-poll/poll-header"; import PollHeader from "./desktop-poll/poll-header";
import { useAddParticipantMutation } from "./mutations"; import {
useAddParticipantMutation,
if (typeof window !== "undefined") { useUpdateParticipantMutation,
smoothscroll.polyfill(); } from "./mutations";
}
const MotionButton = motion(Button); const MotionButton = motion(Button);
@ -27,7 +28,8 @@ const minSidebarWidth = 200;
const Poll: React.VoidFunctionComponent = () => { const Poll: React.VoidFunctionComponent = () => {
const { t } = useTranslation("app"); const { t } = useTranslation("app");
const { poll, options, targetTimeZone, setTargetTimeZone } = usePoll(); const { poll, options, targetTimeZone, setTargetTimeZone, userAlreadyVoted } =
usePoll();
const { participants } = useParticipants(); const { participants } = useParticipants();
@ -35,7 +37,7 @@ const Poll: React.VoidFunctionComponent = () => {
const [editingParticipantId, setEditingParticipantId] = const [editingParticipantId, setEditingParticipantId] =
React.useState<string | null>(null); React.useState<string | null>(null);
const actionColumnWidth = 140; const actionColumnWidth = 100;
const columnWidth = Math.min( const columnWidth = Math.min(
130, 130,
Math.max( Math.max(
@ -65,7 +67,8 @@ const Poll: React.VoidFunctionComponent = () => {
const maxScrollPosition = const maxScrollPosition =
columnWidth * options.length - columnWidth * numberOfVisibleColumns; columnWidth * options.length - columnWidth * numberOfVisibleColumns;
const shouldShowNewParticipantForm = !poll.closed; const [shouldShowNewParticipantForm, setShouldShowNewParticipantForm] =
React.useState(!poll.closed && !userAlreadyVoted);
const pollWidth = const pollWidth =
sidebarWidth + options.length * columnWidth + actionColumnWidth; sidebarWidth + options.length * columnWidth + actionColumnWidth;
@ -87,6 +90,8 @@ const Poll: React.VoidFunctionComponent = () => {
); );
}; };
const updateParticipant = useUpdateParticipantMutation();
const participantListContainerRef = React.useRef<HTMLDivElement>(null); const participantListContainerRef = React.useRef<HTMLDivElement>(null);
return ( return (
<PollContext.Provider <PollContext.Provider
@ -192,28 +197,93 @@ const Poll: React.VoidFunctionComponent = () => {
isEditing ? participant.id : null, isEditing ? participant.id : null,
); );
}} }}
onSubmit={async ({ name, votes }) => {
await updateParticipant.mutateAsync({
participantId: participant.id,
pollId: poll.id,
votes,
name,
});
}}
/> />
); );
})} })}
</div> </div>
) : null} ) : null}
{shouldShowNewParticipantForm ? ( {shouldShowNewParticipantForm &&
!poll.closed &&
!editingParticipantId ? (
<ParticipantRowForm <ParticipantRowForm
className="border-t bg-gray-50" className="shrink-0 border-t bg-gray-50"
onSubmit={async ({ name, votes }) => { onSubmit={async ({ name, votes }) => {
const participant = await addParticipant.mutateAsync({ await addParticipant.mutateAsync({
name, name,
votes, votes,
pollId: poll.id, pollId: poll.id,
}); });
setTimeout(() => { setShouldShowNewParticipantForm(false);
participantListContainerRef.current
?.querySelector(`[data-participantid=${participant.id}]`)
?.scrollIntoView();
}, 100);
}} }}
/> />
) : null} ) : null}
{!poll.closed ? (
<div className="flex h-14 shrink-0 items-center border-t bg-gray-50 px-3">
{shouldShowNewParticipantForm || editingParticipantId ? (
<div className="flex items-center space-x-3">
<Button
key="submit"
form="participant-row-form"
htmlType="submit"
type="primary"
icon={<Check />}
loading={
addParticipant.isLoading || updateParticipant.isLoading
}
>
{t("save")}
</Button>
<Button
onClick={() => {
if (editingParticipantId) {
setEditingParticipantId(null);
} else {
setShouldShowNewParticipantForm(false);
}
}}
>
{t("cancel")}
</Button>
<div className="text-sm">
<Trans
t={t}
i18nKey="saveInstruction"
values={{
save: t("save"),
}}
components={{ b: <strong /> }}
/>
</div>
</div>
) : (
<div className="flex w-full items-center space-x-3">
<Button
key="add-participant"
onClick={() => {
setShouldShowNewParticipantForm(true);
}}
icon={<Plus />}
>
{t("addParticipant")}
</Button>
{userAlreadyVoted ? (
<div className="flex items-center text-sm text-gray-400">
<Check className="mr-1 h-5" />
<div>{t("alreadyVoted")}</div>
</div>
) : null}
</div>
)}
</div>
) : null}
</div> </div>
</div> </div>
</PollContext.Provider> </PollContext.Provider>

View file

@ -1,11 +1,10 @@
import clsx from "clsx"; import clsx from "clsx";
import { AnimatePresence, motion } from "framer-motion";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import * as React from "react"; import * as React from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import CompactButton from "@/components/compact-button"; import ArrowRight from "@/components/icons/arrow-right.svg";
import Check from "@/components/icons/check.svg";
import X from "@/components/icons/x.svg";
import { requiredString } from "../../../utils/form-validation"; import { requiredString } from "../../../utils/form-validation";
import { Button } from "../../button"; import { Button } from "../../button";
@ -17,6 +16,7 @@ import { VoteSelector } from "../vote-selector";
import ControlledScrollArea from "./controlled-scroll-area"; import ControlledScrollArea from "./controlled-scroll-area";
import { usePollContext } from "./poll-context"; import { usePollContext } from "./poll-context";
const MotionButton = motion(Button);
export interface ParticipantRowFormProps { export interface ParticipantRowFormProps {
defaultValues?: Partial<ParticipantForm>; defaultValues?: Partial<ParticipantForm>;
onSubmit: (data: ParticipantFormSubmitted) => Promise<void>; onSubmit: (data: ParticipantFormSubmitted) => Promise<void>;
@ -43,7 +43,7 @@ const ParticipantRowForm: React.ForwardRefRenderFunction<
const { const {
handleSubmit, handleSubmit,
control, control,
formState: { errors, submitCount, isSubmitting }, formState: { errors, submitCount },
reset, reset,
} = useForm({ } = useForm({
defaultValues: { defaultValues: {
@ -69,6 +69,7 @@ const ParticipantRowForm: React.ForwardRefRenderFunction<
return ( return (
<form <form
id="participant-row-form"
ref={ref} ref={ref}
onSubmit={handleSubmit(async ({ name, votes }) => { onSubmit={handleSubmit(async ({ name, votes }) => {
await onSubmit({ await onSubmit({
@ -91,7 +92,7 @@ const ParticipantRowForm: React.ForwardRefRenderFunction<
className={clsx("w-full", { className={clsx("w-full", {
"input-error": errors.name && submitCount > 0, "input-error": errors.name && submitCount > 0,
})} })}
placeholder="Your name" placeholder={t("yourName")}
{...field} {...field}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.code === "Tab" && scrollPosition > 0) { if (e.code === "Tab" && scrollPosition > 0) {
@ -126,7 +127,7 @@ const ParticipantRowForm: React.ForwardRefRenderFunction<
return ( return (
<div <div
key={optionId} key={optionId}
className="flex shrink-0 items-center justify-center" className="flex shrink-0 items-center justify-center px-2"
style={{ width: columnWidth }} style={{ width: columnWidth }}
> >
<VoteSelector <VoteSelector
@ -162,28 +163,25 @@ const ParticipantRowForm: React.ForwardRefRenderFunction<
/> />
<div className="flex items-center space-x-2 px-2 transition-all"> <div className="flex items-center space-x-2 px-2 transition-all">
{scrollPosition >= maxScrollPosition ? (
<Button
htmlType="submit"
icon={<Check />}
type="primary"
loading={isSubmitting}
data-testid="submitNewParticipant"
>
{t("save")}
</Button>
) : null}
{scrollPosition < maxScrollPosition ? ( {scrollPosition < maxScrollPosition ? (
<Button <AnimatePresence initial={false}>
onClick={(e) => { {scrollPosition < maxScrollPosition ? (
e.stopPropagation(); <MotionButton
transition={{ duration: 0.1 }}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
className="text-xs"
rounded={true}
onClick={() => {
goToNextPage(); goToNextPage();
}} }}
> >
{t("next")} &rarr; <ArrowRight className="h-4 w-4" />
</Button> </MotionButton>
) : null}
</AnimatePresence>
) : null} ) : null}
{onCancel ? <CompactButton onClick={onCancel} icon={X} /> : null}
</div> </div>
</form> </form>
); );

View file

@ -8,7 +8,7 @@ import Trash from "@/components/icons/trash.svg";
import { usePoll } from "@/components/poll-context"; import { usePoll } from "@/components/poll-context";
import { useSession } from "@/components/session"; import { useSession } from "@/components/session";
import { useUpdateParticipantMutation } from "../mutations"; import { ParticipantFormSubmitted } from "../types";
import { useDeleteParticipantModal } from "../use-delete-participant-modal"; import { useDeleteParticipantModal } from "../use-delete-participant-modal";
import UserAvatar from "../user-avatar"; import UserAvatar from "../user-avatar";
import VoteIcon from "../vote-icon"; import VoteIcon from "../vote-icon";
@ -18,8 +18,9 @@ import { usePollContext } from "./poll-context";
export interface ParticipantRowProps { export interface ParticipantRowProps {
participant: Participant & { votes: Vote[] }; participant: Participant & { votes: Vote[] };
editMode: boolean; editMode?: boolean;
onChangeEditMode: (value: boolean) => void; onChangeEditMode?: (editMode: boolean) => void;
onSubmit?: (data: ParticipantFormSubmitted) => Promise<void>;
} }
export const ParticipantRowView: React.VoidFunctionComponent<{ export const ParticipantRowView: React.VoidFunctionComponent<{
@ -49,7 +50,7 @@ export const ParticipantRowView: React.VoidFunctionComponent<{
<div <div
data-testid="participant-row" data-testid="participant-row"
data-participantid={participantId} data-participantid={participantId}
className="group flex h-14" className="group flex h-14 items-center"
> >
<div <div
className="flex shrink-0 items-center px-4" className="flex shrink-0 items-center px-4"
@ -74,12 +75,12 @@ export const ParticipantRowView: React.VoidFunctionComponent<{
return ( return (
<div <div
key={i} key={i}
className="relative shrink-0 transition-colors" className="relative flex shrink-0 items-center justify-center px-2 transition-colors"
style={{ width: columnWidth }} style={{ width: columnWidth }}
> >
<div <div
className={clsx( className={clsx(
"absolute inset-1 flex items-center justify-center rounded-lg", "flex h-10 w-full items-center justify-center rounded-md",
{ {
"bg-green-50": vote === "yes", "bg-green-50": vote === "yes",
"bg-amber-50": vote === "ifNeedBe", "bg-amber-50": vote === "ifNeedBe",
@ -100,12 +101,11 @@ export const ParticipantRowView: React.VoidFunctionComponent<{
const ParticipantRow: React.VoidFunctionComponent<ParticipantRowProps> = ({ const ParticipantRow: React.VoidFunctionComponent<ParticipantRowProps> = ({
participant, participant,
editMode, editMode,
onSubmit,
onChangeEditMode, onChangeEditMode,
}) => { }) => {
const { columnWidth, sidebarWidth } = usePollContext(); const { columnWidth, sidebarWidth } = usePollContext();
const updateParticipant = useUpdateParticipantMutation();
const confirmDeleteParticipant = useDeleteParticipantModal(); const confirmDeleteParticipant = useDeleteParticipantModal();
const session = useSession(); const session = useSession();
@ -128,12 +128,7 @@ const ParticipantRow: React.VoidFunctionComponent<ParticipantRowProps> = ({
}), }),
}} }}
onSubmit={async ({ name, votes }) => { onSubmit={async ({ name, votes }) => {
await updateParticipant.mutateAsync({ await onSubmit?.({ name, votes });
participantId: participant.id,
pollId: poll.id,
votes,
name,
});
onChangeEditMode?.(false); onChangeEditMode?.(false);
}} }}
onCancel={() => onChangeEditMode?.(false)} onCancel={() => onChangeEditMode?.(false)}

View file

@ -0,0 +1,27 @@
import clsx from "clsx";
import Cookies from "js-cookie";
import { useRouter } from "next/router";
import { useTranslation } from "next-i18next";
export const LanguageSelect: React.VoidFunctionComponent<{
className?: string;
onChange?: (language: string) => void;
}> = ({ className, onChange }) => {
const { t } = useTranslation("common");
const router = useRouter();
return (
<select
className={clsx("input", className)}
defaultValue={router.locale}
onChange={(e) => {
Cookies.set("NEXT_LOCALE", e.target.value, {
expires: 365,
});
onChange?.(e.target.value);
}}
>
<option value="en">{t("english")}</option>
<option value="de">{t("german")}</option>
</select>
);
};

View file

@ -213,7 +213,8 @@ const ManagePoll: React.VoidFunctionComponent<{
onClick={() => { onClick={() => {
modalContext.render({ modalContext.render({
overlayClosable: true, overlayClosable: true,
content: ({ close }) => ( content: function Content({ close }) {
return (
<DeletePollForm <DeletePollForm
onConfirm={async () => { onConfirm={async () => {
close(); close();
@ -222,7 +223,8 @@ const ManagePoll: React.VoidFunctionComponent<{
onCancel={close} onCancel={close}
urlId={urlId} urlId={urlId}
/> />
), );
},
footer: null, footer: null,
}); });
}} }}

View file

@ -229,6 +229,7 @@ const PollOption: React.VoidFunctionComponent<PollOptionProps> = ({
ref={selectorRef} ref={selectorRef}
value={vote} value={vote}
onChange={onChange} onChange={onChange}
className="w-9"
/> />
</div> </div>
) : ( ) : (

View file

@ -29,6 +29,10 @@ export const useAddParticipantMutation = () => {
return [...existingParticipants, participant]; return [...existingParticipants, participant];
}, },
); );
queryClient.invalidateQueries([
"polls.participants.list",
{ pollId: participant.pollId },
]);
session.refresh(); session.refresh();
}, },
}); });

View file

@ -1,4 +1,5 @@
import { VoteType } from "@prisma/client"; import { VoteType } from "@prisma/client";
import clsx from "clsx";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import * as React from "react"; import * as React from "react";
@ -10,6 +11,7 @@ export interface VoteSelectorProps {
onFocus?: React.FocusEventHandler<HTMLButtonElement>; onFocus?: React.FocusEventHandler<HTMLButtonElement>;
onBlur?: React.FocusEventHandler<HTMLButtonElement>; onBlur?: React.FocusEventHandler<HTMLButtonElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>; onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
className?: string;
} }
const orderedVoteTypes: VoteType[] = ["yes", "ifNeedBe", "no"]; const orderedVoteTypes: VoteType[] = ["yes", "ifNeedBe", "no"];
@ -23,7 +25,10 @@ const getNext = (value: VoteType) => {
export const VoteSelector = React.forwardRef< export const VoteSelector = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
VoteSelectorProps VoteSelectorProps
>(function VoteSelector({ value, onChange, onFocus, onBlur, onKeyDown }, ref) { >(function VoteSelector(
{ value, onChange, onFocus, onBlur, onKeyDown, className },
ref,
) {
return ( return (
<button <button
data-testid="vote-selector" data-testid="vote-selector"
@ -31,7 +36,20 @@ export const VoteSelector = React.forwardRef<
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur} onBlur={onBlur}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
className="focus-visible:ring-primary-500 relative inline-flex h-9 w-9 items-center justify-center rounded-lg border bg-white shadow-sm transition focus-visible:border-0 focus-visible:ring-2 active:scale-95" className={clsx(
"group relative inline-flex h-9 w-full items-center justify-center overflow-hidden rounded-md border bg-white transition-all hover:ring-4 focus-visible:border-0 focus-visible:ring-2 focus-visible:ring-primary-500",
{
"border-green-200 bg-green-50 hover:ring-green-100/50 active:bg-green-100/50":
value === "yes",
"border-amber-200 bg-amber-50 hover:ring-amber-100/50 active:bg-amber-100/50":
value === "ifNeedBe",
"border-gray-200 bg-gray-50 hover:ring-gray-100/50 active:bg-gray-100/50":
value === "no",
"border-gray-200 hover:ring-gray-100/50 active:bg-gray-100/50":
value === undefined,
},
className,
)}
onClick={() => { onClick={() => {
onChange?.(value ? getNext(value) : orderedVoteTypes[0]); onChange?.(value ? getNext(value) : orderedVoteTypes[0]);
}} }}
@ -40,10 +58,10 @@ export const VoteSelector = React.forwardRef<
<AnimatePresence initial={false}> <AnimatePresence initial={false}>
<motion.span <motion.span
className="absolute flex items-center justify-center" className="absolute flex items-center justify-center"
transition={{ duration: 0.15 }} transition={{ duration: 0.2 }}
initial={{ opacity: 0, y: -15 }} initial={{ opacity: 0, scale: 1.5, y: -45 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, y: 15 }} exit={{ opacity: 0, scale: 0.5, y: 45 }}
key={value} key={value}
> >
<VoteIcon type={value} /> <VoteIcon type={value} />

View file

@ -1,29 +1,33 @@
import clsx from "clsx"; import clsx from "clsx";
import { useRouter } from "next/router";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { usePlausible } from "next-plausible"; import { usePlausible } from "next-plausible";
import React from "react"; import React from "react";
import Calendar from "@/components/icons/calendar.svg"; import { LanguageSelect } from "./poll/language-selector";
import { usePreferences } from "./preferences/use-preferences"; import { usePreferences } from "./preferences/use-preferences";
const Preferences: React.VoidFunctionComponent = () => { const Preferences: React.VoidFunctionComponent = () => {
const { t } = useTranslation("app"); const { t } = useTranslation(["app", "common"]);
const { weekStartsOn, setWeekStartsOn, timeFormat, setTimeFormat } = const { weekStartsOn, setWeekStartsOn, timeFormat, setTimeFormat } =
usePreferences(); usePreferences();
const router = useRouter();
const plausible = usePlausible(); const plausible = usePlausible();
return ( return (
<div className="-mb-2"> <div>
<div className="mb-4 flex items-center space-x-2 text-base font-semibold"> <div className="mb-4 space-y-2">
<Calendar className="inline-block w-5" /> <div className="grow text-sm text-slate-500">
<span>{t("timeAndDate")}</span> {t("common:language")}
</div> </div>
<div className="grow"> <LanguageSelect className="w-full" onChange={() => router.reload()} />
<div className="mb-2"> </div>
<div className="grow space-y-2">
<div>
<div className="mb-2 grow text-sm text-slate-500"> <div className="mb-2 grow text-sm text-slate-500">
{t("weekStartsOn")} {t("app:weekStartsOn")}
</div> </div>
<div> <div>
<div className="segment-button inline-flex"> <div className="segment-button inline-flex">
@ -41,7 +45,7 @@ const Preferences: React.VoidFunctionComponent = () => {
}} }}
type="button" type="button"
> >
{t("monday")} {t("app:monday")}
</button> </button>
<button <button
className={clsx({ className={clsx({
@ -57,14 +61,14 @@ const Preferences: React.VoidFunctionComponent = () => {
}} }}
type="button" type="button"
> >
{t("sunday")} {t("app:sunday")}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div className="mb-2"> <div className="">
<div className="mb-2 grow text-sm text-slate-500"> <div className="mb-2 grow text-sm text-slate-500">
{t("timeFormat")} {t("app:timeFormat")}
</div> </div>
<div className="segment-button inline-flex"> <div className="segment-button inline-flex">
<button <button
@ -81,7 +85,7 @@ const Preferences: React.VoidFunctionComponent = () => {
}} }}
type="button" type="button"
> >
{t("12h")} {t("app:12h")}
</button> </button>
<button <button
className={clsx({ className={clsx({
@ -97,7 +101,7 @@ const Preferences: React.VoidFunctionComponent = () => {
}} }}
type="button" type="button"
> >
{t("24h")} {t("app:24h")}
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,4 +1,5 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import de from "dayjs/locale/de";
import en from "dayjs/locale/en"; import en from "dayjs/locale/en";
import duration from "dayjs/plugin/duration"; import duration from "dayjs/plugin/duration";
import isBetween from "dayjs/plugin/isBetween"; import isBetween from "dayjs/plugin/isBetween";
@ -9,12 +10,18 @@ import minMax from "dayjs/plugin/minMax";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
import timezone from "dayjs/plugin/timezone"; import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import { useRouter } from "next/router";
import * as React from "react"; import * as React from "react";
import { useLocalStorage } from "react-use"; import { useLocalStorage } from "react-use";
type TimeFormat = "12h" | "24h"; type TimeFormat = "12h" | "24h";
type StartOfWeek = "monday" | "sunday"; type StartOfWeek = "monday" | "sunday";
const dayJsLocales = {
de,
en,
};
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
dayjs.extend(localeData); dayjs.extend(localeData);
@ -43,11 +50,13 @@ const PreferencesProvider: React.VoidFunctionComponent<{
const [weekStartsOn = "monday", setWeekStartsOn] = const [weekStartsOn = "monday", setWeekStartsOn] =
useLocalStorage<StartOfWeek>("rallly-week-starts-on"); useLocalStorage<StartOfWeek>("rallly-week-starts-on");
const router = useRouter();
const userLocale = dayJsLocales[router.locale ?? "en"];
const [timeFormat = "12h", setTimeFormat] = const [timeFormat = "12h", setTimeFormat] =
useLocalStorage<TimeFormat>("rallly-time-format"); useLocalStorage<TimeFormat>("rallly-time-format");
dayjs.locale({ dayjs.locale({
...en, ...userLocale,
weekStart: weekStartsOn === "monday" ? 1 : 0, weekStart: weekStartsOn === "monday" ? 1 : 0,
formats: { LT: timeFormat === "12h" ? "h:mm A" : "HH:mm" }, formats: { LT: timeFormat === "12h" ? "h:mm A" : "HH:mm" },
}); });

View file

@ -12,6 +12,7 @@ import Logo from "~/public/logo.svg";
import Dropdown, { DropdownItem, DropdownProps } from "./dropdown"; import Dropdown, { DropdownItem, DropdownProps } from "./dropdown";
import Adjustments from "./icons/adjustments.svg"; import Adjustments from "./icons/adjustments.svg";
import Cash from "./icons/cash.svg"; import Cash from "./icons/cash.svg";
import Discord from "./icons/discord.svg";
import DotsVertical from "./icons/dots-vertical.svg"; import DotsVertical from "./icons/dots-vertical.svg";
import Github from "./icons/github.svg"; import Github from "./icons/github.svg";
import Login from "./icons/login.svg"; import Login from "./icons/login.svg";
@ -293,7 +294,7 @@ const StandardLayout: React.VoidFunctionComponent<{
<AnimatePresence initial={false}> <AnimatePresence initial={false}>
{user ? ( {user ? (
<UserDropdown <UserDropdown
className="w-full" className="mb-4 w-full"
placement="bottom-end" placement="bottom-end"
openLoginModal={openLoginModal} openLoginModal={openLoginModal}
trigger={ trigger={
@ -358,25 +359,34 @@ const StandardLayout: React.VoidFunctionComponent<{
</Link> </Link>
<div className="hidden text-slate-300 lg:block">&bull;</div> <div className="hidden text-slate-300 lg:block">&bull;</div>
<div className="flex items-center space-x-6"> <div className="flex items-center space-x-6">
<Link href="https://twitter.com/ralllyco"> <a
<a className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"> href="https://twitter.com/ralllyco"
className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"
>
<Twitter className="h-5 w-5" /> <Twitter className="h-5 w-5" />
</a> </a>
</Link> <a
<Link href="https://github.com/lukevella/rallly"> href="https://github.com/lukevella/rallly"
<a className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"> className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"
>
<Github className="h-5 w-5" /> <Github className="h-5 w-5" />
</a> </a>
</Link> <a
href="https://discord.gg/m5UFXavc2C"
className="text-sm text-slate-400 transition-colors hover:text-primary-500 hover:no-underline"
>
<Discord className="h-5 w-5" />
</a>
</div> </div>
</div> </div>
<div className="hidden text-slate-300 lg:block">&bull;</div> <div className="hidden text-slate-300 lg:block">&bull;</div>
<Link href="https://www.paypal.com/donate/?hosted_button_id=7QXP2CUBLY88E"> <a
<a className="inline-flex h-8 items-center rounded-full bg-slate-100 pl-2 pr-3 text-sm text-slate-400 transition-colors hover:bg-primary-500 hover:text-white hover:no-underline focus:ring-2 focus:ring-primary-500 focus:ring-offset-1 active:bg-primary-600"> href="https://www.paypal.com/donate/?hosted_button_id=7QXP2CUBLY88E"
className="inline-flex h-8 items-center rounded-full bg-slate-100 pl-2 pr-3 text-sm text-slate-400 transition-colors hover:bg-primary-500 hover:text-white hover:no-underline focus:ring-2 focus:ring-primary-500 focus:ring-offset-1 active:bg-primary-600"
>
<Cash className="mr-1 inline-block w-5" /> <Cash className="mr-1 inline-block w-5" />
<span>{t("donate")}</span> <span>{t("donate")}</span>
</a> </a>
</Link>
</div> </div>
</div> </div>
</div> </div>

22
src/middleware.ts Normal file
View file

@ -0,0 +1,22 @@
import { NextRequest, NextResponse } from "next/server";
export function middleware({ headers, cookies, nextUrl }: NextRequest) {
const locale =
cookies.get("NEXT_LOCALE") ??
(headers
.get("accept-language")
?.split(",")?.[0]
.split("-")?.[0]
.toLowerCase() ||
"en");
const newUrl = nextUrl.clone();
newUrl.pathname = `/${locale}${newUrl.pathname}`;
return NextResponse.rewrite(newUrl);
}
export const config = {
// these are paths we should rewrite to prev
matcher: ["/admin/:id", "/demo", "/p/:id", "/profile", "/new"],
};

View file

@ -1,13 +1,13 @@
import { GetStaticProps, NextPage } from "next"; import { NextPage } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { usePlausible } from "next-plausible"; import { usePlausible } from "next-plausible";
import React from "react"; import React from "react";
import { useMount } from "react-use"; import { useMount } from "react-use";
import FullPageLoader from "../components/full-page-loader"; import FullPageLoader from "../components/full-page-loader";
import { trpc } from "../utils/trpc"; import { trpc } from "../utils/trpc";
import { withPageTranslations } from "../utils/with-page-translations";
const Demo: NextPage = () => { const Demo: NextPage = () => {
const { t } = useTranslation("app"); const { t } = useTranslation("app");
@ -25,12 +25,6 @@ const Demo: NextPage = () => {
return <FullPageLoader>{t("creatingDemo")}</FullPageLoader>; return <FullPageLoader>{t("creatingDemo")}</FullPageLoader>;
}; };
export const getStaticProps: GetStaticProps = async ({ locale = "en" }) => { export const getServerSideProps = withPageTranslations(["common", "app"]);
return {
props: {
...(await serverSideTranslations(locale, ["app"])),
},
};
};
export default Demo; export default Demo;

View file

@ -4,13 +4,9 @@ import { serverSideTranslations } from "next-i18next/serverSideTranslations";
export { default } from "@/components/home"; export { default } from "@/components/home";
export const getStaticProps: GetStaticProps = async ({ locale = "en" }) => { export const getStaticProps: GetStaticProps = async ({ locale = "en" }) => {
try {
return { return {
props: { props: {
...(await serverSideTranslations(locale, ["homepage"])), ...(await serverSideTranslations(locale, ["common", "homepage"])),
}, },
}; };
} catch {
return { notFound: true };
}
}; };

View file

@ -1,19 +1,11 @@
import { GetServerSideProps } from "next"; import { GetServerSideProps } from "next";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { withSessionSsr } from "../utils/auth"; import { withSessionSsr } from "../utils/auth";
import { withPageTranslations } from "../utils/with-page-translations";
export const getServerSideProps: GetServerSideProps = withSessionSsr( export const getServerSideProps: GetServerSideProps = withSessionSsr(
async ({ locale = "en", query, req }) => { withPageTranslations(["common", "app"]),
return {
props: {
...(await serverSideTranslations(locale, ["app"])),
...query,
user: req.session.user ?? null,
},
};
},
); );
export default dynamic(() => import("@/components/create-poll"), { export default dynamic(() => import("@/components/create-poll"), {

View file

@ -2,21 +2,21 @@ import { GetServerSideProps, NextPage } from "next";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React from "react"; import React from "react";
import FullPageLoader from "@/components/full-page-loader"; import FullPageLoader from "@/components/full-page-loader";
import { PollContextProvider } from "@/components/poll-context"; import { PollContextProvider } from "@/components/poll-context";
import { SessionProps, withSession } from "@/components/session"; import { withSession } from "@/components/session";
import { ParticipantsProvider } from "../components/participants-provider"; import { ParticipantsProvider } from "../components/participants-provider";
import { withSessionSsr } from "../utils/auth"; import { withSessionSsr } from "../utils/auth";
import { trpc } from "../utils/trpc"; import { trpc } from "../utils/trpc";
import { withPageTranslations } from "../utils/with-page-translations";
import Custom404 from "./404"; import Custom404 from "./404";
const PollPage = dynamic(() => import("@/components/poll"), { ssr: false }); const PollPage = dynamic(() => import("@/components/poll"), { ssr: false });
const PollPageLoader: NextPage<SessionProps> = () => { const PollPageLoader: NextPage = () => {
const { query, asPath } = useRouter(); const { query, asPath } = useRouter();
const { t } = useTranslation("app"); const { t } = useTranslation("app");
const urlId = query.urlId as string; const urlId = query.urlId as string;
@ -50,14 +50,7 @@ const PollPageLoader: NextPage<SessionProps> = () => {
}; };
export const getServerSideProps: GetServerSideProps = withSessionSsr( export const getServerSideProps: GetServerSideProps = withSessionSsr(
async ({ locale = "en", req }) => { withPageTranslations(["common", "app"]),
return {
props: {
...(await serverSideTranslations(locale, ["app"])),
user: req.session.user ?? null,
},
};
},
); );
export default withSession(PollPageLoader); export default withSession(PollPageLoader);

View file

@ -370,7 +370,7 @@ export const getStaticProps: GetStaticProps = async ({ locale = "en" }) => {
try { try {
return { return {
props: { props: {
...(await serverSideTranslations(locale, ["app", "homepage"])), ...(await serverSideTranslations(locale, ["common", "homepage"])),
}, },
}; };
} catch { } catch {

View file

@ -1,11 +1,11 @@
import { NextPage } from "next"; import { NextPage } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { withSessionSsr } from "@/utils/auth"; import { withSessionSsr } from "@/utils/auth";
import { Profile } from "../components/profile"; import { Profile } from "../components/profile";
import { withSession } from "../components/session"; import { withSession } from "../components/session";
import StandardLayout from "../components/standard-layout"; import StandardLayout from "../components/standard-layout";
import { withPageTranslations } from "../utils/with-page-translations";
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
@ -16,14 +16,7 @@ const Page: NextPage = () => {
}; };
export const getServerSideProps = withSessionSsr( export const getServerSideProps = withSessionSsr(
async ({ locale = "en", query }) => { withPageTranslations(["common", "app"]),
return {
props: {
...(await serverSideTranslations(locale, ["app"])),
...query,
},
};
},
); );
export default withSession(Page); export default withSession(Page);

View file

@ -1,6 +1,5 @@
import * as Eta from "eta"; import * as Eta from "eta";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { NextApiRequest } from "next";
import path from "path"; import path from "path";
import { prisma } from "~/prisma/db"; import { prisma } from "~/prisma/db";
@ -8,11 +7,6 @@ import { prisma } from "~/prisma/db";
import { absoluteUrl } from "./absolute-url"; import { absoluteUrl } from "./absolute-url";
import { sendEmail } from "./send-email"; import { sendEmail } from "./send-email";
export const getQueryParam = (req: NextApiRequest, queryKey: string) => {
const value = req.query[queryKey];
return typeof value === "string" ? value : value[0];
};
type NotificationAction = type NotificationAction =
| { | {
type: "newParticipant"; type: "newParticipant";

View file

@ -32,7 +32,13 @@ export function withSessionSsr(handler: GetServerSideProps) {
req.session.user = await createGuestUser(); req.session.user = await createGuestUser();
await req.session.save(); await req.session.save();
} }
return await handler(context); const res = await handler(context);
if ("props" in res) {
return { ...res, props: { ...res.props, user: req.session.user } };
}
return res;
}, sessionOptions); }, sessionOptions);
} }

View file

@ -0,0 +1,15 @@
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
export const withPageTranslations = (
namespaces: string[],
): GetServerSideProps => {
return async (ctx: GetServerSidePropsContext) => {
const locale = ctx.locale ?? "en";
return {
props: {
...(await serverSideTranslations(locale, namespaces)),
},
};
};
};

View file

@ -32,7 +32,7 @@
@apply outline-none; @apply outline-none;
} }
a { a {
@apply rounded-sm font-medium text-primary-500 outline-none hover:text-primary-400 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1; @apply rounded-sm font-medium text-primary-500 outline-none hover:text-primary-500 hover:underline hover:no-underline focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1;
} }
label { label {
@apply mb-1 block text-sm text-slate-800; @apply mb-1 block text-sm text-slate-800;

View file

@ -11,12 +11,12 @@ test("should be able to vote and comment on a poll", async ({ page }) => {
await expect(page.locator('text="Lunch Meeting"')).toBeVisible(); await expect(page.locator('text="Lunch Meeting"')).toBeVisible();
await page.type('[placeholder="Your name"]', "Test user"); await page.type('[placeholder="Your name"]', "Test user");
// There is a hidden checkbox (nth=0) that exists so that the behaviour of the form is consistent even // There is a hidden checkbox (nth=0) that exists so that the behaviour of the form is consistent even
// when we only have a single option/checkbox. // when we only have a single option/checkbox.
await page.locator("data-testid=vote-selector >> nth=0").click(); await page.locator("data-testid=vote-selector >> nth=0").click();
await page.locator("data-testid=vote-selector >> nth=2").click(); await page.locator("data-testid=vote-selector >> nth=2").click();
await page.click('[data-testid="submitNewParticipant"]'); await page.click("text='Save'");
await expect(page.locator("text='Test user'")).toBeVisible(); await expect(page.locator("text='Test user'")).toBeVisible();
await expect(page.locator("text=Guest")).toBeVisible(); await expect(page.locator("text=Guest")).toBeVisible();
await expect( await expect(

507
yarn.lock
View file

@ -1188,77 +1188,82 @@
dependencies: dependencies:
webpack-bundle-analyzer "4.3.0" webpack-bundle-analyzer "4.3.0"
"@next/env@12.1.4": "@next/env@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.4.tgz#5af629b43075281ecd7f87938802b7cf5b67e94b" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.2.2.tgz#cc1a0a445bd254499e30f632968c03192455f4cc"
integrity sha512-7gQwotJDKnfMxxXd8xJ2vsX5AzyDxO3zou0+QOXX8/unypA6icw5+wf6A62yKZ6qQ4UZHHxS68pb6UV+wNneXg== integrity sha512-BqDwE4gDl1F608TpnNxZqrCn6g48MBjvmWFEmeX5wEXDXh3IkAOw6ASKUgjT8H4OUePYFqghDFUss5ZhnbOUjw==
"@next/eslint-plugin-next@12.1.0": "@next/eslint-plugin-next@12.2.2":
version "12.1.0" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.0.tgz#32586a11378b3ffa5a93ac40a3c44ad99d70e95a" resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.2.2.tgz#b4a22c06b6454068b54cc44502168d90fbb29a6d"
integrity sha512-WFiyvSM2G5cQmh32t/SiQuJ+I2O+FHVlK/RFw5b1565O2kEM/36EXncjt88Pa+X5oSc+1SS+tWxowWJd1lqI+g== integrity sha512-XOi0WzJhGH3Lk51SkSu9eZxF+IY1ZZhWcJTIGBycAbWU877IQa6+6KxMATWCOs7c+bmp6Sd8KywXJaDRxzu0JA==
dependencies: dependencies:
glob "7.1.7" glob "7.1.7"
"@next/swc-android-arm-eabi@12.1.4": "@next/swc-android-arm-eabi@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.4.tgz#c3dae178b7c15ad627d2e9b8dfb38caecb5c4ac7" resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.2.tgz#f6c4111e6371f73af6bf80c9accb3d96850a92cd"
integrity sha512-FJg/6a3s2YrUaqZ+/DJZzeZqfxbbWrynQMT1C5wlIEq9aDLXCFpPM/PiOyJh0ahxc0XPmi6uo38Poq+GJTuKWw== integrity sha512-VHjuCHeq9qCprUZbsRxxM/VqSW8MmsUtqB5nEpGEgUNnQi/BTm/2aK8tl7R4D0twGKRh6g1AAeFuWtXzk9Z/vQ==
"@next/swc-android-arm64@12.1.4": "@next/swc-android-arm64@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.4.tgz#f320d60639e19ecffa1f9034829f2d95502a9a51" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.2.2.tgz#b69de59c51e631a7600439e7a8993d6e82f3369e"
integrity sha512-LXraazvQQFBgxIg3Htny6G5V5he9EK7oS4jWtMdTGIikmD/OGByOv8ZjLuVLZLtVm3UIvaAiGtlQSLecxJoJDw== integrity sha512-v5EYzXUOSv0r9mO/2PX6mOcF53k8ndlu9yeFHVAWW1Dhw2jaJcvTRcCAwYYN8Q3tDg0nH3NbEltJDLKmcJOuVA==
"@next/swc-darwin-arm64@12.1.4": "@next/swc-darwin-arm64@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.4.tgz#fd578278312613eddcf3aee26910100509941b63" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.2.tgz#80157c91668eff95b72d052428c353eab0fc4c50"
integrity sha512-SSST/dBymecllZxcqTCcSTCu5o1NKk9I+xcvhn/O9nH6GWjgvGgGkNqLbCarCa0jJ1ukvlBA138FagyrmZ/4rQ== integrity sha512-JCoGySHKGt+YBk7xRTFGx1QjrnCcwYxIo3yGepcOq64MoiocTM3yllQWeOAJU2/k9MH0+B5E9WUSme4rOCBbpA==
"@next/swc-darwin-x64@12.1.4": "@next/swc-darwin-x64@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.4.tgz#ace5f80d8c8348efe194f6d7074c6213c52b3944" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.2.tgz#12be2f58e676fccff3d48a62921b9927ed295133"
integrity sha512-p1lwdX0TVjaoDXQVuAkjtxVBbCL/urgxiMCBwuPDO7TikpXtSRivi+mIzBj5q7ypgICFmIAOW3TyupXeoPRAnA== integrity sha512-dztDtvfkhUqiqpXvrWVccfGhLe44yQ5tQ7B4tBfnsOR6vxzI9DNPHTlEOgRN9qDqTAcFyPxvg86mn4l8bB9Jcw==
"@next/swc-linux-arm-gnueabihf@12.1.4": "@next/swc-freebsd-x64@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.4.tgz#2bf2c83863635f19c71c226a2df936e001cce29c" resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.2.tgz#de1363431a49059f1efb8c0f86ce6a79c53b3a95"
integrity sha512-67PZlgkCn3TDxacdVft0xqDCL7Io1/C4xbAs0+oSQ0xzp6OzN2RNpuKjHJrJgKd0DsE1XZ9sCP27Qv0591yfyg== integrity sha512-JUnXB+2xfxqsAvhFLPJpU1NeyDsvJrKoOjpV7g3Dxbno2Riu4tDKn3kKF886yleAuD/1qNTUCpqubTvbbT2VoA==
"@next/swc-linux-arm64-gnu@12.1.4": "@next/swc-linux-arm-gnueabihf@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.4.tgz#d577190f641c9b4b463719dd6b8953b6ba9be8d9" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.2.tgz#d5b8e0d1bb55bbd9db4d2fec018217471dc8b9e6"
integrity sha512-OnOWixhhw7aU22TQdQLYrgpgFq0oA1wGgnjAiHJ+St7MLj82KTDyM9UcymAMbGYy6nG/TFOOHdTmRMtCRNOw0g== integrity sha512-XeYC/qqPLz58R4pjkb+x8sUUxuGLnx9QruC7/IGkK68yW4G17PHwKI/1njFYVfXTXUukpWjcfBuauWwxp9ke7Q==
"@next/swc-linux-arm64-musl@12.1.4": "@next/swc-linux-arm64-gnu@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.4.tgz#e70ffe70393d8f9242deecdb282ce5a8fd588b14" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.2.tgz#3bc75984e1d5ec8f59eb53702cc382d8e1be2061"
integrity sha512-UoRMzPZnsAavdWtVylYxH8DNC7Uy0i6RrvNwT4PyQVdfANBn2omsUkcH5lgS2O7oaz0nAYLk1vqyZDO7+tJotA== integrity sha512-d6jT8xgfKYFkzR7J0OHo2D+kFvY/6W8qEo6/hmdrTt6AKAqxs//rbbcdoyn3YQq1x6FVUUd39zzpezZntg9Naw==
"@next/swc-linux-x64-gnu@12.1.4": "@next/swc-linux-arm64-musl@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.4.tgz#91498a130387fb1961902f2bee55863f8e910cff" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.2.tgz#270db73e07a18d999f61e79a917943fa5bc1ef56"
integrity sha512-nM+MA/frxlTLUKLJKorctdI20/ugfHRjVEEkcLp/58LGG7slNaP1E5d5dRA1yX6ISjPcQAkywas5VlGCg+uTvA== integrity sha512-rIZRFxI9N/502auJT1i7coas0HTHUM+HaXMyJiCpnY8Rimbo0495ir24tzzHo3nQqJwcflcPTwEh/DV17sdv9A==
"@next/swc-linux-x64-musl@12.1.4": "@next/swc-linux-x64-gnu@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.4.tgz#78057b03c148c121553d41521ad38f6c732762ff" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.2.tgz#e6c72fa20478552e898c434f4d4c0c5e89d2ea78"
integrity sha512-GoRHxkuW4u4yKw734B9SzxJwVdyEJosaZ62P7ifOwcujTxhgBt3y76V2nNUrsSuopcKI2ZTDjaa+2wd5zyeXbA== integrity sha512-ir1vNadlUDj7eQk15AvfhG5BjVizuCHks9uZwBfUgT5jyeDCeRvaDCo1+Q6+0CLOAnYDR/nqSCvBgzG2UdFh9A==
"@next/swc-win32-arm64-msvc@12.1.4": "@next/swc-linux-x64-musl@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.4.tgz#05bbaabacac23b8edf6caa99eb86b17550a09051" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.2.tgz#b9ef9efe2c401839cdefa5e70402386aafdce15a"
integrity sha512-6TQkQze0ievXwHJcVUrIULwCYVe3ccX6T0JgZ1SiMeXpHxISN7VJF/O8uSCw1JvXZYZ6ud0CJ7nfC5HXivgfPg== integrity sha512-bte5n2GzLN3O8JdSFYWZzMgEgDHZmRz5wiispiiDssj4ik3l8E7wq/czNi8RmIF+ioj2sYVokUNa/ekLzrESWw==
"@next/swc-win32-ia32-msvc@12.1.4": "@next/swc-win32-arm64-msvc@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.4.tgz#8fd2fb48f04a2802e51fc320878bf6b411c1c866" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.2.tgz#18fa7ec7248da3a7926a0601d9ececc53ac83157"
integrity sha512-CsbX/IXuZ5VSmWCpSetG2HD6VO5FTsO39WNp2IR2Ut/uom9XtLDJAZqjQEnbUTLGHuwDKFjrIO3LkhtROXLE/g== integrity sha512-ZUGCmcDmdPVSAlwJ/aD+1F9lYW8vttseiv4n2+VCDv5JloxiX9aY32kYZaJJO7hmTLNrprvXkb4OvNuHdN22Jg==
"@next/swc-win32-x64-msvc@12.1.4": "@next/swc-win32-ia32-msvc@12.2.2":
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.4.tgz#a72ed44c9b1f850986a30fe36c59e01f8a79b5f3" resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.2.tgz#54936e84f4a219441d051940354da7cd3eafbb4f"
integrity sha512-JtYuWzKXKLDMgE/xTcFtCm1MiCIRaAc5XYZfYX3n/ZWSI1SJS/GMm+Su0SAHJgRFavJh6U/p998YwO/iGTIgqQ== integrity sha512-v7ykeEDbr9eXiblGSZiEYYkWoig6sRhAbLKHUHQtk8vEWWVEqeXFcxmw6LRrKu5rCN1DY357UlYWToCGPQPCRA==
"@next/swc-win32-x64-msvc@12.2.2":
version "12.2.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.2.tgz#7460be700a60d75816f01109400b51fe929d7e89"
integrity sha512-2D2iinWUL6xx8D9LYVZ5qi7FP6uLAoWymt8m8aaG2Ld/Ka8/k723fJfiklfuAcwOxfufPJI+nRbT5VcgHGzHAQ==
"@nodelib/fs.scandir@2.1.4": "@nodelib/fs.scandir@2.1.4":
version "2.1.4" version "2.1.4"
@ -1324,10 +1329,10 @@
lodash "^4.17.20" lodash "^4.17.20"
lodash-es "^4.17.20" lodash-es "^4.17.20"
"@rushstack/eslint-patch@^1.0.8": "@rushstack/eslint-patch@^1.1.3":
version "1.1.1" version "1.1.4"
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.1.tgz#782fa5da44c4f38ae9fd38e9184b54e451936118" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz#0c8b74c50f29ee44f423f7416829c0bf8bb5eb27"
integrity sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg== integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==
"@sentry/browser@7.0.0": "@sentry/browser@7.0.0":
version "7.0.0" version "7.0.0"
@ -1573,6 +1578,13 @@
"@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-jsx" "^6.2.1"
"@svgr/plugin-svgo" "^6.2.0" "@svgr/plugin-svgo" "^6.2.0"
"@swc/helpers@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.2.tgz#ed1f6997ffbc22396665d9ba74e2a5c0a2d782f8"
integrity sha512-556Az0VX7WR6UdoTn4htt/l3zPQ7bsQWK+HqdG4swV7beUCxo/BqmvbOpUkTIm/9ih86LIf1qsUnywNL3obGHw==
dependencies:
tslib "^2.4.0"
"@tailwindcss/forms@^0.4.0": "@tailwindcss/forms@^0.4.0":
version "0.4.0" version "0.4.0"
resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.4.0.tgz" resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.4.0.tgz"
@ -1799,16 +1811,6 @@
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/parser@^5.0.0":
version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508"
integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==
dependencies:
"@typescript-eslint/scope-manager" "5.16.0"
"@typescript-eslint/types" "5.16.0"
"@typescript-eslint/typescript-estree" "5.16.0"
debug "^4.3.2"
"@typescript-eslint/parser@^5.21.0": "@typescript-eslint/parser@^5.21.0":
version "5.21.0" version "5.21.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.21.0.tgz#6cb72673dbf3e1905b9c432175a3c86cdaf2071f" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.21.0.tgz#6cb72673dbf3e1905b9c432175a3c86cdaf2071f"
@ -1819,14 +1821,6 @@
"@typescript-eslint/typescript-estree" "5.21.0" "@typescript-eslint/typescript-estree" "5.21.0"
debug "^4.3.2" debug "^4.3.2"
"@typescript-eslint/scope-manager@5.16.0":
version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a"
integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==
dependencies:
"@typescript-eslint/types" "5.16.0"
"@typescript-eslint/visitor-keys" "5.16.0"
"@typescript-eslint/scope-manager@5.21.0": "@typescript-eslint/scope-manager@5.21.0":
version "5.21.0" version "5.21.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.21.0.tgz#a4b7ed1618f09f95e3d17d1c0ff7a341dac7862e" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.21.0.tgz#a4b7ed1618f09f95e3d17d1c0ff7a341dac7862e"
@ -1844,29 +1838,11 @@
debug "^4.3.2" debug "^4.3.2"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/types@5.16.0":
version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee"
integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==
"@typescript-eslint/types@5.21.0": "@typescript-eslint/types@5.21.0":
version "5.21.0" version "5.21.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.21.0.tgz#8cdb9253c0dfce3f2ab655b9d36c03f72e684017" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.21.0.tgz#8cdb9253c0dfce3f2ab655b9d36c03f72e684017"
integrity sha512-XnOOo5Wc2cBlq8Lh5WNvAgHzpjnEzxn4CJBwGkcau7b/tZ556qrWXQz4DJyChYg8JZAD06kczrdgFPpEQZfDsA== integrity sha512-XnOOo5Wc2cBlq8Lh5WNvAgHzpjnEzxn4CJBwGkcau7b/tZ556qrWXQz4DJyChYg8JZAD06kczrdgFPpEQZfDsA==
"@typescript-eslint/typescript-estree@5.16.0":
version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61"
integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==
dependencies:
"@typescript-eslint/types" "5.16.0"
"@typescript-eslint/visitor-keys" "5.16.0"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.21.0": "@typescript-eslint/typescript-estree@5.21.0":
version "5.21.0" version "5.21.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.21.0.tgz#9f0c233e28be2540eaed3df050f0d54fb5aa52de" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.21.0.tgz#9f0c233e28be2540eaed3df050f0d54fb5aa52de"
@ -1892,14 +1868,6 @@
eslint-scope "^5.1.1" eslint-scope "^5.1.1"
eslint-utils "^3.0.0" eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.16.0":
version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb"
integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==
dependencies:
"@typescript-eslint/types" "5.16.0"
eslint-visitor-keys "^3.0.0"
"@typescript-eslint/visitor-keys@5.21.0": "@typescript-eslint/visitor-keys@5.21.0":
version "5.21.0" version "5.21.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz#453fb3662409abaf2f8b1f65d515699c888dd8ae" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz#453fb3662409abaf2f8b1f65d515699c888dd8ae"
@ -2078,6 +2046,17 @@ array-includes@^3.1.4:
get-intrinsic "^1.1.1" get-intrinsic "^1.1.1"
is-string "^1.0.7" is-string "^1.0.7"
array-includes@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
get-intrinsic "^1.1.1"
is-string "^1.0.7"
array-union@^2.1.0: array-union@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
@ -2111,14 +2090,15 @@ array.prototype.flatmap@^1.2.4:
es-abstract "^1.18.0-next.1" es-abstract "^1.18.0-next.1"
function-bind "^1.1.1" function-bind "^1.1.1"
array.prototype.flatmap@^1.2.5: array.prototype.flatmap@^1.3.0:
version "1.2.5" version "1.3.0"
resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f"
integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==
dependencies: dependencies:
call-bind "^1.0.0" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
es-abstract "^1.19.0" es-abstract "^1.19.2"
es-shim-unscopables "^1.0.0"
ast-types-flow@^0.0.7: ast-types-flow@^0.0.7:
version "0.0.7" version "0.0.7"
@ -2280,16 +2260,16 @@ camelcase@^6.2.0:
resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001283:
version "1.0.30001304"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001304.tgz"
integrity sha512-bdsfZd6K6ap87AGqSHJP/s1V+U6Z5lyrcbBu3ovbCCf8cSYpwTtGrCBObMpJqwxfTbLW6YTIdbb1jEeTelcpYQ==
caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297: caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297:
version "1.0.30001303" version "1.0.30001303"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz"
integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ== integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ==
caniuse-lite@^1.0.30001332:
version "1.0.30001367"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz#2b97fe472e8fa29c78c5970615d7cd2ee414108a"
integrity sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==
chalk@^2.0.0: chalk@^2.0.0:
version "2.4.2" version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
@ -2584,6 +2564,14 @@ define-properties@^1.1.3:
dependencies: dependencies:
object-keys "^1.0.12" object-keys "^1.0.12"
define-properties@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
dependencies:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
defined@^1.0.0: defined@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz"
@ -2784,6 +2772,42 @@ es-abstract@^1.19.0, es-abstract@^1.19.1:
string.prototype.trimstart "^1.0.4" string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1" unbox-primitive "^1.0.1"
es-abstract@^1.19.2, es-abstract@^1.19.5:
version "1.20.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
function.prototype.name "^1.1.5"
get-intrinsic "^1.1.1"
get-symbol-description "^1.0.0"
has "^1.0.3"
has-property-descriptors "^1.0.0"
has-symbols "^1.0.3"
internal-slot "^1.0.3"
is-callable "^1.2.4"
is-negative-zero "^2.0.2"
is-regex "^1.1.4"
is-shared-array-buffer "^1.0.2"
is-string "^1.0.7"
is-weakref "^1.0.2"
object-inspect "^1.12.0"
object-keys "^1.1.1"
object.assign "^4.1.2"
regexp.prototype.flags "^1.4.3"
string.prototype.trimend "^1.0.5"
string.prototype.trimstart "^1.0.5"
unbox-primitive "^1.0.2"
es-shim-unscopables@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
dependencies:
has "^1.0.3"
es-to-primitive@^1.2.1: es-to-primitive@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
@ -2803,20 +2827,20 @@ escape-string-regexp@^1.0.5:
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
eslint-config-next@12.1.0: eslint-config-next@^12.2.2:
version "12.1.0" version "12.2.2"
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.0.tgz#8ace680dc5207e6ab6c915f3989adec122f582e7" resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.2.2.tgz#4bb996026e118071849bc4011283a160ad5bde46"
integrity sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA== integrity sha512-oJhWBLC4wDYYUFv/5APbjHUFd0QRFCojMdj/QnMoOEktmeTvwnnoA8F8uaXs0fQgsaTK0tbUxBRv9/Y4/rpxOA==
dependencies: dependencies:
"@next/eslint-plugin-next" "12.1.0" "@next/eslint-plugin-next" "12.2.2"
"@rushstack/eslint-patch" "^1.0.8" "@rushstack/eslint-patch" "^1.1.3"
"@typescript-eslint/parser" "^5.0.0" "@typescript-eslint/parser" "^5.21.0"
eslint-import-resolver-node "^0.3.4" eslint-import-resolver-node "^0.3.6"
eslint-import-resolver-typescript "^2.4.0" eslint-import-resolver-typescript "^2.7.1"
eslint-plugin-import "^2.25.2" eslint-plugin-import "^2.26.0"
eslint-plugin-jsx-a11y "^6.5.1" eslint-plugin-jsx-a11y "^6.5.1"
eslint-plugin-react "^7.27.0" eslint-plugin-react "^7.29.4"
eslint-plugin-react-hooks "^4.3.0" eslint-plugin-react-hooks "^4.5.0"
eslint-import-resolver-node@^0.3.4: eslint-import-resolver-node@^0.3.4:
version "0.3.4" version "0.3.4"
@ -2834,7 +2858,7 @@ eslint-import-resolver-node@^0.3.6:
debug "^3.2.7" debug "^3.2.7"
resolve "^1.20.0" resolve "^1.20.0"
eslint-import-resolver-typescript@^2.4.0, eslint-import-resolver-typescript@^2.7.0: eslint-import-resolver-typescript@^2.7.0:
version "2.7.0" version "2.7.0"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.0.tgz#1f9d391b636dccdbaa4a3b1a87eb9a8237e23963" resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.0.tgz#1f9d391b636dccdbaa4a3b1a87eb9a8237e23963"
integrity sha512-MNHS3u5pebvROX4MjGP9coda589ZGfL1SqdxUV4kSrcclfDRWvNE2D+eljbnWVMvWDVRgT89nhscMHPKYGcObQ== integrity sha512-MNHS3u5pebvROX4MjGP9coda589ZGfL1SqdxUV4kSrcclfDRWvNE2D+eljbnWVMvWDVRgT89nhscMHPKYGcObQ==
@ -2845,6 +2869,17 @@ eslint-import-resolver-typescript@^2.4.0, eslint-import-resolver-typescript@^2.7
resolve "^1.22.0" resolve "^1.22.0"
tsconfig-paths "^3.14.1" tsconfig-paths "^3.14.1"
eslint-import-resolver-typescript@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz#a90a4a1c80da8d632df25994c4c5fdcdd02b8751"
integrity sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==
dependencies:
debug "^4.3.4"
glob "^7.2.0"
is-glob "^4.0.3"
resolve "^1.22.0"
tsconfig-paths "^3.14.1"
eslint-module-utils@^2.6.0: eslint-module-utils@^2.6.0:
version "2.6.0" version "2.6.0"
resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz" resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz"
@ -2853,7 +2888,7 @@ eslint-module-utils@^2.6.0:
debug "^2.6.9" debug "^2.6.9"
pkg-dir "^2.0.0" pkg-dir "^2.0.0"
eslint-module-utils@^2.7.2: eslint-module-utils@^2.7.3:
version "2.7.3" version "2.7.3"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
@ -2880,24 +2915,24 @@ eslint-plugin-import@^2.22.1:
resolve "^1.17.0" resolve "^1.17.0"
tsconfig-paths "^3.9.0" tsconfig-paths "^3.9.0"
eslint-plugin-import@^2.25.2: eslint-plugin-import@^2.26.0:
version "2.25.4" version "2.26.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
dependencies: dependencies:
array-includes "^3.1.4" array-includes "^3.1.4"
array.prototype.flat "^1.2.5" array.prototype.flat "^1.2.5"
debug "^2.6.9" debug "^2.6.9"
doctrine "^2.1.0" doctrine "^2.1.0"
eslint-import-resolver-node "^0.3.6" eslint-import-resolver-node "^0.3.6"
eslint-module-utils "^2.7.2" eslint-module-utils "^2.7.3"
has "^1.0.3" has "^1.0.3"
is-core-module "^2.8.0" is-core-module "^2.8.1"
is-glob "^4.0.3" is-glob "^4.0.3"
minimatch "^3.0.4" minimatch "^3.1.2"
object.values "^1.1.5" object.values "^1.1.5"
resolve "^1.20.0" resolve "^1.22.0"
tsconfig-paths "^3.12.0" tsconfig-paths "^3.14.1"
eslint-plugin-jsx-a11y@^6.5.1: eslint-plugin-jsx-a11y@^6.5.1:
version "6.5.1" version "6.5.1"
@ -2922,10 +2957,10 @@ eslint-plugin-react-hooks@^4.2.0:
resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz" resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz"
integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==
eslint-plugin-react-hooks@^4.3.0: eslint-plugin-react-hooks@^4.5.0:
version "4.3.0" version "4.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
eslint-plugin-react@^7.23.2: eslint-plugin-react@^7.23.2:
version "7.23.2" version "7.23.2"
@ -2945,25 +2980,25 @@ eslint-plugin-react@^7.23.2:
resolve "^2.0.0-next.3" resolve "^2.0.0-next.3"
string.prototype.matchall "^4.0.4" string.prototype.matchall "^4.0.4"
eslint-plugin-react@^7.27.0: eslint-plugin-react@^7.29.4:
version "7.29.4" version "7.30.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz#2be4ab23ce09b5949c6631413ba64b2810fd3e22"
integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== integrity sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==
dependencies: dependencies:
array-includes "^3.1.4" array-includes "^3.1.5"
array.prototype.flatmap "^1.2.5" array.prototype.flatmap "^1.3.0"
doctrine "^2.1.0" doctrine "^2.1.0"
estraverse "^5.3.0" estraverse "^5.3.0"
jsx-ast-utils "^2.4.1 || ^3.0.0" jsx-ast-utils "^2.4.1 || ^3.0.0"
minimatch "^3.1.2" minimatch "^3.1.2"
object.entries "^1.1.5" object.entries "^1.1.5"
object.fromentries "^2.0.5" object.fromentries "^2.0.5"
object.hasown "^1.1.0" object.hasown "^1.1.1"
object.values "^1.1.5" object.values "^1.1.5"
prop-types "^15.8.1" prop-types "^15.8.1"
resolve "^2.0.0-next.3" resolve "^2.0.0-next.3"
semver "^6.3.0" semver "^6.3.0"
string.prototype.matchall "^4.0.6" string.prototype.matchall "^4.0.7"
eslint-plugin-simple-import-sort@^7.0.0: eslint-plugin-simple-import-sort@^7.0.0:
version "7.0.0" version "7.0.0"
@ -3230,11 +3265,26 @@ function-bind@^1.1.1:
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function.prototype.name@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
es-abstract "^1.19.0"
functions-have-names "^1.2.2"
functional-red-black-tree@^1.0.1: functional-red-black-tree@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
functions-have-names@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
gauge@~2.7.3: gauge@~2.7.3:
version "2.7.4" version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@ -3271,11 +3321,6 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2" call-bind "^1.0.2"
get-intrinsic "^1.1.1" get-intrinsic "^1.1.1"
github-buttons@^2.21.1:
version "2.21.1"
resolved "https://registry.yarnpkg.com/github-buttons/-/github-buttons-2.21.1.tgz#9e55eb83b70c9149a21c235db2e971c53d4d98a2"
integrity sha512-n9bCQ8sj+5oX1YH5NeyWGbAclRDtHEhMBzqw2ctsWpdEHOwVgfruRu0VIVy01Ah10dd/iFajMHYU71L7IBWBOw==
glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
@ -3367,6 +3412,11 @@ has-bigints@^1.0.1:
resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz" resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
has-flag@^3.0.0: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
@ -3377,6 +3427,13 @@ has-flag@^4.0.0:
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
dependencies:
get-intrinsic "^1.1.1"
has-symbols@^1.0.1, has-symbols@^1.0.2: has-symbols@^1.0.1, has-symbols@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
@ -3590,7 +3647,7 @@ is-core-module@^2.2.0:
dependencies: dependencies:
has "^1.0.3" has "^1.0.3"
is-core-module@^2.8.0, is-core-module@^2.8.1: is-core-module@^2.8.1:
version "2.8.1" version "2.8.1"
resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz"
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
@ -3638,6 +3695,11 @@ is-negative-zero@^2.0.1:
resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz" resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz"
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
is-negative-zero@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
is-number-object@^1.0.4: is-number-object@^1.0.4:
version "1.0.5" version "1.0.5"
resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz" resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz"
@ -3669,6 +3731,13 @@ is-shared-array-buffer@^1.0.1:
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
dependencies:
call-bind "^1.0.2"
is-string@^1.0.5: is-string@^1.0.5:
version "1.0.6" version "1.0.6"
resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz" resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz"
@ -3688,7 +3757,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
dependencies: dependencies:
has-symbols "^1.0.2" has-symbols "^1.0.2"
is-weakref@^1.0.1: is-weakref@^1.0.1, is-weakref@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
@ -4093,28 +4162,31 @@ next-plausible@^3.1.9:
resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-3.1.9.tgz#4795df2e83a6ca14495d2fa0d31a92649c42425f" resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-3.1.9.tgz#4795df2e83a6ca14495d2fa0d31a92649c42425f"
integrity sha512-6Ro6lVnuXAtqbbBQfuKuu0cpZHWWvJWbOE1G+Rx6i42T6lLYtbQzbu09Cutv3vc/wD/4ySHzJkuTnxsqnlArGA== integrity sha512-6Ro6lVnuXAtqbbBQfuKuu0cpZHWWvJWbOE1G+Rx6i42T6lLYtbQzbu09Cutv3vc/wD/4ySHzJkuTnxsqnlArGA==
next@^12.1.4: next@^12.2.2:
version "12.1.4" version "12.2.2"
resolved "https://registry.yarnpkg.com/next/-/next-12.1.4.tgz#597a9bdec7aec778b442c4f6d41afd2c64a54b23" resolved "https://registry.yarnpkg.com/next/-/next-12.2.2.tgz#029bf5e4a18a891ca5d05b189b7cd983fd22c072"
integrity sha512-DA4g97BM4Z0nKtDvCTm58RxdvoQyYzeg0AeVbh0N4Y/D8ELrNu47lQeEgRGF8hV4eQ+Sal90zxrJQQG/mPQ8CQ== integrity sha512-zAYFY45aBry/PlKONqtlloRFqU/We3zWYdn2NoGvDZkoYUYQSJC8WMcalS5C19MxbCZLUVCX7D7a6gTGgl2yLg==
dependencies: dependencies:
"@next/env" "12.1.4" "@next/env" "12.2.2"
caniuse-lite "^1.0.30001283" "@swc/helpers" "0.4.2"
caniuse-lite "^1.0.30001332"
postcss "8.4.5" postcss "8.4.5"
styled-jsx "5.0.1" styled-jsx "5.0.2"
use-sync-external-store "1.1.0"
optionalDependencies: optionalDependencies:
"@next/swc-android-arm-eabi" "12.1.4" "@next/swc-android-arm-eabi" "12.2.2"
"@next/swc-android-arm64" "12.1.4" "@next/swc-android-arm64" "12.2.2"
"@next/swc-darwin-arm64" "12.1.4" "@next/swc-darwin-arm64" "12.2.2"
"@next/swc-darwin-x64" "12.1.4" "@next/swc-darwin-x64" "12.2.2"
"@next/swc-linux-arm-gnueabihf" "12.1.4" "@next/swc-freebsd-x64" "12.2.2"
"@next/swc-linux-arm64-gnu" "12.1.4" "@next/swc-linux-arm-gnueabihf" "12.2.2"
"@next/swc-linux-arm64-musl" "12.1.4" "@next/swc-linux-arm64-gnu" "12.2.2"
"@next/swc-linux-x64-gnu" "12.1.4" "@next/swc-linux-arm64-musl" "12.2.2"
"@next/swc-linux-x64-musl" "12.1.4" "@next/swc-linux-x64-gnu" "12.2.2"
"@next/swc-win32-arm64-msvc" "12.1.4" "@next/swc-linux-x64-musl" "12.2.2"
"@next/swc-win32-ia32-msvc" "12.1.4" "@next/swc-win32-arm64-msvc" "12.2.2"
"@next/swc-win32-x64-msvc" "12.1.4" "@next/swc-win32-ia32-msvc" "12.2.2"
"@next/swc-win32-x64-msvc" "12.2.2"
node-fetch@^2.6.7: node-fetch@^2.6.7:
version "2.6.7" version "2.6.7"
@ -4190,6 +4262,11 @@ object-inspect@^1.11.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
object-inspect@^1.12.0:
version "1.12.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
object-inspect@^1.9.0: object-inspect@^1.9.0:
version "1.10.3" version "1.10.3"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz"
@ -4248,13 +4325,13 @@ object.fromentries@^2.0.5:
define-properties "^1.1.3" define-properties "^1.1.3"
es-abstract "^1.19.1" es-abstract "^1.19.1"
object.hasown@^1.1.0: object.hasown@^1.1.1:
version "1.1.0" version "1.1.1"
resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3"
integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==
dependencies: dependencies:
define-properties "^1.1.3" define-properties "^1.1.4"
es-abstract "^1.19.1" es-abstract "^1.19.5"
object.values@^1.1.1, object.values@^1.1.3: object.values@^1.1.1, object.values@^1.1.3:
version "1.1.3" version "1.1.3"
@ -4579,13 +4656,6 @@ react-dom@17.0.2:
object-assign "^4.1.1" object-assign "^4.1.1"
scheduler "^0.20.2" scheduler "^0.20.2"
react-github-btn@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/react-github-btn/-/react-github-btn-1.2.2.tgz#9aab2498ff311b9f9c448a2d2b902d0277037d5c"
integrity sha512-X4IcX2qwaLciSa4wcUsrFgF2PcT+ukMbZZRBT50ZvO2HJMyqQJNYNHErCN2R0sgZfSFQHUuUHlGndF15VQUhPA==
dependencies:
github-buttons "^2.21.1"
react-hook-form@^7.31.3: react-hook-form@^7.31.3:
version "7.31.3" version "7.31.3"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.31.3.tgz#b61bafb9a7435f91695351a7a9f714d8c4df0121" resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.31.3.tgz#b61bafb9a7435f91695351a7a9f714d8c4df0121"
@ -4772,6 +4842,15 @@ regexp.prototype.flags@^1.4.1:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
regexp.prototype.flags@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
functions-have-names "^1.2.2"
regexpp@^3.1.0: regexpp@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz"
@ -5128,7 +5207,7 @@ string.prototype.matchall@^4.0.4:
regexp.prototype.flags "^1.3.1" regexp.prototype.flags "^1.3.1"
side-channel "^1.0.4" side-channel "^1.0.4"
string.prototype.matchall@^4.0.6: string.prototype.matchall@^4.0.7:
version "4.0.7" version "4.0.7"
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d"
integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==
@ -5150,6 +5229,15 @@ string.prototype.trimend@^1.0.4:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
string.prototype.trimend@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
string.prototype.trimstart@^1.0.4: string.prototype.trimstart@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz" resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz"
@ -5158,6 +5246,15 @@ string.prototype.trimstart@^1.0.4:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
string.prototype.trimstart@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
string_decoder@~1.1.1: string_decoder@~1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@ -5204,10 +5301,10 @@ style-value-types@5.0.0:
hey-listen "^1.0.8" hey-listen "^1.0.8"
tslib "^2.1.0" tslib "^2.1.0"
styled-jsx@5.0.1: styled-jsx@5.0.2:
version "5.0.1" version "5.0.2"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.1.tgz#78fecbbad2bf95ce6cd981a08918ce4696f5fc80" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729"
integrity sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw== integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==
stylis@^4.0.6: stylis@^4.0.6:
version "4.0.13" version "4.0.13"
@ -5349,7 +5446,7 @@ ts-easing@^0.2.0:
resolved "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz" resolved "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz"
integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==
tsconfig-paths@^3.12.0, tsconfig-paths@^3.14.1: tsconfig-paths@^3.14.1:
version "3.14.1" version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
@ -5379,6 +5476,11 @@ tslib@^2.1.0:
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
tslib@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tsutils@^3.21.0: tsutils@^3.21.0:
version "3.21.0" version "3.21.0"
resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
@ -5423,6 +5525,16 @@ unbox-primitive@^1.0.0, unbox-primitive@^1.0.1:
has-symbols "^1.0.2" has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2" which-boxed-primitive "^1.0.2"
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
dependencies:
call-bind "^1.0.2"
has-bigints "^1.0.2"
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
uncontrollable@^7.0.0: uncontrollable@^7.0.0:
version "7.2.1" version "7.2.1"
resolved "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz" resolved "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz"
@ -5476,6 +5588,11 @@ use-isomorphic-layout-effect@^1.1.1:
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
use-sync-external-store@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82"
integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==
util-deprecate@^1.0.2, util-deprecate@~1.0.1: util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"