dydx-v4-web/src/views/forms/TradeForm/PlaceOrderButtonAndReceipt.tsx
Bill 50606a750f
Add Rewards abacus transactions and trade form receipt (#47)
* temp

* add into reciept

* bump localization

* add tag
2023-09-25 17:45:46 -04:00

181 lines
5.9 KiB
TypeScript

import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { OrderSide } from '@dydxprotocol/v4-client-js';
import type { TradeInputSummary } from '@/constants/abacus';
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { useStringGetter } from '@/hooks';
import { AssetIcon } from '@/components/AssetIcon';
import { Button } from '@/components/Button';
import { Output, OutputType, ShowSign } from '@/components/Output';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { WithTooltip } from '@/components/WithTooltip';
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
import { calculateCanAccountTrade } from '@/state/accountCalculators';
import { getSubaccountId } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import { getCurrentInput, getInputTradeData } from '@/state/inputsSelectors';
import { getSelectedOrderSide, getSelectedTradeType } from '@/lib/tradeData';
type ElementProps = {
isLoading: boolean;
isClosePosition?: boolean;
actionStringKey?: string;
summary?: TradeInputSummary;
hasValidationErrors?: boolean;
currentStep?: MobilePlaceOrderSteps;
showDeposit?: boolean;
showConnectWallet?: boolean;
};
export const PlaceOrderButtonAndReceipt = ({
isLoading,
isClosePosition,
actionStringKey,
summary,
hasValidationErrors,
currentStep,
showDeposit,
showConnectWallet,
}: ElementProps) => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
const canAccountTrade = useSelector(calculateCanAccountTrade);
const subaccountNumber = useSelector(getSubaccountId);
const currentInput = useSelector(getCurrentInput);
const currentTradeData = useSelector(getInputTradeData, shallowEqual);
const hasMissingData = subaccountNumber === undefined;
const shouldEnableTrade =
canAccountTrade && !hasMissingData && !hasValidationErrors && currentInput !== 'transfer';
const { side, type } = currentTradeData || {};
const selectedTradeType = getSelectedTradeType(type);
const selectedOrderSide = getSelectedOrderSide(side);
const { fee, price: expectedPrice, total, reward } = summary || {};
const items = [
{
key: 'expected-price',
label: (
<WithTooltip tooltip="expected-price" side="right">
{stringGetter({ key: STRING_KEYS.EXPECTED_PRICE })}
</WithTooltip>
),
value: <Output type={OutputType.Fiat} value={expectedPrice} useGrouping />,
},
{
key: 'fee',
label: stringGetter({ key: STRING_KEYS.FEE }),
value: <Output type={OutputType.Fiat} value={fee} useGrouping />,
},
{
key: 'max-reward',
label: (
<>
{stringGetter({ key: STRING_KEYS.MAXIMUM_REWARDS })}
{/* <AssetIcon symbol="DYDX" /> */}
</>
),
value: <Output type={OutputType.Asset} value={reward} useGrouping tag={reward ? "Dv4TNT" : ''} />,
tooltip: 'max-reward',
},
{
key: 'total',
label: stringGetter({ key: STRING_KEYS.TOTAL }),
value: <Output type={OutputType.Fiat} value={total} showSign={ShowSign.None} useGrouping />,
},
];
const orderSideAction = {
[OrderSide.BUY]: ButtonAction.Create,
[OrderSide.SELL]: ButtonAction.Destroy,
}[selectedOrderSide];
const buttonStatesPerStep = {
[MobilePlaceOrderSteps.EditOrder]: {
buttonTextStringKey: shouldEnableTrade
? STRING_KEYS.PREVIEW_ORDER
: actionStringKey
? actionStringKey
: STRING_KEYS.UNAVAILABLE,
buttonAction: ButtonAction.Primary,
buttonState: { isDisabled: !shouldEnableTrade },
},
[MobilePlaceOrderSteps.PreviewOrder]: {
buttonTextStringKey: STRING_KEYS.CONFIRM_ORDER,
buttonAction: isClosePosition ? ButtonAction.Destroy : orderSideAction,
buttonState: { isLoading },
},
[MobilePlaceOrderSteps.PlacingOrder]: {
buttonTextStringKey: STRING_KEYS.RETURN_TO_MARKET,
buttonAction: ButtonAction.Secondary,
buttonState: {},
},
[MobilePlaceOrderSteps.Confirmation]: {
buttonTextStringKey: STRING_KEYS.RETURN_TO_MARKET,
buttonAction: ButtonAction.Secondary,
buttonState: {},
},
};
const buttonAction = currentStep
? buttonStatesPerStep[currentStep].buttonAction
: isClosePosition
? ButtonAction.Destroy
: orderSideAction;
let buttonTextStringKey = STRING_KEYS.UNAVAILABLE;
if (currentStep) {
buttonTextStringKey = buttonStatesPerStep[currentStep].buttonTextStringKey;
} else if (shouldEnableTrade) {
buttonTextStringKey = isClosePosition ? STRING_KEYS.CLOSE_POSITION : STRING_KEYS.PLACE_ORDER;
} else if (actionStringKey) {
buttonTextStringKey = actionStringKey;
}
const buttonState = currentStep
? buttonStatesPerStep[currentStep].buttonState
: { isDisabled: !shouldEnableTrade || isLoading, isLoading };
return (
<WithDetailsReceipt detailItems={items}>
{!canAccountTrade || showConnectWallet ? (
<OnboardingTriggerButton size={ButtonSize.Base} />
) : showDeposit ? (
<Button
action={ButtonAction.Primary}
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
>
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
</Button>
) : (
<Button state={buttonState} type={ButtonType.Submit} action={buttonAction}>
{stringGetter({
key: buttonTextStringKey,
params: {
ORDER: stringGetter({
key: isClosePosition
? STRING_KEYS.CLOSE_ORDER
: TRADE_TYPE_STRINGS[selectedTradeType].tradeTypeKey,
}),
},
})}
</Button>
)}
</WithDetailsReceipt>
);
};