<!-- start pr-codex -->
## PR-Codex overview
This PR updates loading states in various components to use `isPending` instead of `isLoading`.
### Detailed summary
- Replaced `isLoading` with `isPending` in multiple components for loading state handling.
> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/manage/components/InstalledModulesTable.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/hooks/usePayCustomers.ts`, `apps/dashboard/src/components/pay/PayConfig.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/client/add-partner-form.client.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PaymentHistory.tsx`, `apps/dashboard/src/contract-ui/tabs/split/components/distribute-button.tsx`, `apps/dashboard/src/components/onboarding/LinkWallet.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/TotalVolumePieChart.tsx`, `apps/dashboard/package.json`, `apps/dashboard/src/components/pay/PayAnalytics/hooks/usePayPurchases.ts`, `apps/dashboard/src/components/engine/configuration/local-config.tsx.tsx`, `apps/dashboard/src/components/settings/ApiKeys/Create/index.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/server/partners-table.tsx`, `apps/dashboard/src/contract-ui/components/solidity-inputs/string-input.tsx`, `apps/dashboard/src/components/settings/Account/Billing/index.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/client/update-partner-form.client.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/page.tsx`, `apps/dashboard/src/components/configure-networks/Form/IconUpload.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/create/hooks/use-create-ecosystem.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/create/components/client/create-ecosystem-form.client.tsx`, `apps/dashboard/src/components/engine/engine-instances-table.tsx`, `apps/dashboard/src/components/engine/contract-subscription/contract-subscriptions-table.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PayCustomersTable.tsx`, `apps/dashboard/src/pages/api/revalidate/publish.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/hooks/use-update-ecosystem.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/hooks/use-add-partner.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/hooks/use-delete-partner.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/hooks/use-update-partner.ts`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/live-stats.tsx`, `apps/dashboard/src/contract-ui/tabs/shared-components/marketplace-table.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/query/useQueryWithNetwork.ts`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/pay/components/webhooks.client.tsx`, `apps/dashboard/src/components/contract-components/tables/deployed-contracts.tsx`, `apps/dashboard/src/contract-ui/tabs/proposals/components/proposal.tsx`, `apps/dashboard/src/components/app-layouts/app.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/client/integration-permissions-toggle.client.tsx`, `apps/dashboard/src/app/account/settings/AccountSettingsPageUI.tsx`, `apps/dashboard/src/components/cmd-k-search/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useLoggedInUser.ts`, `apps/dashboard/src/components/contract-components/hooks.ts`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useRegistry.ts`, `apps/dashboard/src/contract-ui/tabs/manage/components/ModuleForm.tsx`, `apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.tsx`, `apps/dashboard/src/components/storage/your-files.tsx`, `apps/dashboard/src/components/contract-functions/interactive-abi-function.tsx`, `apps/dashboard/src/components/ipfs-upload/dropzone.tsx`, `apps/dashboard/src/core-ui/nft-drawer/useNftDrawerTabs.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts`, `pnpm-lock.yaml`, `apps/dashboard/src/contract-ui/hooks/useRouteConfig.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts`
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
259 lines
6.8 KiB
TypeScript
259 lines
6.8 KiB
TypeScript
import { type Account, useUpdateAccount } from "@3rdweb-sdk/react/hooks/useApi";
|
|
import {
|
|
Flex,
|
|
FormControl,
|
|
HStack,
|
|
Input,
|
|
VStack,
|
|
useColorModeValue,
|
|
} from "@chakra-ui/react";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { ManageBillingButton } from "components/settings/Account/Billing/ManageButton";
|
|
import { useTrack } from "hooks/analytics/useTrack";
|
|
import { useTxNotifications } from "hooks/useTxNotifications";
|
|
import { type ChangeEvent, useState } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import {
|
|
Button,
|
|
type ButtonProps,
|
|
Checkbox,
|
|
FormErrorMessage,
|
|
FormLabel,
|
|
Heading,
|
|
Text,
|
|
} from "tw-components";
|
|
import {
|
|
type AccountValidationSchema,
|
|
accountValidationSchema,
|
|
} from "./validations";
|
|
|
|
interface AccountFormProps {
|
|
account: Account;
|
|
horizontal?: boolean;
|
|
previewEnabled?: boolean;
|
|
showBillingButton?: boolean;
|
|
showSubscription?: boolean;
|
|
hideName?: boolean;
|
|
buttonProps?: ButtonProps;
|
|
buttonText?: string;
|
|
padded?: boolean;
|
|
trackingCategory?: string;
|
|
disableUnchanged?: boolean;
|
|
onSave?: (email: string) => void;
|
|
onDuplicateError?: (email: string) => void;
|
|
}
|
|
|
|
export const AccountForm: React.FC<AccountFormProps> = ({
|
|
account,
|
|
onSave,
|
|
onDuplicateError,
|
|
buttonProps,
|
|
buttonText = "Save",
|
|
horizontal = false,
|
|
previewEnabled = false,
|
|
hideName = false,
|
|
showBillingButton = false,
|
|
showSubscription = false,
|
|
disableUnchanged = false,
|
|
padded = true,
|
|
}) => {
|
|
const [isSubscribing, setIsSubscribing] = useState(
|
|
showSubscription && !!account.email?.length,
|
|
);
|
|
const trackEvent = useTrack();
|
|
const bg = useColorModeValue("backgroundCardHighlight", "transparent");
|
|
|
|
const form = useForm<AccountValidationSchema>({
|
|
resolver: zodResolver(accountValidationSchema),
|
|
defaultValues: {
|
|
name: account.name || "",
|
|
email: account.unconfirmedEmail || account.email || "",
|
|
},
|
|
values: {
|
|
name: account.name || "",
|
|
email: account.unconfirmedEmail || account.email || "",
|
|
},
|
|
});
|
|
|
|
const updateMutation = useUpdateAccount();
|
|
|
|
const { onSuccess, onError } = useTxNotifications(
|
|
"Billing account saved.",
|
|
"Failed to save your billing account.",
|
|
);
|
|
|
|
const handleSubmit = form.handleSubmit((values) => {
|
|
const formData = {
|
|
...values,
|
|
...(showSubscription
|
|
? {
|
|
subscribeToUpdates: isSubscribing,
|
|
}
|
|
: {}),
|
|
};
|
|
|
|
trackEvent({
|
|
category: "account",
|
|
action: "update",
|
|
label: "attempt",
|
|
data: formData,
|
|
});
|
|
|
|
updateMutation.mutate(formData, {
|
|
onSuccess: (data) => {
|
|
if (onSave) {
|
|
onSave(values.email);
|
|
}
|
|
onSuccess();
|
|
|
|
trackEvent({
|
|
category: "account",
|
|
action: "update",
|
|
label: "success",
|
|
data,
|
|
});
|
|
},
|
|
onError: (err) => {
|
|
const error = err as Error;
|
|
|
|
if (
|
|
onDuplicateError &&
|
|
error?.message.match(/email address already exists/)
|
|
) {
|
|
onDuplicateError(values.email);
|
|
} else {
|
|
onError(error);
|
|
}
|
|
|
|
trackEvent({
|
|
category: "account",
|
|
action: "update",
|
|
label: "error",
|
|
error,
|
|
fromOnboarding: !!onDuplicateError,
|
|
});
|
|
},
|
|
});
|
|
});
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit}>
|
|
<VStack
|
|
alignItems="flex-start"
|
|
w="full"
|
|
gap={horizontal ? 6 : 8}
|
|
borderRadius="xl"
|
|
borderColor="borderColor"
|
|
borderWidth={padded ? 1 : 0}
|
|
bg={bg}
|
|
p={padded ? 6 : 0}
|
|
>
|
|
<Flex
|
|
gap={horizontal ? 4 : 8}
|
|
flexDir={horizontal ? "row" : "column"}
|
|
w="full"
|
|
>
|
|
<FormControl
|
|
isRequired
|
|
isInvalid={!!form.getFieldState("email", form.formState).error}
|
|
>
|
|
<FormLabel>Email</FormLabel>
|
|
|
|
{previewEnabled ? (
|
|
<Flex
|
|
borderRadius="md"
|
|
borderColor="borderColor"
|
|
borderWidth={1}
|
|
h={10}
|
|
px={3}
|
|
alignItems="center"
|
|
>
|
|
<Heading size="subtitle.sm">{form.getValues("email")}</Heading>
|
|
</Flex>
|
|
) : (
|
|
<Input
|
|
placeholder="[email protected]"
|
|
type="email"
|
|
{...form.register("email")}
|
|
/>
|
|
)}
|
|
|
|
{form.getFieldState("email", form.formState).error && (
|
|
<FormErrorMessage size="body.sm">
|
|
{form.getFieldState("email", form.formState).error?.message}
|
|
</FormErrorMessage>
|
|
)}
|
|
</FormControl>
|
|
|
|
{!hideName && (
|
|
<FormControl
|
|
isInvalid={!!form.getFieldState("name", form.formState).error}
|
|
>
|
|
<FormLabel>Name</FormLabel>
|
|
|
|
{previewEnabled ? (
|
|
<Flex
|
|
borderRadius="md"
|
|
borderColor="borderColor"
|
|
borderWidth={1}
|
|
h={10}
|
|
px={3}
|
|
alignItems="center"
|
|
>
|
|
<Heading size="subtitle.sm">{form.getValues("name")}</Heading>
|
|
</Flex>
|
|
) : (
|
|
<Input
|
|
placeholder="Company Inc."
|
|
type="text"
|
|
{...form.register("name")}
|
|
/>
|
|
)}
|
|
|
|
{form.getFieldState("name", form.formState).error && (
|
|
<FormErrorMessage size="body.sm">
|
|
{form.getFieldState("name", form.formState).error?.message}
|
|
</FormErrorMessage>
|
|
)}
|
|
</FormControl>
|
|
)}
|
|
|
|
{showSubscription && (
|
|
<Checkbox
|
|
defaultChecked
|
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
setIsSubscribing(e.target.checked)
|
|
}
|
|
>
|
|
<Text>Subscribe to new features and key product updates</Text>
|
|
</Checkbox>
|
|
)}
|
|
</Flex>
|
|
|
|
<HStack
|
|
justifyContent={showBillingButton ? "space-between" : "flex-end"}
|
|
w="full"
|
|
>
|
|
{showBillingButton && <ManageBillingButton account={account} />}
|
|
|
|
{!previewEnabled && (
|
|
<Button
|
|
{...buttonProps}
|
|
type="button"
|
|
onClick={handleSubmit}
|
|
colorScheme={buttonProps?.variant ? undefined : "blue"}
|
|
isDisabled={
|
|
updateMutation.isPending ||
|
|
(disableUnchanged && !form.formState.isDirty)
|
|
}
|
|
isLoading={updateMutation.isPending}
|
|
>
|
|
{buttonText}
|
|
</Button>
|
|
)}
|
|
</HStack>
|
|
</VStack>
|
|
</form>
|
|
);
|
|
};
|