Build a Finance SaaS Platform -8 (Add User)

Install form/input component

1
2
3
npx shadcn@latest add form
npx shadcn@latest add input
npx shadcn@latest add sonner

Install Zustand

1
npm i zustand

Add Create API

add features/accounts/api/use-create-account.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { InferRequestType,InferResponseType } from "hono";
import { toast } from "sonner";
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { client } from "@/lib/hono";

type ResponseType = InferResponseType<typeof client.api.accounts.$post>;
type RequestType = InferRequestType<typeof client.api.accounts.$post>["json"];

export const useCreateAccount = () => {
const queryClient = useQueryClient();

const mutation = useMutation<
ResponseType,
Error,
RequestType
>({
mutationFn: async (json) => {
const response = await client.api.accounts.$post({json});
return response.json();
},
onSuccess: () => {
toast("Account Created!");
queryClient.invalidateQueries({ queryKey:["accounts"]});
},
onError: () => {
toast("Failed to create account")
},
});

return mutation;
}

Add Create User Sheet and Form

Add features/accounts/components/new-account-sheet.tsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { z } from "zod";
import { insertAccountSchema } from "@/db/schema";
import { useNewAccount } from "@/features/accounts/hooks/use-new-account";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle } from "@/components/ui/sheet";

import { AccountForm } from "@/features/accounts/components/account-form"
import { useCreateAccount } from "@/features/accounts/api/use-create-account";

const formSchema = insertAccountSchema.pick({
name: true,
});

type FormValues = z.input<typeof formSchema>;

export function NewAccountSheet() {
const { open, onClose } = useNewAccount();

const mutation = useCreateAccount();

const onSubmit = (values: FormValues)=> {
mutation.mutate(values,{
onSuccess: ()=>{
onClose();
}
});
};

return (
<Sheet open={open} onOpenChange={onClose}>
<SheetContent className="space-y-4">
<SheetHeader>
<SheetTitle>New Account</SheetTitle>
<SheetDescription>
Create a new account to track your finances.
</SheetDescription>
</SheetHeader>
<AccountForm
onSubmit={onSubmit}
disabled={mutation.isPending}
defaultValues={{
name: "",
}}
/>
</SheetContent>
</Sheet>
);
}

Add features/accounts/components/account-form.tsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { z } from "zod";
import { insertAccountSchema } from "@/db/schema";
import { Trash } from "lucide-react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";

const formSchema = insertAccountSchema.pick({
name: true,
});

type FormValues = z.input<typeof formSchema>;

type Props = {
id?: string;
defaultValues?: FormValues;
onSubmit: (values: FormValues) => void;
onDelete?: () => void;
disabled?: boolean;
};

export const AccountForm = ({
id,
defaultValues,
onSubmit,
onDelete,
disabled,
}: Props) => {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues,
});

const handleSubmit = (values: FormValues) => {
onSubmit(values);
};

const handleDelete = () => {
onDelete?.();
};

return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(handleSubmit)}
className="space-y-4 pt-4"
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input
disabled={disabled}
placeholder="e.g. Cash, Bank, etc."
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button className="w-full" disabled={disabled}>
{id ? "Save Changes":"Create account" }
</Button>
<Button
type="button"
disabled={disabled}
onClick={handleDelete}
className="w-full"
variant="outline"
>
<Trash className="size-4 mr-3"/>
Delete Account
</Button>
</form>
</Form>
)
};

请我喝杯咖啡吧~

支付宝
微信