Skip to content

Commit 1e18e10

Browse files
committed
Dashboard: Migrate Various forms from chakra to tailwind CSS
1 parent 4887480 commit 1e18e10

File tree

4 files changed

+868
-643
lines changed

4 files changed

+868
-643
lines changed
Lines changed: 97 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
1-
import {
2-
Flex,
3-
FormControl,
4-
IconButton,
5-
Input,
6-
InputGroup,
7-
InputRightElement,
8-
Tooltip,
9-
} from "@chakra-ui/react";
10-
import { Button } from "chakra/button";
11-
import { FormErrorMessage, FormLabel } from "chakra/form";
12-
import { BanIcon, PlusIcon, TrashIcon, UploadIcon, XIcon } from "lucide-react";
1+
import { PlusIcon, TrashIcon, XIcon } from "lucide-react";
132
import { useEffect } from "react";
143
import {
154
type ArrayPath,
@@ -25,7 +14,16 @@ import {
2514
type WatchObserver,
2615
} from "react-hook-form";
2716
import type { ThirdwebClient } from "thirdweb";
28-
import { FileInput } from "@/components/blocks/FileInput";
17+
import { Button } from "@/components/ui/button";
18+
import {
19+
FormControl,
20+
FormField,
21+
FormItem,
22+
FormLabel,
23+
FormMessage,
24+
} from "@/components/ui/form";
25+
import { Input } from "@/components/ui/input";
26+
import { cn } from "@/lib/utils";
2927

3028
type OptionalPropertiesInput = {
3129
[key: string]: string | number;
@@ -46,17 +44,15 @@ interface IPropertiesFormControlProps<
4644
client: ThirdwebClient;
4745
}
4846

49-
export const PropertiesFormControl = <
47+
export function PropertiesFormControl<
5048
TFieldValues extends IPropertyFieldValues,
5149
>({
5250
control,
53-
register,
5451
watch,
5552
errors,
5653
setValue,
57-
client,
58-
}: React.PropsWithChildren<IPropertiesFormControlProps<TFieldValues>>) => {
59-
const { fields, append, remove, replace } = useFieldArray({
54+
}: React.PropsWithChildren<IPropertiesFormControlProps<TFieldValues>>) {
55+
const { fields, append, remove } = useFieldArray({
6056
control,
6157
name: "attributes" as ArrayPath<TFieldValues>,
6258
});
@@ -72,122 +68,116 @@ export const PropertiesFormControl = <
7268

7369
return (
7470
<div className="flex flex-col gap-4">
75-
<Flex align="center" direction="row" justify="space-between">
76-
<FormLabel m={0}>Attributes</FormLabel>
77-
<Button
78-
colorScheme="red"
79-
// biome-ignore lint/suspicious/noExplicitAny: FIXME
80-
onClick={() => replace([{ trait_type: "", value: "" } as any])}
81-
rightIcon={<BanIcon className="size-4" />}
82-
size="xs"
83-
variant="outline"
84-
>
85-
Reset
86-
</Button>
87-
</Flex>
71+
<FormLabel>Attributes</FormLabel>
8872
{fields.map((field, index) => {
8973
// biome-ignore lint/suspicious/noExplicitAny: FIXME
9074
const keyError = (errors as any)?.attributes?.[index]?.trait_type
9175
?.message as string | undefined;
9276
// biome-ignore lint/suspicious/noExplicitAny: FIXME
9377
const valueError = (errors as any)?.attributes?.[index]?.value
9478
?.message as string | undefined;
95-
const isInvalid = !!(keyError || valueError);
79+
const _isInvalid = !!(keyError || valueError);
9680

9781
return (
9882
<div className="flex flex-row items-center gap-2" key={field.id}>
99-
<FormControl
100-
className="flex flex-row items-start gap-3"
101-
isInvalid={isInvalid}
102-
>
103-
<FormControl isInvalid={!!keyError}>
104-
<Input
105-
{...register(
106-
`attributes.${index}.trait_type` as Path<TFieldValues>,
107-
)}
108-
placeholder="trait_type"
109-
/>
110-
<FormErrorMessage>{keyError}</FormErrorMessage>
111-
</FormControl>
112-
<FormControl isInvalid={!!valueError}>
113-
{watch(
114-
`attributes.${index}.value` as unknown as WatchObserver<TFieldValues>,
115-
) instanceof File ? (
116-
<InputGroup>
117-
<Input
118-
isDisabled
119-
value={
120-
watch(`attributes.${index}.value` as Path<TFieldValues>)
121-
.name
122-
}
123-
/>
124-
<InputRightElement>
125-
<TrashIcon
126-
className="size-4 cursor-pointer text-red-300 hover:text-red-200"
127-
onClick={() =>
128-
setValue(
129-
`attributes.${index}.value` as Path<TFieldValues>,
130-
"" as PathValue<TFieldValues, Path<TFieldValues>>,
131-
)
132-
}
83+
<div className="flex flex-row items-start gap-3 flex-1">
84+
<FormField
85+
control={control}
86+
name={`attributes.${index}.trait_type` as Path<TFieldValues>}
87+
render={({ field: traitField }) => (
88+
<FormItem className="flex-1">
89+
<FormControl>
90+
<Input
91+
{...traitField}
92+
placeholder="trait_type"
93+
className={cn(
94+
"bg-card",
95+
keyError && "border-destructive",
96+
)}
13397
/>
134-
</InputRightElement>
135-
</InputGroup>
136-
) : (
137-
<InputGroup>
138-
<Input
139-
{...register(
140-
`attributes.${index}.value` as Path<TFieldValues>,
98+
</FormControl>
99+
{keyError && <FormMessage>{keyError}</FormMessage>}
100+
</FormItem>
101+
)}
102+
/>
103+
104+
<FormField
105+
control={control}
106+
name={`attributes.${index}.value` as Path<TFieldValues>}
107+
render={({ field: valueField }) => (
108+
<FormItem className="flex-1">
109+
<FormControl>
110+
{watch(
111+
`attributes.${index}.value` as unknown as WatchObserver<TFieldValues>,
112+
) instanceof File ? (
113+
<div className="relative">
114+
<Input
115+
disabled
116+
value={
117+
watch(
118+
`attributes.${index}.value` as Path<TFieldValues>,
119+
).name
120+
}
121+
className="pr-10 bg-card"
122+
/>
123+
<Button
124+
type="button"
125+
variant="ghost"
126+
size="sm"
127+
className="absolute right-0 top-0 h-full px-3 hover:bg-transparent"
128+
onClick={() =>
129+
setValue(
130+
`attributes.${index}.value` as Path<TFieldValues>,
131+
"" as PathValue<
132+
TFieldValues,
133+
Path<TFieldValues>
134+
>,
135+
)
136+
}
137+
>
138+
<TrashIcon className="size-4 text-muted-foreground hover:text-destructive" />
139+
</Button>
140+
</div>
141+
) : (
142+
<div className="relative">
143+
<Input
144+
{...valueField}
145+
placeholder="value"
146+
className={`pr-10 bg-card ${valueError ? "border-destructive" : ""}`}
147+
/>
148+
</div>
141149
)}
142-
placeholder="value"
143-
/>
144-
<InputRightElement>
145-
<Tooltip label="Upload file" shouldWrapChildren>
146-
<FileInput
147-
client={client}
148-
setValue={(file) => {
149-
setValue(
150-
`attributes.${index}.value` as Path<TFieldValues>,
151-
file as PathValue<
152-
TFieldValues,
153-
Path<TFieldValues>
154-
>,
155-
);
156-
}}
157-
>
158-
<UploadIcon className="size-4 text-muted-foreground" />
159-
</FileInput>
160-
</Tooltip>
161-
</InputRightElement>
162-
</InputGroup>
150+
</FormControl>
151+
{valueError && <FormMessage>{valueError}</FormMessage>}
152+
</FormItem>
163153
)}
164-
<FormErrorMessage>{valueError}</FormErrorMessage>
165-
</FormControl>
166-
</FormControl>
167-
<IconButton
168-
aria-label="remove key value pair"
169-
colorScheme="red"
170-
icon={<XIcon />}
154+
/>
155+
</div>
156+
<Button
157+
type="button"
158+
variant="outline"
159+
size="sm"
160+
className="rounded-full p-0 size-10 bg-card"
171161
onClick={() => remove(index)}
172-
size="xs"
173-
variant="ghost"
174-
/>
162+
>
163+
<XIcon className="size-4" />
164+
</Button>
175165
</div>
176166
);
177167
})}
178168
<div className="flex flex-row gap-2">
179169
<Button
180-
colorScheme="purple"
181-
leftIcon={<PlusIcon className="size-5" />}
170+
className="rounded-full"
182171
onClick={() =>
183172
// biome-ignore lint/suspicious/noExplicitAny: FIXME
184173
append({ trait_type: undefined, value: undefined } as any)
185174
}
186175
size="sm"
187176
>
177+
<PlusIcon className="size-4 mr-2" />
188178
Add Row
189179
</Button>
190180
</div>
191181
</div>
192182
);
193-
};
183+
}

0 commit comments

Comments
 (0)