Skip to content

Commit

Permalink
feat(withdraw-dialog): withdraw dialog rewrite 1/n (#1413)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredvu authored Jan 8, 2025
1 parent 7bbd125 commit dc4c816
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 10 deletions.
2 changes: 2 additions & 0 deletions src/constants/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export type UnlimitedAnnouncementDialogProps = {};
export type UnstakeDialogProps = {};
export type VaultDepositWithdrawDialogProps = { initialType?: 'DEPOSIT' | 'WITHDRAW' };
export type WithdrawDialogProps = {};
export type WithdrawDialog2Props = {};
export type DepositDialog2Props = {};
export type WithdrawalGatedDialogProps = {
transferType: 'withdrawal' | 'transfer';
Expand Down Expand Up @@ -145,6 +146,7 @@ export const DialogTypes = unionize(
Unstake: ofType<UnstakeDialogProps>(),
VaultDepositWithdraw: ofType<VaultDepositWithdrawDialogProps>(),
Withdraw: ofType<WithdrawDialogProps>(),
Withdraw2: ofType<WithdrawDialog2Props>(),
WithdrawalGated: ofType<WithdrawalGatedDialogProps>(),
},
{ tag: 'type' as const, value: 'props' as const }
Expand Down
2 changes: 2 additions & 0 deletions src/layout/DialogManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { UnlimitedAnnouncementDialog } from '@/views/dialogs/UnlimitedAnnounceme
import { UnstakeDialog } from '@/views/dialogs/UnstakeDialog';
import { VaultDepositWithdrawDialog } from '@/views/dialogs/VaultDepositWithdrawDialog';
import { WithdrawDialog } from '@/views/dialogs/WithdrawDialog';
import { WithdrawDialog2 } from '@/views/dialogs/WithdrawDialog2/WithdrawDialog2';
import { WithdrawalGateDialog } from '@/views/dialogs/WithdrawalGateDialog';

import { useAppDispatch, useAppSelector } from '@/state/appTypes';
Expand Down Expand Up @@ -117,6 +118,7 @@ export const DialogManager = React.memo(() => {
Unstake: (args) => <UnstakeDialog {...args} {...modalProps} />,
VaultDepositWithdraw: (args) => <VaultDepositWithdrawDialog {...args} {...modalProps} />,
Withdraw: (args) => <WithdrawDialog {...args} {...modalProps} />,
Withdraw2: (args) => <WithdrawDialog2 {...args} {...modalProps} />,
WithdrawalGated: (args) => <WithdrawalGateDialog {...args} {...modalProps} />,
Criteria: (args) => <CriteriaDialog {...args} {...modalProps} />,
});
Expand Down
4 changes: 4 additions & 0 deletions src/lib/testFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class TestFlags {
get showNewDepositFlow() {
return !!this.queryParams.deposit_rewrite;
}

get showNewWithdrawFlow() {
return !!this.queryParams.withdraw_rewrite;
}
}

export const testFlags = new TestFlags();
21 changes: 19 additions & 2 deletions src/pages/portfolio/Portfolio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { useAppDispatch, useAppSelector } from '@/state/appTypes';
import { openDialog } from '@/state/dialogs';

import { shortenNumberForDisplay } from '@/lib/numbers';
import { testFlags } from '@/lib/testFlags';

import { VaultTransactionsTable } from '../vaults/VaultTransactions';
import { PortfolioNavMobile } from './PortfolioNavMobile';
Expand Down Expand Up @@ -244,15 +245,31 @@ const PortfolioPage = () => {
{complianceState === ComplianceStates.FULL_ACCESS && (
<Button
action={ButtonAction.Primary}
onClick={() => dispatch(openDialog(DialogTypes.Deposit({})))}
onClick={() =>
dispatch(
openDialog(
testFlags.showNewDepositFlow
? DialogTypes.Deposit2({})
: DialogTypes.Deposit({})
)
)
}
>
{stringGetter({ key: STRING_KEYS.DEPOSIT })}
</Button>
)}
{usdcBalance > 0 && (
<Button
action={ButtonAction.Base}
onClick={() => dispatch(openDialog(DialogTypes.Withdraw()))}
onClick={() =>
dispatch(
openDialog(
testFlags.showNewWithdrawFlow
? DialogTypes.Withdraw2({})
: DialogTypes.Withdraw()
)
)
}
>
{stringGetter({ key: STRING_KEYS.WITHDRAW })}
</Button>
Expand Down
17 changes: 15 additions & 2 deletions src/views/AccountInfo/AccountInfoSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { useAppDispatch, useAppSelector } from '@/state/appTypes';
import { openDialog } from '@/state/dialogs';

import { isNumber, MustBigNumber } from '@/lib/numbers';
import { testFlags } from '@/lib/testFlags';

import { AccountInfoDiffOutput } from './AccountInfoDiffOutput';

Expand Down Expand Up @@ -66,7 +67,13 @@ export const AccountInfoSection = () => {
const withdrawButton = (
<$Button
state={{ isDisabled: !dydxAccounts }}
onClick={() => dispatch(openDialog(DialogTypes.Withdraw()))}
onClick={() =>
dispatch(
openDialog(
testFlags.showNewWithdrawFlow ? DialogTypes.Withdraw2({}) : DialogTypes.Withdraw()
)
)
}
shape={ButtonShape.Rectangle}
size={ButtonSize.XSmall}
buttonStyle={ButtonStyle.WithoutBackground}
Expand All @@ -79,7 +86,13 @@ export const AccountInfoSection = () => {
const depositButton = (
<$Button
state={{ isDisabled: !dydxAccounts }}
onClick={() => dispatch(openDialog(DialogTypes.Deposit({})))}
onClick={() =>
dispatch(
openDialog(
testFlags.showNewDepositFlow ? DialogTypes.Deposit2({}) : DialogTypes.Deposit({})
)
)
}
shape={ButtonShape.Rectangle}
size={ButtonSize.XSmall}
buttonStyle={ButtonStyle.WithoutBackground}
Expand Down
7 changes: 6 additions & 1 deletion src/views/dialogs/OnboardingDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { useAppDispatch, useAppSelector } from '@/state/appTypes';
import { forceOpenDialog } from '@/state/dialogs';

import { track } from '@/lib/analytics/analytics';
import { testFlags } from '@/lib/testFlags';

import { DepositForm } from '../forms/AccountManagementForms/DepositForm';
import { LanguageSelector } from '../menus/LanguageSelector';
Expand All @@ -54,7 +55,11 @@ export const OnboardingDialog = ({ setIsOpen }: DialogProps<OnboardingDialogProp
if (!currentOnboardingStep) setIsOpen(false);
if (currentOnboardingStep === OnboardingSteps.DepositFunds) {
setIsOpen(false);
dispatch(forceOpenDialog(DialogTypes.Deposit({})));
dispatch(
forceOpenDialog(
testFlags.showNewDepositFlow ? DialogTypes.Deposit2({}) : DialogTypes.Deposit({})
)
);
}
}, [currentOnboardingStep, setIsOpen, dispatch]);

Expand Down
67 changes: 67 additions & 0 deletions src/views/dialogs/WithdrawDialog2/AddressInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { EventHandler } from 'react';

import { SyntheticInputEvent } from 'react-number-format/types/types';
import styled from 'styled-components';

import { STRING_KEYS } from '@/constants/localization';
import { WalletNetworkType } from '@/constants/wallets';

import { useAccounts } from '@/hooks/useAccounts';
import { useStringGetter } from '@/hooks/useStringGetter';

import { AssetIcon } from '@/components/AssetIcon';
import { Icon, IconName } from '@/components/Icon';

type AddressInputProps = {
value: string;
onChange: (newValue: string) => void;
_destinationChain: string;
onDestinationClicked: () => void;
};

export const AddressInput = ({
value,
onChange,
_destinationChain,
onDestinationClicked,
}: AddressInputProps) => {
const stringGetter = useStringGetter();
const { sourceAccount } = useAccounts();

const onValueChange: EventHandler<SyntheticInputEvent> = (e) => {
onChange(e.target.value);
};

return (
<div tw="flex items-center justify-between gap-0.5 rounded-0.75 border border-solid border-color-border bg-color-layer-4 px-1.25 py-0.75">
<div tw="flex flex-1 flex-col gap-0.5 text-small">
<div>{stringGetter({ key: STRING_KEYS.ADDRESS })}</div>
<input
placeholder={sourceAccount.address}
tw="flex-1 bg-color-layer-4 text-large font-medium outline-none"
value={value}
onChange={onValueChange}
/>
</div>
<button
tw="flex items-center gap-0.75 rounded-0.75 border border-solid border-color-layer-6 bg-color-layer-5 px-0.5 py-0.375"
type="button"
disabled={sourceAccount.chain === WalletNetworkType.Solana}
onClick={onDestinationClicked}
>
<div tw="flex items-center gap-0.5">
<AssetIcon tw="h-[2rem] w-[2rem]" symbol="ETH" />
<div>Ethereum</div>
</div>
{sourceAccount.chain !== WalletNetworkType.Solana && (
<$CaretIcon size="10px" iconName={IconName.Caret} />
)}
</button>
</div>
);
};

const $CaretIcon = styled(Icon)`
transform: rotate(-90deg);
color: var(--color-text-0);
`;
87 changes: 87 additions & 0 deletions src/views/dialogs/WithdrawDialog2/AmountInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { EventHandler } from 'react';

import { BonsaiCore } from '@/abacus-ts/ontology';
import { SyntheticInputEvent } from 'react-number-format/types/types';

import { STRING_KEYS } from '@/constants/localization';
import { USDC_DECIMALS } from '@/constants/tokens';

import { useStringGetter } from '@/hooks/useStringGetter';

import { Output, OutputType } from '@/components/Output';

import { useAppSelector } from '@/state/appTypes';

import { orEmptyObj } from '@/lib/typeUtils';

type AmountInputProps = {
value: string;
onChange: (newValue: string) => void;
};

export const AmountInput = ({ value, onChange }: AmountInputProps) => {
const stringGetter = useStringGetter();

const onValueChange: EventHandler<SyntheticInputEvent> = (e) => {
onChange(e.target.value);
};

const isLoading =
useAppSelector(BonsaiCore.account.parentSubaccountSummary.loading) === 'pending';

const { freeCollateral } = orEmptyObj(
useAppSelector(BonsaiCore.account.parentSubaccountSummary.data)
);

const onClickMax = () => {
if (!freeCollateral) return;
onChange(freeCollateral.toString());
};

const onMaxDisabled = !freeCollateral || isLoading;

return (
<div tw="flex items-center justify-between gap-0.5 rounded-0.75 border border-solid border-color-border bg-color-layer-4 px-1.25 py-0.75">
<div tw="flex flex-1 flex-col gap-0.5 text-small">
<div>
{stringGetter({ key: STRING_KEYS.AMOUNT })}

{freeCollateral && (
<>
<span></span>
<Output
tw="inline font-medium text-color-text-0"
fractionDigits={USDC_DECIMALS}
slotRight={` ${stringGetter({ key: STRING_KEYS.AVAILABLE })}`}
value={freeCollateral}
type={OutputType.Fiat}
/>
</>
)}

{freeCollateral && (
<>
<span></span>
<button
disabled={onMaxDisabled}
onClick={onClickMax}
type="button"
tw="font-medium"
style={{ color: onMaxDisabled ? 'var(--color-text-0)' : 'var(--color-accent)' }}
>
{stringGetter({ key: STRING_KEYS.MAX })}
</button>
</>
)}
</div>
<input
type="number"
placeholder="0.00"
tw="flex-1 bg-color-layer-4 text-large font-medium outline-none"
value={value}
onChange={onValueChange}
/>
</div>
</div>
);
};
53 changes: 53 additions & 0 deletions src/views/dialogs/WithdrawDialog2/ChainSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Dispatch, Fragment, SetStateAction } from 'react';

import { mainnet } from 'viem/chains';

import { CHAIN_INFO } from '@/constants/chains';

import { AssetIcon } from '@/components/AssetIcon';

export const ChainSelect = ({
onBack,
selectedChain,
setSelectedChain,
}: {
onBack: () => void;
selectedChain: string;
setSelectedChain: Dispatch<SetStateAction<string>>;
}) => {
const onChainClick = (newChainId: string) => () => {
setSelectedChain(newChainId);
onBack();
};

return (
<div tw="flex flex-col gap-0.5 py-1">
<div tw="flex flex-col">
{[mainnet.id].map((chain) => {
const chainId = chain.toString();

return (
<Fragment key={chainId}>
<button
onClick={onChainClick(chainId)}
type="button"
style={{
backgroundColor: chainId === selectedChain ? 'var(--color-layer-4)' : undefined,
}}
tw="flex w-full justify-between px-1.25 py-1 hover:bg-color-layer-4"
key={chainId}
>
<div tw="flex items-center gap-0.75">
<AssetIcon tw="h-[2rem] w-[2rem]" symbol="ETH" />
<div tw="flex flex-col items-start gap-0.125">
<div tw="text-medium font-medium">{CHAIN_INFO[chainId]?.name}</div>
</div>
</div>
</button>
</Fragment>
);
})}
</div>
</div>
);
};
Loading

0 comments on commit dc4c816

Please sign in to comment.