Skip to content

Commit 66cba85

Browse files
committed
Dashboard: Migrate various components from chakra to tailwind (#7743)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR primarily focuses on refactoring and enhancing forms in various components by replacing `@chakra-ui/react` form elements with a custom UI form system. It also introduces new validation schemas using `zod` for improved form handling and user feedback. ### Detailed summary - Replaced `FormControl`, `FormLabel`, and related components from `@chakra-ui/react` with custom UI components in multiple files. - Introduced `FormFieldSetup` and `FormField` components for better form structure. - Added `zod` validation schemas for form data validation in `ClaimTab` and `NFTClaimButton`. - Updated form submission logic to use the new form handling approach. - Enhanced user feedback through improved error handling and notifications. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 0426fe5 commit 66cba85

File tree

8 files changed

+523
-445
lines changed

8 files changed

+523
-445
lines changed

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/ModuleForm.tsx

Lines changed: 82 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"use client";
22

3-
import { FormControl, Input, Select, Skeleton, Spacer } from "@chakra-ui/react";
43
import { useMutation, useQuery } from "@tanstack/react-query";
5-
import { FormErrorMessage, FormLabel } from "chakra/form";
64
import { useMemo } from "react";
75
import { FormProvider, type UseFormReturn, useForm } from "react-hook-form";
86
import { toast } from "sonner";
@@ -26,8 +24,18 @@ import {
2624
toFunctionSelector,
2725
} from "thirdweb/utils";
2826
import type { Account } from "thirdweb/wallets";
27+
import { FormFieldSetup } from "@/components/blocks/FormFieldSetup";
2928
import { TransactionButton } from "@/components/tx-button";
29+
import { Input } from "@/components/ui/input";
3030
import { Spinner } from "@/components/ui/Spinner/Spinner";
31+
import {
32+
Select,
33+
SelectContent,
34+
SelectItem,
35+
SelectTrigger,
36+
SelectValue,
37+
} from "@/components/ui/select";
38+
import { Skeleton } from "@/components/ui/skeleton";
3139
import {
3240
useAllVersions,
3341
usePublishedContractsQuery,
@@ -65,7 +73,7 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
6573
version: "latest",
6674
},
6775
});
68-
const { register, watch, formState, resetField, reset } = form;
76+
const { register, watch, formState, resetField, reset, setValue } = form;
6977
const { contract, account } = props;
7078
const { errors } = formState;
7179

@@ -144,10 +152,6 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
144152
installMutation.mutate();
145153
};
146154

