mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-06-02 22:26:57 -05:00
form ready for submitting sr records
This commit is contained in:
parent
6341361e3f
commit
2cb22fb5d8
|
|
@ -1,2 +1,7 @@
|
||||||
export const ADMIN_DISCORD_ID = "79237403620945920";
|
export const ADMIN_DISCORD_ID = "79237403620945920";
|
||||||
export const GANBA_DISCORD_ID = "312082701865713665";
|
export const GANBA_DISCORD_ID = "312082701865713665";
|
||||||
|
export const SALMON_RUN_ADMIN_DISCORD_IDS = [
|
||||||
|
"81154649993785344", // Brian
|
||||||
|
"116999083796725761", // Marty
|
||||||
|
"78546869373906944", // Minaraii
|
||||||
|
];
|
||||||
|
|
|
||||||
31
lib/validators/salmonRunRecord.ts
Normal file
31
lib/validators/salmonRunRecord.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import * as z from "zod";
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/3809435
|
||||||
|
const urlRegex = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
|
||||||
|
|
||||||
|
export const salmonRunRecordSchema = z.object({
|
||||||
|
rotationId: z.number(), // check on db level
|
||||||
|
goldenEggCount: z.number().min(0).max(300),
|
||||||
|
category: z.string(), // check on db level
|
||||||
|
userIds: z.array(z.number()),
|
||||||
|
links: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => {
|
||||||
|
const lines = linesFromTextareaValue(val);
|
||||||
|
if (lines.length === 0 || lines.length > 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, "Include 1-4 links")
|
||||||
|
.refine((val) => {
|
||||||
|
return linesFromTextareaValue(val).every((link) => urlRegex.test(link));
|
||||||
|
}, "One of the links is invalid"),
|
||||||
|
});
|
||||||
|
|
||||||
|
function linesFromTextareaValue(value: string) {
|
||||||
|
return value
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.filter((val) => val !== "");
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import {
|
||||||
Button,
|
Button,
|
||||||
Flex,
|
Flex,
|
||||||
FormControl,
|
FormControl,
|
||||||
|
FormErrorMessage,
|
||||||
FormHelperText,
|
FormHelperText,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
NumberDecrementStepper,
|
NumberDecrementStepper,
|
||||||
|
|
@ -12,23 +13,18 @@ import {
|
||||||
Select,
|
Select,
|
||||||
Textarea,
|
Textarea,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { t, Trans } from "@lingui/macro";
|
import { t, Trans } from "@lingui/macro";
|
||||||
import { useLingui } from "@lingui/react";
|
import { useLingui } from "@lingui/react";
|
||||||
import { SalmonRunRecordCategory } from "@prisma/client";
|
|
||||||
import Breadcrumbs from "components/common/Breadcrumbs";
|
import Breadcrumbs from "components/common/Breadcrumbs";
|
||||||
import MyContainer from "components/common/MyContainer";
|
import MyContainer from "components/common/MyContainer";
|
||||||
import UserSelector from "components/common/UserSelector";
|
import UserSelector from "components/common/UserSelector";
|
||||||
import RotationSelector from "components/sr/RotationSelector";
|
import RotationSelector from "components/sr/RotationSelector";
|
||||||
|
import { salmonRunRecordSchema } from "lib/validators/salmonRunRecord";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
interface RecordFormData {
|
import * as z from "zod";
|
||||||
rotationId: number;
|
|
||||||
userIds: number[];
|
|
||||||
category: SalmonRunRecordCategory;
|
|
||||||
goldenEggCount: number;
|
|
||||||
links: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const salmonRunCategoryToNatural = {
|
const salmonRunCategoryToNatural = {
|
||||||
TOTAL: t`All waves`,
|
TOTAL: t`All waves`,
|
||||||
|
|
@ -52,10 +48,20 @@ const salmonRunCategoryToNatural = {
|
||||||
LT_COHOCK: t`Cohock Charge`,
|
LT_COHOCK: t`Cohock Charge`,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
type FormData = z.infer<typeof salmonRunRecordSchema>;
|
||||||
|
|
||||||
const AddRecordModal = () => {
|
const AddRecordModal = () => {
|
||||||
const { i18n } = useLingui();
|
const { i18n } = useLingui();
|
||||||
const [sending, setSending] = useState(false);
|
const [sending, setSending] = useState(false);
|
||||||
const [form, setForm] = useState<Partial<RecordFormData>>({ rotationId: 1 });
|
const { handleSubmit, errors, register, control, watch } = useForm<FormData>({
|
||||||
|
resolver: zodResolver(salmonRunRecordSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const watchRotationId = watch("rotationId", undefined);
|
||||||
|
|
||||||
|
const onSubmit = async (data: FormData) => {
|
||||||
|
console.log("data", data);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MyContainer>
|
<MyContainer>
|
||||||
|
|
@ -66,36 +72,22 @@ const AddRecordModal = () => {
|
||||||
{ name: t`New record` },
|
{ name: t`New record` },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<form /*onSubmit={handleSubmit(onSubmit)}*/>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<RotationSelector
|
<Controller
|
||||||
rotationId={form.rotationId}
|
name="rotationId"
|
||||||
setRotationId={(rotationId) => {
|
control={control}
|
||||||
if (!rotationId) {
|
defaultValue={undefined}
|
||||||
const newForm = { ...form };
|
render={({ value, onChange }) => (
|
||||||
delete newForm.rotationId;
|
<RotationSelector rotationId={value} setRotationId={onChange} />
|
||||||
setForm(newForm);
|
)}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setForm({ ...form, rotationId });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{form.rotationId && (
|
{watchRotationId && (
|
||||||
<>
|
<>
|
||||||
<FormLabel htmlFor="category" mt={4}>
|
<FormLabel htmlFor="category" mt={4}>
|
||||||
<Trans>Category</Trans>
|
<Trans>Category</Trans>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<Select
|
<Select name="category" ref={register}>
|
||||||
name="category"
|
|
||||||
value={form.category}
|
|
||||||
onChange={(e) =>
|
|
||||||
setForm({
|
|
||||||
...form,
|
|
||||||
category: e.target.value as SalmonRunRecordCategory,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Object.entries(salmonRunCategoryToNatural).map(
|
{Object.entries(salmonRunCategoryToNatural).map(
|
||||||
([key, value]) => (
|
([key, value]) => (
|
||||||
<option key={key} value={key}>
|
<option key={key} value={key}>
|
||||||
|
|
@ -105,46 +97,70 @@ const AddRecordModal = () => {
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<FormLabel htmlFor="goldenEggCount" mt={4}>
|
<FormControl isInvalid={!!errors.goldenEggCount}>
|
||||||
<Flex alignItems="center">
|
<FormLabel htmlFor="goldenEggCount" mt={4}>
|
||||||
<Flex align="center" mr={1}>
|
<Flex alignItems="center">
|
||||||
<Image
|
<Flex align="center" mr={1}>
|
||||||
src="/images/salmonRunIcons/Golden%20Egg.png"
|
<Image
|
||||||
width={32}
|
src="/images/salmonRunIcons/Golden%20Egg.png"
|
||||||
height={32}
|
width={32}
|
||||||
/>
|
height={32}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Trans>Golden Egg Count</Trans>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Trans>Golden Egg Count</Trans>
|
</FormLabel>
|
||||||
</Flex>
|
<Controller
|
||||||
</FormLabel>
|
name="goldenEggCount"
|
||||||
<NumberInput name="goldenEggCount" maxW={48}>
|
control={control}
|
||||||
<NumberInputField />
|
defaultValue={0}
|
||||||
<NumberInputStepper>
|
render={({ value, onChange }) => (
|
||||||
<NumberIncrementStepper />
|
<NumberInput
|
||||||
<NumberDecrementStepper />
|
name="goldenEggCount"
|
||||||
</NumberInputStepper>
|
maxW={48}
|
||||||
</NumberInput>
|
value={value}
|
||||||
|
onChange={(_, value) => onChange(value)}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormErrorMessage>
|
||||||
|
{errors.goldenEggCount?.message}
|
||||||
|
</FormErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<FormLabel mt={4}>
|
<FormLabel mt={4}>
|
||||||
<Trans>Players</Trans>
|
<Trans>Players</Trans>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<UserSelector
|
<Controller
|
||||||
value={form.userIds ?? []}
|
name="userIds"
|
||||||
setValue={(userIds: number[]) => setForm({ ...form, userIds })}
|
control={control}
|
||||||
isMulti={true}
|
defaultValue={[]}
|
||||||
maxMultiCount={3}
|
render={({ value, onChange }) => (
|
||||||
|
<UserSelector
|
||||||
|
value={value}
|
||||||
|
setValue={onChange}
|
||||||
|
isMulti={true}
|
||||||
|
maxMultiCount={3}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<FormHelperText>
|
<FormHelperText>
|
||||||
Add up to three people you played with when you got the result.
|
Add up to three people you played with when you got the result.
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl isInvalid={!!errors.links}>
|
||||||
<FormLabel mt={4}>
|
<FormLabel mt={4}>
|
||||||
<Trans>Links</Trans>
|
<Trans>Links</Trans>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormHelperText mb={4} mt="-10px">
|
<FormHelperText mb={3} mt="-7px">
|
||||||
<Trans>
|
<Trans>
|
||||||
Add one to four links to provide context behind the record
|
Add one to four links to provide context behind the record
|
||||||
(e.g. VoDs on YouTube, screenshots on Twitter). One link per
|
(e.g. VoDs on YouTube, screenshots on Twitter). One link per
|
||||||
|
|
@ -152,17 +168,20 @@ const AddRecordModal = () => {
|
||||||
</Trans>
|
</Trans>
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
<Textarea
|
<Textarea
|
||||||
value={form.links}
|
name="links"
|
||||||
onChange={(e) => setForm({ ...form, links: e.target.value })}
|
ref={register}
|
||||||
rows={4}
|
rows={4}
|
||||||
resize="none"
|
resize="none"
|
||||||
placeholder={
|
placeholder={
|
||||||
"https://twitter.com/BrianTheDrumer/status/1338469066797953024\nhttps://www.youtube.com/watch?v=6evFXzxrTfU"
|
"https://twitter.com/BrianTheDrumer/status/1338469066797953024\nhttps://www.youtube.com/watch?v=6evFXzxrTfU"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<FormErrorMessage mt="-1px">
|
||||||
|
{errors.links?.message}
|
||||||
|
</FormErrorMessage>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<Button mt={6} /*type="submit"*/ isLoading={sending}>
|
<Button mt={6} type="submit" isLoading={sending}>
|
||||||
<Trans>Submit</Trans>
|
<Trans>Submit</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user