Skip to content

Commit

Permalink
feat(wallet-dashboard): style send entry screen WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cpl121 committed Oct 30, 2024
1 parent 1a4f3f8 commit 7bd6cbf
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 33 deletions.
30 changes: 15 additions & 15 deletions apps/wallet-dashboard/components/Coins/MyCoins.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import React, { useState } from 'react';
import { useCurrentAccount, useIotaClientQuery } from '@iota/dapp-kit';
import { CoinItem, SendCoinPopup } from '@/components';
import { usePopups } from '@/hooks';
import { CoinItem, SendTokenDialog } from '@/components';
import { CoinBalance } from '@iota/iota-sdk/client';
import {
COINS_QUERY_REFETCH_INTERVAL,
Expand All @@ -14,9 +13,10 @@ import {
} from '@iota/core';

function MyCoins(): React.JSX.Element {
const { openPopup, closePopup } = usePopups();
const account = useCurrentAccount();
const activeAccountAddress = account?.address;
const [isSendTokenDialogOpen, setIsSendTokenDialogOpen] = useState(false);
const [selectedCoinType, setSelectedCoinType] = useState('');

const { data: coinBalances } = useIotaClientQuery(
'getAllBalances',
Expand All @@ -30,16 +30,10 @@ function MyCoins(): React.JSX.Element {
);
const { recognized, unrecognized } = useSortedCoinsByCategories(coinBalances ?? []);

function openSendTokenPopup(coin: CoinBalance, address: string): void {
function openSendTokenPopup(coin: CoinBalance): void {
if (coinBalances) {
openPopup(
<SendCoinPopup
coin={coin}
senderAddress={address}
onClose={closePopup}
coins={coinBalances}
/>,
);
setIsSendTokenDialogOpen(true);
setSelectedCoinType(coin.coinType);
}
}

Expand All @@ -52,7 +46,7 @@ function MyCoins(): React.JSX.Element {
key={index}
coinType={coin.coinType}
balance={BigInt(coin.totalBalance)}
onClick={() => openSendTokenPopup(coin, account?.address ?? '')}
onClick={() => openSendTokenPopup(coin)}
/>
);
})}
Expand All @@ -63,10 +57,16 @@ function MyCoins(): React.JSX.Element {
key={index}
coinType={coin.coinType}
balance={BigInt(coin.totalBalance)}
onClick={() => openSendTokenPopup(coin, account?.address ?? '')}
onClick={() => openSendTokenPopup(coin)}
/>
);
})}
<SendTokenDialog
coinType={selectedCoinType}
activeAddress={activeAccountAddress!}
open={isSendTokenDialogOpen}
setOpen={setIsSendTokenDialogOpen}
/>
</div>
);
}
Expand Down
216 changes: 216 additions & 0 deletions apps/wallet-dashboard/components/Dialogs/SendTokenDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import {
InfoBox,
InfoBoxStyle,
InfoBoxType,
ButtonType,
ButtonHtmlType,
Button,
Dialog,
DialogContent,
DialogBody,
Header,
DialogPosition,
} from '@iota/apps-ui-kit';
import { parseAmount, useCoinMetadata, useGetAllCoins, useIotaAddressValidation } from '@iota/core';
import { CoinStruct } from '@iota/iota-sdk/client';
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
import { Exclamation } from '@iota/ui-icons';
import { Field, Form, Formik, useFormikContext } from 'formik';
import Input from '../Input';
import { ChangeEventHandler, useCallback } from 'react';

const INITIAL_VALUES = {
to: '',
amount: '',
isPayAllIota: false,
gasBudgetEst: '',
};

export type FormValues = typeof INITIAL_VALUES;

export type SubmitProps = {
to: string;
amount: string;
isPayAllIota: boolean;
coinIds: string[];
coins: CoinStruct[];
gasBudgetEst: string;
};

export type SendTokenFormProps = {
coinType: string;
activeAddress: string;
setOpen: (bool: boolean) => void;
open: boolean;
};

function totalBalance(coins: CoinStruct[]): bigint {
return coins.reduce((partialSum, c) => partialSum + getBalanceFromCoinStruct(c), BigInt(0));
}
function getBalanceFromCoinStruct(coin: CoinStruct): bigint {
return BigInt(coin.balance);
}

