hooks#useAccount TypeScript Examples
The following examples show how to use
hooks#useAccount.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Accounts.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
function Accounts({ list, onChange }: Props) {
const { switchAccount } = useAccount();
const isAnyAccount = list.length > 0;
const handleAccountButtonClick = (account: InjectedAccountWithMeta) => {
switchAccount(account);
// TODO: 'account' to consts
localStorage.setItem('account', account.address);
onChange();
};
const getAccounts = () =>
list.map((account) => (
<li key={account.address}>
<AccountButton
address={account.address}
name={account.meta.name}
isActive={isLoggedIn(account)}
onClick={() => handleAccountButtonClick(account)}
block
/>
</li>
));
return isAnyAccount ? (
<ul className={styles.list}>{getAccounts()}</ul>
) : (
<p>
No accounts found. Please open Polkadot extension, create a new account or import existing one and reload the
page.
</p>
);
}
Example #2
Source File: Message.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
Message = ({ message }: Props) => {
const { id } = message;
const { api } = useApi();
const { account } = useAccount();
const alert = useAlert();
const showErrorAlert = (error: string) => {
alert.error(error);
};
const showSuccessAlert = (data: ISubmittableResult) => {
if (!data.status.isBroadcast) {
alert.success(`Status: ${data.status}`);
}
};
const handleClaimButtonClick = () => {
if (account) {
const { address, meta } = account;
api.claimValueFromMailbox.submit(id);
web3FromSource(meta.source)
.then(({ signer }) => api.claimValueFromMailbox.signAndSend(address, { signer }, showSuccessAlert))
.catch((error: Error) => showErrorAlert(error.message));
}
};
return (
<div className={styles.message}>
<pre className={styles.pre}>{getPreformattedText(message)}</pre>
<div>
<ReplyLink to={id} />
<Button text="Claim value" icon={claimIcon} color="secondary" size="small" onClick={handleClaimButtonClick} />
</div>
</div>
);
}
Example #3
Source File: Mailbox.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
Mailbox = () => {
const { api } = useApi();
const { account } = useAccount();
const [mailbox, setMailbox] = useState<MailboxType>([]);
const isAnyMessage = mailbox.length > 0;
useEffect(() => {
if (account) {
api.mailbox.read(account.address).then(setMailbox);
} else {
setMailbox([]);
}
}, [account, api.mailbox]);
const getMessages = () => mailbox.map(([, message], index) => <Message key={index} message={message} />);
return (
<div className="wrapper">
<Box className={styles.box}>
<h2 className={styles.heading}>Mailbox:</h2>
<div className={styles.messages}>{isAnyMessage ? getMessages() : <p>No messages</p>}</div>
</Box>
</div>
);
}
Example #4
Source File: Account.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
function Account() {
const { accounts, account } = useAccount();
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
return (
<>
{account ? (
<Wallet balance={account.balance} address={account.address} name={account.meta.name} onClick={openModal} />
) : (
<Button icon={userSVG} text="Sign in" onClick={openModal} />
)}
{isModalOpen && <AccountsModal accounts={accounts} close={closeModal} />}
</>
);
}
Example #5
Source File: Accounts.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
function Accounts({ list, onChange }: Props) {
const { switchAccount } = useAccount();
const isAnyAccount = list.length > 0;
const handleAccountButtonClick = (account: InjectedAccountWithMeta) => {
switchAccount(account);
// TODO: 'account' to consts
localStorage.setItem('account', account.address);
onChange();
};
const getAccounts = () =>
list.map((account) => (
<li key={account.address}>
<AccountButton
address={account.address}
name={account.meta.name}
isActive={isLoggedIn(account)}
onClick={() => handleAccountButtonClick(account)}
block
/>
</li>
));
return isAnyAccount ? (
<ul className={styles.list}>{getAccounts()}</ul>
) : (
<p>
No accounts found. Please open Polkadot extension, create a new account or import existing one and reload the
page.
</p>
);
}
Example #6
Source File: Account.tsx From gear-js with GNU General Public License v3.0 | 6 votes |
function Account() {
const { account } = useAccount();
const accounts = useAccounts();
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
return (
<>
{account ? (
<Wallet balance={account.balance} address={account.address} name={account.meta.name} onClick={openModal} />
) : (
<Button icon={userSVG} text="Sign in" onClick={openModal} />
)}
{isModalOpen && <AccountsModal accounts={accounts} close={closeModal} />}
</>
);
}
Example #7
Source File: hooks.ts From gear-js with GNU General Public License v3.0 | 5 votes |
function useListing() {
const { id } = useParams() as Params;
const { account } = useAccount();
const nft = useNft(id);
const { name, description, ownerId, media, reference } = nft || {};
const [details, setDetails] = useState<NFTDetails>();
const { royalty, rarity, attributes } = details || {};
const marketNft = useMarketNft(id);
const { price, auction, offers } = marketNft || {};
const { currentPrice, bids } = auction || {};
const isSale = !!price;
const isAuction = !!auction;
const isListed = isSale || isAuction;
const isOwner = account ? GearKeyring.decodeAddress(account.address) === ownerId : false;
useEffect(() => {
if (reference) {
fetch(reference)
.then((response) => response.json())
.then(setDetails);
}
}, [reference]);
const heading = `${name} #${id}`;
return {
heading,
description,
ownerId,
media,
reference,
royalty,
rarity,
attributes,
price,
offers,
currentPrice,
bids,
isSale,
isAuction,
isListed,
isOwner,
};
}
Example #8
Source File: Listing.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
function Listing() {
const { id } = useParams() as Params;
const { account } = useAccount();
const nft = useNft(id);
const [details, setDetails] = useState<NFTDetails>();
const { royalty, rarity, attributes } = details || {};
const marketNft = useMarketNft(id);
const { price, auction, offers } = marketNft || {};
const { startedAt, endedAt, currentPrice, bids } = auction || {};
const isSale = !!price;
const isAuction = !!auction;
const isOwner = account?.decodedAddress === nft?.ownerId;
useEffect(() => {
const { reference } = nft || {};
if (reference) {
const path = `${IPFS_GATEWAY_ADDRESS}/${reference}`;
fetch(path)
.then((response) => response.json())
.then(setDetails);
}
}, [nft]);
// eslint-disable-next-line no-nested-ternary
return nft ? (
// eslint-disable-next-line no-nested-ternary
isSale ? (
<SaleListing
id={id}
isOwner={isOwner}
heading={`${nft.name} #${id}`}
description={nft.description}
image={nft.media}
owner={nft.ownerId}
price={price}
offers={offers || []}
rarity={rarity}
royalty={royalty}
attrs={attributes}
/>
) : isAuction ? (
<AuctionListing
id={id}
isOwner={isOwner}
heading={`${nft.name} #${id}`}
description={nft.description}
image={nft.media}
owner={nft.ownerId}
price={currentPrice}
offers={bids || []}
rarity={rarity}
royalty={royalty}
attrs={attributes}
startedAt={startedAt || ''}
endedAt={endedAt || ''}
/>
) : (
<OwnerListing
id={id}
isOwner={isOwner}
heading={`${nft.name} #${id}`}
description={nft.description}
image={nft.media}
owner={nft.ownerId}
offers={offers || []}
rarity={rarity}
royalty={royalty}
attrs={attributes}
/>
)
) : null;
}
Example #9
Source File: useMessage.ts From gear-js with GNU General Public License v3.0 | 5 votes |
function useMessage(destination: Hex, metadata: Metadata | undefined) {
const alert = useAlert();
const { api } = useApi();
const { account } = useAccount();
const { enableLoading, disableLoading } = useLoading();
const handleEventsStatus = (events: EventRecord[]) => {
events.forEach(({ event: { method } }) => {
if (method === 'DispatchMessageEnqueued') {
alert.success('Send message: Finalized');
// onSucessCallback();
} else if (method === 'ExtrinsicFailed') {
alert.error('Extrinsic failed');
}
});
};
const handleStatus = (result: ISubmittableResult) => {
const { status, events } = result;
const { isInBlock, isInvalid, isFinalized } = status;
if (isInvalid) {
alert.error('Transaction error. Status: isInvalid');
disableLoading();
} else if (isInBlock) {
alert.success('Send message: In block');
} else if (isFinalized) {
handleEventsStatus(events);
disableLoading();
}
};
// TODO: eslint
// eslint-disable-next-line consistent-return
const sendMessage = async (payload: AnyJson, value: string | number = 0) => {
if (account && metadata) {
enableLoading();
const { address, decodedAddress, meta } = account;
const gasLimit = await api.program.gasSpent.handle(decodedAddress, destination, payload, value, metadata);
const message = { destination, payload, gasLimit, value };
api.message.submit(message, metadata);
const { source } = meta;
const { signer } = await web3FromSource(source);
return api.message.signAndSend(address, { signer }, handleStatus);
}
};
return sendMessage;
}
Example #10
Source File: OnLogin.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
function OnLogin({ children, fallback }: Props) {
const { account } = useAccount();
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{account ? children : fallback}</>;
}
Example #11
Source File: SelectAccountModal.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
SelectAccountModal = (props: Props) => {
const alert = useAlert();
const { logout, switchAccount } = useAccount();
const { isOpen, accounts, onClose } = props;
const selectAccount = (account: InjectedAccountWithMeta) => {
switchAccount(account);
localStorage.setItem(LOCAL_STORAGE.ACCOUNT, account.address);
localStorage.setItem(LOCAL_STORAGE.PUBLIC_KEY_RAW, GearKeyring.decodeAddress(account.address));
onClose();
alert.success('Account successfully changed');
};
const handleLogout = () => {
logout()
localStorage.removeItem(LOCAL_STORAGE.ACCOUNT);
localStorage.removeItem(LOCAL_STORAGE.PUBLIC_KEY_RAW);
onClose();
};
return (
<Modal
open={isOpen}
title="Connect"
content={
accounts ? (
<>
<AccountList list={accounts} toggleAccount={selectAccount} />
<Button
aria-label="Logout"
icon={logoutSVG}
color="transparent"
className={styles.logoutButton}
onClick={handleLogout}
/>
</>
) : (
<p className={styles.message}>
Polkadot extension was not found or disabled. Please{' '}
<a href="https://polkadot.js.org/extension/" target="_blank" rel="noreferrer">
install it
</a>
</p>
)
}
handleClose={onClose}
/>
);
}
Example #12
Source File: Wallet.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
Wallet = () => {
const { api } = useApi();
const accounts = useAccounts();
const { account } = useAccount();
const [isModalOpen, setIsModalOpen] = useState(false);
const [accountBalance, setAccountBalance] = useState('');
useEffect(() => {
if (account && api) {
api.balance.findOut(account.address).then((result) => setAccountBalance(result.toHuman()));
}
}, [account, api]);
useEffect(() => {
// TODO: think how to wrap it hook
let unsub: UnsubscribePromise | undefined;
if (account && api) {
unsub = api.gearEvents.subscribeToBalanceChange(account.address, (balance) => {
setAccountBalance(balance.toHuman());
});
}
return () => {
if (unsub) {
unsub.then((callback) => callback());
}
};
}, [api, account]);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
const balanceSectionClassName = clsx(styles.section, styles.balance);
const accButtonClassName = clsx(
buttonStyles.button,
buttonStyles.normal,
buttonStyles.secondary,
styles.accountButton
);
return (
<>
<div className={styles.wallet}>
{account ? (
<>
<div className={balanceSectionClassName}>
<p>
Balance: <span className={styles.balanceAmount}>{accountBalance}</span>
</p>
</div>
<div className={styles.section}>
<button type="button" className={accButtonClassName} onClick={openModal}>
<Identicon value={account.address} size={28} theme="polkadot" className={styles.avatar} />
{account.meta.name}
</button>
</div>
</>
) : (
<div>
<Button text="Connect" color="secondary" className={styles.accountButton} onClick={openModal} />
</div>
)}
</div>
<SelectAccountModal isOpen={isModalOpen} accounts={accounts} onClose={closeModal} />
</>
);
}
Example #13
Source File: Offer.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
function Offer({ bid, bidder, listingOwner, hash }: Props) {
const { id } = useParams() as Params;
const sendMessage = useMarketplaceMessage();
const { account } = useAccount();
const [isModalOpen, setIsModalOpen] = useState(false);
const isOwner = account?.decodedAddress === listingOwner;
const isSale = !!hash;
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
const accept = () => {
const payload = {
AcceptOffer: { nftContractId: NFT_CONTRACT_ADDRESS, tokenId: id, offerHash: hash },
};
sendMessage(payload).then(closeModal);
};
return (
<>
<div className={styles.offer}>
<div className={styles.info}>
<p className={styles.bid}>{bid}</p>
<p className={styles.bidder}>{bidder}</p>
</div>
{isOwner && isSale && <Button text="Accept" size="small" onClick={openModal} />}
</div>
{isModalOpen && (
<ConfirmationModal heading={`Do you agree to sell the item for ${bid}?`} close={closeModal} onSubmit={accept} />
)}
</>
);
}
Example #14
Source File: Messages.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
Messages = () => {
const [searchParams, setSearchParams] = useSearchParams();
const { account } = useAccount();
const page = searchParams.has(URL_PARAMS.PAGE) ? Number(searchParams.get(URL_PARAMS.PAGE)) : 1;
const query = searchParams.has(URL_PARAMS.QUERY) ? String(searchParams.get(URL_PARAMS.QUERY)) : '';
const [messages, setMessages] = useState<MessageModel[]>([]);
const [messagesCount, setMessagesCount] = useState(0);
useChangeEffect(() => {
searchParams.set(URL_PARAMS.PAGE, String(1));
searchParams.set(URL_PARAMS.QUERY, '');
setSearchParams(searchParams);
}, [account]);
useEffect(() => {
if (account) {
const messageParams = {
destination: GearKeyring.decodeAddress(account.address),
limit: INITIAL_LIMIT_BY_PAGE,
offset: (page - 1) * INITIAL_LIMIT_BY_PAGE,
query,
};
getMessages(messageParams).then(({ result }) => {
setMessages(result.messages);
setMessagesCount(result.count);
});
}
}, [page, query, account]);
return (
<div className="messages">
<div className="pagination__wrapper">
<span className="pagination__wrapper-caption">Total results: {messagesCount || 0}</span>
<Pagination page={page} pagesAmount={messagesCount || 1} />
</div>
<SearchForm placeholder="Find message by ID" />
<MessagesList messages={messages} />
{messagesCount > 0 && (
<div className="pagination_bottom">
<Pagination page={page} pagesAmount={messagesCount || 1} />
</div>
)}
</div>
);
}
Example #15
Source File: All.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
All = () => {
const [searchParams] = useSearchParams();
const { account } = useAccount();
const accountDecodedAddress = GearKeyring.decodeAddress(account?.address || '0x00');
const page = searchParams.has(URL_PARAMS.PAGE) ? Number(searchParams.get(URL_PARAMS.PAGE)) : 1;
const query = searchParams.has(URL_PARAMS.QUERY) ? String(searchParams.get(URL_PARAMS.QUERY)) : '';
const [programs, setPrograms] = useState<ProgramModel[]>([]);
const [programsCount, setProgramsCount] = useState(0);
useEffect(() => {
const programParams = { limit: INITIAL_LIMIT_BY_PAGE, offset: (page - 1) * INITIAL_LIMIT_BY_PAGE, query };
getPrograms(programParams).then(({ result }) => {
setPrograms(result.programs);
setProgramsCount(result.count);
});
}, [page, query]);
return (
<div className="all-programs">
<div className={styles.paginationWrapper}>
<span>Total results: {programsCount || 0}</span>
<Pagination page={page} pagesAmount={programsCount || 1} />
</div>
<SearchForm placeholder="Find program" />
<ProgramsLegend />
<div className={styles.allProgramsList}>
{programs.map((program: ProgramModel) => (
<UserProgram key={program.id} program={program} isMetaLinkActive={accountDecodedAddress === program.owner} />
))}
</div>
{programsCount > 0 && (
<div className={styles.paginationBottom}>
<Pagination page={page} pagesAmount={programsCount || 1} />
</div>
)}
</div>
);
}
Example #16
Source File: Recent.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
Recent = () => {
const [searchParams, setSearchParams] = useSearchParams();
const { account } = useAccount();
const page = searchParams.has(URL_PARAMS.PAGE) ? Number(searchParams.get(URL_PARAMS.PAGE)) : 1;
const query = searchParams.has(URL_PARAMS.QUERY) ? String(searchParams.get(URL_PARAMS.QUERY)) : '';
const [programs, setPrograms] = useState<ProgramModel[]>([]);
const [programsCount, setProgramsCount] = useState(0);
useChangeEffect(() => {
searchParams.set(URL_PARAMS.PAGE, String(1));
searchParams.set(URL_PARAMS.QUERY, '');
setSearchParams(searchParams);
}, [account]);
useEffect(() => {
if (account) {
const params = {
query,
owner: GearKeyring.decodeAddress(account.address),
limit: INITIAL_LIMIT_BY_PAGE,
offset: (page - 1) * INITIAL_LIMIT_BY_PAGE,
};
getUserPrograms(params).then(({ result }) => {
setPrograms(result.programs);
setProgramsCount(result.count);
});
}
}, [page, query, account]);
return (
<div className={styles.blockList}>
<div className={styles.paginationWrapper}>
<span>Total results: {programsCount || 0}</span>
<Pagination page={page} pagesAmount={programsCount || 1} />
</div>
<SearchForm placeholder="Find program" />
<ProgramsLegend />
<div>
{programs.map((program: ProgramModel) => (
<UserProgram key={program.id} program={program} />
))}
</div>
{programsCount > 0 && (
<div className={styles.paginationBottom}>
<Pagination page={page} pagesAmount={programsCount || 1} />
</div>
)}
</div>
);
}
Example #17
Source File: MessageForm.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
MessageForm: VFC<Props> = ({ id, metadata, replyErrorCode }) => {
const { api } = useApi();
const alert = useAlert();
const { account: currentAccount } = useAccount();
const initialValues = useRef<FormValues>({
value: 0,
payload: '',
gasLimit: 20000000,
payloadType: 'Bytes',
destination: id,
});
const isReply = !!replyErrorCode;
const isMeta = useMemo(() => metadata && Object.keys(metadata).length > 0, [metadata]);
const handleSubmit = (values: FormValues, { resetForm }: FormikHelpers<FormValues>) => {
if (!currentAccount) {
alert.error(`WALLET NOT CONNECTED`);
return;
}
const payload = getSubmitPayload(values.payload);
const apiMethod = isReply ? api.reply : api.message;
const payloadType = isMeta ? void 0 : values.payloadType;
const message = {
value: values.value.toString(),
payload,
gasLimit: values.gasLimit.toString(),
replyToId: values.destination,
destination: values.destination,
};
sendMessage(apiMethod, currentAccount, message, alert, resetForm, metadata, payloadType);
};
const handleCalculateGas = (values: FormValues, setFieldValue: SetFieldValue) => () => {
const method = isReply ? 'reply' : 'handle';
calculateGas(method, api, values, alert, metadata, null, id, replyErrorCode).then((gasLimit) =>
setFieldValue('gasLimit', gasLimit)
);
};
const payloadFormValues = useMemo(() => getPayloadFormValues(metadata?.types, metadata?.handle_input), [metadata]);
return (
<Formik initialValues={initialValues.current} validateOnBlur validationSchema={Schema} onSubmit={handleSubmit}>
{({ errors, touched, values, setFieldValue }) => (
<Form id="message-form">
<div className="message-form--wrapper">
<div className="message-form--col">
<div className="message-form--info">
<label htmlFor="destination" className="message-form__field">
{isReply ? 'Message Id:' : 'Destination:'}
</label>
<div className="message-form__field-wrapper">
<Field
id="destination"
name="destination"
type="text"
className={clsx(
'inputField',
errors.destination && touched.destination && 'message-form__input-error'
)}
/>
{errors.destination && touched.destination && (
<div className="message-form__error">{errors.destination}</div>
)}
</div>
</div>
<div className="message-form--info">
<label htmlFor="payload" className="message-form__field">
Payload:
</label>
<FormPayload name="payload" values={payloadFormValues} />
</div>
{!isMeta && (
<div className="message-form--info">
<label htmlFor="payloadType" className="message-form__field">
Payload type:
</label>
<PayloadType />
</div>
)}
<div className="message-form--info">
<label htmlFor="gasLimit" className="message-form__field">
Gas limit:
</label>
<div className="message-form__field-wrapper">
<NumberFormat
name="gasLimit"
placeholder="20,000,000"
value={values.gasLimit}
thousandSeparator
allowNegative={false}
className={clsx('inputField', errors.gasLimit && touched.gasLimit && 'message-form__input-error')}
onValueChange={(val) => {
const { floatValue } = val;
setFieldValue('gasLimit', floatValue);
}}
/>
{errors.gasLimit && touched.gasLimit ? (
<div className="message-form__error">{errors.gasLimit}</div>
) : null}
</div>
</div>
<div className="message-form--info">
<label htmlFor="value" className="message-form__field">
Value:
</label>
<div className="message-form__field-wrapper">
<Field
id="value"
name="value"
placeholder="20000"
type="number"
className={clsx('inputField', errors.value && touched.value && 'message-form__input-error')}
/>
{errors.value && touched.value ? <div className="message-form__error">{errors.value}</div> : null}
</div>
</div>
<div className="message-form--btns">
<button
className="message-form__button"
type="button"
onClick={handleCalculateGas(values, setFieldValue)}
>
Calculate Gas
</button>
<button className="message-form__button" type="submit">
<img src={MessageIllustration} alt="message" />
{isReply ? 'Send reply' : 'Send message'}
</button>
</div>
</div>
</div>
</Form>
)}
</Formik>
);
}
Example #18
Source File: useCodeUpload.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
useCodeUpload = () => {
const { api } = useApi();
const alert = useAlert();
const { account } = useAccount();
const submit = async (file: File) => {
const arrayBuffer = (await readFileAsync(file)) as ArrayBuffer;
const buffer = Buffer.from(arrayBuffer);
return api.code.submit(buffer);
};
const getErrorMessage = (event: Event) => {
const { docs, method: errorMethod } = api.getExtrinsicFailedError(event);
const formattedDocs = docs.filter(Boolean).join('. ');
return `${errorMethod}: ${formattedDocs}`;
};
const uploadCode = async (file: File) => {
if (!account) {
alert.error('Wallet not connected');
return;
}
const { address, meta } = account;
const alertTitle = 'gear.submitCode';
const alertId = alert.loading('SignIn', { title: alertTitle });
try {
const { signer } = await web3FromSource(meta.source);
const { codeHash } = await submit(file);
await api.code.signAndSend(address, { signer }, ({ events, status }) => {
if (status.isReady) {
alert.update(alertId, 'Ready');
return;
}
if (status.isInBlock) {
alert.update(alertId, 'InBlock');
events.forEach(({ event }) => {
const { method, section } = event;
if (method === 'CodeSaved') {
alert.success(<CopiedInfo title="Code hash" info={codeHash} />, {
title: `${section}.CodeSaved`,
timeout: 0,
});
return;
}
if (method === 'ExtrinsicFailed') {
alert.error(getErrorMessage(event), { title: `${section}.ExtrinsicFailed` });
return;
}
});
return;
}
if (status.isFinalized) {
alert.update(alertId, 'Finalized', DEFAULT_SUCCESS_OPTIONS);
return;
}
if (status.isInvalid) {
alert.update(alertId, PROGRAM_ERRORS.INVALID_TRANSACTION, DEFAULT_ERROR_OPTIONS);
}
});
} catch (error) {
alert.update(alertId, `${error}`, DEFAULT_ERROR_OPTIONS);
console.error(error);
}
};
return uploadCode;
}
Example #19
Source File: UploadForm.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
UploadForm: VFC<Props> = ({ setDroppedFile, droppedFile }) => {
const { api } = useApi();
const alert = useAlert();
const { account } = useAccount();
const [fieldFromFile, setFieldFromFile] = useState<string[] | null>(null);
const [meta, setMeta] = useState<Metadata | null>(null);
const [metaFile, setMetaFile] = useState<string | null>(null);
const [droppedMetaFile, setDroppedMetaFile] = useState<File>();
const [isMetaFromFile, setIsMetaFromFile] = useState<boolean>(true);
const handleResetForm = () => {
setDroppedFile(null);
};
const handleResetMetaForm = (setValues: SetValues) => {
setMeta(null);
setMetaFile(null);
setDroppedMetaFile(void 0);
setFieldFromFile(null);
setValues(INITIAL_VALUES, false);
};
const handleUploadMetaFile = (setValues: SetValues) => async (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) {
return handleResetMetaForm(setValues);
}
try {
if (!checkFileFormat(file)) {
throw new Error('Wrong file format');
}
setDroppedMetaFile(file);
const readedFile = (await readFileAsync(file)) as Buffer;
const metadata: Metadata = await getWasmMetadata(readedFile);
if (!metadata) {
throw new Error('Failed to load metadata');
}
const metaBufferString = Buffer.from(new Uint8Array(readedFile)).toString('base64');
const valuesFromFile = getMetaValues(metadata);
setMeta(metadata);
setMetaFile(metaBufferString);
setFieldFromFile(Object.keys(valuesFromFile));
setValues(
({ programValues }) => ({
metaValues: valuesFromFile,
programValues: {
...programValues,
programName: metadata?.title || '',
},
}),
false
);
} catch (error) {
alert.error(`${error}`);
}
};
const handleSubmitForm = (values: FormValues) => {
if (!account) {
alert.error(`Wallet not connected`);
return;
}
const { value, payload, gasLimit, programName } = values.programValues;
const programOptions: UploadProgramModel = {
meta: void 0,
value,
title: '',
gasLimit,
programName,
initPayload: meta ? getSubmitPayload(payload) : payload,
};
if (meta) {
programOptions.meta = isMetaFromFile ? meta : values.metaValues;
}
UploadProgram(api, account, droppedFile, programOptions, metaFile, alert, handleResetForm).catch(() => {
alert.error(`Invalid JSON format`);
});
};
const handleCalculateGas = async (values: ProgramValues, setFieldValue: SetFieldValue) => {
const fileBuffer = (await readFileAsync(droppedFile)) as ArrayBuffer;
const code = Buffer.from(new Uint8Array(fileBuffer));
calculateGas('init', api, values, alert, meta, code).then((gasLimit) =>
setFieldValue('programValues.gasLimit', gasLimit)
);
};
const payloadFormValues = useMemo(() => getPayloadFormValues(meta?.types, meta?.init_input), [meta]);
const metaFields = isMetaFromFile ? fieldFromFile : META_FIELDS;
const isUploadAvailable = !(account && parseInt(account.balance.value, 10) > 0);
return (
<Box className={styles.uploadFormWrapper}>
<h3 className={styles.heading}>UPLOAD NEW PROGRAM</h3>
<Formik initialValues={INITIAL_VALUES} validateOnBlur validationSchema={Schema} onSubmit={handleSubmitForm}>
{({ values, setFieldValue, setValues }) => (
<Form className={styles.uploadForm}>
<div className={styles.formContent}>
<div className={styles.program}>
<div className={styles.fieldWrapper}>
<span className={styles.caption}>File:</span>
<span className={styles.fileName}>{droppedFile.name}</span>
</div>
<FormInput
name="programValues.programName"
label="Name:"
placeholder="Name"
className={styles.formField}
/>
<FormNumberFormat
name="programValues.gasLimit"
label="Gas limit:"
placeholder="20,000,000"
thousandSeparator
allowNegative={false}
className={styles.formField}
/>
<FormInput
type="number"
name="programValues.value"
label="Initial value:"
placeholder="0"
className={styles.formField}
/>
<div className={styles.fieldWrapper}>
<label htmlFor="programValues.payload" className={clsx(styles.caption, styles.top)}>
Initial payload:
</label>
<FormPayload name="programValues.payload" values={payloadFormValues} />
</div>
</div>
<fieldset className={styles.meta}>
<legend className={styles.metaLegend}>Metadata:</legend>
<MetaSwitch isMetaFromFile={isMetaFromFile} onChange={setIsMetaFromFile} className={styles.formField} />
{isMetaFromFile && (
<div className={styles.fieldWrapper}>
<FileInput
label="Metadata file:"
value={droppedMetaFile}
className={clsx(styles.formField, styles.fileInput)}
onChange={handleUploadMetaFile(setValues)}
/>
</div>
)}
{metaFields?.map((field) => {
const FormField = field === 'types' ? FormTextarea : FormInput;
return (
<FormField
key={field}
name={`metaValues.${field}`}
label={`${field}:`}
disabled={isMetaFromFile}
className={styles.formField}
/>
);
})}
</fieldset>
</div>
<div className={styles.buttons}>
<Button type="submit" text="Upload program" disabled={isUploadAvailable} />
<Button
text="Calculate Gas"
onClick={() => {
handleCalculateGas(values.programValues, setFieldValue);
}}
/>
<Button
type="submit"
text="Cancel upload"
color="transparent"
aria-label="closeUploadForm"
onClick={handleResetForm}
/>
</div>
</Form>
)}
</Formik>
</Box>
);
}
Example #20
Source File: UploadMetaForm.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
UploadMetaForm = ({ programId, programName }: Props) => {
const alert = useAlert();
const { account } = useAccount();
const [isFileUpload, setFileUpload] = useState(true);
const [meta, setMeta] = useState<Metadata | null>(null);
const [metaFile, setMetaFile] = useState<File | null>(null);
const [metaBuffer, setMetaBuffer] = useState<string | null>(null);
const [fieldsFromFile, setFieldFromFile] = useState<string[] | null>(null);
const [initialValues, setInitialValues] = useState<FormValues>({
name: programName,
...INITIAL_VALUES,
});
const handleUploadMetaFile = async (file: File) => {
try {
const fileBuffer = (await readFileAsync(file)) as Buffer;
const currentMetaWasm = await getWasmMetadata(fileBuffer);
if (!currentMetaWasm) {
return;
}
const valuesFromFile = getMetaValues(currentMetaWasm);
const currentMetaBuffer = Buffer.from(new Uint8Array(fileBuffer)).toString('base64');
setMeta(currentMetaWasm);
setMetaBuffer(currentMetaBuffer);
setFieldFromFile(Object.keys(valuesFromFile));
setInitialValues({
...INITIAL_VALUES,
...valuesFromFile,
name: currentMetaWasm.title ?? programName,
});
} catch (error) {
alert.error(`${error}`);
} finally {
setMetaFile(file);
}
};
const resetForm = () => {
setMetaFile(null);
setMeta(null);
setMetaBuffer(null);
setFieldFromFile(null);
setInitialValues({
name: programName,
...INITIAL_VALUES,
});
};
const handleSubmit = (values: FormValues, actions: FormikHelpers<FormValues>) => {
if (!account) {
alert.error(`WALLET NOT CONNECTED`);
return;
}
const { name, ...formMeta } = values;
if (isFileUpload) {
if (meta) {
addMetadata(meta, metaBuffer, account, programId, name, alert);
} else {
alert.error(`ERROR: metadata not loaded`);
}
} else {
addMetadata(formMeta, null, account, programId, name, alert);
}
actions.setSubmitting(false);
resetForm();
};
const fields = isFileUpload ? fieldsFromFile : META_FIELDS;
return (
<Formik
initialValues={initialValues}
validateOnBlur
validationSchema={Schema}
enableReinitialize
onSubmit={handleSubmit}
>
{({ isValid, isSubmitting }: FormikProps<FormValues>) => {
const emptyFile = isFileUpload && !meta;
const disabledBtn = emptyFile || !isValid || isSubmitting;
return (
<Form className={styles.uploadMetaForm}>
<MetaSwitch isMetaFromFile={isFileUpload} onChange={setFileUpload} className={styles.formField} />
<FormInput name="name" label="Program name:" className={styles.formField} />
{fields?.map((field) => {
const MetaField = field === 'types' ? FormTextarea : FormInput;
return (
<MetaField
key={field}
name={field}
label={`${field}:`}
disabled={isFileUpload}
className={styles.formField}
/>
);
})}
{isFileUpload && (
<MetaFile
file={metaFile}
className={styles.formField}
onUpload={handleUploadMetaFile}
onDelete={resetForm}
/>
)}
<div className={styles.formBtnWrapper}>
<Button type="submit" text="Upload metadata" className={styles.formSubmitBtn} disabled={disabledBtn} />
</div>
</Form>
);
}}
</Formik>
);
}
Example #21
Source File: ProgramSwitch.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
ProgramSwitch: VFC<Props> = ({ pageType }) => {
const { api } = useApi();
const alert = useAlert();
const { account: currentAccount } = useAccount();
const [captchaToken, setCaptchaToken] = useState('');
const captchaRef = useRef<HCaptcha>(null);
const handleTransferBalance = async () => {
try {
if (!currentAccount) {
throw new Error(`WALLET NOT CONNECTED`);
}
const apiRequest = new ServerRPCRequestService();
const response = await apiRequest.callRPC(RPC_METHODS.GET_TEST_BALANCE, {
address: `${currentAccount.address}`,
token: captchaToken,
});
if (response.error) {
alert.error(`${response.error.message}`);
}
} catch (error) {
alert.error(`${error}`);
}
};
useEffect(() => {
if (captchaToken) {
handleTransferBalance();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [captchaToken]);
const handleTestBalanceClick = () => {
if (captchaToken) {
handleTransferBalance();
} else {
captchaRef.current?.execute();
}
};
const handleTransferBalanceFromAlice = () => {
try {
if (!currentAccount) {
throw new Error(`WALLET NOT CONNECTED`);
}
if (api) {
api.balance.transferFromAlice(currentAccount.address, GEAR_BALANCE_TRANSFER_VALUE);
}
} catch (error) {
alert.error(`${error}`);
}
};
return (
<div className="switch-block">
<div className="switch-block--wrapper">
<div className="switch-buttons">
<Link
to={routes.main}
className={clsx(
'switch-buttons__item',
pageType === SWITCH_PAGE_TYPES.UPLOAD_PROGRAM && 'switch-buttons__item--active'
)}
>
Upload program
</Link>
<Link
to={routes.uploadedPrograms}
className={clsx(
'switch-buttons__item',
pageType === SWITCH_PAGE_TYPES.UPLOADED_PROGRAMS && 'switch-buttons__item--active'
)}
>
My programs
</Link>
<Link
to={routes.allPrograms}
className={clsx(
'switch-buttons__item',
pageType === SWITCH_PAGE_TYPES.ALL_PROGRAMS && 'switch-buttons__item--active'
)}
>
All programs
</Link>
<Link
to={routes.messages}
className={clsx(
'switch-buttons__item',
pageType === SWITCH_PAGE_TYPES.ALL_MESSAGES && 'switch-buttons__item--active'
)}
>
Messages
</Link>
</div>
{currentAccount && (
<>
<Button
className="test-balance-button"
text="Get test balance"
onClick={isDevChain() ? handleTransferBalanceFromAlice : handleTestBalanceClick}
/>
<HCaptcha
sitekey={HCAPTCHA_SITE_KEY}
onVerify={setCaptchaToken}
onExpire={() => setCaptchaToken('')}
ref={captchaRef}
theme="dark"
size="invisible"
/>
</>
)}
</div>
<BlocksSummary />
</div>
);
}