<!-- 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 -->
544 lines
18 KiB
TypeScript
544 lines
18 KiB
TypeScript
"use client";
|
|
|
|
import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect";
|
|
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
|
|
import { Box, Divider, Flex, Icon, IconButton } from "@chakra-ui/react";
|
|
import {
|
|
CONTRACT_ADDRESSES,
|
|
ExtraPublishMetadataSchemaInput,
|
|
detectFeatures,
|
|
isExtensionEnabled,
|
|
} from "@thirdweb-dev/sdk";
|
|
import type { Abi } from "abitype";
|
|
import { defaultChains } from "constants/chains";
|
|
import { useTrack } from "hooks/analytics/useTrack";
|
|
import { useTxNotifications } from "hooks/useTxNotifications";
|
|
import { useRouter } from "next/router";
|
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
import { FormProvider, useForm } from "react-hook-form";
|
|
import { IoChevronBack } from "react-icons/io5";
|
|
import { useActiveAccount } from "thirdweb/react";
|
|
import { Button, Text } from "tw-components";
|
|
import { z } from "zod";
|
|
import {
|
|
useContractFullPublishMetadata,
|
|
useContractPrePublishMetadata,
|
|
useContractPublishMetadataFromURI,
|
|
useEns,
|
|
useFunctionParamsFromABI,
|
|
usePublishMutation,
|
|
} from "../hooks";
|
|
import type { ContractId } from "../types";
|
|
import { ContractParamsFieldset } from "./contract-params-fieldset";
|
|
import { FactoryFieldset } from "./factory-fieldset";
|
|
import { LandingFieldset } from "./landing-fieldset";
|
|
import { NetworksFieldset } from "./networks-fieldset";
|
|
|
|
const ExtraPublishMetadataSchema = ExtraPublishMetadataSchemaInput.extend({
|
|
customFactoryAddresses: z.array(
|
|
z.object({
|
|
key: z.number(),
|
|
value: z.string(),
|
|
}),
|
|
),
|
|
});
|
|
|
|
interface ContractPublishFormProps {
|
|
contractId: ContractId;
|
|
}
|
|
|
|
export const ContractPublishForm: React.FC<ContractPublishFormProps> = ({
|
|
contractId,
|
|
}) => {
|
|
const [customFactoryAbi, setCustomFactoryAbi] = useState<Abi>([]);
|
|
const configuredChainsIds = defaultChains.map((c) => c.id);
|
|
const [fieldsetToShow, setFieldsetToShow] = useState<
|
|
"landing" | "factory" | "contractParams" | "networks"
|
|
>("landing");
|
|
const trackEvent = useTrack();
|
|
|
|
const router = useRouter();
|
|
const { onSuccess, onError } = useTxNotifications(
|
|
"Successfully published contract",
|
|
"Failed to publish contract",
|
|
);
|
|
const address = useActiveAccount()?.address;
|
|
const publishMutation = usePublishMutation();
|
|
|
|
const publishMetadata = useContractPublishMetadataFromURI(contractId);
|
|
const prePublishMetadata = useContractPrePublishMetadata(contractId, address);
|
|
|
|
const latestVersion =
|
|
prePublishMetadata.data?.latestPublishedContractMetadata?.publishedMetadata
|
|
.version;
|
|
|
|
const placeholderVersion = useMemo(() => {
|
|
if (latestVersion) {
|
|
const versplit = latestVersion.split(".");
|
|
return `${versplit[0]}.${versplit[1]}.${Number(versplit[2]) + 1 || 0}`;
|
|
}
|
|
return "1.0.0";
|
|
}, [latestVersion]);
|
|
|
|
const transformedQueryData = useMemo(() => {
|
|
return {
|
|
...prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata,
|
|
changelog: "",
|
|
version: placeholderVersion,
|
|
displayName:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata.displayName ||
|
|
prePublishMetadata.data?.preDeployMetadata.info.title ||
|
|
publishMetadata.data?.name ||
|
|
"",
|
|
description:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata.description ||
|
|
prePublishMetadata.data?.preDeployMetadata.info.notice ||
|
|
"",
|
|
factoryDeploymentData: prePublishMetadata.data
|
|
?.latestPublishedContractMetadata?.publishedMetadata
|
|
?.factoryDeploymentData || {
|
|
factoryAddresses: Object.fromEntries(
|
|
configuredChainsIds
|
|
.map((id) =>
|
|
id in CONTRACT_ADDRESSES
|
|
? [
|
|
id,
|
|
CONTRACT_ADDRESSES[id as keyof typeof CONTRACT_ADDRESSES]
|
|
.twFactory,
|
|
]
|
|
: null,
|
|
)
|
|
.filter(Boolean) as [number, string][],
|
|
),
|
|
implementationAddresses: Object.fromEntries(
|
|
configuredChainsIds.map((id) => [id, ""]),
|
|
),
|
|
implementationInitializerFunction: "initialize",
|
|
customFactoryInput: {
|
|
factoryFunction:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata.factoryDeploymentData?.customFactoryInput
|
|
?.factoryFunction || "deployProxyByImplementation",
|
|
customFactoryAddresses:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.factoryDeploymentData?.customFactoryInput
|
|
?.customFactoryAddresses || {},
|
|
},
|
|
},
|
|
constructorParams:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.constructorParams || {},
|
|
networksForDeployment: prePublishMetadata.data
|
|
?.latestPublishedContractMetadata?.publishedMetadata
|
|
.networksForDeployment || {
|
|
allNetworks: true,
|
|
},
|
|
deployType:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.deployType || "standard",
|
|
customFactoryAddresses: Object.entries(
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.factoryDeploymentData?.customFactoryInput
|
|
?.customFactoryAddresses || {},
|
|
).map(([key, value]) => ({ key: Number(key), value })),
|
|
defaultExtensions:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.defaultExtensions || [],
|
|
defaultModules:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata?.defaultModules || [],
|
|
extensionsParamName:
|
|
prePublishMetadata.data?.latestPublishedContractMetadata
|
|
?.publishedMetadata.factoryDeploymentData?.modularFactoryInput
|
|
?.extensionsParamName || "",
|
|
};
|
|
}, [
|
|
configuredChainsIds,
|
|
placeholderVersion,
|
|
prePublishMetadata.data?.latestPublishedContractMetadata?.publishedMetadata,
|
|
prePublishMetadata.data?.preDeployMetadata.info.notice,
|
|
prePublishMetadata.data?.preDeployMetadata.info.title,
|
|
publishMetadata.data?.name,
|
|
]);
|
|
|
|
const form = useForm<z.input<typeof ExtraPublishMetadataSchema>>({
|
|
defaultValues: transformedQueryData,
|
|
values: transformedQueryData,
|
|
resetOptions: {
|
|
keepDirty: true,
|
|
keepDirtyValues: true,
|
|
},
|
|
});
|
|
|
|
const hasTrackedImpression = useRef<boolean>(false);
|
|
// TODO: figure out a better way to track impressions
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
useEffect(() => {
|
|
if (publishMetadata.data && !hasTrackedImpression.current) {
|
|
hasTrackedImpression.current = true;
|
|
trackEvent({
|
|
action: "impression",
|
|
category: "publish",
|
|
analytics: publishMetadata.data.analytics,
|
|
});
|
|
}
|
|
}, [publishMetadata.data, trackEvent]);
|
|
|
|
const disableNext =
|
|
!form.watch("version") ||
|
|
!form.watch("displayName") ||
|
|
!!form.getFieldState("version", form.formState).error;
|
|
|
|
const ensQuery = useEns(address);
|
|
|
|
const ensNameOrAddress = useMemo(() => {
|
|
return ensQuery?.data?.ensName || ensQuery.data?.address;
|
|
}, [ensQuery.data]);
|
|
|
|
const successRedirectUrl = useMemo(() => {
|
|
if (!ensNameOrAddress || !publishMetadata.data?.name) {
|
|
return undefined;
|
|
}
|
|
return `/${ensNameOrAddress}/${publishMetadata.data.name}`;
|
|
}, [ensNameOrAddress, publishMetadata.data?.name]);
|
|
|
|
const isDisabled = useMemo(
|
|
() => !successRedirectUrl || !address,
|
|
[successRedirectUrl, address],
|
|
);
|
|
|
|
const fullPublishMetadata = useContractFullPublishMetadata(contractId);
|
|
const constructorParams =
|
|
publishMetadata.data?.abi?.find((c) => c.type === "constructor")?.inputs ||
|
|
[];
|
|
|
|
const initializerParams = useFunctionParamsFromABI(
|
|
(form.watch("deployType") === "customFactory"
|
|
? customFactoryAbi
|
|
: publishMetadata.data?.abi) as Abi,
|
|
form.watch("deployType") === "customFactory"
|
|
? form.watch(
|
|
"factoryDeploymentData.customFactoryInput.factoryFunction",
|
|
) ||
|
|
fullPublishMetadata.data?.factoryDeploymentData?.customFactoryInput
|
|
?.factoryFunction ||
|
|
"deployProxyByImplementation"
|
|
: form.watch("factoryDeploymentData.implementationInitializerFunction") ||
|
|
fullPublishMetadata.data?.factoryDeploymentData
|
|
?.implementationInitializerFunction ||
|
|
"initialize",
|
|
);
|
|
|
|
const deployParams =
|
|
form.watch("deployType") === "standard"
|
|
? constructorParams
|
|
: initializerParams;
|
|
|
|
const extensions = detectFeatures(publishMetadata.data?.abi || []);
|
|
|
|
const isPluginRouter = useMemo(
|
|
() =>
|
|
isExtensionEnabled(
|
|
publishMetadata.data?.abi || [],
|
|
"PluginRouter",
|
|
extensions,
|
|
),
|
|
[publishMetadata.data?.abi, extensions],
|
|
);
|
|
|
|
const isDynamicContract = useMemo(
|
|
() =>
|
|
isExtensionEnabled(
|
|
publishMetadata.data?.abi || [],
|
|
"DynamicContract",
|
|
extensions,
|
|
),
|
|
[publishMetadata.data?.abi, extensions],
|
|
);
|
|
|
|
const isModularContract = useMemo(
|
|
() =>
|
|
isExtensionEnabled(
|
|
publishMetadata.data?.abi || [],
|
|
"ModularCore",
|
|
extensions,
|
|
),
|
|
[publishMetadata.data?.abi, extensions],
|
|
);
|
|
|
|
const hasExtensionsParam = useMemo(
|
|
() =>
|
|
constructorParams.some(
|
|
(param) => param.name === "_extensions" || "_marketplaceV3Params",
|
|
),
|
|
[constructorParams],
|
|
);
|
|
|
|
const shouldShowDynamicFactoryInput = useMemo(
|
|
() =>
|
|
isPluginRouter ||
|
|
(isDynamicContract && hasExtensionsParam) ||
|
|
isModularContract,
|
|
[isPluginRouter, isDynamicContract, isModularContract, hasExtensionsParam],
|
|
);
|
|
|
|
const shouldShowModularFactoryInput = useMemo(
|
|
() => isModularContract,
|
|
[isModularContract],
|
|
);
|
|
|
|
const shouldShowModulesParamInput = useMemo(
|
|
() => isModularContract,
|
|
[isModularContract],
|
|
);
|
|
|
|
// during loading and after success we should stay in loading state
|
|
const isLoading = publishMutation.isPending || publishMutation.isSuccess;
|
|
|
|
useIsomorphicLayoutEffect(() => {
|
|
window?.scrollTo({
|
|
top: 0,
|
|
behavior: "smooth",
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<FormProvider {...form}>
|
|
<Box w="100%">
|
|
<Flex
|
|
as="form"
|
|
id="contract-release-form"
|
|
onSubmit={form.handleSubmit((data) => {
|
|
const addressArray =
|
|
Object.keys(data?.customFactoryAddresses || {}).length > 0
|
|
? (data?.customFactoryAddresses as unknown as {
|
|
key: number;
|
|
value: string;
|
|
}[])
|
|
: [];
|
|
|
|
const addressObj = addressArray.reduce<Record<number, string>>(
|
|
(obj, item) => {
|
|
obj[item.key] = item.value;
|
|
return obj;
|
|
},
|
|
{},
|
|
);
|
|
|
|
trackEvent({
|
|
category: "publish",
|
|
action: "click",
|
|
label: "attempt",
|
|
uris: contractId,
|
|
release_id: `${ensNameOrAddress}/${publishMetadata.data?.name}`,
|
|
});
|
|
publishMutation.mutate(
|
|
{
|
|
predeployUri: contractId,
|
|
extraMetadata: {
|
|
...data,
|
|
networksForDeployment: {
|
|
allNetworks:
|
|
data.deployType === "customFactory"
|
|
? false
|
|
: data.networksForDeployment?.allNetworks,
|
|
networksEnabled:
|
|
addressArray.length > 0
|
|
? Object.keys(addressObj).map((val) => Number(val))
|
|
: data.networksForDeployment?.networksEnabled,
|
|
},
|
|
factoryDeploymentData: {
|
|
...data.factoryDeploymentData,
|
|
implementationAddresses:
|
|
data.factoryDeploymentData?.implementationAddresses || {},
|
|
customFactoryInput: {
|
|
factoryFunction:
|
|
data.factoryDeploymentData?.customFactoryInput
|
|
?.factoryFunction || "deployProxyByImplementation",
|
|
customFactoryAddresses:
|
|
addressObj ||
|
|
data.factoryDeploymentData?.customFactoryInput
|
|
?.customFactoryAddresses,
|
|
},
|
|
modularFactoryInput: {
|
|
modulesParamName:
|
|
data.factoryDeploymentData?.modularFactoryInput
|
|
?.modulesParamName || "",
|
|
},
|
|
},
|
|
},
|
|
contractName: publishMetadata.data?.name,
|
|
},
|
|
{
|
|
onSuccess: () => {
|
|
onSuccess();
|
|
trackEvent({
|
|
category: "publish",
|
|
action: "click",
|
|
label: "success",
|
|
uris: contractId,
|
|
release_id: `${ensNameOrAddress}/${publishMetadata.data?.name}`,
|
|
version: data.version,
|
|
type: data.deployType,
|
|
});
|
|
if (successRedirectUrl) {
|
|
router.push(
|
|
successRedirectUrl,
|
|
undefined,
|
|
// reset scroll after redirect
|
|
{ scroll: true },
|
|
);
|
|
}
|
|
},
|
|
onError: (err) => {
|
|
onError(err);
|
|
trackEvent({
|
|
category: "publish",
|
|
action: "click",
|
|
label: "error",
|
|
uris: contractId,
|
|
release_id: `${ensNameOrAddress}/${publishMetadata.data?.name}`,
|
|
is_factory: data.isDeployableViaFactory,
|
|
});
|
|
},
|
|
},
|
|
);
|
|
})}
|
|
direction="column"
|
|
gap={6}
|
|
>
|
|
{fieldsetToShow !== "landing" && (
|
|
<Box>
|
|
<IconButton
|
|
w="inherit"
|
|
variant="ghost"
|
|
onClick={() =>
|
|
fieldsetToShow === "contractParams" &&
|
|
(form.watch("deployType") === "autoFactory" ||
|
|
form.watch("deployType") === "customFactory")
|
|
? setFieldsetToShow("factory")
|
|
: fieldsetToShow === "contractParams" &&
|
|
form.watch("deployType") === "standard"
|
|
? setFieldsetToShow("networks")
|
|
: setFieldsetToShow("landing")
|
|
}
|
|
aria-label="Back"
|
|
icon={<Icon as={IoChevronBack} boxSize={6} />}
|
|
>
|
|
Back
|
|
</IconButton>
|
|
</Box>
|
|
)}
|
|
{fieldsetToShow === "landing" && (
|
|
<LandingFieldset
|
|
latestVersion={latestVersion}
|
|
placeholderVersion={placeholderVersion}
|
|
/>
|
|
)}
|
|
{fieldsetToShow === "contractParams" && (
|
|
<ContractParamsFieldset deployParams={deployParams} />
|
|
)}
|
|
{fieldsetToShow === "factory" && (
|
|
<Flex flexDir="column" gap={24}>
|
|
<FactoryFieldset
|
|
abi={(publishMetadata.data?.abi || []) as Abi}
|
|
setCustomFactoryAbi={setCustomFactoryAbi}
|
|
shouldShowDynamicFactoryInput={shouldShowDynamicFactoryInput}
|
|
shouldShowModularFactoryInput={shouldShowModularFactoryInput}
|
|
shouldShowModulesParamInput={shouldShowModulesParamInput}
|
|
deployParams={deployParams}
|
|
/>
|
|
</Flex>
|
|
)}
|
|
{fieldsetToShow === "networks" && (
|
|
<Flex flexDir="column" gap={24}>
|
|
<NetworksFieldset fromStandard />
|
|
</Flex>
|
|
)}
|
|
<Flex flexDir="column" gap={6}>
|
|
<Divider />
|
|
<Flex
|
|
justifyContent="space-between"
|
|
alignItems="center"
|
|
flexDir={{ base: "column", md: "row" }}
|
|
gap={4}
|
|
>
|
|
{!address ? (
|
|
<>
|
|
<Box />
|
|
<CustomConnectWallet />
|
|
</>
|
|
) : fieldsetToShow === "landing" &&
|
|
form.watch("deployType") === "standard" ? (
|
|
<>
|
|
<Box />
|
|
<Button
|
|
onClick={() => setFieldsetToShow("networks")}
|
|
colorScheme="primary"
|
|
isDisabled={disableNext}
|
|
>
|
|
Next
|
|
</Button>
|
|
</>
|
|
) : fieldsetToShow === "landing" &&
|
|
(form.watch("deployType") === "autoFactory" ||
|
|
form.watch("deployType") === "customFactory") ? (
|
|
<>
|
|
<Box />
|
|
<Button
|
|
onClick={() => setFieldsetToShow("factory")}
|
|
colorScheme="primary"
|
|
isDisabled={disableNext}
|
|
>
|
|
Next
|
|
</Button>
|
|
</>
|
|
) : fieldsetToShow !== "contractParams" &&
|
|
deployParams?.length > 0 ? (
|
|
<>
|
|
<Box />
|
|
<Button
|
|
isDisabled={disableNext}
|
|
onClick={() => setFieldsetToShow("contractParams")}
|
|
colorScheme="primary"
|
|
>
|
|
Next
|
|
</Button>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Text fontStyle="italic">
|
|
Publishing your contract is free, we cover all gas costs.
|
|
</Text>
|
|
<Button
|
|
// differentiate this from the edit button
|
|
key="submit-button"
|
|
borderRadius="md"
|
|
position="relative"
|
|
role="group"
|
|
colorScheme="blue"
|
|
isLoading={isLoading}
|
|
form="contract-release-form"
|
|
isDisabled={isDisabled}
|
|
loadingText={
|
|
publishMutation.isSuccess
|
|
? "Preparing page"
|
|
: "Publishing contract"
|
|
}
|
|
type="submit"
|
|
>
|
|
Publish Contract
|
|
</Button>
|
|
</>
|
|
)}
|
|
</Flex>
|
|
</Flex>
|
|
</Flex>
|
|
</Box>
|
|
</FormProvider>
|
|
);
|
|
};
|