From a53a448a7f8cadb30762eb2e2d2cdb72cc21493e Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 30 Jul 2022 16:41:16 +0300 Subject: [PATCH] Add tournament action data schema --- app/components/Input.tsx | 10 ++- app/constants.ts | 7 ++ app/routes/calendar/new.tsx | 126 +++++++++++++++++++++++++++++++++--- app/utils/dates.ts | 5 ++ app/utils/zod.ts | 28 ++++++++ 5 files changed, 164 insertions(+), 12 deletions(-) diff --git a/app/components/Input.tsx b/app/components/Input.tsx index fb6b3a8b5..87faaf30b 100644 --- a/app/components/Input.tsx +++ b/app/components/Input.tsx @@ -2,17 +2,21 @@ import clsx from "clsx"; export function Input({ name, - leftAddon, className, + minLength, + maxLength, + leftAddon, }: { name: string; - leftAddon?: string; className?: string; + minLength?: number; + maxLength?: number; + leftAddon?: string; }) { return (
{leftAddon ?
{leftAddon}
: null} - +
); } diff --git a/app/constants.ts b/app/constants.ts index 246ddd23d..7cfe351b7 100644 --- a/app/constants.ts +++ b/app/constants.ts @@ -2,9 +2,16 @@ export const TWEET_LENGTH_MAX_LENGTH = 280; export const DISCORD_MESSAGE_MAX_LENGTH = 2000; export const USER_BIO_MAX_LENGTH = DISCORD_MESSAGE_MAX_LENGTH; + export const PlUS_SUGGESTION_FIRST_COMMENT_MAX_LENGTH = 500; export const PlUS_SUGGESTION_COMMENT_MAX_LENGTH = TWEET_LENGTH_MAX_LENGTH; + +export const CALENDAR_EVENT_NAME_MIN_LENGTH = 2; +export const CALENDAR_EVENT_NAME_MAX_LENGTH = 100; export const CALENDAR_EVENT_DESCRIPTION_MAX_LENGTH = DISCORD_MESSAGE_MAX_LENGTH; +export const CALENDAR_EVENT_DISCORD_INVITE_CODE_MAX_LENGTH = 50; +export const CALENDAR_EVENT_BRACKET_URL_MAX_LENGTH = 100; +export const CALENDAR_EVENT_MAX_AMOUNT_OF_DATES = 5; export const PLUS_TIERS = [1, 2, 3]; diff --git a/app/routes/calendar/new.tsx b/app/routes/calendar/new.tsx index ec6257b9c..6439a31f5 100644 --- a/app/routes/calendar/new.tsx +++ b/app/routes/calendar/new.tsx @@ -7,9 +7,21 @@ import type { CalendarEvent, CalendarEventTag, } from "~/db/types"; -import { CALENDAR_EVENT_DESCRIPTION_MAX_LENGTH } from "~/constants"; +import { + CALENDAR_EVENT_BRACKET_URL_MAX_LENGTH, + CALENDAR_EVENT_DESCRIPTION_MAX_LENGTH, + CALENDAR_EVENT_DISCORD_INVITE_CODE_MAX_LENGTH, + CALENDAR_EVENT_MAX_AMOUNT_OF_DATES, + CALENDAR_EVENT_NAME_MAX_LENGTH, + CALENDAR_EVENT_NAME_MIN_LENGTH, +} from "~/constants"; import { Button } from "~/components/Button"; -import { json, type LinksFunction, type LoaderArgs } from "@remix-run/node"; +import { + json, + type ActionFunction, + type LinksFunction, + type LoaderArgs, +} from "@remix-run/node"; import styles from "~/styles/calendar-new.css"; import clsx from "clsx"; import { useTranslation } from "react-i18next"; @@ -22,11 +34,70 @@ import { Tags } from "./components/Tags"; import { db } from "~/db"; import { requireUser } from "~/modules/auth"; import { Badge } from "~/components/Badge"; +import { z } from "zod"; +import { + date, + falsyToNull, + id, + processMany, + removeDuplicates, + safeJSONParse, +} from "~/utils/zod"; +import { parseRequestFormData } from "~/utils/remix"; +import { dateToYearMonthDayHourMinuteString } from "~/utils/dates"; + +const MIN_DATE = new Date(Date.UTC(2015, 4, 28)); + +const MAX_DATE = new Date(); +MAX_DATE.setFullYear(MAX_DATE.getFullYear() + 1); export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: styles }]; }; +const newCalendarEventActionSchema = z.object({ + name: z + .string() + .min(CALENDAR_EVENT_NAME_MIN_LENGTH) + .max(CALENDAR_EVENT_NAME_MAX_LENGTH), + description: z.preprocess( + falsyToNull, + z.string().max(CALENDAR_EVENT_DESCRIPTION_MAX_LENGTH).nullable() + ), + dates: z.preprocess( + safeJSONParse, + z + .array(z.preprocess(date, z.date().min(MIN_DATE).max(MAX_DATE))) + .min(1) + .max(CALENDAR_EVENT_MAX_AMOUNT_OF_DATES) + ), + bracketUrl: z.string().url().max(CALENDAR_EVENT_BRACKET_URL_MAX_LENGTH), + discordInviteCode: z.preprocess( + falsyToNull, + z.string().max(CALENDAR_EVENT_DISCORD_INVITE_CODE_MAX_LENGTH).nullable() + ), + tags: z.preprocess( + processMany(safeJSONParse, removeDuplicates), + z + .array(z.string().refine((val) => Object.keys(allTags).includes(val))) + .nullable() + ), + badges: z.preprocess( + processMany(safeJSONParse, removeDuplicates), + z.array(id).nullable() + ), +}); + +export const action: ActionFunction = async ({ request }) => { + const user = await requireUser(request); + const data = await parseRequestFormData({ + request, + schema: newCalendarEventActionSchema, + }); + + return null; +}; + export const handle = { i18n: "calendar", }; @@ -64,7 +135,12 @@ function NameInput() { - + ); } @@ -110,6 +186,13 @@ function DatesInput() { return (
+ {dates.length > 0 && ( + date.getTime()))} + /> + )}
); } @@ -192,7 +281,12 @@ function BracketUrlInput() { - +
); } @@ -200,6 +294,7 @@ function BracketUrlInput() { function TagsAdder() { const { t } = useTranslation("calendar"); const [tags, setTags] = React.useState([]); + const id = React.useId(); const tagsForSelect = ( Object.keys(allTags) as Array @@ -207,10 +302,15 @@ function TagsAdder() { return (
+ 0 ? tags : null)} + />
- + 0 ? badges.map((b) => b.id) : null + )} + />
- +