feat: UI simple create ap view (#191)
* feat: add create app context * chore: add stepper and nfa picker * chore: crete step component * chore: fix create AP text * chore: update query to list NFAs * chore: changes PR * feat: handle error on create AP * chore: add message error when create AP * chore: add form context * Update ui/src/views/access-point/create-ap.form-body.tsx Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com> --------- Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>
This commit is contained in:
parent
ac618f9a32
commit
f3f35bb19b
|
|
@ -1,5 +1,5 @@
|
|||
query lastMintsPaginated($pageSize: Int, $skip: Int) {
|
||||
newMints(
|
||||
query lastNFAsPaginated($pageSize: Int, $skip: Int) {
|
||||
tokens(
|
||||
first: $pageSize
|
||||
skip: $skip
|
||||
orderDirection: desc
|
||||
|
|
@ -18,6 +18,20 @@ query totalTokens {
|
|||
}
|
||||
}
|
||||
|
||||
query getLatestNFAs {
|
||||
tokens {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
query getNFA($id: ID!) {
|
||||
token(id: $id) {
|
||||
tokenId
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
# query to get the ens name of an address
|
||||
query getENSNames($address: ID!) {
|
||||
account(id: $address) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const App = () => {
|
|||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap" element={<CreateAP />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ export const ChevronDownIcon: React.FC<IS.CustomProps> = (props) => (
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M0.96967 0.21967C1.26256 -0.0732233 1.73744 -0.0732233 2.03033 0.21967L6 4.18934L9.96967 0.21967C10.2626 -0.0732233 10.7374 -0.0732233 11.0303 0.21967C11.3232 0.512563 11.3232 0.987437 11.0303 1.28033L6.53033 5.78033C6.23744 6.07322 5.76256 6.07322 5.46967 5.78033L0.96967 1.28033C0.676777 0.987437 0.676777 0.512563 0.96967 0.21967Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ export * from './form';
|
|||
export * from './card';
|
||||
export * from './spinner';
|
||||
export * from './toast';
|
||||
export * from './step';
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export * from './step';
|
||||
|
|
@ -31,12 +31,12 @@ const Container = ({ children }: MintStepContainerProps) => (
|
|||
</Flex>
|
||||
);
|
||||
|
||||
type MintStepProps = {
|
||||
type StepProps = {
|
||||
children: React.ReactNode;
|
||||
header: string;
|
||||
};
|
||||
|
||||
export const MintStep: React.FC<MintStepProps> = ({ children, header }) => {
|
||||
export const Step: React.FC<StepProps> = ({ children, header }) => {
|
||||
return (
|
||||
<Container>
|
||||
<StepperIndicatorContainer>
|
||||
|
|
@ -179,6 +179,11 @@ export namespace ArgumentsMaps {
|
|||
boolean // bool accessPointAutoApproval
|
||||
];
|
||||
|
||||
addAccessPoint: [
|
||||
number, // tokenId
|
||||
string // access point DNS
|
||||
];
|
||||
|
||||
/**
|
||||
* TODO: Add other functions arguments as they are needed.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import { Card, Grid, Icon, IconButton, Stepper } from '@/components';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
import { CreateAccessPointFormBody } from './create-ap.form-body';
|
||||
|
||||
export const CreateAccessPointForm = () => {
|
||||
const { prevStep } = Stepper.useContext();
|
||||
|
||||
const { nfa } = CreateAccessPoint.useContext();
|
||||
|
||||
return (
|
||||
<Card.Container css={{ width: '$107h' }}>
|
||||
<Card.Heading
|
||||
title={`Create Access Point - ${nfa.label || ''}`}
|
||||
leftIcon={
|
||||
<IconButton
|
||||
aria-label="Add"
|
||||
colorScheme="gray"
|
||||
variant="link"
|
||||
icon={<Icon name="back" />}
|
||||
css={{ mr: '$2' }}
|
||||
onClick={prevStep}
|
||||
/>
|
||||
}
|
||||
rightIcon={
|
||||
<IconButton
|
||||
aria-label="Add"
|
||||
colorScheme="gray"
|
||||
variant="link"
|
||||
icon={<Icon name="info" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Card.Body>
|
||||
<Grid
|
||||
css={{
|
||||
rowGap: '$6',
|
||||
}}
|
||||
>
|
||||
<CreateAccessPointFormBody />
|
||||
</Grid>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
import {
|
||||
Button,
|
||||
Card,
|
||||
Flex,
|
||||
Form,
|
||||
Grid,
|
||||
Icon,
|
||||
IconButton,
|
||||
Stepper,
|
||||
} from '@/components';
|
||||
import { useTransactionCost } from '@/hooks';
|
||||
import { FleekERC721 } from '@/integrations';
|
||||
import { useMemo } from 'react';
|
||||
import { ethers } from 'ethers';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
import { useAccessPointFormContext } from './create-ap.form.context';
|
||||
|
||||
export const CreateAccessPointPreview = () => {
|
||||
const { prevStep } = Stepper.useContext();
|
||||
const {
|
||||
prepare: { status: prepareStatus, data: prepareData, error: prepareError },
|
||||
write: { status: writeStatus, write },
|
||||
transaction: { status: transactionStatus },
|
||||
} = CreateAccessPoint.useTransactionContext();
|
||||
const {
|
||||
form: {
|
||||
appName: {
|
||||
value: [appName],
|
||||
},
|
||||
},
|
||||
} = useAccessPointFormContext();
|
||||
const { nfa } = CreateAccessPoint.useContext();
|
||||
|
||||
const [cost, currency, isCostLoading] = useTransactionCost(
|
||||
prepareData?.request.value,
|
||||
prepareData?.request.gasLimit
|
||||
);
|
||||
|
||||
const message = useMemo(() => {
|
||||
if (isCostLoading || prepareStatus === 'loading')
|
||||
return 'Calculating cost...';
|
||||
|
||||
if (prepareError) {
|
||||
const parsedError = FleekERC721.parseError(
|
||||
(prepareError as any).error?.data.data
|
||||
);
|
||||
if (parsedError.isIdentified) {
|
||||
return parsedError.message;
|
||||
}
|
||||
|
||||
return 'An error occurred while preparing the transaction';
|
||||
}
|
||||
|
||||
const formattedCost = ethers.utils.formatEther(cost).slice(0, 9);
|
||||
return `Creating this Access Point will cost ${formattedCost} ${currency}.`;
|
||||
}, [prepareData, isCostLoading, prepareStatus]);
|
||||
|
||||
const isLoading = useMemo(
|
||||
() =>
|
||||
[prepareStatus, writeStatus, transactionStatus].some(
|
||||
(status) => status === 'loading'
|
||||
),
|
||||
[prepareStatus, writeStatus, transactionStatus]
|
||||
);
|
||||
|
||||
return (
|
||||
<Card.Container css={{ width: '$107h' }}>
|
||||
<Card.Heading
|
||||
title={`Create Access Point ${nfa.label || ''}`}
|
||||
leftIcon={
|
||||
<IconButton
|
||||
aria-label="Add"
|
||||
colorScheme="gray"
|
||||
variant="link"
|
||||
icon={<Icon name="back" />}
|
||||
css={{ mr: '$2' }}
|
||||
onClick={prevStep}
|
||||
/>
|
||||
}
|
||||
rightIcon={
|
||||
<IconButton
|
||||
aria-label="Add"
|
||||
colorScheme="gray"
|
||||
variant="link"
|
||||
icon={<Icon name="info" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Card.Body>
|
||||
<Grid
|
||||
css={{
|
||||
rowGap: '$6',
|
||||
}}
|
||||
>
|
||||
<Flex>
|
||||
<span>NFA: {nfa.value}</span>
|
||||
<span>{appName}</span>
|
||||
<span className="text-slate11 text-sm">{message}</span>
|
||||
</Flex>
|
||||
<Button
|
||||
disabled={!!prepareError || !nfa}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={write}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Grid>
|
||||
</Card.Body>
|
||||
</Card.Container>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { ComboboxItem } from '@/components';
|
||||
import { EthereumHooks } from '@/integrations';
|
||||
import { useFleekERC721Billing } from '@/store';
|
||||
import { AppLog, createContext, pushToast } from '@/utils';
|
||||
import { useState } from 'react';
|
||||
|
||||
export type AccessPointContext = {
|
||||
billing: string | undefined;
|
||||
nfa: ComboboxItem;
|
||||
setNfa: (nfa: ComboboxItem) => void;
|
||||
};
|
||||
|
||||
const [CreateAPProvider, useContext] = createContext<AccessPointContext>({
|
||||
name: 'CreateAPProvider.Context',
|
||||
hookName: 'CreateAPProvider.useContext',
|
||||
providerName: 'CreateAPProvider.Provider',
|
||||
});
|
||||
|
||||
const [TransactionProvider, useTransactionContext] =
|
||||
EthereumHooks.createFleekERC721WriteContext('addAccessPoint');
|
||||
|
||||
export abstract class CreateAccessPoint {
|
||||
static readonly useContext = useContext;
|
||||
|
||||
static readonly useTransactionContext = useTransactionContext;
|
||||
|
||||
static readonly Provider: React.FC<CreateAccessPoint.ProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [billing] = useFleekERC721Billing('AddAccessPoint');
|
||||
const [nfa, setNfa] = useState<ComboboxItem>({} as ComboboxItem);
|
||||
|
||||
const value = {
|
||||
billing,
|
||||
nfa,
|
||||
setNfa,
|
||||
};
|
||||
|
||||
return (
|
||||
<CreateAPProvider value={value}>
|
||||
<TransactionProvider
|
||||
config={{
|
||||
transaction: {
|
||||
onSuccess: (data) => {
|
||||
AppLog.info('Transaction:', data);
|
||||
pushToast('success', 'Your transaction was successful!');
|
||||
},
|
||||
onError: (error) => {
|
||||
AppLog.errorToast(
|
||||
'There was an error trying to create the Access Point. Please try again'
|
||||
);
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</TransactionProvider>
|
||||
</CreateAPProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export namespace CreateAccessPoint {
|
||||
export type ProviderProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import { Button, Flex, Form, Spinner, Stepper } from '@/components';
|
||||
import { AppLog } from '@/utils';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { ethers } from 'ethers';
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useAccessPointFormContext } from './create-ap.form.context';
|
||||
import { NfaPicker } from './nfa-picker';
|
||||
import { getNFADocument } from '@/graphclient';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
|
||||
export const CreateAccessPointFormBody = () => {
|
||||
const { id } = useParams();
|
||||
const { nextStep } = Stepper.useContext();
|
||||
const { nfa, setNfa, billing } = CreateAccessPoint.useContext();
|
||||
const { setArgs } = CreateAccessPoint.useTransactionContext();
|
||||
|
||||
const {
|
||||
form: {
|
||||
appName: {
|
||||
value: [appName],
|
||||
},
|
||||
isValid: [isValid],
|
||||
},
|
||||
} = useAccessPointFormContext();
|
||||
|
||||
const {
|
||||
form: { appName: appNameContext },
|
||||
} = useAccessPointFormContext();
|
||||
|
||||
const {
|
||||
data: nfaData,
|
||||
error: nfaError,
|
||||
loading: nfaLoading,
|
||||
} = useQuery(getNFADocument, {
|
||||
skip: id === undefined,
|
||||
variables: {
|
||||
id: ethers.utils.hexlify(Number(id)),
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (nfaError) {
|
||||
AppLog.errorToast('Error fetching NFA');
|
||||
}
|
||||
}, [nfaError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (nfaData) {
|
||||
if (nfaData.token && id) {
|
||||
const { name } = nfaData.token;
|
||||
setNfa({ value: id, label: name });
|
||||
} else {
|
||||
AppLog.errorToast("We couldn't find the NFA you are looking for");
|
||||
}
|
||||
}
|
||||
}, [nfaData, id]);
|
||||
|
||||
if (nfaLoading) {
|
||||
return (
|
||||
<Flex
|
||||
css={{
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '$48',
|
||||
}}
|
||||
>
|
||||
<Spinner />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
const handleContinueClick = () => {
|
||||
if (nfa && appName) {
|
||||
setArgs([Number(nfa.value), appName, { value: billing }]);
|
||||
nextStep();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* TODO will have to do some changes on the Form.Combobox if we use this component for the NFA picker */}
|
||||
{id === undefined && <NfaPicker />}
|
||||
<Form.Field context={appNameContext}>
|
||||
<Form.Label>App Name</Form.Label>
|
||||
<Form.Input />
|
||||
</Form.Field>
|
||||
<Button
|
||||
disabled={!isValid}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={handleContinueClick}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { FormField, useFormField } from '@/components';
|
||||
import { createContext, StringValidators } from '@/utils';
|
||||
import { useState } from 'react';
|
||||
|
||||
export type CreateAccessPointFormContext = {
|
||||
form: {
|
||||
appName: FormField;
|
||||
isValid: ReactState<boolean>;
|
||||
};
|
||||
};
|
||||
|
||||
export const [CreateAccessPointFormProvider, useAccessPointFormContext] =
|
||||
createContext<CreateAccessPointFormContext>({
|
||||
name: 'MintFormContext',
|
||||
hookName: 'useMintFormContext',
|
||||
providerName: 'MintFormProvider',
|
||||
});
|
||||
|
||||
export const useAccessPointFormContextInit =
|
||||
(): CreateAccessPointFormContext => ({
|
||||
form: {
|
||||
appName: useFormField('appName', [
|
||||
StringValidators.required,
|
||||
StringValidators.maxLength(50),
|
||||
]),
|
||||
isValid: useState(false),
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import { Form, Step, Stepper } from '@/components';
|
||||
import { WalletStep } from '../mint/wallet-step';
|
||||
import { CreateAccessPointForm } from './create-ap-form';
|
||||
import { CreateAccessPointPreview } from './create-ap-preview';
|
||||
import { useAccessPointFormContext } from './create-ap.form.context';
|
||||
|
||||
export const CreateApStepper = () => {
|
||||
const {
|
||||
form: {
|
||||
isValid: [, setIsValid],
|
||||
},
|
||||
} = useAccessPointFormContext();
|
||||
return (
|
||||
<Stepper.Root initialStep={1}>
|
||||
<Form.Root onValidationChange={setIsValid}>
|
||||
<Stepper.Container>
|
||||
<Stepper.Step>
|
||||
<Step header="Connect your Ethereum Wallet to create Access Point">
|
||||
<WalletStep />
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
|
||||
<Stepper.Step>
|
||||
<Step header="Set Access Point">
|
||||
<CreateAccessPointForm />
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
|
||||
<Stepper.Step>
|
||||
<Step header="Create Access Point">
|
||||
<CreateAccessPointPreview />
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
</Stepper.Container>
|
||||
</Form.Root>
|
||||
</Stepper.Root>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,6 +1,27 @@
|
|||
import { useParams } from 'react-router-dom';
|
||||
import { Flex } from '@/components';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
import {
|
||||
CreateAccessPointFormProvider,
|
||||
useAccessPointFormContextInit,
|
||||
} from './create-ap.form.context';
|
||||
import { CreateApStepper } from './create-ap.stepper';
|
||||
|
||||
export const CreateAP = () => {
|
||||
const { id } = useParams();
|
||||
return <>Token to create AP:{id}</>;
|
||||
const context = useAccessPointFormContextInit();
|
||||
return (
|
||||
<Flex
|
||||
css={{
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<CreateAccessPoint.Provider>
|
||||
<CreateAccessPointFormProvider value={context}>
|
||||
<CreateApStepper />
|
||||
</CreateAccessPointFormProvider>
|
||||
</CreateAccessPoint.Provider>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { Combobox, ComboboxItem } from '@/components';
|
||||
import { getLatestNFAsDocument } from '@/graphclient';
|
||||
import { AppLog } from '@/utils';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useMemo } from 'react';
|
||||
import { CreateAccessPoint } from './create-ap.context';
|
||||
|
||||
export const NfaPicker = () => {
|
||||
const { nfa, setNfa } = CreateAccessPoint.useContext();
|
||||
const { data, loading, error } = useQuery(getLatestNFAsDocument);
|
||||
|
||||
const handleNfaChange = (item: ComboboxItem) => {
|
||||
setNfa(item);
|
||||
};
|
||||
|
||||
const items = useMemo(() => {
|
||||
return data
|
||||
? data.tokens.map(
|
||||
(nfa) => ({ value: nfa.id, label: nfa.name } as ComboboxItem)
|
||||
)
|
||||
: [];
|
||||
}, [data]);
|
||||
|
||||
if (loading) return <div>Loading...</div>;
|
||||
|
||||
if (error) {
|
||||
AppLog.errorToast('Error loading NFA list');
|
||||
}
|
||||
|
||||
return (
|
||||
<Combobox items={items} selectedValue={nfa} onChange={handleNfaChange} />
|
||||
);
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Button, Card, Flex, NoResults } from '@/components';
|
||||
import { lastMintsPaginatedDocument, totalTokensDocument } from '@/graphclient';
|
||||
import { lastNFAsPaginatedDocument, totalTokensDocument } from '@/graphclient';
|
||||
import { FleekERC721 } from '@/integrations/ethereum/contracts';
|
||||
|
||||
const pageSize = 10; //Set this size to test pagination
|
||||
|
|
@ -23,7 +23,7 @@ export const NFAList = () => {
|
|||
data: dataMintedTokens,
|
||||
loading: loadingMintedTokens,
|
||||
error: errorMintedTokens,
|
||||
} = useQuery(lastMintsPaginatedDocument, {
|
||||
} = useQuery(lastNFAsPaginatedDocument, {
|
||||
variables: {
|
||||
//first page is 0
|
||||
pageSize,
|
||||
|
|
@ -68,8 +68,8 @@ export const NFAList = () => {
|
|||
</Button>
|
||||
</Flex>
|
||||
<div>
|
||||
{dataMintedTokens && dataMintedTokens.newMints.length > 0 ? (
|
||||
dataMintedTokens.newMints.map((mint) => (
|
||||
{dataMintedTokens && dataMintedTokens.tokens.length > 0 ? (
|
||||
dataMintedTokens.tokens.map((mint) => (
|
||||
<Card.Container
|
||||
key={mint.tokenId}
|
||||
css={{ display: 'inline-block', m: '$2' }}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Form, Stepper } from '@/components';
|
||||
import { Form, Stepper, Step } from '@/components';
|
||||
import { MintPreview } from './preview-step/mint-preview';
|
||||
import { GithubStep } from './github-step';
|
||||
import { MintStep } from './mint-step';
|
||||
import { WalletStep } from './wallet-step';
|
||||
import { NFAStep } from './nfa-step';
|
||||
import { Mint } from './mint.context';
|
||||
|
|
@ -24,27 +23,27 @@ export const MintStepper = () => {
|
|||
<Form.Root onValidationChange={setIsValid}>
|
||||
<Stepper.Container>
|
||||
<Stepper.Step>
|
||||
<MintStep header="Connect your Ethereum Wallet to mint an NFA">
|
||||
<Step header="Connect your Ethereum Wallet to mint an NFA">
|
||||
<WalletStep />
|
||||
</MintStep>
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
|
||||
<Stepper.Step>
|
||||
<MintStep header="Connect GitHub and select repository">
|
||||
<Step header="Connect GitHub and select repository">
|
||||
<GithubStep />
|
||||
</MintStep>
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
|
||||
<Stepper.Step>
|
||||
<MintStep header="Finalize a few key things for your NFA">
|
||||
<Step header="Finalize a few key things for your NFA">
|
||||
<NFAStep />
|
||||
</MintStep>
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
|
||||
<Stepper.Step>
|
||||
<MintStep header="Review your NFA and mint it on Polygon">
|
||||
<Step header="Review your NFA and mint it on Polygon">
|
||||
<MintPreview />
|
||||
</MintStep>
|
||||
</Step>
|
||||
</Stepper.Step>
|
||||
</Stepper.Container>
|
||||
</Form.Root>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Icon, IconButton, Stepper } from '@/components';
|
||||
import { useTransactionCost } from '@/hooks';
|
||||
import { FleekERC721 } from '@/integrations';
|
||||
import { AppLog } from '@/utils';
|
||||
import { Mint } from '@/views/mint/mint.context';
|
||||
import { ethers } from 'ethers';
|
||||
import { useMemo } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { NftCard } from '../nft-card';
|
||||
|
||||
export const MintPreview = () => {
|
||||
|
|
@ -49,6 +50,20 @@ export const MintPreview = () => {
|
|||
[prepareStatus, writeStatus, transactionStatus]
|
||||
);
|
||||
|
||||
const error = useMemo(
|
||||
() =>
|
||||
[prepareStatus, writeStatus, transactionStatus].some(
|
||||
(status) => status === 'error'
|
||||
),
|
||||
[prepareStatus, writeStatus, transactionStatus]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
AppLog.errorToast('An error occurred while minting the NFA');
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<NftCard
|
||||
title="Mint NFA"
|
||||
|
|
|
|||
Loading…
Reference in New Issue