147-
const moduleContractInputProps = register("moduleContract", {
148-
required: "Module name is required",
149-
});
150-
151155
const selectedModule = modulesOnly?.find(
152156
(x) => x.contractId === watch("moduleContract"),
153157
);
@@ -267,62 +271,65 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
267271
}}
268272
>
269273
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
270-
<FormControl isInvalid={!!errors.publisherAddress}>
271-
<FormLabel>Publisher</FormLabel>
274+
<FormFieldSetup
275+
htmlFor="publisherAddress"
276+
label="Publisher"
277+
errorMessage={errors.publisherAddress?.message}
278+
isRequired={true}
279+
>
272280
<Input
273-
bg="backgroundHighlight"
281+
id="publisherAddress"
274282
disabled={installMutation.isPending}
275283
placeholder="Publisher address"
276284
{...register("publisherAddress", {
277285
required: "Publisher address is required",
278286
})}
279287
/>
280-
<FormErrorMessage>
281-
{errors.publisherAddress?.message}
282-
</FormErrorMessage>
283-
</FormControl>
284-
285-
<FormControl
286-
isInvalid={
287-
!!errors.moduleContract || isModuleCompatibleQuery.data === false
288+
</FormFieldSetup>
289+
290+
<FormFieldSetup
291+
htmlFor="moduleContract"
292+
label="Module Name"
293+
errorMessage={
294+
!isModuleCompatibleQuery.isFetching &&
295+
isModuleCompatibleQuery.data === false
296+
? "Module is not compatible"
297+
: errors.moduleContract?.message
288298
}
289299
isRequired={true}
290300
>
291-
<FormLabel>Module Name</FormLabel>
292-
<Skeleton
293-
borderRadius="lg"
294-
isLoaded={!!modulesOnly.length || !isFetching}
295-
>
301+
{!modulesOnly.length && isFetching ? (
302+
<Skeleton className="h-10 w-full rounded-md" />
303+
) : (
296304
<Select
297-
bg="backgroundHighlight"
298305
disabled={
299306
installMutation.isPending ||
300307
modulesOnly?.length === 0 ||
301308
isPending
302309
}
303-
{...moduleContractInputProps}
304-
onChange={(e) => {
310+
value={watch("moduleContract")}
311+
onValueChange={(value) => {
312+
setValue("moduleContract", value);
305313
// reset version when module changes
306314
resetField("version");
307-
moduleContractInputProps.onChange(e);
308315
}}
309-
placeholder={
310-
modulesOnly.length === 0 ? "No modules" : "Select module"
311-
}
312316
>
313-
{modulesOnly.map(({ contractId }) => (
314-
<option key={contractId} value={contractId}>
315-
{contractId}
316-
</option>
317-
))}
317+
<SelectTrigger>
318+
<SelectValue
319+
placeholder={
320+
modulesOnly.length === 0 ? "No modules" : "Select module"
321+
}
322+
/>
323+
</SelectTrigger>
324+
<SelectContent>
325+
{modulesOnly.map(({ contractId }) => (
326+
<SelectItem key={contractId} value={contractId}>
327+
{contractId}
328+
</SelectItem>
329+
))}
330+
</SelectContent>
318331
</Select>
319-
</Skeleton>
320-
<FormErrorMessage fontWeight={500}>
321-
{!isModuleCompatibleQuery.isFetching &&
322-
isModuleCompatibleQuery.data === false &&
323-
"Module is not compatible"}
324-
{errors.moduleContract?.message}
325-
</FormErrorMessage>
332+
)}
326333

327334
{isModuleCompatibleQuery.isFetching && selectedModule && (
328335
<div className="mt-2 flex items-center gap-1.5 text-link-foreground">
@@ -338,39 +345,52 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
338345
</p>
339346
</div>
340347
)}
341-
</FormControl>
348+
</FormFieldSetup>
342349

343-
<FormControl isInvalid={!!errors.version} isRequired={true}>
344-
<FormLabel>Module Version</FormLabel>
345-
<Skeleton borderRadius="lg" isLoaded={!allVersions.isFetching}>
350+
<FormFieldSetup
351+
htmlFor="version"
352+
label="Module Version"
353+
errorMessage={errors.version?.message}
354+
isRequired={true}
355+
>
356+
{allVersions.isFetching ? (
357+
<Skeleton className="h-10 w-full rounded-md" />
358+
) : (
346359
<Select
347-
bg="backgroundHighlight"
348360
disabled={
349361
!allVersions.data ||
350362
allVersions.isPending ||
351363
isModuleCompatibleQuery.data === false ||
352364
installMutation.isPending ||
353365
isModuleCompatibleQuery.isFetching
354366
}
355-
w="full"
356-
{...register("version", {
357-
required: "Version is required",
358-
})}
367+
value={watch("version")}
368+
onValueChange={(value) => setValue("version", value)}
359369
>
360-
<option value="latest">Latest</option>
361-
{allVersions?.data?.map(({ version }) => (
362-
<option key={version} value={version}>
363-
{version}
364-
</option>
365-
))}
370+
<SelectTrigger>
371+
<SelectValue placeholder="Select version" />
372+
</SelectTrigger>
373+
<SelectContent>
374+
<SelectItem value="latest">Latest</SelectItem>
375+
{allVersions?.data?.map(({ version }) => {
376+
if (!version) {
377+
return null;
378+
}
379+
380+
return (
381+
<SelectItem key={version} value={version}>
382+
{version}
383+
</SelectItem>
384+
);
385+
})}
386+
</SelectContent>
366387
</Select>
367-
</Skeleton>
368-
<FormErrorMessage>{errors.version?.message}</FormErrorMessage>
369-
</FormControl>
388+
)}
389+
</FormFieldSetup>
370390
</div>
371391

372392
{moduleInstallParams.isFetching ? (
373-
<Skeleton h="80px" mt={4} />
393+
<Skeleton className="h-20 w-full mt-4" />
374394
) : (
375395
moduleInstallParams.data &&
376396
!isModuleCompatibleQuery.isFetching &&
@@ -383,7 +403,7 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
383403
)
384404
)}
385405

386-
<Spacer h={5} />
406+
<div className="h-5" />
387407

388408
{/* Submit */}
389409
<div className="flex justify-end">

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/install-module-params.tsx

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { FormControl } from "@chakra-ui/react";
21
import { useQuery } from "@tanstack/react-query";
3-
import { FormErrorMessage, FormLabel } from "chakra/form";
42
import type { ThirdwebClient } from "thirdweb";
53
import invariant from "tiny-invariant";
4+
import { FormFieldSetup } from "@/components/blocks/FormFieldSetup";
65
import { SolidityInput } from "@/components/solidity-inputs";
76
import { getModuleInstalledParams } from "./getModuleInstalledParams";
87
import type { InstallModuleForm } from "./ModuleForm";
@@ -48,14 +47,14 @@ export function ModuleInstallParams(props: {
4847
const formFieldKey = `moduleInstallFormParams.${param.name}` as const;
4948

5049
return (
51-
<FormControl
52-
isInvalid={
53-
!!form.getFieldState(formFieldKey, form.formState).error
54-
}
55-
isRequired
50+
<FormFieldSetup
5651
key={formFieldKey}
52+
isRequired
53+
label={param.name}
54+
errorMessage={
55+
form.getFieldState(formFieldKey, form.formState).error?.message
56+
}
5757
>
58-
<FormLabel> {param.name}</FormLabel>
5958
<SolidityInput
6059
// @ts-expect-error - old types, need to update
6160
solidityComponents={
@@ -66,13 +65,7 @@ export function ModuleInstallParams(props: {
6665
{...form.register(formFieldKey)}
6766
isDisabled={props.disableInputs}
6867
/>
69-
<FormErrorMessage>
70-
{
71-
form.getFieldState(formFieldKey, form.formState).error
72-
?.message
73-
}
74-
</FormErrorMessage>
75-
</FormControl>
68+
</FormFieldSetup>
7669
);
7770
})}
7871
</div>

0 commit comments

Comments
 (0)