From b23dd812c32f1536f01d5735b9012d681916b05a Mon Sep 17 00:00:00 2001 From: ppc Date: Wed, 7 Aug 2024 20:18:38 +0100 Subject: [PATCH] add card creation form --- aimenet-web/components/card-creation-form.tsx | 148 ++++++++++++++++++ aimenet-web/hooks/use-media-query.tsx | 19 +++ 2 files changed, 167 insertions(+) create mode 100644 aimenet-web/components/card-creation-form.tsx create mode 100644 aimenet-web/hooks/use-media-query.tsx diff --git a/aimenet-web/components/card-creation-form.tsx b/aimenet-web/components/card-creation-form.tsx new file mode 100644 index 0000000..cce06b9 --- /dev/null +++ b/aimenet-web/components/card-creation-form.tsx @@ -0,0 +1,148 @@ +"use client"; + +import {z} from "zod"; +import React from "react"; +import {Form, FormProvider, useForm} from "react-hook-form"; +import {FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; +import {generateAimeCardId, validateAimeCardId} from "@/lib/aime-card"; +import {useMediaQuery} from "@/hooks/use-media-query"; +import {zodResolver} from "@hookform/resolvers/zod"; +import {Button} from "@/components/ui/button"; +import {Input} from "@/components/ui/input"; +import {AimeCard, db} from "@/lib/database"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger +} from "@/components/ui/dialog"; +import { + Drawer, DrawerClose, + DrawerContent, + DrawerDescription, DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger +} from "@/components/ui/drawer"; +import {Check, X} from "lucide-react"; + +const schema = z.object({ + name: z.string().min(1, { + message: "A name/description must be provided" + }), + id: z.string().refine(validateAimeCardId, { + message: "Card id must be 20 digits and not start with the number 3" + }) +}); + +export function CardCreationDialog(props: { children: Readonly }) { + const [open, setOpen] = React.useState(false); + const isDesktop = useMediaQuery("(min-width: 768px)"); + + if (isDesktop) { + return ( + + + {props.children} + + + + Add new card + + setOpen(false)}/> + + + ); + } + + return ( + + + {props.children} + + + + Add card + + Enter the card details below, and press submit to add it to your profile. + + +
+ setOpen(false)}/> +
+ + + + + +
+
+ ); +} + +function AimeCardCreationForm(props: { callback?: () => void }) { + const form = useForm>({ + resolver: zodResolver(schema) + }); + + async function onSubmit(values: z.infer) { + const card: AimeCard = { + name: values.name, + id: values.id.replaceAll(" ", "") + }; + + const isDuplicate = await db.cards.where("id").equals(card.id).limit(1).count(); + + if (!isDuplicate) { + await db.cards.add(card); + } else { + // todo toast + } + + if (props.callback) { + props.callback(); + } + } + + return ( + +
+ ( + + Name + + + + + + )}/> + + ( + + Card Number + + + + + If you've got a card, enter the matrix code here. If not, you can + form.setValue("id", generateAimeCardId())}> + generate a new one. + + + + + )}/> + + + +
+ ); +} \ No newline at end of file diff --git a/aimenet-web/hooks/use-media-query.tsx b/aimenet-web/hooks/use-media-query.tsx new file mode 100644 index 0000000..4b3cbab --- /dev/null +++ b/aimenet-web/hooks/use-media-query.tsx @@ -0,0 +1,19 @@ +import * as React from "react" + +export function useMediaQuery(query: string) { + const [value, setValue] = React.useState(false) + + React.useEffect(() => { + function onChange(event: MediaQueryListEvent) { + setValue(event.matches) + } + + const result = matchMedia(query) + result.addEventListener("change", onChange) + setValue(result.matches) + + return () => result.removeEventListener("change", onChange) + }, [query]) + + return value +} \ No newline at end of file