Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow deck selection in card creattion #51

Merged
merged 11 commits into from
Apr 20, 2024
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
"db:seed": "tsx --env-file=.env src/seed.ts"
},
"dependencies": {
"@hookform/resolvers": "^3.3.4",
"@libsql/client": "^0.6.0",
"@milkdown/core": "^7.3.6",
"@milkdown/ctx": "^7.3.6",
"@milkdown/plugin-clipboard": "^7.3.6",
"@milkdown/plugin-history": "^7.3.6",
"@milkdown/plugin-listener": "^7.3.6",
"@milkdown/preset-commonmark": "^7.3.6",
"@milkdown/preset-gfm": "^7.3.6",
"@milkdown/prose": "^7.3.6",
Expand All @@ -30,6 +32,7 @@
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7",
Expand All @@ -53,6 +56,7 @@
"next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.51.3",
"sonner": "^1.4.41",
"superjson": "^2.2.1",
"tailwind-merge": "^2.2.2",
Expand Down
99 changes: 98 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<html lang="en" suppressHydrationWarning>
<body
className={cn(
"min-h-screen bg-background font-sans antialiased",
Expand Down
102 changes: 48 additions & 54 deletions src/components/decks/create-deck-form.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,85 @@
"use client";

import { FormTextInput } from "@/components/form/form-input";
import { FormTextarea } from "@/components/form/form-textarea";
import { Button } from "@/components/ui/button";
import {
UiCard,
UiCardContent,
UiCardDescription,
UiCardFooter,
UiCardHeader,
UiCardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Textarea, TextareaClasses } from "@/components/ui/textarea";
import { Form } from "@/components/ui/form";
import { DeckFormValues, deckDefaultValues, deckFormSchema } from "@/form";
import { useCreateDeck } from "@/hooks/deck/use-create-deck";
import { RouterInputs } from "@/utils/trpc";
import { cn } from "@/utils/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { Loader2 } from "lucide-react";
import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { toast } from "sonner";

type DeckInputs = RouterInputs["deck"]["create"];

const emptyDeck = {
name: "",
description: "",
} satisfies DeckInputs;

export function CreateDeckForm() {
const createDeckMutation = useCreateDeck();
const [deck, setDeck] = useState<DeckInputs>(structuredClone(emptyDeck));
const form = useForm<DeckFormValues>({
resolver: zodResolver(deckFormSchema),
defaultValues: deckDefaultValues,
});

const isLoading = createDeckMutation.isPending;

const handleCreate = () => {
toast.promise(createDeckMutation.mutateAsync(deck), {
const onSubmit: SubmitHandler<DeckFormValues> = (data) => {
toast.promise(createDeckMutation.mutateAsync(data), {
loading: "Creating deck...",
success: () => {
setDeck(structuredClone(emptyDeck));
form.reset();
return "Deck created.";
},
error: "Failed to create deck.",
});
};

return (
<UiCard className="w-full md:w-[36rem]">
<UiCardHeader>
<UiCard className="w-full border-0 md:w-[36rem] md:border">
<UiCardHeader className="px-2 md:px-6">
<UiCardTitle>Create</UiCardTitle>
<UiCardDescription>
Provide a name and description for your new deck.
</UiCardDescription>
</UiCardHeader>

<UiCardContent className="flex min-h-96 flex-col gap-y-4">
<Input
placeholder="Name"
className={cn("text-md")}
value={deck.name}
onChange={(e) => setDeck({ ...deck, name: e.target.value })}
/>
<Textarea
className="h-40 resize-none border-0"
disabled={isLoading}
spellCheck="false"
placeholder="Description"
value={deck.description}
onChange={(e) => {
setDeck({
...deck,
description: e.target.value,
});
}}
onKeyDown={(e) => e.stopPropagation()}
/>

<hr className="mx-auto w-8" />
</UiCardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<UiCardContent className="flex min-h-96 flex-col gap-y-4 px-2 md:px-6">
<FormTextInput
name="name"
label="Name"
form={form}
disabled={isLoading}
/>
<hr className="mx-auto w-8" />
<FormTextarea
name="description"
label="Description"
form={form}
disabled={isLoading}
/>
</UiCardContent>

<UiCardContent className="h-24">
<Button
className="mt-4 w-full"
disabled={isLoading || !deck.name}
size="lg"
variant="outline"
onClick={() => handleCreate()}
>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Create
</Button>
</UiCardContent>
<UiCardFooter className="px-2 md:px-6">
<Button
className="mt-4 w-full"
disabled={isLoading}
size="lg"
variant="outline"
type="submit"
>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Create
</Button>
</UiCardFooter>
</form>
</Form>
</UiCard>
);
}
Expand Down
Loading