* Abacus 6: New init, deprecate asset.symbol * deprecate asset.symbol * Update networks constants * filesystem * Update networks.ts * 0.6.0 -> 0.6.3 * Remove Market filter
172 lines
5.3 KiB
TypeScript
172 lines
5.3 KiB
TypeScript
import { useState } from 'react';
|
|
import { shallowEqual, useSelector } from 'react-redux';
|
|
import styled, { AnyStyledComponent, css } from 'styled-components';
|
|
|
|
import { STRING_KEYS } from '@/constants/localization';
|
|
import { MobilePlaceOrderSteps } from '@/constants/trade';
|
|
|
|
import { useBreakpoints, useStringGetter } from '@/hooks';
|
|
import { layoutMixins } from '@/styles/layoutMixins';
|
|
|
|
import { AssetIcon } from '@/components/AssetIcon';
|
|
import { ClosePositionForm } from '@/views/forms/ClosePositionForm';
|
|
import { Dialog, DialogPlacement } from '@/components/Dialog';
|
|
import { GreenCheckCircle } from '@/components/GreenCheckCircle';
|
|
import { Ring } from '@/components/Ring';
|
|
import { VerticalSeparator } from '@/components/Separator';
|
|
import { MidMarketPrice } from '@/views/MidMarketPrice';
|
|
import { Output, OutputType } from '@/components/Output';
|
|
|
|
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
|
import { getCurrentMarketData } from '@/state/perpetualsSelectors';
|
|
|
|
import abacusStateManager from '@/lib/abacus';
|
|
import { MustBigNumber } from '@/lib/numbers';
|
|
|
|
type ElementProps = {
|
|
setIsOpen?: (open: boolean) => void;
|
|
};
|
|
|
|
export const ClosePositionDialog = ({ setIsOpen }: ElementProps) => {
|
|
const { id } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
|
|
const { isTablet } = useBreakpoints();
|
|
const stringGetter = useStringGetter();
|
|
|
|
const [currentStep, setCurrentStep] = useState<MobilePlaceOrderSteps>(
|
|
MobilePlaceOrderSteps.EditOrder
|
|
);
|
|
|
|
const dialogProps: {
|
|
[key in MobilePlaceOrderSteps]: {
|
|
title: string | JSX.Element;
|
|
description?: string;
|
|
slotIcon?: JSX.Element;
|
|
dialogIconSize?: string;
|
|
};
|
|
} = {
|
|
[MobilePlaceOrderSteps.EditOrder]: {
|
|
title: <CloseOrderHeader />,
|
|
slotIcon: <AssetIcon symbol={id} />,
|
|
},
|
|
[MobilePlaceOrderSteps.PreviewOrder]: {
|
|
title: (
|
|
<Styled.PreviewTitle>
|
|
{stringGetter({ key: STRING_KEYS.PREVIEW_ORDER_TITLE })}
|
|
</Styled.PreviewTitle>
|
|
),
|
|
description: stringGetter({ key: STRING_KEYS.PREVIEW_ORDER_DESCRIPTION }),
|
|
},
|
|
[MobilePlaceOrderSteps.PlacingOrder]: {
|
|
title: stringGetter({ key: STRING_KEYS.PLACING_ORDER_TITLE }),
|
|
description: stringGetter({ key: STRING_KEYS.PLACING_ORDER_DESCRIPTION }),
|
|
slotIcon: <Styled.Ring withAnimation value={0.25} />,
|
|
},
|
|
// TODO(@aforaleka): add error state if trade didn't actually go through
|
|
[MobilePlaceOrderSteps.Confirmation]: {
|
|
title: stringGetter({ key: STRING_KEYS.CONFIRMED_TITLE }),
|
|
description: stringGetter({ key: STRING_KEYS.CONFIRMED_DESCRIPTION }),
|
|
slotIcon: <Styled.GreenCheckCircle />,
|
|
},
|
|
};
|
|
|
|
return (
|
|
<Styled.Dialog
|
|
isOpen={isTablet}
|
|
setIsOpen={(isOpen: boolean) => {
|
|
setIsOpen?.(isOpen);
|
|
if (!isOpen)
|
|
abacusStateManager.clearClosePositionInputValues({ shouldFocusOnTradeInput: true });
|
|
}}
|
|
slotIcon={dialogProps[currentStep].slotIcon}
|
|
title={dialogProps[currentStep].title}
|
|
description={dialogProps[currentStep].description}
|
|
placement={DialogPlacement.FullScreen}
|
|
hasHeaderBorder
|
|
currentStep={currentStep}
|
|
>
|
|
<ClosePositionForm currentStep={currentStep} setCurrentStep={setCurrentStep} />
|
|
</Styled.Dialog>
|
|
);
|
|
};
|
|
|
|
const CloseOrderHeader = () => {
|
|
const stringGetter = useStringGetter();
|
|
const { priceChange24H, priceChange24HPercent } =
|
|
useSelector(getCurrentMarketData, shallowEqual) ?? {};
|
|
|
|
return (
|
|
<Styled.CloseOrderHeader>
|
|
<h2>{stringGetter({ key: STRING_KEYS.CLOSE })}</h2>
|
|
<Styled.Right>
|
|
<Styled.MarketDetails>
|
|
<MidMarketPrice />
|
|
<Styled.PriceChange
|
|
type={OutputType.Percent}
|
|
value={MustBigNumber(priceChange24HPercent).abs()}
|
|
isNegative={MustBigNumber(priceChange24H).isNegative()}
|
|
/>
|
|
</Styled.MarketDetails>
|
|
<Styled.VerticalSeparator />
|
|
</Styled.Right>
|
|
</Styled.CloseOrderHeader>
|
|
);
|
|
};
|
|
|
|
const Styled: Record<string, AnyStyledComponent> = {};
|
|
|
|
Styled.Dialog = styled(Dialog)<{ currentStep: MobilePlaceOrderSteps }>`
|
|
--dialog-backgroundColor: var(--color-layer-2);
|
|
--dialog-header-height: 1rem;
|
|
--dialog-content-paddingTop: 1.5rem;
|
|
--dialog-content-paddingBottom: 1.25rem;
|
|
--dialog-content-paddingLeft: 1.5rem;
|
|
--dialog-content-paddingRight: 1.5rem;
|
|
--dialog-icon-size: 2rem;
|
|
|
|
${({ currentStep }) =>
|
|
currentStep === MobilePlaceOrderSteps.EditOrder &&
|
|
css`
|
|
--dialog-icon-size: 2.5rem;
|
|
`}
|
|
`;
|
|
|
|
Styled.Ring = styled(Ring)`
|
|
--ring-color: var(--color-accent);
|
|
`;
|
|
|
|
Styled.GreenCheckCircle = styled(GreenCheckCircle)`
|
|
--icon-size: 2rem;
|
|
`;
|
|
|
|
Styled.CloseOrderHeader = styled.div`
|
|
${layoutMixins.spacedRow}
|
|
`;
|
|
|
|
Styled.Right = styled.div`
|
|
${layoutMixins.inlineRow}
|
|
gap: 1rem;
|
|
margin-right: 0.5rem;
|
|
`;
|
|
|
|
Styled.MarketDetails = styled.div`
|
|
${layoutMixins.rowColumn}
|
|
justify-items: flex-end;
|
|
font: var(--font-medium-medium);
|
|
`;
|
|
|
|
Styled.PriceChange = styled(Output)<{ isNegative?: boolean }>`
|
|
font: var(--font-base-book);
|
|
color: ${({ isNegative }) => (isNegative ? `var(--color-negative)` : `var(--color-positive)`)};
|
|
`;
|
|
|
|
Styled.VerticalSeparator = styled(VerticalSeparator)`
|
|
&& {
|
|
height: 3rem;
|
|
}
|
|
`;
|
|
|
|
Styled.PreviewTitle = styled.div`
|
|
${layoutMixins.inlineRow}
|
|
height: var(--dialog-icon-size);
|
|
`;
|