From 49062284f743383f4c67af3c90bbf2cbd057cfcb Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sun, 15 Feb 2026 21:10:27 +0200 Subject: [PATCH] Fix SendouForm date validation (#2808) --- app/features/scrims/scrims-schemas.ts | 4 +- .../tournament-organization-schemas.ts | 2 +- app/features/vods/vods-schemas.ts | 2 +- app/form/fields.ts | 54 +++++++++---------- app/form/types.ts | 4 +- locales/da/forms.json | 2 + locales/de/forms.json | 2 + locales/en/forms.json | 2 + locales/es-ES/forms.json | 2 + locales/es-US/forms.json | 2 + locales/fr-CA/forms.json | 2 + locales/fr-EU/forms.json | 2 + locales/he/analyzer.json | 2 + locales/he/art.json | 1 + locales/he/badges.json | 1 + locales/he/forms.json | 2 + locales/it/forms.json | 2 + locales/ja/forms.json | 2 + locales/ko/forms.json | 2 + locales/nl/forms.json | 2 + locales/pl/forms.json | 2 + locales/pt-BR/forms.json | 2 + locales/ru/forms.json | 2 + locales/zh/forms.json | 2 + 24 files changed, 66 insertions(+), 36 deletions(-) diff --git a/app/features/scrims/scrims-schemas.ts b/app/features/scrims/scrims-schemas.ts index abfc9b831..d1f5bbc98 100644 --- a/app/features/scrims/scrims-schemas.ts +++ b/app/features/scrims/scrims-schemas.ts @@ -222,8 +222,8 @@ export const scrimsNewFormSchema = z at: datetimeRequired({ label: "labels.start", bottomText: "bottomTexts.scrimStart", - min: sub(new Date(), { days: 1 }), - max: add(new Date(), { days: 15 }), + min: () => sub(new Date(), { days: 1 }), + max: () => add(new Date(), { days: 15 }), minMessage: "errors.dateInPast", maxMessage: "errors.dateTooFarInFuture", }), diff --git a/app/features/tournament-organization/tournament-organization-schemas.ts b/app/features/tournament-organization/tournament-organization-schemas.ts index 8629bcc89..936c76695 100644 --- a/app/features/tournament-organization/tournament-organization-schemas.ts +++ b/app/features/tournament-organization/tournament-organization-schemas.ts @@ -95,7 +95,7 @@ export const banUserActionSchema = z.object({ expiresAt: datetimeOptional({ label: "labels.banUserExpiresAt", bottomText: "bottomTexts.banUserExpiresAtHelp", - min: new Date(), + min: () => new Date(), minMessage: "errors.dateInPast", }), }); diff --git a/app/features/vods/vods-schemas.ts b/app/features/vods/vods-schemas.ts index dd2d9374a..93fd491bb 100644 --- a/app/features/vods/vods-schemas.ts +++ b/app/features/vods/vods-schemas.ts @@ -153,7 +153,7 @@ export const vodFormBaseSchema = z.object({ }), date: dayMonthYearRequired({ label: "labels.vodDate", - max: add(new Date(), { days: 1 }), + max: () => add(new Date(), { days: 1 }), maxMessage: "errors.dateMustNotBeFuture", minMessage: "errors.dateTooOld", }), diff --git a/app/form/fields.ts b/app/form/fields.ts index 067e2a2d2..45ddf98ad 100644 --- a/app/form/fields.ts +++ b/app/form/fields.ts @@ -389,22 +389,20 @@ type DateTimeArgs = WithTypedTranslationKeys< }; export function datetimeRequired(args: DateTimeArgs) { - const minDate = args.min ?? new Date(Date.UTC(2015, 4, 28)); - const maxDate = args.max ?? new Date(Date.UTC(2030, 4, 28)); + const resolveMin = args.min ?? (() => new Date(Date.UTC(2015, 4, 28))); + const resolveMax = args.max ?? (() => new Date(Date.UTC(2030, 4, 28))); return z .preprocess( date, z .date({ message: "forms:errors.required" }) - .min( - minDate, - args.minMessage ? { message: `forms:${args.minMessage}` } : undefined, - ) - .max( - maxDate, - args.maxMessage ? { message: `forms:${args.maxMessage}` } : undefined, - ), + .refine((d) => d >= resolveMin(), { + message: `forms:${args.minMessage ?? "errors.dateTooEarly"}`, + }) + .refine((d) => d <= resolveMax(), { + message: `forms:${args.maxMessage ?? "errors.dateTooLate"}`, + }), ) .register(formRegistry, { ...args, @@ -417,22 +415,20 @@ export function datetimeRequired(args: DateTimeArgs) { } export function datetimeOptional(args: DateTimeArgs) { - const minDate = args.min ?? new Date(Date.UTC(2015, 4, 28)); - const maxDate = args.max ?? new Date(Date.UTC(2030, 4, 28)); + const resolveMin = args.min ?? (() => new Date(Date.UTC(2015, 4, 28))); + const resolveMax = args.max ?? (() => new Date(Date.UTC(2030, 4, 28))); return z .preprocess( date, z .date() - .min( - minDate, - args.minMessage ? { message: `forms:${args.minMessage}` } : undefined, - ) - .max( - maxDate, - args.maxMessage ? { message: `forms:${args.maxMessage}` } : undefined, - ) + .refine((d) => d >= resolveMin(), { + message: `forms:${args.minMessage ?? "errors.dateTooEarly"}`, + }) + .refine((d) => d <= resolveMax(), { + message: `forms:${args.maxMessage ?? "errors.dateTooLate"}`, + }) .nullish(), ) .register(formRegistry, { @@ -446,22 +442,20 @@ export function datetimeOptional(args: DateTimeArgs) { } export function dayMonthYearRequired(args: DateTimeArgs) { - const minDate = args.min ?? new Date(Date.UTC(2015, 4, 28)); - const maxDate = args.max ?? new Date(Date.UTC(2030, 4, 28)); + const resolveMin = args.min ?? (() => new Date(Date.UTC(2015, 4, 28))); + const resolveMax = args.max ?? (() => new Date(Date.UTC(2030, 4, 28))); return z .preprocess( date, z .date({ message: "forms:errors.required" }) - .min( - minDate, - args.minMessage ? { message: `forms:${args.minMessage}` } : undefined, - ) - .max( - maxDate, - args.maxMessage ? { message: `forms:${args.maxMessage}` } : undefined, - ), + .refine((d) => d >= resolveMin(), { + message: `forms:${args.minMessage ?? "errors.dateTooEarly"}`, + }) + .refine((d) => d <= resolveMax(), { + message: `forms:${args.maxMessage ?? "errors.dateTooLate"}`, + }), ) .transform((d) => ({ day: d.getDate(), diff --git a/app/form/types.ts b/app/form/types.ts index 07e89bcf9..aff72ba66 100644 --- a/app/form/types.ts +++ b/app/form/types.ts @@ -87,8 +87,8 @@ export interface FormFieldInputGroup } export interface FormFieldDatetime extends FormFieldBase { - min?: Date; - max?: Date; + min?: () => Date; + max?: () => Date; required: boolean; } diff --git a/locales/da/forms.json b/locales/da/forms.json index 24b4cde19..9cc0a818a 100644 --- a/locales/da/forms.json +++ b/locales/da/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/de/forms.json b/locales/de/forms.json index 24053a992..37667c008 100644 --- a/locales/de/forms.json +++ b/locales/de/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/en/forms.json b/locales/en/forms.json index 6c371b4eb..b8faa05da 100644 --- a/locales/en/forms.json +++ b/locales/en/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "Start time", "bottomTexts.scrimRequestStartTime": "Select a time within the post's time range", "errors.dateInPast": "Date can not be in the past", + "errors.dateTooEarly": "Date is too early", + "errors.dateTooLate": "Date is too late", "errors.dateTooFarInFuture": "Date can not be more than 2 weeks in the future", "errors.minUsersExcludingYourself": "Must have at least {{min}} users excluding yourself", "errors.usersMustBeUnique": "Users must be unique", diff --git a/locales/es-ES/forms.json b/locales/es-ES/forms.json index 710ee69e7..78cd75cd5 100644 --- a/locales/es-ES/forms.json +++ b/locales/es-ES/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/es-US/forms.json b/locales/es-US/forms.json index 86cbdb2d1..122ca4633 100644 --- a/locales/es-US/forms.json +++ b/locales/es-US/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/fr-CA/forms.json b/locales/fr-CA/forms.json index 3aff44993..ad46a5169 100644 --- a/locales/fr-CA/forms.json +++ b/locales/fr-CA/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/fr-EU/forms.json b/locales/fr-EU/forms.json index 7cd23db97..376bc6ebb 100644 --- a/locales/fr-EU/forms.json +++ b/locales/fr-EU/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/he/analyzer.json b/locales/he/analyzer.json index d0944b264..42fe2f91c 100644 --- a/locales/he/analyzer.json +++ b/locales/he/analyzer.json @@ -163,6 +163,7 @@ "dmgHtdExplanation": "נזק = פגיעה | פ'ל = פגיעות להרוס", "noDmgData": "אין נתונים על נזק של הנשק הזה. בדקו מאוחר יותר!", "perInkTankGrid.header_one": "יריות של {{weapon}} לאחר ×{{count}} שימוש בנשק משני", + "perInkTankGrid.header_two": "", "perInkTankGrid.header_other": "יריות של {{weapon}} לאחר ×{{count}} שימוש בנשקים משניים", "bigBubblerExplanation": "משך הזמן של {{weapon}} גדל גם ככל שהעמידות גדלה", "button.showChart": "הצג תרשים", @@ -183,6 +184,7 @@ "comp.showWeaponGrid": "הצג בורר נשק", "comp.hideWeaponGrid": "הסתר בורר נשק", "comp.hits_one": "{{count}} פגיעה", + "comp.hits_two": "", "comp.hits_other": "{{count}} פגיעות", "comp.enemyRes": "Ink Resistance Up של היריב", "comp.enemySubDef": "Sub Defense Up של היריב", diff --git a/locales/he/art.json b/locales/he/art.json index dcf074f3d..5ff06b5d3 100644 --- a/locales/he/art.json +++ b/locales/he/art.json @@ -1,5 +1,6 @@ { "pendingApproval_one": "יש לכם תמונה {{count}} שממתינה לאישור מנחה", + "pendingApproval_two": "", "pendingApproval_other": "יש לכם {{count}} תמונות שממתינות לאישור מנחה", "madeBy": "מאת", "radios.all": "הכל", diff --git a/locales/he/badges.json b/locales/he/badges.json index fa0881d61..f5307f8f6 100644 --- a/locales/he/badges.json +++ b/locales/he/badges.json @@ -3,6 +3,7 @@ "patreon+": "תומך+ של sendou.ink ב-Patreon", "xp": "מוענק עבור הגעה ל-{{xpText}}", "tournament_one": "מוענק עבור ניצחון {{tournament}}", + "tournament_two": "", "tournament_other": "מוענק עבור ניצחון {{tournament}} (×{{count}})", "forYourEvent": "תג לאירוע שלכם?", "managedBy": "מנוהל על ידי <0>", diff --git a/locales/he/forms.json b/locales/he/forms.json index ca2f0cc1e..8d6b33159 100644 --- a/locales/he/forms.json +++ b/locales/he/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/it/forms.json b/locales/it/forms.json index a81abd0c0..da3e3c379 100644 --- a/locales/it/forms.json +++ b/locales/it/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/ja/forms.json b/locales/ja/forms.json index b757c170d..f338db093 100644 --- a/locales/ja/forms.json +++ b/locales/ja/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/ko/forms.json b/locales/ko/forms.json index 9644e8caf..226cfcb04 100644 --- a/locales/ko/forms.json +++ b/locales/ko/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/nl/forms.json b/locales/nl/forms.json index b45f81091..b0b8a100a 100644 --- a/locales/nl/forms.json +++ b/locales/nl/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/pl/forms.json b/locales/pl/forms.json index 2da3fbf58..73fd053fb 100644 --- a/locales/pl/forms.json +++ b/locales/pl/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/pt-BR/forms.json b/locales/pt-BR/forms.json index db26eee5b..a9b9cc564 100644 --- a/locales/pt-BR/forms.json +++ b/locales/pt-BR/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/ru/forms.json b/locales/ru/forms.json index 2c127e38a..851e524ff 100644 --- a/locales/ru/forms.json +++ b/locales/ru/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "", diff --git a/locales/zh/forms.json b/locales/zh/forms.json index 8947638f4..60ddbda21 100644 --- a/locales/zh/forms.json +++ b/locales/zh/forms.json @@ -69,6 +69,8 @@ "labels.scrimRequestStartTime": "", "bottomTexts.scrimRequestStartTime": "", "errors.dateInPast": "", + "errors.dateTooEarly": "", + "errors.dateTooLate": "", "errors.dateTooFarInFuture": "", "errors.minUsersExcludingYourself": "", "errors.usersMustBeUnique": "",