export function SendTokenDialog({
coinType,
activeAddress,
setOpen,
open,
}: SendTokenFormProps): React.JSX.Element {
const { data: coinsData } = useGetAllCoins(coinType, activeAddress!);
const { setFieldValue, validateField } = useFormikContext();
const iotaAddressValidation = useIotaAddressValidation();

const { data: iotaCoinsData } = useGetAllCoins(IOTA_TYPE_ARG, activeAddress!);

const iotaCoins = iotaCoinsData;
const coins = coinsData;
const coinBalance = totalBalance(coins || []);
const iotaBalance = totalBalance(iotaCoins || []);

const coinMetadata = useCoinMetadata(coinType);
const coinDecimals = coinMetadata.data?.decimals ?? 0;

// const validationSchemaStepOne = useMemo(
// () => createValidationSchemaStepOne(coinBalance, symbol, coinDecimals),
// [client, coinBalance, symbol, coinDecimals],
// );

// remove the comma from the token balance
const initAmountBig = parseAmount('0', coinDecimals);
// const initAmountBig = parseAmount(initialAmount, coinDecimals);

const handleAddressChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
(e) => {
const address = e.currentTarget.value;
setFieldValue(activeAddress, iotaAddressValidation.cast(address)).then(() => {
validateField(activeAddress);
});
},
[setFieldValue, activeAddress, iotaAddressValidation],
);

async function handleFormSubmit({ to, amount, isPayAllIota, gasBudgetEst }: FormValues) {
if (!coins || !iotaCoins) return;
const coinsIDs = [...coins]
.sort((a, b) => Number(b.balance) - Number(a.balance))
.map(({ coinObjectId }) => coinObjectId);

const data = {
to,
amount,
isPayAllIota,
coins,
coinIds: coinsIDs,
gasBudgetEst,
};
console.log('data', data);

// onSubmit(data);
}

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent containerId="overlay-portal-container" position={DialogPosition.Right}>
<Header title="Send" onClose={() => setOpen(false)} />
<DialogBody>
<Formik
initialValues={{
amount: '0',
to: 'initialTo',
// amount: initialAmount,
// to: initialTo,
isPayAllIota:
!!initAmountBig &&
initAmountBig === coinBalance &&
coinType === IOTA_TYPE_ARG,
gasBudgetEst: '',
}}
// validationSchema={validationSchemaStepOne}
enableReinitialize
validateOnChange={false}
validateOnBlur={false}
onSubmit={handleFormSubmit}
>
{({ isValid, isSubmitting, setFieldValue, values, submitForm }) => {
const newPayIotaAll =
parseAmount(values.amount, coinDecimals) === coinBalance &&
coinType === IOTA_TYPE_ARG;
if (values.isPayAllIota !== newPayIotaAll) {
setFieldValue('isPayAllIota', newPayIotaAll);
}

const hasEnoughBalance =
values.isPayAllIota ||
iotaBalance >
parseAmount(values.gasBudgetEst, coinDecimals) +
parseAmount(
coinType === IOTA_TYPE_ARG ? values.amount : '0',
coinDecimals,
);

return (
<div className="flex h-full w-full flex-col">
<Form autoComplete="off" noValidate className="flex-1">
<div className="flex h-full w-full flex-col gap-md">
{!hasEnoughBalance ? (
<InfoBox
type={InfoBoxType.Error}
supportingText="Insufficient IOTA to cover transaction"
style={InfoBoxStyle.Elevated}
icon={<Exclamation />}
/>
) : null}

{/* <SendTokenFormInput
coinDecimals={coinDecimals}
symbol={symbol}
coins={coins}
values={values}
onActionClick={onMaxTokenButtonClick}
isActionButtonDisabled={isMaxActionDisabled}
/> */}
<Field
component={
<Input
type="text"
value={activeAddress}
placeholder="Enter Address"
onChange={(e) => handleAddressChange(e)}
label="Enter recipient address"
/>
}
allowNegative={false}
name="to"
placeholder="Enter Address"
/>
</div>
</Form>

<div className="pt-xs">
<Button
onClick={submitForm}
htmlType={ButtonHtmlType.Submit}
type={ButtonType.Primary}
disabled={
!isValid ||
isSubmitting ||
!hasEnoughBalance ||
values.gasBudgetEst === ''
}
text="Review"
fullWidth
/>
</div>
</div>
);
}}
</Formik>
</DialogBody>
</DialogContent>
</Dialog>
);
}
4 changes: 4 additions & 0 deletions apps/wallet-dashboard/components/Dialogs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './SendTokenDialog';
1 change: 1 addition & 0 deletions apps/wallet-dashboard/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from './Popup';
export * from './AppList';
export * from './Cards';
export * from './Buttons';
export * from './Dialogs';
1 change: 1 addition & 0 deletions apps/wallet-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@tanstack/react-query": "^5.50.1",
"@tanstack/react-virtual": "^3.5.0",
"clsx": "^2.1.1",
"formik": "^2.4.2",
"next": "14.2.10",
"react": "^18.3.1",
"react-hot-toast": "^2.4.1",
Expand Down
Loading

0 comments on commit 7bd6cbf

Please sign in to comment.