diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 072aad3de3..e651f4d70c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -42,4 +42,4 @@ jobs: category: "/language:${{matrix.language}}" - name: eslint-annotations - uses: DerLev/eslint-annotations@v1.0.1 + uses: DerLev/eslint-annotations@v1.1.1 diff --git a/assets/png/currencies/WBTC.png b/assets/png/currencies/WBTC.png new file mode 100644 index 0000000000..5565d60c15 Binary files /dev/null and b/assets/png/currencies/WBTC.png differ diff --git a/components/Badge/MarketBadge.tsx b/components/Badge/MarketBadge.tsx index bf12b93cb8..ee83e69fbe 100644 --- a/components/Badge/MarketBadge.tsx +++ b/components/Badge/MarketBadge.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -20,45 +20,43 @@ type TransitionBadgeProps = { isOpen: boolean; }; -export const TransitionBadge: FC = ({ isOpen }) => { +export const TransitionBadge: FC = memo(({ isOpen }) => { const { t } = useTranslation(); return ( - {t(`futures.market.state.${isOpen ? 'closes-soon' : 'opens-soon'}`)} + {t(`futures.market.state.${isOpen ? 'closes' : 'opens'}-soon`)} ); -}; +}); -export const MarketBadge: FC = ({ - currencyKey, - isFuturesMarketClosed, - futuresClosureReason, -}) => { - const { t } = useTranslation(); - const isOpen = marketIsOpen((currencyKey as CurrencyKey) ?? null); +export const MarketBadge: FC = memo( + ({ currencyKey, isFuturesMarketClosed, futuresClosureReason }) => { + const { t } = useTranslation(); + const isOpen = marketIsOpen((currencyKey as CurrencyKey) ?? null); - const nextOpen = marketNextOpen((currencyKey as CurrencyKey) ?? ''); - const nextTransition = marketNextTransition((currencyKey as CurrencyKey) ?? ''); + const nextOpen = marketNextOpen((currencyKey as CurrencyKey) ?? ''); + const nextTransition = marketNextTransition((currencyKey as CurrencyKey) ?? ''); - const timerSetting = isOpen === null ? null : isOpen ? nextTransition : nextOpen; - const isMarketTransitioning = useIsMarketTransitioning(timerSetting ?? null); + const timerSetting = isOpen === null ? null : isOpen ? nextTransition : nextOpen; + const isMarketTransitioning = useIsMarketTransitioning(timerSetting ?? null); - if (typeof isFuturesMarketClosed !== 'boolean') { - return null; - } + if (typeof isFuturesMarketClosed !== 'boolean') { + return null; + } - if (isFuturesMarketClosed) { - const reason = futuresClosureReason || 'unknown'; - return {t(`futures.market.state.${reason}`)}; - } + if (isFuturesMarketClosed) { + const reason = futuresClosureReason || 'unknown'; + return {t(`futures.market.state.${reason}`)}; + } - if (isMarketTransitioning && isOpen !== null) { - return ; - } + if (isMarketTransitioning && isOpen !== null) { + return ; + } - return null; -}; + return null; + } +); export default MarketBadge; diff --git a/components/BaseModal/BaseModal.tsx b/components/BaseModal/BaseModal.tsx index e661eb1693..ed13b49587 100644 --- a/components/BaseModal/BaseModal.tsx +++ b/components/BaseModal/BaseModal.tsx @@ -1,10 +1,10 @@ import { DialogOverlay, DialogContent } from '@reach/dialog'; -import { FC, ReactNode } from 'react'; +import { FC, memo, ReactNode } from 'react'; import { Rnd, Props } from 'react-rnd'; import styled from 'styled-components'; import CrossIcon from 'assets/svg/app/cross.svg'; -import Card from 'components/Card'; +import Card, { CardHeader, CardBody } from 'components/Card'; import { zIndex } from 'constants/ui'; import { resetButtonCSS } from 'styles/common'; import media from 'styles/media'; @@ -19,32 +19,32 @@ type BaseModalProps = { rndProps?: Props; }; -export const BaseModal: FC = ({ - onDismiss, - title, - children, - isOpen, - showCross = true, - lowercase, - rndProps = { disableDragging: true, enableResizing: false }, - ...rest -}) => ( - - - {rndProps.disableDragging ? ( - - - {title} - {showCross && ( - - - - )} - - {children} - - ) : ( - +type ModalContentWrapperProps = { + rndProps?: Props; +}; + +const ModalContentWrapper: FC = memo(({ children, rndProps }) => { + if (rndProps?.disableDragging) { + return <>{children}; + } else { + return {children}; + } +}); + +export const BaseModal: FC = memo( + ({ + onDismiss, + title, + children, + isOpen, + showCross = true, + lowercase, + rndProps = { disableDragging: true, enableResizing: false }, + ...rest + }) => ( + + + {title} @@ -56,10 +56,10 @@ export const BaseModal: FC = ({ {children} - - )} - - + + + + ) ); const StyledDialogOverlay = styled(DialogOverlay)` @@ -100,14 +100,14 @@ const StyledCard = styled(Card)` `} `; -const StyledCardHeader = styled(Card.Header)` +const StyledCardHeader = styled(CardHeader)` height: 45px; font-size: 16px; font-family: ${(props) => props.theme.fonts.regular}; padding: 20px; `; -const StyledCardBody = styled(Card.Body)` +const StyledCardBody = styled(CardBody)` overflow-y: scroll; padding: 0 20px; padding-bottom: 20px; diff --git a/components/Button/NavButton.tsx b/components/Button/NavButton.tsx deleted file mode 100644 index 5ca51e0a68..0000000000 --- a/components/Button/NavButton.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import Button from './Button'; - -type NavButtonProps = { - title: string; - isActive: boolean; - onClick?: React.MouseEventHandler | undefined; - disabled?: boolean; - noOutline?: boolean; -}; - -const NavButton: React.FC = ({ title, ...props }) => { - return ( -
- -

{title}

-
-
- ); -}; - -const StyledButton = styled(Button)` - height: initial; - display: flex; - - margin-top: 8px; - margin-bottom: 8px; - - padding-top: 10px; - padding-bottom: 10px; - - border: transparent; - background: ${(props) => - props.isActive ? props.theme.colors.selectedTheme.button.fill : 'transparent'}; - box-shadow: none; - border-radius: 100px; - - p { - margin: 0; - font-size: 15px; - text-align: left; - } - - .title { - color: ${(props) => - props.isActive - ? props.theme.colors.selectedTheme.button.text.primary - : props.theme.colors.selectedTheme.gray}; - } - - &:disabled { - background-color: transparent; - - p { - color: ${(props) => props.theme.colors.selectedTheme.button.tab.disabled.text}; - } - - border: transparent; - - .badge { - display: none; - } - } -`; - -export default NavButton; diff --git a/components/Button/TabButton.tsx b/components/Button/TabButton.tsx index b4dbc6d4a0..d73b8a5096 100644 --- a/components/Button/TabButton.tsx +++ b/components/Button/TabButton.tsx @@ -19,8 +19,8 @@ export type TabButtonProps = { }; const TabButton: React.FC = React.memo( - ({ title, detail, badge, active, icon, vertical, titleIcon, nofill, ...props }) => ( - + ({ title, detail, badge, icon, titleIcon, ...props }) => ( + {!!icon &&
{icon}
}
diff --git a/components/Card/Card.tsx b/components/Card/Card.tsx index e1c1ba3b81..6078180d66 100644 --- a/components/Card/Card.tsx +++ b/components/Card/Card.tsx @@ -1,30 +1,18 @@ import { FC, memo } from 'react'; import styled from 'styled-components'; -import CardBody, { CardBodyProps } from './CardBody'; -import CardHeader, { CardHeaderProps } from './CardHeader'; - type CardProps = { children: React.ReactNode; isRounded?: boolean; className?: string; }; -interface StaticComponents { - Header: FC; - Body: FC; -} - -// @ts-ignore -const Card: FC & StaticComponents = memo(({ children, isRounded, ...rest }) => ( +const Card: FC = memo(({ children, isRounded, ...rest }) => ( {children} )); -Card.Header = CardHeader; -Card.Body = CardBody; - const Container = styled.div<{ isRounded?: boolean }>` display: flex; flex-direction: column; diff --git a/components/Card/CardBody.tsx b/components/Card/CardBody.tsx index 1b14512c56..0b869938c8 100644 --- a/components/Card/CardBody.tsx +++ b/components/Card/CardBody.tsx @@ -1,7 +1,7 @@ import { FC, memo } from 'react'; import styled from 'styled-components'; -import { FlexDivCol } from 'styles/common'; +import { FlexDivCol } from 'components/layout/flex'; export type CardBodyProps = { children: React.ReactNode; diff --git a/components/Card/CardHeader.tsx b/components/Card/CardHeader.tsx index b4b6d53346..2c56526372 100644 --- a/components/Card/CardHeader.tsx +++ b/components/Card/CardHeader.tsx @@ -1,7 +1,7 @@ import React, { FC, memo } from 'react'; import styled from 'styled-components'; -import { FlexDivCentered } from 'styles/common'; +import { FlexDivCentered } from 'components/layout/flex'; export type CardHeaderProps = { children: React.ReactNode; @@ -21,7 +21,7 @@ const CardHeader: FC = memo( const Container = styled(FlexDivCentered)<{ lowercase: boolean; noBorder: boolean }>` position: relative; color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - border-bottom: ${(props) => (props.noBorder ? 'none' : `1px solid ${props.theme.colors.navy}`)}; + border-bottom: ${(props) => (props.noBorder ? 'none' : props.theme.colors.selectedTheme.border)}; height: 32px; padding: 0 18px; justify-content: flex-start; diff --git a/components/Card/index.ts b/components/Card/index.ts index c68311df80..cf56eb9b32 100644 --- a/components/Card/index.ts +++ b/components/Card/index.ts @@ -1 +1,3 @@ export { default } from './Card'; +export { default as CardHeader } from './CardHeader'; +export { default as CardBody } from './CardBody'; diff --git a/components/ChangePercent/ChangePercent.tsx b/components/ChangePercent/ChangePercent.tsx index 272f7797f4..75fbaa0208 100644 --- a/components/ChangePercent/ChangePercent.tsx +++ b/components/ChangePercent/ChangePercent.tsx @@ -1,5 +1,5 @@ import { wei, WeiSource } from '@synthetixio/wei'; -import { FC } from 'react'; +import { FC, memo } from 'react'; import styled from 'styled-components'; import ChangeNegativeIcon from 'assets/svg/app/change-negative.svg'; @@ -14,31 +14,28 @@ type ChangePercentProps = { showArrow?: boolean; }; -export const ChangePercent: FC = ({ - value, - decimals = 2, - showArrow = true, - ...rest -}) => { - const isValid = !!value; - const isZero = value && wei(value).eq(0); - const isPositive = value && wei(value).gt(0); +export const ChangePercent: FC = memo( + ({ value, decimals = 2, showArrow = true, ...rest }) => { + const isValid = !!value; + const isZero = value && wei(value).eq(0); + const isPositive = value && wei(value).gt(0); - return ( - - {!isValid ? ( - <>{NO_VALUE} - ) : !showArrow ? ( - <> - ) : !isZero && isPositive ? ( - - ) : ( - - )} - {value && formatPercent(wei(value).abs(), { minDecimals: decimals })} - - ); -}; + return ( + + {!isValid ? ( + <>{NO_VALUE} + ) : !showArrow ? ( + <> + ) : !isZero && isPositive ? ( + + ) : ( + + )} + {value && formatPercent(wei(value).abs(), { minDecimals: decimals })} + + ); + } +); const CurrencyChange = styled.span<{ isValid: boolean; isPositive: boolean }>` display: inline-flex; diff --git a/components/Checkbox/Checkbox.tsx b/components/Checkbox/Checkbox.tsx index de590c706f..c367c0f649 100644 --- a/components/Checkbox/Checkbox.tsx +++ b/components/Checkbox/Checkbox.tsx @@ -1,22 +1,19 @@ +import { FC, memo } from 'react'; import styled from 'styled-components'; -export const Checkbox = ({ - id, - label, - checked, - onChange, - ...props -}: { +type CheckboxProps = { id: string; label: string; checked: boolean; onChange: () => void; -}) => ( +}; + +export const Checkbox: FC = memo(({ id, label, checked, onChange, ...props }) => ( -); +)); const CheckboxContainer = styled.div` color: ${(props) => props.theme.colors.selectedTheme.gray}; diff --git a/components/Currency/CurrencyAmount/CurrencyAmount.tsx b/components/Currency/CurrencyAmount/CurrencyAmount.tsx index 9ea92af667..cdf0298377 100644 --- a/components/Currency/CurrencyAmount/CurrencyAmount.tsx +++ b/components/Currency/CurrencyAmount/CurrencyAmount.tsx @@ -1,12 +1,11 @@ import Wei, { wei } from '@synthetixio/wei'; import { ethers } from 'ethers'; -import React, { FC } from 'react'; +import { FC, memo } from 'react'; import styled from 'styled-components'; +import { ContainerRowMixin } from 'components/layout/grid'; import { formatCurrency, FormatCurrencyOptions } from 'utils/formatters/number'; -import { ContainerRowMixin } from '../common'; - type WeiSource = Wei | number | string | ethers.BigNumber; type CurrencyAmountProps = { @@ -21,32 +20,36 @@ type CurrencyAmountProps = { showValue?: boolean; }; -export const CurrencyAmount: FC = ({ - currencyKey, - amount, - totalValue, - sign, - conversionRate, - formatAmountOptions = {}, - formatTotalValueOptions = {}, - showTotalValue = true, - showValue = true, - ...rest -}) => ( - - {!showValue ? null : ( - {formatCurrency(currencyKey, amount, formatAmountOptions)} - )} - {!showTotalValue ? null : ( - - {formatCurrency( - currencyKey, - conversionRate != null ? wei(totalValue).div(conversionRate) : totalValue, - { sign, ...formatTotalValueOptions } - )} - - )} - +export const CurrencyAmount: FC = memo( + ({ + currencyKey, + amount, + totalValue, + sign, + conversionRate, + formatAmountOptions = {}, + formatTotalValueOptions = {}, + showTotalValue = true, + showValue = true, + ...rest + }) => ( + + {!showValue ? null : ( + + {formatCurrency(currencyKey, amount, formatAmountOptions)} + + )} + {!showTotalValue ? null : ( + + {formatCurrency( + currencyKey, + conversionRate != null ? wei(totalValue).div(conversionRate) : totalValue, + { sign, ...formatTotalValueOptions } + )} + + )} + + ) ); const Container = styled.span` diff --git a/components/Currency/CurrencyIcon/TokenIcon.tsx b/components/Currency/CurrencyIcon/TokenIcon.tsx index 6b28ab1087..458d49b770 100644 --- a/components/Currency/CurrencyIcon/TokenIcon.tsx +++ b/components/Currency/CurrencyIcon/TokenIcon.tsx @@ -1,8 +1,8 @@ -import { FC } from 'react'; +import { FC, memo } from 'react'; import styled from 'styled-components'; +import { FlexDivCentered } from 'components/layout/flex'; import { useAppSelector } from 'state/hooks'; -import { FlexDivCentered } from 'styles/common'; export type TokenIconProps = { currencyKey: string; @@ -15,7 +15,7 @@ export type TokenIconProps = { url?: string; }; -const TokenIcon: FC = ({ currencyKey, isDeprecated, ...props }) => { +const TokenIcon: FC = memo(({ currencyKey, isDeprecated, ...props }) => { const tokensMap = useAppSelector(({ exchange }) => exchange.tokensMap); if (!!tokensMap[currencyKey]) { @@ -29,7 +29,7 @@ const TokenIcon: FC = ({ currencyKey, isDeprecated, ...props }) ); } -}; +}); const TokenImage = styled.img<{ $isDeprecated?: boolean }>` border-radius: 100%; diff --git a/components/Currency/CurrencyName/CurrencyName.tsx b/components/Currency/CurrencyName/CurrencyName.tsx index e615a3f8db..122a322b63 100644 --- a/components/Currency/CurrencyName/CurrencyName.tsx +++ b/components/Currency/CurrencyName/CurrencyName.tsx @@ -1,11 +1,11 @@ -import React, { FC } from 'react'; +import React, { memo, FC } from 'react'; import { useTranslation } from 'react-i18next'; import styled, { css } from 'styled-components'; +import { ContainerRowMixin } from 'components/layout/grid'; import MarketClosureIcon from 'components/MarketClosureIcon'; import { MarketClosureReason } from 'hooks/useMarketClosed'; -import { ContainerRowMixin } from '../common'; import CurrencyIcon from '../CurrencyIcon'; import { CurrencyIconProps } from '../CurrencyIcon/CurrencyIcon'; @@ -19,43 +19,45 @@ type CurrencyNameProps = { isDeprecated?: boolean; }; -export const CurrencyName: FC = ({ - currencyKey, - symbol, - name = null, - showIcon = false, - iconProps = {}, - marketClosureReason, - isDeprecated = false, - ...rest -}) => { - const { t } = useTranslation(); - return ( - - {showIcon && ( - - - {marketClosureReason != null ? ( - - - - ) : null} - - )} - - - {symbol || currencyKey} - {!isDeprecated ? null : ( - - {t('common.currency.deprecated')} - - )} - - {name && {name}} - - - ); -}; +export const CurrencyName: FC = memo( + ({ + currencyKey, + symbol, + name = null, + showIcon = false, + iconProps = {}, + marketClosureReason, + isDeprecated = false, + ...rest + }) => { + const { t } = useTranslation(); + return ( + + {showIcon && ( + + + {marketClosureReason != null ? ( + + + + ) : null} + + )} + + + {symbol || currencyKey} + {!isDeprecated ? null : ( + + {t('common.currency.deprecated')} + + )} + + {name && {name}} + + + ); + } +); const Container = styled.span<{ showIcon?: boolean }>` ${(props) => diff --git a/components/Currency/CurrencyPrice/CurrencyPrice.tsx b/components/Currency/CurrencyPrice/CurrencyPrice.tsx index 49daa658aa..896b88e0f6 100644 --- a/components/Currency/CurrencyPrice/CurrencyPrice.tsx +++ b/components/Currency/CurrencyPrice/CurrencyPrice.tsx @@ -1,14 +1,13 @@ import Wei, { wei } from '@synthetixio/wei'; import { ethers } from 'ethers'; -import React, { FC, useMemo } from 'react'; +import React, { FC, memo } from 'react'; import styled from 'styled-components'; import ChangePercent from 'components/ChangePercent'; +import { ContainerRowMixin } from 'components/layout/grid'; import { CurrencyKey } from 'constants/currency'; import { formatCurrency, FormatCurrencyOptions } from 'utils/formatters/number'; -import { ContainerRowMixin } from '../common'; - type WeiSource = Wei | number | string | ethers.BigNumber; type CurrencyPriceProps = { @@ -22,55 +21,43 @@ type CurrencyPriceProps = { truncate?: boolean; }; -export const CurrencyPrice: FC = ({ - currencyKey, - price, - sign, - change, - conversionRate, - showCurrencyKey, - formatOptions, - truncate = false, - ...rest -}) => { - const cleanPrice = useMemo(() => { - try { - return wei(price); - } catch { - return ''; - } - }, [price]); +export const CurrencyPrice: FC = memo( + ({ + currencyKey, + price, + sign, + change, + conversionRate, + showCurrencyKey, + formatOptions, + truncate = false, + ...rest + }) => { + const cleanPrice = wei(price); + const cleanConversionRate = wei(conversionRate ?? 0); - const cleanConversionRate = useMemo(() => { - try { - return wei(conversionRate); - } catch { - return ''; + if (truncate && price > 1e6) { + formatOptions = { ...formatOptions, truncation: { divisor: 1e6, unit: 'M' } }; } - }, [conversionRate]); - if (truncate && price > 1e6) { - formatOptions = { ...formatOptions, truncation: { divisor: 1e6, unit: 'M' } }; + return ( + + + {formatCurrency( + currencyKey, + cleanConversionRate.gt(0) ? cleanPrice.div(cleanConversionRate) : cleanPrice, + { + sign, + currencyKey: showCurrencyKey ? currencyKey : undefined, + ...formatOptions, + } + )} + + {!!change && } + + ); } - return ( - - - {formatCurrency( - currencyKey, - cleanConversionRate && cleanPrice && cleanConversionRate.gt(0) - ? cleanPrice.div(cleanConversionRate) - : cleanPrice, - { - sign, - currencyKey: showCurrencyKey != null ? currencyKey : undefined, - ...formatOptions, - } - )} - - {change != null && } - - ); -}; +); const Container = styled.span` ${ContainerRowMixin}; diff --git a/components/Currency/common.tsx b/components/Currency/common.tsx deleted file mode 100644 index fcfd55f1fa..0000000000 --- a/components/Currency/common.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export const ContainerRowMixin = ` - display: inline-grid; - grid-gap: 1px; -`; diff --git a/components/Error/index.ts b/components/Error/index.ts deleted file mode 100644 index 3edca40045..0000000000 --- a/components/Error/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Error'; diff --git a/components/Error/Error.tsx b/components/ErrorView/ErrorView.tsx similarity index 59% rename from components/Error/Error.tsx rename to components/ErrorView/ErrorView.tsx index 9fc5137193..ca63c5b710 100644 --- a/components/Error/Error.tsx +++ b/components/ErrorView/ErrorView.tsx @@ -1,4 +1,4 @@ -import React, { FC, useMemo } from 'react'; +import React, { FC, useMemo, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -24,40 +24,36 @@ export const FRIENDLY_I18N_MESSAGES: Record = { 'Insufficient margin': 'futures.market.errors.insufficient-margin', }; -export const Error: FC = ({ - message, - formatter, - retryButton, - containerStyle, - messageType = 'error', -}) => { - const { t } = useTranslation(); - const formattedMessage = useMemo(() => { - if (FRIENDLY_I18N_MESSAGES[message]) return t(FRIENDLY_I18N_MESSAGES[message]); - switch (formatter) { - case 'revert': - return formatRevert(message); - default: - return message; - } - }, [message, formatter, t]); +export const ErrorView: FC = memo( + ({ message, formatter, retryButton, containerStyle, messageType = 'error' }) => { + const { t } = useTranslation(); + const formattedMessage = useMemo(() => { + if (FRIENDLY_I18N_MESSAGES[message]) return t(FRIENDLY_I18N_MESSAGES[message]); + switch (formatter) { + case 'revert': + return formatRevert(message); + default: + return message; + } + }, [message, formatter, t]); - if (isUserDeniedError(message) || !message) return null; + if (isUserDeniedError(message) || !message) return null; - return ( - -
{truncateString(formattedMessage)}
- {retryButton && ( - <> - - - - )} -
- ); -}; + return ( + +
{truncateString(formattedMessage)}
+ {retryButton && ( + <> + + + + )} +
+ ); + } +); const ErrorContainer = styled.div<{ messageType: MessageType; style: Record }>` color: ${(props) => @@ -84,4 +80,4 @@ const ErrorContainer = styled.div<{ messageType: MessageType; style: Record | undefined) => void; }; -export const FullScreenModal: FC = ({ - title, - children, - isOpen, - onDismiss, - ...rest -}) => ( - - - {title && {title}} -
{children}
-
-
+export const FullScreenModal: FC = memo( + ({ title, children, isOpen, onDismiss, ...rest }) => ( + + + {title && {title}} +
{children}
+
+
+ ) ); const StyledDialogOverlay = styled(DialogOverlay)` diff --git a/components/InfoBox/InfoBox.tsx b/components/InfoBox/InfoBox.tsx index 408f672bd3..9698800a34 100644 --- a/components/InfoBox/InfoBox.tsx +++ b/components/InfoBox/InfoBox.tsx @@ -1,6 +1,7 @@ -import React, { memo } from 'react'; -import styled from 'styled-components'; +import { memo, FC } from 'react'; +import styled, { css } from 'styled-components'; +import * as Text from 'components/Text'; import { NO_VALUE } from 'constants/placeholder'; export type DetailedInfo = { @@ -20,40 +21,49 @@ type InfoBoxProps = { dataTestId?: string; }; -const InfoBox: React.FC = memo( - ({ details, style, className, disabled, dataTestId }) => ( - - {Object.entries(details).map(([key, value], index) => { - if (value) { - return ( - - {value.compactBox ? ( - <>{value.keyNode} - ) : ( -
-
- {key}: {value.keyNode} -
-

- {disabled ? NO_VALUE : value.value} - {value.valueNode} -

-
- )} - {value?.spaceBeneath &&
} -
- ); - } - return null; - })} -
- ) -); +const InfoBox: FC = memo(({ details, disabled, dataTestId, ...props }) => ( + + {Object.entries(details).map(([key, value], index) => ( + + ))} + +)); + +type InfoBoxValueProps = { + title: string; + value?: DetailedInfo | null; + disabled?: boolean; + dataTestId: string; +}; + +const InfoBoxValue: FC = memo(({ title, value, disabled, dataTestId }) => { + if (!value) return null; + + return ( + <> + {value.compactBox ? ( + value.keyNode + ) : ( +
+ + {title}: {value.keyNode} + + + {disabled ? NO_VALUE : value.value} + {value.valueNode} + +
+ )} + {value?.spaceBeneath &&
} + + ); +}); const InfoBoxContainer = styled.div` border: ${(props) => props.theme.colors.selectedTheme.border}; @@ -67,51 +77,48 @@ const InfoBoxContainer = styled.div` justify-content: space-between; align-items: center; - p { - margin: 0; + &:not(:last-of-type) { + margin-bottom: 8px; } + } +`; - .key { - color: ${(props) => props.theme.colors.selectedTheme.text.title}; - font-size: 13px; - text-transform: capitalize; - cursor: default; - } +const InfoBoxKey = styled(Text.Body)` + color: ${(props) => props.theme.colors.selectedTheme.text.title}; + font-size: 13px; + text-transform: capitalize; + cursor: default; +`; - .value { - color: ${(props) => props.theme.colors.selectedTheme.text.value}; - font-family: ${(props) => props.theme.fonts.mono}; - font-size: 13px; - cursor: default; - } +const ValueText = styled(Text.Body)<{ $disabled?: boolean; $color?: DetailedInfo['color'] }>` + color: ${(props) => props.theme.colors.selectedTheme.text.value}; + font-family: ${(props) => props.theme.fonts.mono}; + font-size: 13px; + cursor: default; - .key { - color: ${(props) => props.theme.colors.selectedTheme.text.title}; - font-size: 13px; - text-transform: capitalize; - cursor: default; - } - - .red { + ${(props) => + props.$color === 'red' && + css` color: ${(props) => props.theme.colors.selectedTheme.red}; - } + `} - .green { + ${(props) => + props.$color === 'green' && + css` color: ${(props) => props.theme.colors.selectedTheme.green}; - } + `} - .gold { + ${(props) => + props.$color === 'gold' && + css` color: ${(props) => props.theme.colors.common.primaryGold}; - } + `} - .closed { + ${(props) => + props.$disabled && + css` color: ${(props) => props.theme.colors.selectedTheme.gray}; - } - - &:not(:last-of-type) { - margin-bottom: 8px; - } - } + `} `; export default InfoBox; diff --git a/components/Input/CustomInput.tsx b/components/Input/CustomInput.tsx index eb00df6d89..9eecc3daaa 100644 --- a/components/Input/CustomInput.tsx +++ b/components/Input/CustomInput.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { memo, FC, useCallback } from 'react'; import styled from 'styled-components'; type CustomInputProps = { @@ -19,53 +19,51 @@ type CustomInputProps = { const INVALID_CHARS = ['-', '+', 'e']; -const CustomInput: React.FC = ({ - value, - placeholder, - onChange, - right, - left, - style, - className, - disabled, - id, - defaultValue, - dataTestId, - invalid, - textAlign = 'left', -}) => { - const handleChange = (e: React.ChangeEvent) => { - onChange(e, e.target.value.replace(/,/g, '.').replace(/[e+-]/gi, '')); - }; +const CustomInput: FC = memo( + ({ + value, + placeholder, + onChange, + right, + left, + disabled, + id, + defaultValue, + dataTestId, + textAlign = 'left', + ...props + }) => { + const handleChange = useCallback( + (e: React.ChangeEvent) => { + onChange(e, e.target.value.replace(/,/g, '.').replace(/[e+-]/gi, '')); + }, + [onChange] + ); - return ( - - {typeof left === 'string' ? {left} : left} - - { - if (INVALID_CHARS.includes(e.key)) { - e.preventDefault(); - } - }} - id={id} - defaultValue={defaultValue} - /> - {typeof right === 'string' ? {right} : right} - - ); -}; + return ( + + {typeof left === 'string' ? {left} : left} + { + if (INVALID_CHARS.includes(e.key)) { + e.preventDefault(); + } + }} + id={id} + defaultValue={defaultValue} + /> + {typeof right === 'string' ? {right} : right} + + ); + } +); const CustomInputContainer = styled.div<{ textAlign: string; invalid?: boolean }>` display: flex; diff --git a/components/Input/CustomNumericInput.tsx b/components/Input/CustomNumericInput.tsx index 50f2cf8e10..4bb71295f7 100644 --- a/components/Input/CustomNumericInput.tsx +++ b/components/Input/CustomNumericInput.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, FC } from 'react'; +import { ChangeEvent, FC, memo } from 'react'; import styled from 'styled-components'; import Input from './Input'; @@ -15,63 +15,61 @@ type CustomNumericInputProps = { id?: string; }; -const CustomNumericInput: FC = ({ - value, - placeholder, - suffix, - onChange, - className, - defaultValue, - maxValue, - disabled, - id, - ...rest -}) => { - const style = { - '--numchs': value.length, - '--suffix': `'${value.length === 0 ? '' : suffix}'`, - }; +const CustomNumericInput: FC = memo( + ({ + value, + placeholder, + suffix, + onChange, + className, + defaultValue, + maxValue, + disabled, + id, + ...rest + }) => { + const handleOnChange = (e: ChangeEvent) => { + const { value } = e.target; + const max = maxValue || 0; + const valueIsAboveMax = max !== 0 && Number(value) > max; + if (!valueIsAboveMax) { + onChange( + e, + value + .replace(/[^0-9.,]/g, '') + .replace(/,/g, '.') + .substring(0, 4) + ); + } + }; - const handleOnChange = (e: ChangeEvent) => { - const { value } = e.target; - const max = maxValue || 0; - const valueIsAboveMax = max !== 0 && Number(value) > max; - if (!valueIsAboveMax) { - onChange( - e, - value - .replace(/[^0-9.,]/g, '') - .replace(/,/g, '.') - .substring(0, 4) - ); - } - }; - - return ( - - - - ); -}; + return ( + + + + ); + } +); -export const InputWrapper = styled.div` +export const InputWrapper = styled.div<{ $length: number; $suffix: string }>` position: relative; overflow: hidden; ::after { position: absolute; top: calc(25%); - left: calc((var(--numchs) * 1ch + 1.3ch)); - content: var(--suffix, 'x'); + left: calc(${(props) => props.$length} * 1ch + 1.3ch)); + content: var(${(props) => (props.$length === 0 ? '' : props.$suffix)}); font-family: ${(props) => props.theme.fonts.mono}; font-size: 18px; color: ${(props) => props.theme.colors.selectedTheme.input.placeholder}; diff --git a/components/Input/InputBalanceLabel.tsx b/components/Input/InputBalanceLabel.tsx index ebfdf92abe..7acbccb5a0 100644 --- a/components/Input/InputBalanceLabel.tsx +++ b/components/Input/InputBalanceLabel.tsx @@ -2,7 +2,7 @@ import Wei from '@synthetixio/wei'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import { FlexDivRowCentered } from 'styles/common'; +import { FlexDivRowCentered } from 'components/layout/flex'; import { formatCurrency } from 'utils/formatters/number'; type Props = { diff --git a/components/Input/NumericInput.tsx b/components/Input/NumericInput.tsx index 8b5332bfc6..7b4d976ec7 100644 --- a/components/Input/NumericInput.tsx +++ b/components/Input/NumericInput.tsx @@ -1,9 +1,9 @@ -import { ChangeEvent, FC, memo, useCallback } from 'react'; -import styled from 'styled-components'; +import React, { ChangeEvent, FC, memo, useCallback } from 'react'; +import styled, { css } from 'styled-components'; import Input from './Input'; -type NumericInputProps = { +type NumericInputProps = Omit, 'onChange'> & { value: string | number; placeholder?: string; onChange: (e: ChangeEvent, value: string) => void; @@ -11,46 +11,42 @@ type NumericInputProps = { defaultValue?: any; disabled?: boolean; id?: string; + bold?: boolean; }; const INVALID_CHARS = ['-', '+', 'e']; -const NumericInput: FC = memo( - ({ value, onChange, placeholder, className, defaultValue, disabled, id, ...rest }) => { - const handleOnChange = useCallback( - (e: ChangeEvent) => { - const { value } = e.target; - - onChange(e, value.replace(/,/g, '.').replace(/[e+-]/gi, '')); - }, - [onChange] - ); - - return ( - { - if (INVALID_CHARS.includes(e.key)) { - e.preventDefault(); - } - }} - min="0" - step="any" - defaultValue={defaultValue} - disabled={disabled} - id={id} - /> - ); - } -); - -export const StyledInput = styled(Input)` +const NumericInput: FC = memo(({ onChange, bold, ...props }) => { + const handleOnChange = useCallback( + (e: ChangeEvent) => { + onChange(e, e.target.value.replace(/,/g, '.').replace(/[e+-]/gi, '')); + }, + [onChange] + ); + + return ( + { + if (INVALID_CHARS.includes(e.key)) { + e.preventDefault(); + } + }} + $bold={bold} + {...props} + /> + ); +}); + +export const StyledInput = styled(Input)<{ $bold?: boolean }>` font-family: ${(props) => props.theme.fonts.mono}; + ${(props) => + props.$bold && + css` + font-family: ${props.theme.fonts.monoBold}; + `} text-overflow: ellipsis; `; diff --git a/components/Loader/Loader.tsx b/components/Loader/Loader.tsx index d7674caac4..9ce740d111 100644 --- a/components/Loader/Loader.tsx +++ b/components/Loader/Loader.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { memo, FC } from 'react'; import LoaderIcon from 'assets/svg/app/loader.svg'; import { AbsoluteCenteredDiv } from 'styles/common'; @@ -10,23 +10,19 @@ type LoaderProps = { style?: Record; }; -export const Loader: FC = ({ - inline, - width = '38px', - height = '38px', - style = {}, - ...rest -}) => { - const loader = ; +export const Loader: FC = memo( + ({ inline, width = '38px', height = '38px', style = {}, ...rest }) => { + const loader = ; - return inline ? loader : {loader}; -}; + return inline ? loader : {loader}; + } +); Loader.defaultProps = { inline: false, }; -export const MiniLoader: FC = (props) => { +export const MiniLoader: FC = memo((props) => { return ( = (props) => { style={{ marginLeft: `${!props.centered ? '10px' : '0px'}` }} /> ); -}; +}); -export const ButtonLoader = () => { +export const ButtonLoader = memo(() => { return ; -}; +}); export default Loader; diff --git a/components/MarketClosureIcon/MarketClosureIcon.tsx b/components/MarketClosureIcon/MarketClosureIcon.tsx index ad959f0f7b..30d972ef04 100644 --- a/components/MarketClosureIcon/MarketClosureIcon.tsx +++ b/components/MarketClosureIcon/MarketClosureIcon.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import { FC, memo } from 'react'; import CircuitBreakerIcon from 'assets/svg/app/market-closure/circuit-breaker.svg'; import EmergencyShutdownIcon from 'assets/svg/app/market-closure/emergency-shutdown.svg'; @@ -11,30 +11,26 @@ type MarketClosureIconProps = { size?: 'sm' | 'lg'; }; -export const MarketClosureIcon: FC = ({ - marketClosureReason, - size = 'lg', -}) => { - const sharedProps = { - width: size === 'sm' ? 16 : 32, - height: size === 'sm' ? 16 : 32, - className: 'market-closure-icon', - }; +export const MarketClosureIcon: FC = memo( + ({ marketClosureReason, size = 'lg' }) => { + const sharedProps = { + width: size === 'sm' ? 16 : 32, + height: size === 'sm' ? 16 : 32, + className: 'market-closure-icon', + }; - const defaultIcon = ; - - switch (marketClosureReason) { - case 'frozen': - return ; - case 'market-closure': - return defaultIcon; - case 'circuit-breaker': - return ; - case 'emergency': - return ; - default: - return defaultIcon; + switch (marketClosureReason) { + case 'frozen': + return ; + case 'circuit-breaker': + return ; + case 'emergency': + return ; + case 'market-closure': + default: + return ; + } } -}; +); export default MarketClosureIcon; diff --git a/components/Nav/DropDownLabel.tsx b/components/Nav/DropDownLabel.tsx index e69dabe02c..f36a278cd4 100644 --- a/components/Nav/DropDownLabel.tsx +++ b/components/Nav/DropDownLabel.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; -import { FlexDivRow } from 'styles/common'; +import { FlexDivRow } from 'components/layout/flex'; export const LabelContainer = styled(FlexDivRow)<{ noPadding?: boolean }>` padding: ${(props) => !props.noPadding && '16px'}; diff --git a/components/Nav/NavLink.tsx b/components/Nav/NavLink.tsx new file mode 100644 index 0000000000..c07ffa028e --- /dev/null +++ b/components/Nav/NavLink.tsx @@ -0,0 +1,57 @@ +import Link from 'next/link'; +import React from 'react'; +import styled from 'styled-components'; + +import { linkCSS } from 'styles/common'; + +type NavButtonProps = { + title: string; + isActive: boolean; + href: string; + disabled?: boolean; + external?: boolean; +}; + +const NavButton: React.FC = ({ title, href, external, disabled, ...props }) => { + return ( +
+ + + {title} + + +
+ ); +}; + +const StyledLink = styled.a<{ isActive: boolean; disabled?: boolean }>` + ${linkCSS}; + display: inline-block; + padding: 10px 14px; + margin: 8px 0; + font-family: ${(props) => props.theme.fonts.bold}; + font-size: 15px; + text-transform: capitalize; + border-radius: 100px; + background: ${(props) => + props.isActive ? props.theme.colors.selectedTheme.button.fill : 'transparent'}; + color: ${(props) => + props.isActive + ? props.theme.colors.selectedTheme.button.text.primary + : props.theme.colors.selectedTheme.gray}; + &:hover { + background: ${(props) => props.theme.colors.selectedTheme.button.fill}; + } + + &.disabled { + color: ${(props) => props.theme.colors.selectedTheme.button.disabled.text}; + background: transparent; + pointer-events: none; + } +`; + +export default NavButton; diff --git a/components/PoweredBySynthetix/PoweredBySynthetix.tsx b/components/PoweredBySynthetix/PoweredBySynthetix.tsx index 52a968a728..6a2b6cd6df 100644 --- a/components/PoweredBySynthetix/PoweredBySynthetix.tsx +++ b/components/PoweredBySynthetix/PoweredBySynthetix.tsx @@ -3,8 +3,10 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import TextLogo from 'assets/svg/brand/text-logo-white.svg'; +import { FlexDivColCentered } from 'components/layout/flex'; +import { Body } from 'components/Text'; import { EXTERNAL_LINKS } from 'constants/links'; -import { ExternalLink, FlexDivColCentered, Paragraph } from 'styles/common'; +import { ExternalLink } from 'styles/common'; const PoweredBySynthetix = () => { const { t } = useTranslation(); @@ -22,13 +24,12 @@ const Container = styled(FlexDivColCentered)` row-gap: 5px; `; -const Text = styled(Paragraph)` +const Text = styled(Body)` font-size: 10px; color: ${(props) => props.theme.colors.common.primaryWhite}; opacity: 0.5; letter-spacing: 0.04em; font-variant: small-caps; - font-family: ${(props) => props.theme.fonts.regular}; text-transform: uppercase; line-height: 100%; text-align: center; diff --git a/components/PreviewArrow/PreviewArrow.tsx b/components/PreviewArrow/PreviewArrow.tsx index 051471eb59..d11ef4a60e 100644 --- a/components/PreviewArrow/PreviewArrow.tsx +++ b/components/PreviewArrow/PreviewArrow.tsx @@ -1,20 +1,26 @@ +import { memo } from 'react'; import styled from 'styled-components'; +import { MiniLoader } from 'components/Loader'; + type TextColor = 'yellow' | 'red'; type PreviewArrowProps = { color?: TextColor; showPreview: boolean; + loading?: boolean; }; -const PreviewArrow: React.FC = ({ showPreview, children, color }) => { - return showPreview ? ( - <> - - {children} - - ) : null; -}; +const PreviewArrow: React.FC = memo( + ({ showPreview, children, color, loading }) => { + return showPreview ? ( + <> + + {loading ? : children} + + ) : null; + } +); const StyledArrow = styled.span` ::before { diff --git a/components/ProgressBar/ProgressBar.tsx b/components/ProgressBar/ProgressBar.tsx deleted file mode 100644 index 48a0637b6e..0000000000 --- a/components/ProgressBar/ProgressBar.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { FC } from 'react'; -import styled from 'styled-components'; - -type ProgressBarProps = { - percentage: number; -}; - -const ProgressBar: FC = ({ percentage }) => ( - - - -); - -const ProgressBarWrapper = styled.div` - background-color: ${(props) => props.theme.colors.navy}; -`; - -const Bar = styled.div<{ percentage: number }>` - height: 100%; - width: ${(props) => props.percentage * 100}%; - height: 4px; - background: ${(props) => props.theme.colors.gold}; -`; - -export default ProgressBar; diff --git a/components/ProgressBar/index.ts b/components/ProgressBar/index.ts deleted file mode 100644 index 84bf041ae7..0000000000 --- a/components/ProgressBar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ProgressBar'; diff --git a/components/ProgressSteps/ProgressSteps.tsx b/components/ProgressSteps/ProgressSteps.tsx index 63af4bc8b7..062a1c1b36 100644 --- a/components/ProgressSteps/ProgressSteps.tsx +++ b/components/ProgressSteps/ProgressSteps.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, memo } from 'react'; import styled from 'styled-components'; type Props = { @@ -7,7 +7,7 @@ type Props = { complete?: boolean; }; -const ProgressSteps: FC = ({ step, totalSteps, complete }) => { +const ProgressSteps: FC = memo(({ step, totalSteps, complete }) => { const stepList = [...Array(totalSteps)]; return (
@@ -30,7 +30,7 @@ const ProgressSteps: FC = ({ step, totalSteps, complete }) => {
); -}; +}); const BAR_HEIGHT = 3; const CIRCLE_HEIGHT = 18; diff --git a/components/README.md b/components/README.md new file mode 100644 index 0000000000..90bfef15f2 --- /dev/null +++ b/components/README.md @@ -0,0 +1,3 @@ +# Kwenta Components + +## Folder Structure diff --git a/components/StakeCard/StakeCard.tsx b/components/StakeCard/StakeCard.tsx index 969dbe38a6..dc722ec45d 100644 --- a/components/StakeCard/StakeCard.tsx +++ b/components/StakeCard/StakeCard.tsx @@ -5,10 +5,11 @@ import styled from 'styled-components'; import Button from 'components/Button'; import NumericInput from 'components/Input/NumericInput'; +import { FlexDivRowCentered } from 'components/layout/flex'; import SegmentedControl from 'components/SegmentedControl'; +import { StakingCard } from 'sections/dashboard/Stake/card'; import { DEFAULT_CRYPTO_DECIMALS, DEFAULT_TOKEN_DECIMALS } from 'constants/defaults'; -import { StakingCard } from 'sections/dashboard/Stake/common'; -import { FlexDivRowCentered, numericValueCSS } from 'styles/common'; +import { numericValueCSS } from 'styles/common'; import { toWei, truncateNumbers } from 'utils/formatters/number'; type StakeCardProps = { @@ -111,7 +112,7 @@ const StakeCard: FC = memo(
- +
), accessor: 'market', - Cell: (cellProps: CellProps) => { + Cell: (cellProps: CellProps) => { return (
@@ -290,7 +288,7 @@ const FuturesMarketsTable: FC = () => { {cellProps.row.original.market} {
), accessor: 'openInterest', - Cell: (cellProps: CellProps) => { + Cell: (cellProps: CellProps) => { return (
{
), accessor: '24h-change', - Cell: (cellProps: CellProps) => { + Cell: (cellProps: CellProps) => { return (
@@ -359,7 +357,7 @@ const FuturesMarketsTable: FC = () => {
props.theme.colors.selectedTheme.gray}; @@ -423,10 +420,6 @@ const StyledTable = styled(Table)` margin-bottom: 20px; `; -const TableHeader = styled.div` - color: ${(props) => props.theme.colors.selectedTheme.gray}; -`; - const StyledText = styled.div` display: flex; align-items: center; diff --git a/sections/dashboard/FuturesPositionsTable/FuturesPositionsTable.tsx b/sections/dashboard/FuturesPositionsTable/FuturesPositionsTable.tsx index 8bb8cb9662..24d36efd9f 100644 --- a/sections/dashboard/FuturesPositionsTable/FuturesPositionsTable.tsx +++ b/sections/dashboard/FuturesPositionsTable/FuturesPositionsTable.tsx @@ -39,7 +39,7 @@ type FuturesPositionTableProps = { const FuturesPositionsTable: FC = ({ accountType, showCurrentMarket = true, -}: FuturesPositionTableProps) => { +}) => { const { t } = useTranslation(); const { synthsMap } = Connector.useContainer(); const router = useRouter(); @@ -167,9 +167,9 @@ const FuturesPositionsTable: FC = ({ return ( @@ -204,9 +204,9 @@ const FuturesPositionsTable: FC = ({
@@ -231,9 +231,9 @@ const FuturesPositionsTable: FC = ({ {NO_VALUE} ) : ( @@ -255,9 +255,9 @@ const FuturesPositionsTable: FC = ({ }; return ( diff --git a/sections/dashboard/FuturesPositionsTable/MobilePositionRow.tsx b/sections/dashboard/FuturesPositionsTable/MobilePositionRow.tsx index c67c269e19..fe18a5fac6 100644 --- a/sections/dashboard/FuturesPositionsTable/MobilePositionRow.tsx +++ b/sections/dashboard/FuturesPositionsTable/MobilePositionRow.tsx @@ -1,5 +1,5 @@ import { wei } from '@synthetixio/wei'; -import React from 'react'; +import { memo, FC } from 'react'; import styled, { css } from 'styled-components'; import { border } from 'components/Button'; @@ -18,7 +18,7 @@ type MobilePositionRowProps = { onClick(): void; }; -const MobilePositionRow: React.FC = ({ row, onClick }) => { +const MobilePositionRow: FC = memo(({ row, onClick }) => { const prices = useAppSelector(selectPrices); const marketPrice = prices[row.market.asset]?.offChain ?? prices[row.market.asset]?.onChain ?? wei(0); @@ -44,7 +44,7 @@ const MobilePositionRow: React.FC = ({ row, onClick }) =
= ({ row, onClick }) =
= ({ row, onClick }) =
- +
); -}; +}); const OpenPositionContainer = styled.div<{ side?: PositionSide }>` display: flex; diff --git a/sections/dashboard/FuturesPositionsTable/constants.ts b/sections/dashboard/FuturesPositionsTable/constants.ts deleted file mode 100644 index e696e136f8..0000000000 --- a/sections/dashboard/FuturesPositionsTable/constants.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NO_VALUE } from 'constants/placeholder'; - -export const DEFAULT_DATA = [ - { - asset: NO_VALUE, - market: NO_VALUE, - description: NO_VALUE, - notionalValue: NO_VALUE, - position: NO_VALUE, - avgEntryPrice: undefined, - liquidationPrice: NO_VALUE, - pnl: undefined, - pnlPct: undefined, - margin: NO_VALUE, - leverage: NO_VALUE, - size: undefined, - }, -]; diff --git a/sections/dashboard/MobileDashboard/FuturesMarkets.tsx b/sections/dashboard/MobileDashboard/FuturesMarkets.tsx index ee8414d7fc..5e6d581f0b 100644 --- a/sections/dashboard/MobileDashboard/FuturesMarkets.tsx +++ b/sections/dashboard/MobileDashboard/FuturesMarkets.tsx @@ -2,29 +2,19 @@ import { wei } from '@synthetixio/wei'; import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { SectionHeader, SectionTitle } from 'sections/futures/MobileTrade/common'; -import { selectMarkets, selectMarketVolumes } from 'state/futures/selectors'; +import { HeaderContainer, MarketStatsContainer, MarketStat } from 'sections/dashboard/mobile'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; +import { selectMarketVolumes, selectOpenInterest } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { formatDollars, formatNumber, zeroBN } from 'utils/formatters/number'; +import { formatDollars, formatNumber } from 'utils/formatters/number'; import FuturesMarketsTable from '../FuturesMarketsTable'; -import { HeaderContainer, MarketStatsContainer, MarketStat } from './common'; const FuturesMarkets = () => { const { t } = useTranslation(); - const futuresMarkets = useAppSelector(selectMarkets); const futuresVolumes = useAppSelector(selectMarketVolumes); - - const openInterest = useMemo(() => { - return ( - futuresMarkets.reduce( - (total, { openInterest }) => - total.add(openInterest?.shortUSD ?? wei(0)).add(openInterest?.longUSD ?? wei(0)), - wei(0) - ) ?? null - ); - }, [futuresMarkets]); + const openInterest = useAppSelector(selectOpenInterest); const [trades, volume] = useMemo(() => { const { totalTrades, totalVolume } = Object.values(futuresVolumes).reduce( @@ -32,10 +22,7 @@ const FuturesMarkets = () => { totalTrades: totalTrades.add(trades), totalVolume: totalVolume.add(volume), }), - { - totalTrades: wei(0), - totalVolume: wei(0), - } + { totalTrades: wei(0), totalVolume: wei(0) } ); return [totalTrades, totalVolume]; }, [futuresVolumes]); @@ -51,11 +38,7 @@ const FuturesMarkets = () => {
{t('dashboard.overview.futures-markets-table.daily-volume')}
-
- {formatDollars(volume ?? zeroBN, { - minDecimals: 0, - })} -
+
{formatDollars(volume, { minDecimals: 0 })}
@@ -67,7 +50,7 @@ const FuturesMarkets = () => {
{t('dashboard.overview.futures-markets-table.daily-trades')}
-
{formatNumber(trades ?? 0, { minDecimals: 0 })}
+
{formatNumber(trades, { minDecimals: 0 })}
diff --git a/sections/dashboard/MobileDashboard/MobileDashboard.tsx b/sections/dashboard/MobileDashboard/MobileDashboard.tsx index bb6df11ec8..acd0a11b97 100644 --- a/sections/dashboard/MobileDashboard/MobileDashboard.tsx +++ b/sections/dashboard/MobileDashboard/MobileDashboard.tsx @@ -1,4 +1,3 @@ -import Wei from '@synthetixio/wei'; import { FC } from 'react'; import { useRecoilState } from 'recoil'; @@ -16,7 +15,7 @@ const MobileDashboard: FC = ({ exchangeTokens }) => { const [activePositionsTab, setActivePositionsTab] = useRecoilState(activePositionsTabState); const exchangeTokenBalances = exchangeTokens.reduce( - (initial: Wei, { usdBalance }) => initial.add(usdBalance), + (initial, { usdBalance }) => initial.add(usdBalance), zeroBN ); diff --git a/sections/dashboard/MobileDashboard/OpenPositions.tsx b/sections/dashboard/MobileDashboard/OpenPositions.tsx index d0e8c545c8..fd55f564af 100644 --- a/sections/dashboard/MobileDashboard/OpenPositions.tsx +++ b/sections/dashboard/MobileDashboard/OpenPositions.tsx @@ -5,12 +5,12 @@ import { SetterOrUpdater } from 'recoil'; import styled from 'styled-components'; import TabButton from 'components/Button/TabButton'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import { TabPanel } from 'components/Tab'; import { FuturesAccountTypes } from 'queries/futures/types'; -import { SectionHeader, SectionTitle } from 'sections/futures/MobileTrade/common'; import { selectBalances } from 'state/balances/selectors'; import { - selectCrossMarginPositions, + // selectCrossMarginPositions, selectFuturesPortfolio, selectIsolatedMarginPositions, } from 'state/futures/selectors'; @@ -43,7 +43,7 @@ const OpenPositions: React.FC = ({ exchangeTokenBalances, }) => { const { t } = useTranslation(); - const crossPositions = useAppSelector(selectCrossMarginPositions); + // const crossPositions = useAppSelector(selectCrossMarginPositions); const isolatedPositions = useAppSelector(selectIsolatedMarginPositions); const portfolio = useAppSelector(selectFuturesPortfolio); const balances = useAppSelector(selectBalances); @@ -80,9 +80,9 @@ const OpenPositions: React.FC = ({ [ t, isolatedPositions, - crossPositions, + // crossPositions, activePositionsTab, - portfolio.crossMarginFutures, + // portfolio.crossMarginFutures, portfolio.isolatedMarginFutures, balances.totalUSDBalance, exchangeTokenBalances, @@ -121,13 +121,10 @@ const OpenPositions: React.FC = ({ const TabButtonsContainer = styled.div` display: flex; - margin-top: 16px; - margin-bottom: 16px; + margin: 16px 0; - & > button { - &:not(:last-of-type) { - margin-right: 14px; - } + & > button:not(:last-of-type) { + margin-right: 14px; } `; diff --git a/sections/dashboard/MobileDashboard/Portfolio.tsx b/sections/dashboard/MobileDashboard/Portfolio.tsx index 922f1128e4..670def5a15 100644 --- a/sections/dashboard/MobileDashboard/Portfolio.tsx +++ b/sections/dashboard/MobileDashboard/Portfolio.tsx @@ -2,7 +2,7 @@ import Wei from '@synthetixio/wei'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { SectionHeader, SectionTitle } from 'sections/futures/MobileTrade/common'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import PortfolioChart from '../PortfolioChart'; diff --git a/sections/dashboard/MobileDashboard/SpotMarkets.tsx b/sections/dashboard/MobileDashboard/SpotMarkets.tsx index 24972006d6..57ba29ade6 100644 --- a/sections/dashboard/MobileDashboard/SpotMarkets.tsx +++ b/sections/dashboard/MobileDashboard/SpotMarkets.tsx @@ -2,10 +2,10 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import { SectionHeader, SectionTitle } from 'sections/futures/MobileTrade/common'; +import { HeaderContainer } from 'sections/dashboard/mobile'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import SpotMarketsTable from '../SpotMarketsTable'; -import { HeaderContainer } from './common'; const SpotMarkets: React.FC = () => { const { t } = useTranslation(); diff --git a/sections/dashboard/MobileDashboard/common.ts b/sections/dashboard/MobileDashboard/common.ts deleted file mode 100644 index 3e65c8d7ca..0000000000 --- a/sections/dashboard/MobileDashboard/common.ts +++ /dev/null @@ -1,30 +0,0 @@ -import styled from 'styled-components'; - -export const HeaderContainer = styled.div` - padding: 15px; -`; - -export const MarketStatsContainer = styled.div` - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-gap: 8px; -`; - -export const MarketStat = styled.div` - border-radius: 8px; - box-sizing: border-box; - padding: 10px; - border: ${(props) => props.theme.colors.selectedTheme.border}; - - .title { - font-size: 12px; - color: ${(props) => props.theme.colors.selectedTheme.gray}; - margin-bottom: 4px; - } - - .value { - font-size: 16px; - font-family: ${(props) => props.theme.fonts.bold}; - color: ${(props) => props.theme.colors.selectedTheme.text.value}; - } -`; diff --git a/sections/dashboard/Overview/Overview.tsx b/sections/dashboard/Overview/Overview.tsx index 8abf2b70a2..bd96a2b749 100644 --- a/sections/dashboard/Overview/Overview.tsx +++ b/sections/dashboard/Overview/Overview.tsx @@ -15,7 +15,7 @@ import { CompetitionBanner } from 'sections/shared/components/CompetitionBanner' import { selectBalances } from 'state/balances/selectors'; import { sdk } from 'state/config'; import { - selectActiveCrossPositionsCount, + // selectActiveCrossPositionsCount, selectActiveIsolatedPositionsCount, selectFuturesPortfolio, } from 'state/futures/selectors'; @@ -44,12 +44,10 @@ const Overview: FC = () => { const balances = useAppSelector(selectBalances); const portfolio = useAppSelector(selectFuturesPortfolio); const isolatedPositionsCount = useAppSelector(selectActiveIsolatedPositionsCount); - const crossPositionsCount = useAppSelector(selectActiveCrossPositionsCount); + // const crossPositionsCount = useAppSelector(selectActiveCrossPositionsCount); - const [activePositionsTab, setActivePositionsTab] = useRecoilState( - activePositionsTabState - ); - const [activeMarketsTab, setActiveMarketsTab] = useState(MarketsTab.FUTURES); + const [activePositionsTab, setActivePositionsTab] = useRecoilState(activePositionsTabState); + const [activeMarketsTab, setActiveMarketsTab] = useState(MarketsTab.FUTURES); const { network, synthsMap } = Connector.useContainer(); @@ -147,13 +145,13 @@ const Overview: FC = () => { }, ]; }, [ - crossPositionsCount, + // crossPositionsCount, isolatedPositionsCount, exchangeTokens, balances.totalUSDBalance, t, activePositionsTab, - portfolio.crossMarginFutures, + // portfolio.crossMarginFutures, portfolio.isolatedMarginFutures, setActivePositionsTab, ]); diff --git a/sections/dashboard/PortfolioChart/PortfolioChart.tsx b/sections/dashboard/PortfolioChart/PortfolioChart.tsx index 286900d4f6..63c84d151b 100644 --- a/sections/dashboard/PortfolioChart/PortfolioChart.tsx +++ b/sections/dashboard/PortfolioChart/PortfolioChart.tsx @@ -4,6 +4,7 @@ import styled from 'styled-components'; import Currency from 'components/Currency'; import { MobileHiddenView, MobileOnlyView } from 'components/Media'; +import * as Text from 'components/Text'; import { selectBalances } from 'state/balances/selectors'; import { selectFuturesPortfolio } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; @@ -27,11 +28,11 @@ const PortfolioChart: FC = ({ exchangeTokenBalances }) => { Portfolio Value - + - + @@ -45,14 +46,12 @@ const Chart = styled.div` height: 200px; `; -const PortfolioTitle = styled.p` +const PortfolioTitle = styled(Text.Body).attrs({ variant: 'bold' })` color: ${(props) => props.theme.colors.selectedTheme.gray}; - font-family: ${(props) => props.theme.fonts.bold}; font-size: 16px; - margin-top: 26px; - margin-left: 26px; - margin-bottom: 10px; + margin: 26px 0 10px 26px; `; + const PortfolioText = styled(Currency.Price)` color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; font-family: ${(props) => props.theme.fonts.monoBold}; diff --git a/sections/dashboard/SpotHistoryTable/SpotHistoryTable.tsx b/sections/dashboard/SpotHistoryTable/SpotHistoryTable.tsx index a9ef3b87a8..c58d559b20 100644 --- a/sections/dashboard/SpotHistoryTable/SpotHistoryTable.tsx +++ b/sections/dashboard/SpotHistoryTable/SpotHistoryTable.tsx @@ -1,6 +1,4 @@ import { SynthExchangeResult } from '@synthetixio/queries'; -import * as _ from 'lodash/fp'; -import values from 'lodash/values'; import Link from 'next/link'; import { FC, useMemo, ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; @@ -29,20 +27,20 @@ type WalletTradesExchangeResult = Omit & timestamp: number; }; +const conditionalRender = (prop: T, children: ReactElement) => + !prop ?

{NO_VALUE}

: children; + const SpotHistoryTable: FC = () => { const { t } = useTranslation(); const { network, walletAddress, synthsMap } = Connector.useContainer(); const { selectPriceCurrencyRate, selectedPriceCurrency } = useSelectedPriceCurrency(); const walletTradesQuery = useGetWalletTrades(walletAddress!); - const synths = useMemo(() => values(synthsMap) || [], [synthsMap]); + const synths = useMemo(() => Object.values(synthsMap) || [], [synthsMap]); const trades = useMemo(() => { const t = walletTradesQuery.data?.synthExchanges ?? []; - return t.map((trade: any) => ({ - ...trade, - hash: trade.id.split('-')[0], - })); + return t.map((trade: any) => ({ ...trade, hash: trade.id.split('-')[0] })); }, [walletTradesQuery.data]); const filteredHistoricalTrades = useMemo( @@ -54,9 +52,6 @@ const SpotHistoryTable: FC = () => { [trades, synths] ); - const conditionalRender = (prop: T, children: ReactElement): ReactElement => - _.isNil(prop) ?

{NO_VALUE}

: children; - return ( { return conditionalRender( cellProps.row.original.timestamp, - + ); }, @@ -105,7 +100,7 @@ const SpotHistoryTable: FC = () => { { { : {}; return ( @@ -161,9 +161,9 @@ const SpotMarketsTable: FC = () => { Cell: (cellProps: CellProps) => { return ( ); @@ -258,9 +258,9 @@ const SpotMarketsTable: FC = () => { Cell: (cellProps: CellProps) => { return ( ); diff --git a/sections/dashboard/Stake/EscrowTable.tsx b/sections/dashboard/Stake/EscrowTable.tsx index 0344fb2eb4..cbf1d8cc31 100644 --- a/sections/dashboard/Stake/EscrowTable.tsx +++ b/sections/dashboard/Stake/EscrowTable.tsx @@ -5,13 +5,13 @@ import styled from 'styled-components'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import Table from 'components/Table'; -import { TableCellHead } from 'components/Table/Table'; +import { TableCellHead, TableHeader } from 'components/Table'; import type { EscrowData } from 'sdk/services/kwentaToken'; +import { StakingCard } from 'sections/dashboard/Stake/card'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { vestEscrowedRewards } from 'state/staking/actions'; import { truncateNumbers, zeroBN } from 'utils/formatters/number'; -import { StakingCard } from './common'; import VestConfirmationModal from './VestConfirmationModal'; const EscrowTable = () => { @@ -102,7 +102,9 @@ const EscrowTable = () => { width: 40, }, { - Header: () => {t('dashboard.stake.tabs.escrow.date')}, + Header: () => ( + {t('dashboard.stake.tabs.escrow.date')} + ), Cell: (cellProps: CellProps) => ( {cellProps.row.original.date} ), @@ -111,7 +113,7 @@ const EscrowTable = () => { }, { Header: () => ( - +
{t('dashboard.stake.tabs.escrow.time-until-vestable')}
), @@ -123,7 +125,7 @@ const EscrowTable = () => { }, { Header: () => ( - +
{t('dashboard.stake.tabs.escrow.immediately-vestable')}
), @@ -134,7 +136,9 @@ const EscrowTable = () => { width: 80, }, { - Header: () => {t('dashboard.stake.tabs.escrow.amount')}, + Header: () => ( + {t('dashboard.stake.tabs.escrow.amount')} + ), Cell: (cellProps: CellProps) => ( {truncateNumbers(cellProps.row.original.amount, 4)} ), @@ -143,7 +147,7 @@ const EscrowTable = () => { }, { Header: () => ( - +
{t('dashboard.stake.tabs.escrow.early-vest-fee')}
), @@ -154,7 +158,9 @@ const EscrowTable = () => { width: 80, }, { - Header: () => {t('dashboard.stake.tabs.escrow.status')}, + Header: () => ( + {t('dashboard.stake.tabs.escrow.status')} + ), Cell: (cellProps: CellProps) => ( {cellProps.row.original.status} ), @@ -186,7 +192,9 @@ const EscrowTable = () => { width: 40, }, { - Header: () => {t('dashboard.stake.tabs.escrow.amount')}, + Header: () => ( + {t('dashboard.stake.tabs.escrow.amount')} + ), Cell: (cellProps: CellProps) => ( {truncateNumbers(cellProps.row.original.amount, 4)} ), @@ -195,7 +203,7 @@ const EscrowTable = () => { }, { Header: () => ( - {t('dashboard.stake.tabs.escrow.early-vest-fee')} + {t('dashboard.stake.tabs.escrow.early-vest-fee')} ), Cell: (cellProps: CellProps) => ( {truncateNumbers(cellProps.row.original.fee, 4)} @@ -204,7 +212,9 @@ const EscrowTable = () => { width: 80, }, { - Header: () => {t('dashboard.stake.tabs.escrow.status')}, + Header: () => ( + {t('dashboard.stake.tabs.escrow.status')} + ), Cell: (cellProps: CellProps) => ( {cellProps.row.original.status} ), @@ -264,12 +274,6 @@ const StyledTable = styled(Table)` } `; -const TableHeader = styled.div` - font-size: 10px; - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.text.header}; -`; - const TableCell = styled.div` font-size: 11px; color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; diff --git a/sections/dashboard/Stake/InputCards/RedeemInputCard.tsx b/sections/dashboard/Stake/InputCards/RedeemInputCard.tsx index 2051161ded..8611849f4a 100644 --- a/sections/dashboard/Stake/InputCards/RedeemInputCard.tsx +++ b/sections/dashboard/Stake/InputCards/RedeemInputCard.tsx @@ -3,6 +3,8 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; +import { FlexDivRowCentered } from 'components/layout/flex'; +import { StakingCard } from 'sections/dashboard/Stake/card'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { approveKwentaToken, redeemToken } from 'state/staking/actions'; import { @@ -11,11 +13,9 @@ import { selectVeKwentaBalance, selectVKwentaBalance, } from 'state/staking/selectors'; -import { FlexDivRowCentered, numericValueCSS } from 'styles/common'; +import { numericValueCSS } from 'styles/common'; import { truncateNumbers } from 'utils/formatters/number'; -import { StakingCard } from '../common'; - type RedeemInputCardProps = { inputLabel: string; isVKwenta: boolean; diff --git a/sections/dashboard/Stake/RedemptionTab.tsx b/sections/dashboard/Stake/RedemptionTab.tsx index 725b039e83..2067af54b6 100644 --- a/sections/dashboard/Stake/RedemptionTab.tsx +++ b/sections/dashboard/Stake/RedemptionTab.tsx @@ -1,7 +1,6 @@ import { useTranslation } from 'react-i18next'; -import styled from 'styled-components'; -import media from 'styles/media'; +import { SplitContainer } from 'components/layout/grid'; import RedeemInputCard from './InputCards/RedeemInputCard'; @@ -9,34 +8,14 @@ const RedemptionTab = () => { const { t } = useTranslation(); return ( - + - + ); }; -const StakingTabContainer = styled.div` - ${media.greaterThan('mdUp')` - display: grid; - grid-template-columns: 1fr 1fr; - & > div { - flex: 1; - - &:first-child { - margin-right: 15px; - } - } - `} - - ${media.lessThan('mdUp')` - & > div:first-child { - margin-bottom: 15px; - } - `} -`; - export default RedemptionTab; diff --git a/sections/dashboard/Stake/StakingPortfolio.tsx b/sections/dashboard/Stake/StakingPortfolio.tsx index ce5addf80c..8790704b20 100644 --- a/sections/dashboard/Stake/StakingPortfolio.tsx +++ b/sections/dashboard/Stake/StakingPortfolio.tsx @@ -3,8 +3,10 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import TabButton from 'components/Button/TabButton'; +import { Heading } from 'sections/earn/text'; +import { FlexDivRowCentered } from 'components/layout/flex'; +import { SplitStakingCard } from 'sections/dashboard/Stake/card'; import { EXTERNAL_LINKS } from 'constants/links'; -import { Heading } from 'sections/earn/common'; import { useAppSelector } from 'state/hooks'; import { selectClaimableBalance, @@ -14,12 +16,9 @@ import { selectStakedKwentaBalance, selectTotalVestable, } from 'state/staking/selectors'; -import { FlexDivRowCentered } from 'styles/common'; import media from 'styles/media'; import { truncateNumbers } from 'utils/formatters/number'; -import { SplitStakingCard } from './common'; - export enum StakeTab { Staking = 'staking', Escrow = 'escrow', diff --git a/sections/dashboard/Stake/StakingTab.tsx b/sections/dashboard/Stake/StakingTab.tsx index 44e0f1723d..102d709acd 100644 --- a/sections/dashboard/Stake/StakingTab.tsx +++ b/sections/dashboard/Stake/StakingTab.tsx @@ -3,14 +3,14 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; +import { SplitContainer } from 'components/layout/grid'; +import { StakingCard } from 'sections/dashboard/Stake/card'; import { LogoText } from 'components/Text'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { getReward } from 'state/staking/actions'; import { selectAPY, selectClaimableBalance } from 'state/staking/selectors'; -import media from 'styles/media'; import { formatPercent, truncateNumbers } from 'utils/formatters/number'; -import { StakingCard } from './common'; import StakeInputCard from './InputCards/StakeInputCard'; const StakingTab = () => { @@ -25,7 +25,7 @@ const StakingTab = () => { }, [dispatch]); return ( - +
@@ -48,24 +48,10 @@ const StakingTab = () => { - + ); }; -const StakingTabContainer = styled.div` - ${media.greaterThan('mdUp')` - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 15px; - `} - - ${media.lessThan('mdUp')` - & > div:first-child { - margin-bottom: 15px; - } - `} -`; - const CardGridContainer = styled(StakingCard)` display: flex; flex-direction: column; diff --git a/sections/dashboard/Stake/StakingTabs.tsx b/sections/dashboard/Stake/StakingTabs.tsx index 267ed04d5b..146999f007 100644 --- a/sections/dashboard/Stake/StakingTabs.tsx +++ b/sections/dashboard/Stake/StakingTabs.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import TabButton from 'components/Button/TabButton'; +import { FlexDivRowCentered } from 'components/layout/flex'; import LabelContainer from 'components/Nav/DropDownLabel'; import Select from 'components/Select'; import { DropdownIndicator, IndicatorSeparator } from 'components/Select/Select'; @@ -11,7 +12,6 @@ import useIsL2 from 'hooks/useIsL2'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { setSelectedEpoch } from 'state/staking/reducer'; import { selectEpochData, selectSelectedEpoch } from 'state/staking/selectors'; -import { FlexDivRowCentered } from 'styles/common'; import media from 'styles/media'; import EscrowTab from './EscrowTab'; diff --git a/sections/dashboard/Stake/TradingRewardsTab.tsx b/sections/dashboard/Stake/TradingRewardsTab.tsx index cdc0ee121e..b8239dd853 100644 --- a/sections/dashboard/Stake/TradingRewardsTab.tsx +++ b/sections/dashboard/Stake/TradingRewardsTab.tsx @@ -1,14 +1,16 @@ import { wei } from '@synthetixio/wei'; import { BigNumber } from 'ethers'; import { formatEther } from 'ethers/lib/utils.js'; -import { useCallback, useMemo, FC } from 'react'; +import { useCallback, useMemo, FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import HelpIcon from 'assets/svg/app/question-mark.svg'; import Button from 'components/Button'; -import { LogoText } from 'components/Text'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import { FlexDivRow } from 'components/layout/flex'; +import { SplitContainer } from 'components/layout/grid'; +import { Body, LogoText } from 'components/Text'; +import Tooltip from 'components/Tooltip/Tooltip'; import Connector from 'containers/Connector'; import useGetFile from 'queries/files/useGetFile'; import useGetFuturesFee from 'queries/staking/useGetFuturesFee'; @@ -18,153 +20,148 @@ import { FuturesFeeProps, TradingRewardProps, } from 'queries/staking/utils'; +import { StakingCard } from 'sections/dashboard/Stake/card'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { claimMultipleRewards } from 'state/staking/actions'; import { selectEpochPeriod, selectResetTime, selectTotalRewards } from 'state/staking/selectors'; -import { FlexDivRow } from 'styles/common'; import media from 'styles/media'; import { formatTruncatedDuration } from 'utils/formatters/date'; import { formatDollars, formatPercent, truncateNumbers, zeroBN } from 'utils/formatters/number'; -import { StakingCard } from './common'; - -const TradingRewardsTab: FC = ({ - period = 0, - start = 0, - end = Math.floor(Date.now() / 1000), -}) => { - const { t } = useTranslation(); - const { walletAddress, network } = Connector.useContainer(); - const dispatch = useAppDispatch(); - - const resetTime = useAppSelector(selectResetTime); - const totalRewards = useAppSelector(selectTotalRewards); - const epochPeriod = useAppSelector(selectEpochPeriod); - - const futuresFeeQuery = useGetFuturesFeeForAccount(walletAddress!, start, end); - const futuresFeePaid = useMemo(() => { - const t: FuturesFeeForAccountProps[] = futuresFeeQuery.data ?? []; - - return t - .map((trade) => formatEther(trade.feesPaid.toString())) - .reduce((acc, curr) => acc.add(wei(curr)), zeroBN); - }, [futuresFeeQuery.data]); - - const totalFuturesFeeQuery = useGetFuturesFee(start, end); - const totalFuturesFeePaid = useMemo(() => { - const t: FuturesFeeProps[] = totalFuturesFeeQuery.data ?? []; - - return t - .map((trade) => formatEther(trade.feesCrossMarginAccounts.toString())) - .reduce((acc, curr) => acc.add(wei(curr)), zeroBN); - }, [totalFuturesFeeQuery.data]); - - const estimatedRewardQuery = useGetFile( - `trading-rewards-snapshots/${network.id === 420 ? `goerli-` : ''}epoch-current.json` - ); - const estimatedReward = useMemo( - () => BigNumber.from(estimatedRewardQuery?.data?.claims[walletAddress!]?.amount ?? 0), - [estimatedRewardQuery?.data?.claims, walletAddress] - ); - const weeklyRewards = useMemo(() => BigNumber.from(estimatedRewardQuery?.data?.tokenTotal ?? 0), [ - estimatedRewardQuery?.data?.tokenTotal, - ]); - - const claimDisabled = useMemo(() => totalRewards.lte(0), [totalRewards]); - - const handleClaim = useCallback(() => { - dispatch(claimMultipleRewards()); - }, [dispatch]); - - const ratio = useMemo(() => { - return wei(weeklyRewards).gt(0) ? wei(estimatedReward).div(wei(weeklyRewards)) : zeroBN; - }, [estimatedReward, weeklyRewards]); - - const showEstimatedValue = useMemo(() => wei(period).eq(epochPeriod), [epochPeriod, period]); - - return ( - - - -
-
- {t('dashboard.stake.tabs.trading-rewards.claimable-rewards-all')} -
- {truncateNumbers(totalRewards, 4)} -
-
-
- {t('dashboard.stake.tabs.trading-rewards.trading-activity-reset')} -
-
- {resetTime > new Date().getTime() / 1000 - ? formatTruncatedDuration(resetTime - new Date().getTime() / 1000) - : t('dashboard.stake.tabs.trading-rewards.pending-for-rewards')} +const TradingRewardsTab: FC = memo( + ({ period = 0, start = 0, end = Math.floor(Date.now() / 1000) }) => { + const { t } = useTranslation(); + const { walletAddress, network } = Connector.useContainer(); + const dispatch = useAppDispatch(); + + const resetTime = useAppSelector(selectResetTime); + const totalRewards = useAppSelector(selectTotalRewards); + const epochPeriod = useAppSelector(selectEpochPeriod); + + const futuresFeeQuery = useGetFuturesFeeForAccount(walletAddress!, start, end); + const futuresFeePaid = useMemo(() => { + const t: FuturesFeeForAccountProps[] = futuresFeeQuery.data ?? []; + + return t + .map((trade) => formatEther(trade.feesPaid.toString())) + .reduce((acc, curr) => acc.add(wei(curr)), zeroBN); + }, [futuresFeeQuery.data]); + + const totalFuturesFeeQuery = useGetFuturesFee(start, end); + const totalFuturesFeePaid = useMemo(() => { + const t: FuturesFeeProps[] = totalFuturesFeeQuery.data ?? []; + + return t + .map((trade) => formatEther(trade.feesCrossMarginAccounts.toString())) + .reduce((acc, curr) => acc.add(wei(curr)), zeroBN); + }, [totalFuturesFeeQuery.data]); + + const estimatedRewardQuery = useGetFile( + `trading-rewards-snapshots/${network.id === 420 ? `goerli-` : ''}epoch-current.json` + ); + const estimatedReward = useMemo( + () => BigNumber.from(estimatedRewardQuery?.data?.claims[walletAddress!]?.amount ?? 0), + [estimatedRewardQuery?.data?.claims, walletAddress] + ); + const weeklyRewards = useMemo( + () => BigNumber.from(estimatedRewardQuery?.data?.tokenTotal ?? 0), + [estimatedRewardQuery?.data?.tokenTotal] + ); + + const claimDisabled = useMemo(() => totalRewards.lte(0), [totalRewards]); + + const handleClaim = useCallback(() => { + dispatch(claimMultipleRewards()); + }, [dispatch]); + + const ratio = useMemo(() => { + return wei(weeklyRewards).gt(0) ? wei(estimatedReward).div(wei(weeklyRewards)) : zeroBN; + }, [estimatedReward, weeklyRewards]); + + const showEstimatedValue = useMemo(() => wei(period).eq(epochPeriod), [epochPeriod, period]); + + return ( + + + +
+ {t('dashboard.stake.tabs.trading-rewards.claimable-rewards-all')} + {truncateNumbers(totalRewards, 4)}
-
- - - - - - - -
+ {t('dashboard.stake.tabs.trading-rewards.trading-activity-reset')} + + {resetTime > new Date().getTime() / 1000 + ? formatTruncatedDuration(resetTime - new Date().getTime() / 1000) + : t('dashboard.stake.tabs.trading-rewards.pending-for-rewards')} + +
+
+ + + +
+ + + -
+ {t('dashboard.stake.tabs.trading-rewards.future-fee-paid', { EpochPeriod: period, })} - </div> - <div className="value"> + + {formatDollars(futuresFeePaid, { minDecimals: 2 })} - -
+ +
+
+
+ + {t('dashboard.stake.tabs.trading-rewards.fees-paid', { EpochPeriod: period })} + + {formatDollars(totalFuturesFeePaid, { minDecimals: 2 })}
- -
-
- {t('dashboard.stake.tabs.trading-rewards.fees-paid', { EpochPeriod: period })} -
-
{formatDollars(totalFuturesFeePaid, { minDecimals: 2 })}
-
- {showEstimatedValue ? ( - <> -
-
- {t('dashboard.stake.tabs.trading-rewards.estimated-rewards')} + {showEstimatedValue ? ( + <> +
+ {t('dashboard.stake.tabs.trading-rewards.estimated-rewards')} + {truncateNumbers(wei(estimatedReward), 4)}
- {truncateNumbers(wei(estimatedReward), 4)} -
-
-
- {t('dashboard.stake.tabs.trading-rewards.estimated-reward-share', { - EpochPeriod: period, - })} +
+ + {t('dashboard.stake.tabs.trading-rewards.estimated-reward-share', { + EpochPeriod: period, + })} + + {formatPercent(ratio, { minDecimals: 2 })}
-
{formatPercent(ratio, { minDecimals: 2 })}
-
- + + ) : null} + + {showEstimatedValue ? ( + + {t('dashboard.stake.tabs.trading-rewards.estimated-info')} + ) : null} - - {showEstimatedValue ? ( - - {t('dashboard.stake.tabs.trading-rewards.estimated-info')} - - ) : null} - - - ); -}; + + + ); + } +); const PeriodLabel = styled.div` font-size: 13px; @@ -175,7 +172,7 @@ const PeriodLabel = styled.div` color: ${(props) => props.theme.colors.selectedTheme.gray}; `; -const CustomStyledTooltip = styled(StyledTooltip)` +const CustomStyledTooltip = styled(Tooltip)` padding: 0px 10px 0px; ${media.lessThan('md')` width: 310px; @@ -193,39 +190,34 @@ const CardGridContainer = styled(StakingCard)` justify-content: space-between; `; +const Value = styled(Body).attrs({ variant: 'bold', mono: true })` + color: ${(props) => props.theme.colors.selectedTheme.yellow}; + font-size: 26px; + /*margin-top: 5px;*/ + line-height: initial; +`; + +const Title = styled(Body).attrs({ size: 'medium' })` + color: ${(props) => props.theme.colors.selectedTheme.title}; +`; + const CardGrid = styled.div` display: grid; grid-auto-flow: column; grid-template-rows: 1fr 1fr; grid-template-columns: 1fr 1fr; + & > div { margin-bottom: 20px; } - .value { - margin-top: 5px; - } - - svg { - margin-left: 8px; - } - - .title { - color: ${(props) => props.theme.colors.selectedTheme.title}; - } - ${media.lessThan('md')` column-gap: 10px; `} `; -const TradingRewardsContainer = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - ${media.lessThan('md')` - grid-template-columns: repeat(1, 1fr); - `} - grid-gap: 15px; +const SpacedHelpIcon = styled(HelpIcon)` + margin-left: 8px; `; export default TradingRewardsTab; diff --git a/sections/dashboard/Stake/VestConfirmationModal.tsx b/sections/dashboard/Stake/VestConfirmationModal.tsx index f567a6f98e..42c63e122e 100644 --- a/sections/dashboard/Stake/VestConfirmationModal.tsx +++ b/sections/dashboard/Stake/VestConfirmationModal.tsx @@ -5,9 +5,10 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; +import { FlexDivRowCentered } from 'components/layout/flex'; import Spacer from 'components/Spacer'; import { EXTERNAL_LINKS } from 'constants/links'; -import { ExternalLink, FlexDivRowCentered } from 'styles/common'; +import { ExternalLink } from 'styles/common'; import { truncateNumbers } from 'utils/formatters/number'; type Props = { diff --git a/sections/dashboard/Stake/common.tsx b/sections/dashboard/Stake/card.ts similarity index 100% rename from sections/dashboard/Stake/common.tsx rename to sections/dashboard/Stake/card.ts diff --git a/sections/dashboard/SynthBalancesTable/SynthBalancesTable.tsx b/sections/dashboard/SynthBalancesTable/SynthBalancesTable.tsx index eba2f0c50d..9f91f36d92 100644 --- a/sections/dashboard/SynthBalancesTable/SynthBalancesTable.tsx +++ b/sections/dashboard/SynthBalancesTable/SynthBalancesTable.tsx @@ -1,7 +1,6 @@ import { CurrencyKey } from '@synthetixio/contracts-interface'; import { SynthBalance } from '@synthetixio/queries'; import Wei, { wei } from '@synthetixio/wei'; -import * as _ from 'lodash/fp'; import { FC, ReactElement, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { CellProps, Row } from 'react-table'; @@ -32,18 +31,13 @@ type Cell = { priceChange: Wei | undefined; }; -const calculatePriceChange = (current: Wei | null | undefined, past: Price | undefined) => { - if (_.isNil(current) || _.isNil(past)) { - return undefined; - } - - const priceChange = current.sub(past.price).div(current); - - return priceChange; +const calculatePriceChange = (current?: Wei | null, past?: Price) => { + if (!current || !past) return undefined; + return current.sub(past.price).div(current); }; -const conditionalRender = (prop: T, children: ReactElement): ReactElement => - _.isNil(prop) ? {NO_VALUE} : children; +const conditionalRender = (prop: T, children: ReactElement) => + !prop ? {NO_VALUE} : children; type SynthBalancesTableProps = { exchangeTokens: { @@ -68,9 +62,9 @@ const SynthBalancesTable: FC = ({ exchangeTokens }) => const { currencyKey, balance, usdBalance } = synthBalance; const price = prices[currencyKey].onChain; - const pastPrice = pastRates.find((price: Price) => price.synth === currencyKey); + const pastPrice = pastRates.find((price) => price.synth === currencyKey); + const description = synthsMap?.[currencyKey]?.description ?? ''; - const description = synthsMap != null ? synthsMap[currencyKey]?.description : ''; return { synth: currencyKey, description, @@ -152,9 +146,9 @@ const SynthBalancesTable: FC = ({ exchangeTokens }) => return conditionalRender( cellProps.row.original.usdBalance, ); @@ -177,9 +171,9 @@ const SynthBalancesTable: FC = ({ exchangeTokens }) => return conditionalRender( cellProps.row.original.price, = ({ exchangeTokens }) => {cellProps.row.original.synth} = ({ exchangeTokens }) =>
{formatNumber(cellProps.row.original.balance ?? 0)}
diff --git a/sections/dashboard/mobile.ts b/sections/dashboard/mobile.ts new file mode 100644 index 0000000000..7ec405e8b1 --- /dev/null +++ b/sections/dashboard/mobile.ts @@ -0,0 +1,72 @@ +import styled, { css } from 'styled-components'; + +export const StakingCard = styled.div<{ $noPadding?: boolean }>` + background: ${(props) => props.theme.colors.selectedTheme.surfaceFill}; + padding: 20px; + border-radius: 15px; + border: ${(props) => props.theme.colors.selectedTheme.border}; + + .title { + font-size: 15px; + color: ${(props) => props.theme.colors.selectedTheme.title}; + } + + .value { + font-family: ${(props) => props.theme.fonts.monoBold}; + font-size: 26px; + color: ${(props) => props.theme.colors.selectedTheme.yellow}; + margin-top: 10px; + } + + ${(props) => + props.$noPadding && + css` + padding: 0; + overflow: hidden; + `} +`; + +export const SplitStakingCard = styled(StakingCard)` + display: flex; + padding: 0; + cursor: pointer; + + & > div { + display: flex; + flex: 1; + flex-direction: column; + padding: 30px 0; + padding-left: 30px; + + &:first-of-type { + border-right: ${(props) => props.theme.colors.selectedTheme.border}; + } + } +`; + +export const HeaderContainer = styled.div` + padding: 15px; +`; + +export const MarketStatsContainer = styled.div` + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: 8px; +`; + +export const MarketStat = styled.div` + border-radius: 8px; + box-sizing: border-box; + padding: 10px; + border: ${(props) => props.theme.colors.selectedTheme.border}; + .title { + font-size: 12px; + color: ${(props) => props.theme.colors.selectedTheme.gray}; + margin-bottom: 4px; + } + .value { + font-size: 16px; + font-family: ${(props) => props.theme.fonts.bold}; + color: ${(props) => props.theme.colors.selectedTheme.text.value}; + } +`; diff --git a/sections/earn/GridData.tsx b/sections/earn/GridData.tsx index 92d6e66f62..28aac11cb1 100644 --- a/sections/earn/GridData.tsx +++ b/sections/earn/GridData.tsx @@ -29,7 +29,7 @@ const Title = styled(Body)` `; const GridDataContainer = styled.div` - background-color: ${(props) => props.theme.colors.selectedTheme.segmented.button.background}; + background-color: ${(props) => props.theme.colors.selectedTheme.surfaceFill}; padding: 20px 24px 18px; min-height: 95px; border-bottom: ${(props) => props.theme.colors.selectedTheme.border}; diff --git a/sections/earn/StakeGrid.tsx b/sections/earn/StakeGrid.tsx index 9660370ee1..7bff0009fd 100644 --- a/sections/earn/StakeGrid.tsx +++ b/sections/earn/StakeGrid.tsx @@ -1,25 +1,27 @@ import { useCallback } from 'react'; import Button from 'components/Button'; +import { GridContainer } from 'sections/earn/grid'; import useRewardsTimer from 'hooks/useRewardsTimer'; import { claimRewards } from 'state/earn/actions'; import { selectYieldPerDay } from 'state/earn/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { toWei, truncateNumbers } from 'utils/formatters/number'; -import { GridContainer } from './common'; import GridData from './GridData'; +const TimeRemainingData = () => { + const endDate = useAppSelector(({ earn }) => earn.endDate); + const timeTillDeadline = useRewardsTimer(new Date(endDate * 1000)); + + return ; +}; + const StakeGrid = () => { const dispatch = useAppDispatch(); - const { earnedRewards, endDate } = useAppSelector(({ earn }) => ({ - earnedRewards: earn.earnedRewards, - endDate: earn.endDate, - })); + const earnedRewards = useAppSelector(({ earn }) => earn.earnedRewards); const yieldPerDay = useAppSelector(selectYieldPerDay); - const timeTillDeadline = useRewardsTimer(new Date(endDate * 1000)); - const handleClaim = useCallback(() => { dispatch(claimRewards()); }, [dispatch]); @@ -39,7 +41,7 @@ const StakeGrid = () => { Claim Rewards - + ); }; diff --git a/sections/earn/StepOne.tsx b/sections/earn/StepOne.tsx index 92cd285432..233192d109 100644 --- a/sections/earn/StepOne.tsx +++ b/sections/earn/StepOne.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; -import { Heading, Description } from './common'; +import { Heading, Description } from 'sections/earn/text'; const StepOne = () => { return ( @@ -36,7 +36,7 @@ const BigButton = styled.div` align-items: center; border: ${(props) => props.theme.colors.selectedTheme.border}; border-radius: 15px; - background-color: ${(props) => props.theme.colors.selectedTheme.segmented.button.background}; + background-color: ${(props) => props.theme.colors.selectedTheme.surfaceFill}; `; export default StepOne; diff --git a/sections/earn/StepTwo.tsx b/sections/earn/StepTwo.tsx index dc80cc7ef8..380413dceb 100644 --- a/sections/earn/StepTwo.tsx +++ b/sections/earn/StepTwo.tsx @@ -1,8 +1,8 @@ import styled from 'styled-components'; -import media from 'styles/media'; +import { Heading, Description } from 'sections/earn/text'; +import { SplitContainer } from 'components/layout/grid'; -import { Heading, Description } from './common'; import EarnStakeCard from './EarnStakeCard'; import StakeGrid from './StakeGrid'; @@ -23,26 +23,4 @@ const StepTwoContainer = styled.div` margin-bottom: 50px; `; -const SplitContainer = styled.div` - margin-top: 10px; - - ${media.greaterThan('mdUp')` - display: grid; - grid-template-columns: 1fr 1fr; - & > div { - flex: 1; - - &:first-child { - margin-right: 15px; - } - } - `} - - ${media.lessThan('mdUp')` - & > div:first-child { - margin-bottom: 15px; - } - `} -`; - export default StepTwo; diff --git a/sections/earn/common.tsx b/sections/earn/grid.ts similarity index 62% rename from sections/earn/common.tsx rename to sections/earn/grid.ts index e2f989b650..25c53717fe 100644 --- a/sections/earn/common.tsx +++ b/sections/earn/grid.ts @@ -1,14 +1,7 @@ import styled from 'styled-components'; -import * as Text from 'components/Text'; import media from 'styles/media'; -export const Description = styled(Text.Body)` - font-size: 15px; - color: ${(props) => props.theme.colors.selectedTheme.gray}; - margin: 8px 0; -`; - export const GridContainer = styled.div` display: flex; @@ -17,7 +10,7 @@ export const GridContainer = styled.div` border-radius: 15px; border: ${(props) => props.theme.colors.selectedTheme.border}; overflow: hidden; - background-color: ${(props) => props.theme.colors.selectedTheme.segmented.button.background}; + background-color: ${(props) => props.theme.colors.selectedTheme.surfaceFill}; & > div { box-sizing: border-box; @@ -45,12 +38,3 @@ export const GridContainer = styled.div` flex-direction: column; `} `; - -export const Heading = styled(Text.Heading).attrs({ variant: 'h4' })` - font-family: ${(props) => props.theme.fonts.bold}; - font-size: 21px; - margin-bottom: 4px; - text-transform: uppercase; - font-variant: all-small-caps; - color: ${(props) => props.theme.colors.selectedTheme.yellow}; -`; diff --git a/sections/earn/text.ts b/sections/earn/text.ts new file mode 100644 index 0000000000..51ac1d845e --- /dev/null +++ b/sections/earn/text.ts @@ -0,0 +1,18 @@ +import styled from 'styled-components'; + +import * as Text from 'components/Text'; + +export const Description = styled(Text.Body)` + font-size: 15px; + color: ${(props) => props.theme.colors.selectedTheme.gray}; + margin: 8px 0; +`; + +export const Heading = styled(Text.Heading).attrs({ variant: 'h4' })` + font-family: ${(props) => props.theme.fonts.bold}; + font-size: 21px; + margin-bottom: 4px; + text-transform: uppercase; + font-variant: all-small-caps; + color: ${(props) => props.theme.colors.selectedTheme.yellow}; +`; diff --git a/sections/exchange/BasicSwap/BasicSwap.tsx b/sections/exchange/BasicSwap.tsx similarity index 78% rename from sections/exchange/BasicSwap/BasicSwap.tsx rename to sections/exchange/BasicSwap.tsx index 21a2994d26..3b1c45f1a9 100644 --- a/sections/exchange/BasicSwap/BasicSwap.tsx +++ b/sections/exchange/BasicSwap.tsx @@ -2,12 +2,12 @@ import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import { BoldText } from 'styles/common'; +import * as Text from 'components/Text'; -import BaseCurrencyCard from '../TradeCard/Cards/BaseCurrencyCard'; -import FooterCard from '../TradeCard/Cards/FooterCard'; -import QuoteCurrencyCard from '../TradeCard/Cards/QuoteCurrencyCard'; import SwapCurrencies from './SwapCurrencies'; +import BaseCurrencyCard from './TradeCard/Cards/BaseCurrencyCard'; +import FooterCard from './TradeCard/Cards/FooterCard'; +import QuoteCurrencyCard from './TradeCard/Cards/QuoteCurrencyCard'; const BasicSwap: FC = memo(() => { const { t } = useTranslation(); @@ -29,7 +29,7 @@ const BasicSwap: FC = memo(() => { export default BasicSwap; -const ExchangeTitle = styled(BoldText)` +const ExchangeTitle = styled(Text.Body).attrs({ variant: 'bold' })` color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; font-size: 30px; margin-bottom: 1.5em; diff --git a/sections/exchange/BasicSwap/index.ts b/sections/exchange/BasicSwap/index.ts deleted file mode 100644 index f37d73a622..0000000000 --- a/sections/exchange/BasicSwap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './BasicSwap'; diff --git a/sections/exchange/ExchangeContent/ExchangeContent.tsx b/sections/exchange/ExchangeContent.tsx similarity index 100% rename from sections/exchange/ExchangeContent/ExchangeContent.tsx rename to sections/exchange/ExchangeContent.tsx diff --git a/sections/exchange/ExchangeContent/index.ts b/sections/exchange/ExchangeContent/index.ts deleted file mode 100644 index 18cfec4aa6..0000000000 --- a/sections/exchange/ExchangeContent/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ExchangeContent'; diff --git a/sections/exchange/ExchangeHead/ExchangeHead.tsx b/sections/exchange/ExchangeHead.tsx similarity index 100% rename from sections/exchange/ExchangeHead/ExchangeHead.tsx rename to sections/exchange/ExchangeHead.tsx diff --git a/sections/exchange/ExchangeHead/index.ts b/sections/exchange/ExchangeHead/index.ts deleted file mode 100644 index 8b549d612e..0000000000 --- a/sections/exchange/ExchangeHead/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ExchangeHead'; diff --git a/sections/exchange/ExchangeModals/ExchangeModals.tsx b/sections/exchange/ExchangeModals.tsx similarity index 100% rename from sections/exchange/ExchangeModals/ExchangeModals.tsx rename to sections/exchange/ExchangeModals.tsx diff --git a/sections/exchange/ExchangeModals/index.ts b/sections/exchange/ExchangeModals/index.ts deleted file mode 100644 index 2de2fc2469..0000000000 --- a/sections/exchange/ExchangeModals/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ExchangeModals'; diff --git a/sections/exchange/FooterCard/ConnectWalletCard/ConnectWalletCard.tsx b/sections/exchange/FooterCard/ConnectWalletCard.tsx similarity index 77% rename from sections/exchange/FooterCard/ConnectWalletCard/ConnectWalletCard.tsx rename to sections/exchange/FooterCard/ConnectWalletCard.tsx index cb421ca8a6..c045edf62e 100644 --- a/sections/exchange/FooterCard/ConnectWalletCard/ConnectWalletCard.tsx +++ b/sections/exchange/FooterCard/ConnectWalletCard.tsx @@ -1,16 +1,20 @@ import { useConnectModal } from '@rainbow-me/rainbowkit'; -import { FC } from 'react'; +import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; - -import { MessageButton, MessageContainer, Message, FixedMessageContainerSpacer } from '../common'; +import { + MessageButton, + MessageContainer, + Message, + FixedMessageContainerSpacer, +} from 'sections/exchange/message'; type ConnectWalletCardProps = { className?: string; }; -const ConnectWalletCard: FC = ({ ...rest }) => { +const ConnectWalletCard: FC = memo(({ ...rest }) => { const { t } = useTranslation(); const { openConnectModal: connectWallet } = useConnectModal(); @@ -29,6 +33,6 @@ const ConnectWalletCard: FC = ({ ...rest }) => { ); -}; +}); export default ConnectWalletCard; diff --git a/sections/exchange/FooterCard/ConnectWalletCard/index.ts b/sections/exchange/FooterCard/ConnectWalletCard/index.ts deleted file mode 100644 index 326dd19746..0000000000 --- a/sections/exchange/FooterCard/ConnectWalletCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ConnectWalletCard'; diff --git a/sections/exchange/FooterCard/MarketClosureCard/MarketClosureCard.tsx b/sections/exchange/FooterCard/MarketClosureCard.tsx similarity index 88% rename from sections/exchange/FooterCard/MarketClosureCard/MarketClosureCard.tsx rename to sections/exchange/FooterCard/MarketClosureCard.tsx index 32626f21b7..9b5b894127 100644 --- a/sections/exchange/FooterCard/MarketClosureCard/MarketClosureCard.tsx +++ b/sections/exchange/FooterCard/MarketClosureCard.tsx @@ -1,13 +1,17 @@ -import { FC, useMemo } from 'react'; +import { FC, useMemo, memo } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import useMarketClosed from 'hooks/useMarketClosed'; +import { + MessageContainer, + Message, + MessageButton, + FixedMessageContainerSpacer, +} from 'sections/exchange/message'; import { useAppSelector } from 'state/hooks'; -import { MessageContainer, Message, MessageButton, FixedMessageContainerSpacer } from '../common'; - -const MarketClosureCard: FC = () => { +const MarketClosureCard: FC = memo(() => { const { t } = useTranslation(); const { quoteCurrencyKey, baseCurrencyKey } = useAppSelector(({ exchange }) => ({ quoteCurrencyKey: exchange.quoteCurrencyKey, @@ -50,6 +54,6 @@ const MarketClosureCard: FC = () => { ); -}; +}); export default MarketClosureCard; diff --git a/sections/exchange/FooterCard/MarketClosureCard/index.ts b/sections/exchange/FooterCard/MarketClosureCard/index.ts deleted file mode 100644 index 3754100794..0000000000 --- a/sections/exchange/FooterCard/MarketClosureCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './MarketClosureCard'; diff --git a/sections/exchange/FooterCard/SettleTransactionsCard/SettleTransactionsCard.tsx b/sections/exchange/FooterCard/SettleTransactionsCard.tsx similarity index 92% rename from sections/exchange/FooterCard/SettleTransactionsCard/SettleTransactionsCard.tsx rename to sections/exchange/FooterCard/SettleTransactionsCard.tsx index 64deda8a88..4b712e12d7 100644 --- a/sections/exchange/FooterCard/SettleTransactionsCard/SettleTransactionsCard.tsx +++ b/sections/exchange/FooterCard/SettleTransactionsCard.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback } from 'react'; +import { FC, useCallback, memo } from 'react'; import { useTranslation, Trans } from 'react-i18next'; import styled from 'styled-components'; @@ -6,6 +6,7 @@ import Button from 'components/Button'; import { MobileOrTabletView } from 'components/Media'; import ErrorTooltip from 'components/Tooltip/ErrorTooltip'; import { EXTERNAL_LINKS } from 'constants/links'; +import { MessageContainer, Message, FixedMessageContainerSpacer } from 'sections/exchange/message'; import TxSettleModal from 'sections/shared/modals/TxSettleModal'; import { submitSettle } from 'state/exchange/actions'; import { closeModal } from 'state/exchange/reducer'; @@ -14,9 +15,7 @@ import { NoTextTransform, ExternalLink } from 'styles/common'; import { secondsToTime } from 'utils/formatters/date'; import logError from 'utils/logError'; -import { MessageContainer, Message, FixedMessageContainerSpacer } from '../common'; - -const SettleTransactionsCard: FC = () => { +const SettleTransactionsCard: FC = memo(() => { const { t } = useTranslation(); const { @@ -59,7 +58,7 @@ const SettleTransactionsCard: FC = () => { ]} /> @@ -67,7 +66,7 @@ const SettleTransactionsCard: FC = () => { ]} /> @@ -102,7 +101,7 @@ const SettleTransactionsCard: FC = () => { )} ); -}; +}); const MessageItem = styled(Message)` grid-column-start: 2; diff --git a/sections/exchange/FooterCard/SettleTransactionsCard/index.ts b/sections/exchange/FooterCard/SettleTransactionsCard/index.ts deleted file mode 100644 index 9e3492c9bc..0000000000 --- a/sections/exchange/FooterCard/SettleTransactionsCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SettleTransactionsCard'; diff --git a/sections/exchange/FooterCard/TradeSummaryCard/TradeSummaryCard.tsx b/sections/exchange/FooterCard/TradeSummaryCard.tsx similarity index 77% rename from sections/exchange/FooterCard/TradeSummaryCard/TradeSummaryCard.tsx rename to sections/exchange/FooterCard/TradeSummaryCard.tsx index c1dd347695..42325348fa 100644 --- a/sections/exchange/FooterCard/TradeSummaryCard/TradeSummaryCard.tsx +++ b/sections/exchange/FooterCard/TradeSummaryCard.tsx @@ -4,9 +4,11 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; -import Card from 'components/Card'; +import Card, { CardBody } from 'components/Card'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import ErrorTooltip from 'components/Tooltip/ErrorTooltip'; +import { MessageContainer } from 'sections/exchange/message'; +import { SummaryItems } from 'sections/exchange/summary'; import FeeCostSummaryItem from 'sections/shared/components/FeeCostSummary'; import FeeRateSummaryItem from 'sections/shared/components/FeeRateSummary'; import GasPriceSelect from 'sections/shared/components/GasPriceSelect'; @@ -25,22 +27,12 @@ import { import { useAppDispatch, useAppSelector } from 'state/hooks'; import { secondsToTime } from 'utils/formatters/date'; -import { MessageContainer } from '../common'; -import { SummaryItems } from '../common'; - const TradeSummaryCard: FC = memo(() => { - const { t } = useTranslation(); - - const { feeReclaimPeriod, openModal } = useAppSelector(({ exchange }) => ({ - feeReclaimPeriod: exchange.feeReclaimPeriod, - openModal: exchange.openModal, - })); - - const quoteCurrencyKey = useAppSelector(({ exchange }) => exchange.quoteCurrencyKey); const dispatch = useAppDispatch(); - + const openModal = useAppSelector(({ exchange }) => exchange.openModal); const isApproved = useAppSelector(selectIsApproved); + // TODO: Make this a Redux action in itself. const onSubmit = useCallback(() => { if (!isApproved) { dispatch(submitApprove()); @@ -57,31 +49,16 @@ const TradeSummaryCard: FC = memo(() => { <> - + - + - 0} - preset="top" - content={ -
- {t('exchange.errors.fee-reclamation', { - waitingPeriod: secondsToTime(feeReclaimPeriod), - currencyKey: quoteCurrencyKey, - })} -
- } - > - - - -
+
{openModal === 'confirm' && } {openModal === 'approve' && } @@ -137,6 +114,39 @@ const SubmissionButton = ({ onSubmit, isApproved }: any) => { ); }; +type TradeErrorTooltipProps = { + onSubmit(): void; +}; + +const TradeErrorTooltip: FC = memo(({ onSubmit }) => { + const { t } = useTranslation(); + + const isApproved = useAppSelector(selectIsApproved); + const { feeReclaimPeriod, quoteCurrencyKey } = useAppSelector(({ exchange }) => ({ + feeReclaimPeriod: exchange.feeReclaimPeriod, + quoteCurrencyKey: exchange.quoteCurrencyKey, + })); + + return ( + 0} + preset="top" + content={ +
+ {t('exchange.errors.fee-reclamation', { + waitingPeriod: secondsToTime(feeReclaimPeriod), + currencyKey: quoteCurrencyKey, + })} +
+ } + > + + + +
+ ); +}); + const MobileCard = styled(Card)` margin: 2px auto 20px auto; `; diff --git a/sections/exchange/FooterCard/TradeSummaryCard/index.ts b/sections/exchange/FooterCard/TradeSummaryCard/index.ts deleted file mode 100644 index 6c6b3fa6d1..0000000000 --- a/sections/exchange/FooterCard/TradeSummaryCard/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './TradeSummaryCard'; -export * from './TradeSummaryCard'; diff --git a/sections/exchange/MobileSwap/SwapInfoBox.tsx b/sections/exchange/MobileSwap/SwapInfoBox.tsx index def4b7df1b..09375d42d0 100644 --- a/sections/exchange/MobileSwap/SwapInfoBox.tsx +++ b/sections/exchange/MobileSwap/SwapInfoBox.tsx @@ -7,7 +7,7 @@ import styled from 'styled-components'; import TimerIcon from 'assets/svg/app/timer.svg'; import InfoBox from 'components/InfoBox'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import Tooltip from 'components/Tooltip/Tooltip'; import { NO_VALUE } from 'constants/placeholder'; import { parseGasPriceObject } from 'hooks/useGas'; import useIsL1 from 'hooks/useIsL1'; @@ -80,7 +80,7 @@ const SwapInfoBox: React.FC = () => { .gt(0) ? ( <> {' + '} - { {formatPercent(wei(exchangeFeeRate).sub(baseFeeRate), { minDecimals: 2 })} - + ) : null ) : null} @@ -101,9 +101,7 @@ const SwapInfoBox: React.FC = () => { [t('common.summary.fee-cost')]: { value: feeCost != null - ? formatDollars(feeCost, { - minDecimals: feeCost.lt(0.01) ? 4 : 2, - }) + ? formatDollars(feeCost, { minDecimals: feeCost.lt(0.01) ? 4 : 2 }) : NO_VALUE, }, }} diff --git a/sections/exchange/BasicSwap/SwapCurrencies.tsx b/sections/exchange/SwapCurrencies.tsx similarity index 100% rename from sections/exchange/BasicSwap/SwapCurrencies.tsx rename to sections/exchange/SwapCurrencies.tsx diff --git a/sections/exchange/TradeCard/CurrencyCard/CurrencyCard.tsx b/sections/exchange/TradeCard/CurrencyCard/CurrencyCard.tsx index 58d7f74789..3788653c5d 100644 --- a/sections/exchange/TradeCard/CurrencyCard/CurrencyCard.tsx +++ b/sections/exchange/TradeCard/CurrencyCard/CurrencyCard.tsx @@ -3,8 +3,8 @@ import { FC, useMemo, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled, { css } from 'styled-components'; -import Card from 'components/Card'; -import { FlexDivRowCentered } from 'styles/common'; +import Card, { CardBody } from 'components/Card'; +import { FlexDivRowCentered } from 'components/layout/flex'; import { Side } from '../types'; import CurrencyCardInput from './CurrencyCardInput'; @@ -117,7 +117,7 @@ const StyledCard = styled(Card)<{ interactive?: boolean }>` `} `; -const StyledCardBody = styled(Card.Body)` +const StyledCardBody = styled(CardBody)` padding: 20px 32px; `; diff --git a/sections/exchange/TradeCard/CurrencyCard/CurrencyCardInput.tsx b/sections/exchange/TradeCard/CurrencyCard/CurrencyCardInput.tsx index 69bfbaa1a1..f94ceaff28 100644 --- a/sections/exchange/TradeCard/CurrencyCard/CurrencyCardInput.tsx +++ b/sections/exchange/TradeCard/CurrencyCard/CurrencyCardInput.tsx @@ -5,9 +5,10 @@ import styled, { css } from 'styled-components'; import Button from 'components/Button'; import NumericInput from 'components/Input/NumericInput'; +import { FlexDivCol, FlexDivRowCentered } from 'components/layout/flex'; import Loader from 'components/Loader'; import useSelectedPriceCurrency from 'hooks/useSelectedPriceCurrency'; -import { CapitalizedText, FlexDivCol, FlexDivRowCentered, numericValueCSS } from 'styles/common'; +import { CapitalizedText, numericValueCSS } from 'styles/common'; import { formatDollars, zeroBN } from 'utils/formatters/number'; type CurrencyCardInputProps = { diff --git a/sections/exchange/TradeCard/CurrencyCard/CurrencyCardSelector.tsx b/sections/exchange/TradeCard/CurrencyCard/CurrencyCardSelector.tsx index 93caf41717..bd2e87aa71 100644 --- a/sections/exchange/TradeCard/CurrencyCard/CurrencyCardSelector.tsx +++ b/sections/exchange/TradeCard/CurrencyCard/CurrencyCardSelector.tsx @@ -6,10 +6,11 @@ import styled, { css } from 'styled-components'; import CaretDownIcon from 'assets/svg/app/caret-down-gray.svg'; import { border } from 'components/Button'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; +import { FlexDivColCentered, FlexDivRow } from 'components/layout/flex'; import { NO_VALUE } from 'constants/placeholder'; import { selectInsufficientBalance } from 'state/exchange/selectors'; import { useAppSelector } from 'state/hooks'; -import { CapitalizedText, FlexDivColCentered, FlexDivRow, numericValueCSS } from 'styles/common'; +import { CapitalizedText, numericValueCSS } from 'styles/common'; import { formatCurrency } from 'utils/formatters/number'; type CurrencyCardSelectorProps = { diff --git a/sections/exchange/TradeCard/CurrencyCard/MobileCurrencyCard.tsx b/sections/exchange/TradeCard/CurrencyCard/MobileCurrencyCard.tsx index 8144b79450..2a8a0ecc15 100644 --- a/sections/exchange/TradeCard/CurrencyCard/MobileCurrencyCard.tsx +++ b/sections/exchange/TradeCard/CurrencyCard/MobileCurrencyCard.tsx @@ -6,9 +6,9 @@ import styled from 'styled-components'; import CaretDownIcon from 'assets/svg/app/caret-down-gray.svg'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; import NumericInput from 'components/Input/NumericInput'; +import { SectionHeader, SectionSubTitle, SectionTitle } from 'sections/futures/mobile'; import { NO_VALUE } from 'constants/placeholder'; import useSelectedPriceCurrency from 'hooks/useSelectedPriceCurrency'; -import { SectionHeader, SectionSubTitle, SectionTitle } from 'sections/futures/MobileTrade/common'; import { formatCurrency, zeroBN } from 'utils/formatters/number'; type MobileCurrencyCardProps = { @@ -140,7 +140,6 @@ const SwapTextInput = styled(NumericInput)` border: none; color: ${(props) => props.theme.colors.selectedTheme.text.value}; font-size: 18px; - font-family: ${(props) => props.theme.fonts.mono}; margin-bottom: 10px; height: initial; diff --git a/sections/exchange/FooterCard/common.tsx b/sections/exchange/message.ts similarity index 63% rename from sections/exchange/FooterCard/common.tsx rename to sections/exchange/message.ts index 0f6ac1c048..6dc77385ff 100644 --- a/sections/exchange/FooterCard/common.tsx +++ b/sections/exchange/message.ts @@ -1,31 +1,15 @@ import styled from 'styled-components'; import Button from 'components/Button'; +import { GridDivCenteredRow } from 'components/layout/grid'; import { zIndex } from 'constants/ui'; -import { FixedFooterMixin, GridDivCenteredRow } from 'styles/common'; +import { FixedFooterMixin } from 'styles/common'; import media from 'styles/media'; -export const SummaryItems = styled.div` - display: grid; - grid-auto-flow: column; - flex-grow: 1; - padding-left: 32px; - justify-content: space-between; - ${media.lessThan('md')` - grid-auto-flow: unset; - grid-template-columns: auto auto; - grid-template-rows: auto auto; - grid-gap: 20px; - `} -`; - -export const MessageContainer = styled(GridDivCenteredRow)<{ - showProvider?: boolean; -}>` +export const MessageContainer = styled(GridDivCenteredRow)` -webkit-box-align: center; width: 100%; border-radius: 4px; - grid-template-columns: ${(props) => props.showProvider && '.5fr'} 1fr; grid-template-rows: 99px 70px; margin: 0 0 20px; diff --git a/sections/shared/components/common.tsx b/sections/exchange/summary.ts similarity index 70% rename from sections/shared/components/common.tsx rename to sections/exchange/summary.ts index 33d6ae35c0..4371fdca45 100644 --- a/sections/shared/components/common.tsx +++ b/sections/exchange/summary.ts @@ -3,6 +3,20 @@ import styled from 'styled-components'; import { numericValueCSS } from 'styles/common'; import media from 'styles/media'; +export const SummaryItems = styled.div` + display: grid; + grid-auto-flow: column; + flex-grow: 1; + padding-left: 32px; + justify-content: space-between; + ${media.lessThan('md')` + grid-auto-flow: unset; + grid-template-columns: auto auto; + grid-template-rows: auto auto; + grid-gap: 20px; + `} +`; + export const SummaryItem = styled.div` display: grid; grid-gap: 4px; diff --git a/sections/futures/CrossMarginOnboard/CrossMarginOnboard.tsx b/sections/futures/CrossMarginOnboard/CrossMarginOnboard.tsx index 07d08e1ba7..9a30811e29 100644 --- a/sections/futures/CrossMarginOnboard/CrossMarginOnboard.tsx +++ b/sections/futures/CrossMarginOnboard/CrossMarginOnboard.tsx @@ -10,9 +10,10 @@ import styled from 'styled-components'; import CompleteCheck from 'assets/svg/futures/onboard-complete-check.svg'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import ErrorView from 'components/Error'; +import ErrorView from 'components/ErrorView'; import InputBalanceLabel from 'components/Input/InputBalanceLabel'; import NumericInput from 'components/Input/NumericInput'; +import { FlexDivRowCentered } from 'components/layout/flex'; import Loader from 'components/Loader'; import ProgressSteps from 'components/ProgressSteps'; import { CROSS_MARGIN_BASE_SETTINGS } from 'constants/address'; @@ -29,7 +30,6 @@ import useQueryCrossMarginAccount, { import { selectBalances } from 'state/balances/selectors'; import { useAppSelector } from 'state/hooks'; import { futuresAccountState } from 'store/futures'; -import { FlexDivRowCentered } from 'styles/common'; import { isUserDeniedError } from 'utils/formatters/error'; import { zeroBN } from 'utils/formatters/number'; import logError from 'utils/logError'; diff --git a/sections/futures/FeeInfoBox/FeeInfoBox.tsx b/sections/futures/FeeInfoBox/FeeInfoBox.tsx index ec1f9e40bd..dbbfb7f3d6 100644 --- a/sections/futures/FeeInfoBox/FeeInfoBox.tsx +++ b/sections/futures/FeeInfoBox/FeeInfoBox.tsx @@ -1,13 +1,13 @@ import router from 'next/router'; import React, { useMemo, useEffect } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; import EligibleIcon from 'assets/svg/app/eligible.svg'; import LinkArrowIcon from 'assets/svg/app/link-arrow.svg'; import NotEligibleIcon from 'assets/svg/app/not-eligible.svg'; import InfoBox, { DetailedInfo } from 'components/InfoBox/InfoBox'; -import * as Text from 'components/Text'; +import { Body } from 'components/Text'; import { NO_VALUE } from 'constants/placeholder'; import ROUTES from 'constants/routes'; import Connector from 'containers/Connector'; @@ -138,7 +138,7 @@ const FeeInfoBox: React.FC = () => { i18nKey={`dashboard.stake.tabs.trading-rewards.stake-to-${ isRewardEligible ? 'earn' : 'start' }`} - components={[]} + components={[]} /> @@ -220,11 +220,7 @@ const StyledLinkArrowIcon = styled(LinkArrowIcon)` cursor: pointer; `; -const Emphasis = styled.b` - font-family: ${(props) => props.theme.fonts.bold}; -`; - -const RewardCopy = styled(Text.Body)` +const RewardCopy = styled(Body)` color: ${(props) => props.theme.colors.selectedTheme.text.title}; `; @@ -243,23 +239,24 @@ const CompactBox = styled.div<{ $isEligible: boolean }>` } .badge-red { - color: ${(props) => props.theme.colors.selectedTheme.badge['red'].text}; - background: ${(props) => props.theme.colors.selectedTheme.badge['red'].background}; + color: ${(props) => props.theme.colors.selectedTheme.badge.red.text}; + background: ${(props) => props.theme.colors.selectedTheme.badge.red.background}; min-width: 100px; } .badge-yellow { - color: ${(props) => props.theme.colors.selectedTheme.badge['yellow'].text}; - background: ${(props) => props.theme.colors.selectedTheme.badge['yellow'].background}; + color: ${(props) => props.theme.colors.selectedTheme.badge.yellow.text}; + background: ${(props) => props.theme.colors.selectedTheme.badge.yellow.background}; min-width: 70px; } ${(props) => - css` - border-left: 3px solid - ${props.$isEligible - ? props.theme.colors.selectedTheme.badge.yellow.background - : props.theme.colors.selectedTheme.badge.red.background}; + `border-left: 3px solid + ${ + props.$isEligible + ? props.theme.colors.selectedTheme.badge.yellow.background + : props.theme.colors.selectedTheme.badge.red.background + }; `} `; diff --git a/sections/futures/LeverageInput/LeverageInput.tsx b/sections/futures/LeverageInput/LeverageInput.tsx index d45498e4b6..ed0cc687c8 100644 --- a/sections/futures/LeverageInput/LeverageInput.tsx +++ b/sections/futures/LeverageInput/LeverageInput.tsx @@ -1,10 +1,11 @@ import { wei } from '@synthetixio/wei'; -import { FC, useCallback, useMemo, useState } from 'react'; +import { FC, memo, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; import CustomNumericInput from 'components/Input/CustomNumericInput'; +import { FlexDivCol, FlexDivRow } from 'components/layout/flex'; import { DEFAULT_FIAT_DECIMALS } from 'constants/defaults'; import { editIsolatedMarginSize } from 'state/futures/actions'; import { setIsolatedMarginLeverageInput } from 'state/futures/reducer'; @@ -18,12 +19,11 @@ import { selectNextPriceDisclaimer, } from 'state/futures/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; -import { FlexDivCol, FlexDivRow } from 'styles/common'; import { floorNumber, truncateNumbers, zeroBN } from 'utils/formatters/number'; import LeverageSlider from '../LeverageSlider'; -const LeverageInput: FC = () => { +const LeverageInput: FC = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const [mode, setMode] = useState<'slider' | 'input'>('input'); @@ -36,16 +36,15 @@ const LeverageInput: FC = () => { const leverageInput = useAppSelector(selectIsolatedLeverageInput); const onLeverageChange = useCallback( - (newLeverage: number) => { + (newLeverage: string) => { const remainingMargin = position?.remainingMargin ?? zeroBN; const newTradeSize = marketPrice.eq(0) || remainingMargin.eq(0) ? '' - : wei(newLeverage).mul(remainingMargin).div(marketPrice).toString(); - const input = truncateNumbers(newLeverage, DEFAULT_FIAT_DECIMALS); - dispatch(setIsolatedMarginLeverageInput(input)); + : wei(Number(newLeverage)).mul(remainingMargin).div(marketPrice).toString(); const floored = floorNumber(Number(newTradeSize), 4); dispatch(editIsolatedMarginSize(String(floored), 'native')); + dispatch(setIsolatedMarginLeverageInput(newLeverage)); }, [position?.remainingMargin, marketPrice, dispatch] ); @@ -72,7 +71,7 @@ const LeverageInput: FC = () => { : 10; const truncateLeverage = useMemo( - () => truncateNumbers(wei(leverageInput ?? 0), DEFAULT_FIAT_DECIMALS), + () => truncateNumbers(wei(Number(leverageInput) ?? 0), DEFAULT_FIAT_DECIMALS), [leverageInput] ); @@ -98,7 +97,7 @@ const LeverageInput: FC = () => { maxValue={Number(truncateMaxLeverage)} value={Number(truncateLeverage)} onChange={(_, newValue) => { - onLeverageChange(newValue as number); + onLeverageChange(newValue.toString()); }} /> @@ -111,7 +110,7 @@ const LeverageInput: FC = () => { suffix="x" maxValue={maxLeverage.toNumber()} onChange={(_, newValue) => { - onLeverageChange(Number(newValue)); + onLeverageChange(newValue); }} disabled={isDisabled} /> @@ -121,7 +120,7 @@ const LeverageInput: FC = () => { mono variant="flat" onClick={() => { - onLeverageChange(Number(l)); + onLeverageChange(l); }} disabled={maxLeverage.lt(Number(l)) || marketInfo?.isSuspended} > @@ -132,7 +131,7 @@ const LeverageInput: FC = () => { )} ); -}; +}); const LeverageInputWrapper = styled(FlexDivCol)` margin-bottom: 16px; diff --git a/sections/futures/LeverageSlider/LeverageSlider.tsx b/sections/futures/LeverageSlider/LeverageSlider.tsx index d72eb97f97..9c82dd9adb 100644 --- a/sections/futures/LeverageSlider/LeverageSlider.tsx +++ b/sections/futures/LeverageSlider/LeverageSlider.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { memo, FC } from 'react'; import { SliderProps } from 'components/Slider/Slider'; import StyledSlider from 'components/Slider/StyledSlider'; @@ -12,34 +12,28 @@ type LeverageSliderProps = SliderProps & { onChangeCommitted?: (event: React.ChangeEvent<{}>, value: number | number[]) => void; }; -const LeverageSlider: React.FC = ({ - minValue, - maxValue, - value, - defaultValue, - disabled, - onChange, - onChangeCommitted, -}) => { - return ( - `${v}x`} - $currentMark={value ?? defaultValue ?? 0} - /> - ); -}; +const LeverageSlider: FC = memo( + ({ minValue, maxValue, value, defaultValue, disabled, onChange, onChangeCommitted }) => { + return ( + `${v}x`} + $currentMark={value ?? defaultValue ?? 0} + /> + ); + } +); export default LeverageSlider; diff --git a/sections/futures/MarketDetails/MarketDetail.tsx b/sections/futures/MarketDetails/MarketDetail.tsx index 9a456c600c..400dfc314a 100644 --- a/sections/futures/MarketDetails/MarketDetail.tsx +++ b/sections/futures/MarketDetails/MarketDetail.tsx @@ -1,8 +1,8 @@ -import { ReactElement } from 'react'; +import { ReactElement, memo, FC } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import Tooltip from 'components/Tooltip/Tooltip'; import { selectMarketInfo } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; @@ -15,7 +15,7 @@ type MarketDetailProps = { value: string | ReactElement; }; -const MarketDetail: React.FC = ({ mobile, marketKey, color, value }) => { +const MarketDetail: FC = memo(({ mobile, marketKey, color, value }) => { const { t } = useTranslation(); const marketInfo = useAppSelector(selectMarketInfo); @@ -33,8 +33,6 @@ const MarketDetail: React.FC = ({ mobile, marketKey, color, v return ( @@ -47,8 +45,6 @@ const MarketDetail: React.FC = ({ mobile, marketKey, color, v return ( @@ -58,7 +54,7 @@ const MarketDetail: React.FC = ({ mobile, marketKey, color, v } return children; -}; +}); export default MarketDetail; @@ -67,7 +63,9 @@ const WithCursor = styled.div<{ cursor: 'help' }>` cursor: ${(props) => props.cursor}; `; -const MarketDetailsTooltip = styled(StyledTooltip)<{ mobile?: boolean }>` +const MarketDetailsTooltip = styled(Tooltip).attrs({ position: 'fixed', height: 'auto' })<{ + mobile?: boolean; +}>` z-index: 2; padding: 10px; right: ${(props) => props.mobile && '1px'}; diff --git a/sections/futures/MarketDetails/MarketDetails.tsx b/sections/futures/MarketDetails/MarketDetails.tsx index 28d6c1e900..4357b86422 100644 --- a/sections/futures/MarketDetails/MarketDetails.tsx +++ b/sections/futures/MarketDetails/MarketDetails.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import styled, { css } from 'styled-components'; +import { FlexDivCentered } from 'components/layout/flex'; import { selectMarketAsset } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { FlexDivCentered } from 'styles/common'; import media from 'styles/media'; import MarketsDropdown from '../Trade/MarketsDropdown'; diff --git a/sections/futures/MarketDetails/useGetMarketData.ts b/sections/futures/MarketDetails/useGetMarketData.ts index be49ec8098..bffcd06882 100644 --- a/sections/futures/MarketDetails/useGetMarketData.ts +++ b/sections/futures/MarketDetails/useGetMarketData.ts @@ -49,7 +49,8 @@ const useGetMarketData = (mobile?: boolean) => { const oraclePrice = marketPrices.onChain ?? wei(0); const data: MarketData = useMemo(() => { - const fundingValue = marketInfo?.currentFundingRate; + // TODO: remove this hard-coded display fix for funding + const fundingValue = marketInfo?.currentFundingRate.div(oraclePrice); const marketName = `${marketInfo?.marketName ?? t('futures.market.info.default-market')}`; diff --git a/sections/futures/MarketInfo/MarketHead.tsx b/sections/futures/MarketInfo/MarketHead.tsx index d312688899..6dce43c6bb 100644 --- a/sections/futures/MarketInfo/MarketHead.tsx +++ b/sections/futures/MarketInfo/MarketHead.tsx @@ -1,17 +1,15 @@ import Head from 'next/head'; -import React from 'react'; +import { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { DEFAULT_CRYPTO_DECIMALS } from 'constants/defaults'; -import useSelectedPriceCurrency from 'hooks/useSelectedPriceCurrency'; import { selectMarketAsset, selectSkewAdjustedPrice } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; import { formatCurrency } from 'utils/formatters/number'; import { getDisplayAsset, isDecimalFour } from 'utils/futures'; -const MarketHead: React.FC = () => { +const MarketHead: FC = () => { const { t } = useTranslation(); - const { selectedPriceCurrency } = useSelectedPriceCurrency(); const marketAsset = useAppSelector(selectMarketAsset); const latestPrice = useAppSelector(selectSkewAdjustedPrice); @@ -23,8 +21,8 @@ const MarketHead: React.FC = () => { {latestPrice ? t('futures.market.page-title-rate', { marketName, - rate: formatCurrency(selectedPriceCurrency.name, latestPrice, { - currencyKey: selectedPriceCurrency.name, + rate: formatCurrency('sUSD', latestPrice, { + currencyKey: 'sUSD', minDecimals: marketName != null && isDecimalFour(marketName) ? DEFAULT_CRYPTO_DECIMALS diff --git a/sections/futures/MarketInfoBox/MarketInfoBox.tsx b/sections/futures/MarketInfoBox/MarketInfoBox.tsx index 043981a7dc..0b2457f1d8 100644 --- a/sections/futures/MarketInfoBox/MarketInfoBox.tsx +++ b/sections/futures/MarketInfoBox/MarketInfoBox.tsx @@ -45,17 +45,13 @@ const MarketInfoBox: React.FC = () => { }, [commitDeposit, marketInfo?.keeperDeposit]); const getPotentialAvailableMargin = useCallback( - (trade: FuturesPotentialTradeDetails | null, marketMaxLeverage: Wei | undefined) => { - let inaccessible; - - inaccessible = + (trade: FuturesPotentialTradeDetails | null, marketMaxLeverage?: Wei) => { + let inaccessible = (marketMaxLeverage && trade?.notionalValue.div(marketMaxLeverage).abs()) ?? zeroBN; // If the user has a position open, we'll enforce a min initial margin requirement. - if (inaccessible.gt(0)) { - if (inaccessible.lt(minInitialMargin)) { - inaccessible = minInitialMargin; - } + if (inaccessible.gt(0) && inaccessible.lt(minInitialMargin)) { + inaccessible = minInitialMargin; } // check if available margin will be less than 0 @@ -107,9 +103,7 @@ const MarketInfoBox: React.FC = () => { dataTestId="market-info-box" details={{ 'Available Margin': { - value: `${formatDollars(availableMargin, { - currencyKey: undefined, - })}`, + value: formatDollars(availableMargin, { currencyKey: undefined }), valueNode: ( {formatDollars(previewTradeData?.availableMargin)} @@ -117,9 +111,7 @@ const MarketInfoBox: React.FC = () => { ), }, 'Buying Power': { - value: `${formatDollars(buyingPower, { - currencyKey: undefined, - })}`, + value: formatDollars(buyingPower, { currencyKey: undefined }), valueNode: previewTradeData?.buyingPower && ( {formatDollars(previewTradeData?.buyingPower)} @@ -127,7 +119,7 @@ const MarketInfoBox: React.FC = () => { ), }, 'Margin Usage': { - value: `${formatPercent(marginUsage)}`, + value: formatPercent(marginUsage), valueNode: ( {formatPercent(previewTradeData?.marginUsage)} diff --git a/sections/futures/MobileTrade/OverviewTabs/AccountTab.tsx b/sections/futures/MobileTrade/OverviewTabs/AccountTab.tsx index 5ccf78e6c9..159005e076 100644 --- a/sections/futures/MobileTrade/OverviewTabs/AccountTab.tsx +++ b/sections/futures/MobileTrade/OverviewTabs/AccountTab.tsx @@ -1,13 +1,12 @@ import React from 'react'; +import { Pane, SectionHeader, SectionTitle } from 'sections/futures/mobile'; import MarketInfoBox from 'sections/futures/MarketInfoBox'; import MarketActions from 'sections/futures/Trade/MarketActions'; import MarginInfoBox from 'sections/futures/TradeCrossMargin/CrossMarginInfoBox'; import { selectFuturesType } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { Pane, SectionHeader, SectionTitle } from '../common'; - const AccountTab: React.FC = () => { const accountType = useAppSelector(selectFuturesType); return ( diff --git a/sections/futures/MobileTrade/OverviewTabs/PriceTab.tsx b/sections/futures/MobileTrade/OverviewTabs/PriceTab.tsx index cd8c6309d3..c683ef75f1 100644 --- a/sections/futures/MobileTrade/OverviewTabs/PriceTab.tsx +++ b/sections/futures/MobileTrade/OverviewTabs/PriceTab.tsx @@ -1,10 +1,9 @@ import React from 'react'; import styled from 'styled-components'; +import { Pane } from 'sections/futures/mobile'; import PositionChart from 'sections/futures/PositionChart'; -import { Pane } from '../common'; - const PriceTab: React.FC = () => { return ( diff --git a/sections/futures/MobileTrade/OverviewTabs/StatsTab.tsx b/sections/futures/MobileTrade/OverviewTabs/StatsTab.tsx index 1dc484b124..f06c0b5c01 100644 --- a/sections/futures/MobileTrade/OverviewTabs/StatsTab.tsx +++ b/sections/futures/MobileTrade/OverviewTabs/StatsTab.tsx @@ -1,9 +1,8 @@ import React from 'react'; +import { Pane, SectionHeader, SectionTitle } from 'sections/futures/mobile'; import MarketDetails from 'sections/futures/MarketDetails'; -import { Pane, SectionHeader, SectionTitle } from '../common'; - const StatsTab: React.FC = () => { return ( diff --git a/sections/futures/MobileTrade/OverviewTabs/TradesTab.tsx b/sections/futures/MobileTrade/OverviewTabs/TradesTab.tsx index 6338a56be9..c1210f559c 100644 --- a/sections/futures/MobileTrade/OverviewTabs/TradesTab.tsx +++ b/sections/futures/MobileTrade/OverviewTabs/TradesTab.tsx @@ -1,9 +1,8 @@ import React from 'react'; +import { Pane } from 'sections/futures/mobile'; import TradesHistoryTable from 'sections/futures/TradingHistory/TradesHistoryTable'; -import { Pane } from '../common'; - const TradesTab: React.FC = () => { return ( diff --git a/sections/futures/MobileTrade/PositionDetails.tsx b/sections/futures/MobileTrade/PositionDetails.tsx index b72f52f6fc..81e78630f4 100644 --- a/sections/futures/MobileTrade/PositionDetails.tsx +++ b/sections/futures/MobileTrade/PositionDetails.tsx @@ -1,11 +1,11 @@ import React from 'react'; import styled from 'styled-components'; +import { SectionHeader, SectionSeparator, SectionTitle } from 'sections/futures/mobile'; import { selectPosition } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; import PositionCard from '../PositionCard'; -import { SectionHeader, SectionSeparator, SectionTitle } from './common'; const PositionDetails = () => { const position = useAppSelector(selectPosition); diff --git a/sections/futures/MobileTrade/UserTabs/OrdersTab.tsx b/sections/futures/MobileTrade/UserTabs/OrdersTab.tsx index fa3d3752c8..3de262961c 100644 --- a/sections/futures/MobileTrade/UserTabs/OrdersTab.tsx +++ b/sections/futures/MobileTrade/UserTabs/OrdersTab.tsx @@ -1,9 +1,8 @@ import React from 'react'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import OpenOrdersTable from 'sections/futures/UserInfo/OpenOrdersTable'; -import { SectionHeader, SectionTitle } from '../common'; - const OrdersTab: React.FC = () => { return (
diff --git a/sections/futures/MobileTrade/UserTabs/TradesTab.tsx b/sections/futures/MobileTrade/UserTabs/TradesTab.tsx index d960215d6c..00f9712d6b 100644 --- a/sections/futures/MobileTrade/UserTabs/TradesTab.tsx +++ b/sections/futures/MobileTrade/UserTabs/TradesTab.tsx @@ -4,20 +4,20 @@ import { useTranslation } from 'react-i18next'; import { CellProps } from 'react-table'; import styled, { css } from 'styled-components'; -import Table, { TableNoResults } from 'components/Table'; +import { GridDivCenteredRow } from 'components/layout/grid'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; import { ETH_UNIT } from 'constants/network'; import Connector from 'containers/Connector'; import { FuturesTrade } from 'queries/futures/types'; import useGetFuturesTradesForAccount from 'queries/futures/useGetFuturesTradesForAccount'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import TimeDisplay from 'sections/futures/Trades/TimeDisplay'; import { PositionSide, TradeStatus } from 'sections/futures/types'; import { selectMarketAsset } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { GridDivCenteredRow } from 'styles/common'; import { formatCryptoCurrency } from 'utils/formatters/number'; import { FuturesMarketAsset, getMarketName } from 'utils/futures'; -import { SectionHeader, SectionTitle } from '../common'; import TradeDrawer from '../drawers/TradeDrawer'; const TradesTab: React.FC = () => { @@ -64,24 +64,18 @@ const TradesTab: React.FC = () => { }} columns={[ { - Header: ( - {t('futures.market.user.trades.table.date')} - ), + Header: {t('futures.market.user.trades.table.date')}, accessor: 'timestamp', Cell: (cellProps: CellProps) => ( - + ), width: 70, sortable: true, }, { - Header: ( - - {t('futures.market.user.trades.table.side-type')} - - ), + Header: {t('futures.market.user.trades.table.side-type')}, accessor: 'side', sortType: 'basic', Cell: (cellProps: CellProps) => ( @@ -94,11 +88,7 @@ const TradesTab: React.FC = () => { sortable: true, }, { - Header: ( - - {t('futures.market.user.trades.table.trade-size')} - - ), + Header: {t('futures.market.user.trades.table.trade-size')}, accessor: 'size', sortType: 'basic', Cell: (cellProps: CellProps) => ( @@ -127,11 +117,6 @@ const TradesTab: React.FC = () => { export default TradesTab; -const StyledTableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - text-transform: capitalize; -`; - const StyledPositionSide = styled.div<{ side: PositionSide }>` text-transform: uppercase; font-weight: bold; diff --git a/sections/futures/MobileTrade/UserTabs/TransfersTab.tsx b/sections/futures/MobileTrade/UserTabs/TransfersTab.tsx index c87a6fd0fe..52aac25cae 100644 --- a/sections/futures/MobileTrade/UserTabs/TransfersTab.tsx +++ b/sections/futures/MobileTrade/UserTabs/TransfersTab.tsx @@ -2,18 +2,16 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import Table, { TableNoResults } from 'components/Table'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; import useGetFuturesMarginTransfers from 'queries/futures/useGetFuturesMarginTransfers'; +import { SectionHeader, SectionTitle } from 'sections/futures/mobile'; import { timePresentation } from 'utils/formatters/date'; -import { SectionHeader, SectionTitle } from '../common'; - const TransfersTab: React.FC = () => { const marginTransfersQuery = useGetFuturesMarginTransfers(); - const marginTransfers = React.useMemo( - () => (marginTransfersQuery.isSuccess ? marginTransfersQuery?.data ?? [] : []), - [marginTransfersQuery.isSuccess, marginTransfersQuery.data] - ); + const marginTransfers = React.useMemo(() => marginTransfersQuery?.data ?? [], [ + marginTransfersQuery.data, + ]); const { isLoading, isFetched: isLoaded } = marginTransfersQuery; @@ -30,21 +28,13 @@ const TransfersTab: React.FC = () => { highlightRowsOnHover columns={[ { - Header: ( - - {t('futures.market.user.transfers.table.action')} - - ), + Header: {t('futures.market.user.transfers.table.action')}, accessor: 'action', Cell: (cellProps: any) => {cellProps.value}, width: 50, }, { - Header: ( - - {t('futures.market.user.transfers.table.amount')} - - ), + Header: {t('futures.market.user.transfers.table.amount')}, accessor: 'amount', sortType: 'basic', Cell: (cellProps: any) => ( @@ -56,9 +46,7 @@ const TransfersTab: React.FC = () => { width: 50, }, { - Header: ( - {t('futures.market.user.transfers.table.date')} - ), + Header: {t('futures.market.user.transfers.table.date')}, accessor: 'timestamp', Cell: (cellProps: any) => ( {timePresentation(cellProps.value, t)} @@ -104,9 +92,4 @@ const StyledAmountCell = styled(DefaultCell)<{ isPositive: boolean }>` : props.theme.colors.selectedTheme.red}; `; -const StyledTableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - text-transform: capitalize; -`; - export default TransfersTab; diff --git a/sections/futures/MobileTrade/drawers/TradeDrawer.tsx b/sections/futures/MobileTrade/drawers/TradeDrawer.tsx index bdf0b9e58c..4088cc0334 100644 --- a/sections/futures/MobileTrade/drawers/TradeDrawer.tsx +++ b/sections/futures/MobileTrade/drawers/TradeDrawer.tsx @@ -38,7 +38,7 @@ const TradeDrawer: React.FC = ({ trade, closeDrawer }) => { label: 'Price', value: formatDollars(trade.price), }, - { label: 'Date/Time', value: }, + { label: 'Date/Time', value: }, { label: 'PnL', value: trade.pnl.eq(0) ? ( diff --git a/sections/futures/OrderPriceInput/OrderPriceInput.tsx b/sections/futures/OrderPriceInput/OrderPriceInput.tsx index 3fdfa47866..40c41bd339 100644 --- a/sections/futures/OrderPriceInput/OrderPriceInput.tsx +++ b/sections/futures/OrderPriceInput/OrderPriceInput.tsx @@ -8,7 +8,7 @@ import styled from 'styled-components'; import CustomInput from 'components/Input/CustomInput'; import InputTitle from 'components/Input/InputTitle'; import SegmentedControl from 'components/SegmentedControl'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import Tooltip from 'components/Tooltip/Tooltip'; import { FuturesOrderType } from 'queries/futures/types'; import { selectMarketPrice, selectMarketInfo, selectLeverageSide } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; @@ -96,13 +96,13 @@ export default function OrderPriceInput({ invalid={!!minMaxLabelString} dataTestId="order-price-input" disabled={isDisabled} - right={'sUSD'} + right="sUSD" value={localValue} placeholder="0.0" onChange={handleOnChange} /> - {t('futures.market.trade.orders.fee-rejection-label')}: - + { setPercent(value); diff --git a/sections/futures/OrderSizing/OrderSizing.tsx b/sections/futures/OrderSizing/OrderSizing.tsx index 9151d91dd1..723a33b363 100644 --- a/sections/futures/OrderSizing/OrderSizing.tsx +++ b/sections/futures/OrderSizing/OrderSizing.tsx @@ -1,10 +1,11 @@ import { wei } from '@synthetixio/wei'; -import React, { ChangeEvent, useMemo, useState } from 'react'; +import React, { ChangeEvent, useMemo, useState, memo } from 'react'; import styled from 'styled-components'; import SwitchAssetArrows from 'assets/svg/futures/switch-arrows.svg'; import CustomInput from 'components/Input/CustomInput'; import InputTitle from 'components/Input/InputTitle'; +import { FlexDivRow } from 'components/layout/flex'; import { useFuturesContext } from 'contexts/FuturesContext'; import { editTradeSizeInput } from 'state/futures/actions'; import { @@ -19,7 +20,6 @@ import { selectMarketAsset, } from 'state/futures/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; -import { FlexDivRow } from 'styles/common'; import { floorNumber, isZero, zeroBN } from 'utils/formatters/number'; import { getDisplayAsset } from 'utils/futures'; @@ -30,7 +30,7 @@ type OrderSizingProps = { disabled?: boolean; }; -const OrderSizing: React.FC = ({ disabled, isMobile }) => { +const OrderSizing: React.FC = memo(({ disabled, isMobile }) => { const { maxUsdInputAmount } = useFuturesContext(); const dispatch = useAppDispatch(); @@ -133,7 +133,7 @@ const OrderSizing: React.FC = ({ disabled, isMobile }) => { {selectedAccountType === 'cross_margin' && } ); -}; +}); const OrderSizingContainer = styled.div` margin-top: 28px; diff --git a/sections/futures/PositionButtons/PositionButtons.tsx b/sections/futures/PositionButtons/PositionButtons.tsx index 42c9e25509..fd67661d15 100644 --- a/sections/futures/PositionButtons/PositionButtons.tsx +++ b/sections/futures/PositionButtons/PositionButtons.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { memo, FC } from 'react'; import styled, { css } from 'styled-components'; import Button from 'components/Button'; @@ -13,7 +13,7 @@ interface PositionButtonsProps { type?: 'button' | 'submit' | 'reset' | undefined; } -const PositionButtons: React.FC = ({ selected, onSelect }) => { +const PositionButtons: FC = memo(({ selected, onSelect }) => { const marketInfo = useAppSelector(selectMarketInfo); return ( @@ -40,7 +40,7 @@ const PositionButtons: React.FC = ({ selected, onSelect }) ); -}; +}); type PositionButtonProps = { $position: PositionSide; @@ -74,7 +74,7 @@ const StyledPositionButton = styled(Button)` color: ${props.theme.colors.selectedTheme.green}; ${props.$isActive && css` - border: 1px solid ${(props) => props.theme.colors.selectedTheme.green}; + border: 1px solid ${props.theme.colors.selectedTheme.green}; border-radius: 8px; background: linear-gradient( 180deg, diff --git a/sections/futures/PositionCard/ClosePositionModal.tsx b/sections/futures/PositionCard/ClosePositionModal.tsx index 1987934d5a..6b517f4d8a 100644 --- a/sections/futures/PositionCard/ClosePositionModal.tsx +++ b/sections/futures/PositionCard/ClosePositionModal.tsx @@ -5,15 +5,16 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import Error from 'components/Error'; +import Error from 'components/ErrorView'; +import { FlexDivCentered, FlexDivCol } from 'components/layout/flex'; import { ButtonLoader } from 'components/Loader/Loader'; import Connector from 'containers/Connector'; import { getFuturesMarketContract } from 'queries/futures/utils'; import { FuturesFilledPosition } from 'sdk/types/futures'; import { selectIsClosingPosition, selectMarketAsset } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { FlexDivCentered, FlexDivCol } from 'styles/common'; import { formatCurrency, formatDollars, formatNumber, zeroBN } from 'utils/formatters/number'; +import logError from 'utils/logError'; import { PositionSide } from '../types'; @@ -53,9 +54,7 @@ function ClosePositionModal({ const orderFee = await FuturesMarketContract.orderFee(size.toBN()); setOrderFee(wei(orderFee.fee)); } catch (e) { - // @ts-ignore logError(e.message); - // @ts-ignore setError(e?.data?.message ?? e.message); } }; diff --git a/sections/futures/PositionCard/PositionCard.tsx b/sections/futures/PositionCard/PositionCard.tsx index c4daa23a1d..7c56bd0739 100644 --- a/sections/futures/PositionCard/PositionCard.tsx +++ b/sections/futures/PositionCard/PositionCard.tsx @@ -3,8 +3,10 @@ import React, { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styled, { css } from 'styled-components'; +import { FlexDivCentered, FlexDivCol } from 'components/layout/flex'; import PreviewArrow from 'components/PreviewArrow'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import { Body } from 'components/Text'; +import Tooltip from 'components/Tooltip/Tooltip'; import { DEFAULT_CRYPTO_DECIMALS } from 'constants/defaults'; import { NO_VALUE } from 'constants/placeholder'; import Connector from 'containers/Connector'; @@ -22,7 +24,7 @@ import { selectActivePositionHistory, } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { FlexDivCentered, FlexDivCol, PillButtonDiv } from 'styles/common'; +import { PillButtonDiv } from 'styles/common'; import media from 'styles/media'; import { isFiatCurrency } from 'utils/currencies'; import { formatDollars, formatPercent, zeroBN } from 'utils/formatters/number'; @@ -138,10 +140,7 @@ const PositionCard: React.FC = () => { marketLongName: getSynthDescription(marketAsset, synthsMap, t), marketPrice: ( <> - {`${formatDollars(marketPrice, { - minDecimals, - isAssetPrice: true, - })}`} + {formatDollars(marketPrice, { minDecimals, isAssetPrice: true })} { {formatDollars(previewData.fillPrice ?? zeroBN, { @@ -289,30 +288,22 @@ const PositionCard: React.FC = () => { - {data.marketShortName} + {data.marketShortName} {data.marketPrice} - - + + {t('futures.market.position-card.position-side')} - +
{data.positionSide}
- - + + {t('futures.market.position-card.position-size')} - + {data.positionSize} @@ -320,14 +311,10 @@ const PositionCard: React.FC = () => { - - + + {t('futures.market.position-card.net-funding')} - + {positionDetails ? ( = () => { )} - - - {t('futures.market.position-card.u-pnl')} - + + {t('futures.market.position-card.u-pnl')} {positionDetails ? ( zeroBN ? 'green' : data.pnl < zeroBN ? 'red' : ''}> @@ -360,14 +341,8 @@ const PositionCard: React.FC = () => { )} - - - {t('futures.market.position-card.r-pnl')} - + + {t('futures.market.position-card.r-pnl')} {positionDetails ? ( = () => { - - - {t('futures.market.position-card.leverage')} - + + {t('futures.market.position-card.leverage')} {data.leverage} @@ -403,25 +372,21 @@ const PositionCard: React.FC = () => { - + {t('futures.market.position-card.liquidation-price')} - + {data.liquidationPrice} - + {t('futures.market.position-card.avg-entry-price')} - + {data.avgEntryPrice} @@ -430,6 +395,7 @@ const PositionCard: React.FC = () => { ); }; + export default PositionCard; const Container = styled.div` @@ -482,33 +448,24 @@ const InfoRow = styled.div` } `; -const StyledSubtitle = styled.p` - font-family: ${(props) => props.theme.fonts.regular}; +const Subtitle = styled(Body)` font-size: 13px; color: ${(props) => props.theme.colors.selectedTheme.gray}; text-transform: capitalize; - margin: 0; `; -const StyledSubtitleWithCursor = styled.p` - font-family: ${(props) => props.theme.fonts.regular}; - font-size: 13px; - color: ${(props) => props.theme.colors.selectedTheme.gray}; - text-transform: capitalize; - margin: 0; +const SubtitleWithCursor = styled(Subtitle)` cursor: help; `; -const PositionCardTooltip = styled(StyledTooltip)` +const PositionCardTooltip = styled(Tooltip).attrs({ preset: 'fixed', height: 'auto' })` z-index: 2; padding: 0px 10px 0px 10px; `; -const StyledValue = styled.p` - font-family: ${(props) => props.theme.fonts.mono}; +const StyledValue = styled(Body).attrs({ mono: true })` font-size: 13px; color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - margin: 0; text-align: end; ${Container}#closed & { color: ${(props) => props.theme.colors.selectedTheme.gray}; diff --git a/sections/futures/PositionChart/PositionChart.tsx b/sections/futures/PositionChart/PositionChart.tsx index c397e1d153..2d7f342f3f 100644 --- a/sections/futures/PositionChart/PositionChart.tsx +++ b/sections/futures/PositionChart/PositionChart.tsx @@ -11,6 +11,7 @@ import { selectTradePreview, } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; +import media from 'styles/media'; export default function PositionChart() { const marketAsset = useAppSelector(selectMarketAsset); @@ -43,8 +44,8 @@ export default function PositionChart() { }, [subgraphPosition, position]); const onToggleLines = useCallback(() => { - setShowOrderLines(!showOrderLines); - }, [setShowOrderLines, showOrderLines]); + setShowOrderLines((show) => !show); + }, [setShowOrderLines]); return ( @@ -72,6 +73,9 @@ export default function PositionChart() { const Container = styled.div<{ visible: boolean }>` border: ${(props) => props.theme.colors.selectedTheme.border}; + ${media.lessThan('md')` + border: none; + `} border-radius: 10px; padding: 3px; min-height: 450px; diff --git a/sections/futures/ShareModal/AmountContainer.tsx b/sections/futures/ShareModal/AmountContainer.tsx index c75a0d531b..49f1df45c5 100644 --- a/sections/futures/ShareModal/AmountContainer.tsx +++ b/sections/futures/ShareModal/AmountContainer.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, useMemo } from 'react'; import styled from 'styled-components'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; @@ -14,12 +14,6 @@ type AmountContainerProps = { position: FuturesPosition | null | undefined; }; -const currencyIconStyle = { - height: '1.94vw', - width: 'auto', - margin: '-0.3vw 0.5vw 0vw 0vw', -}; - const AmountContainer: FC = ({ position }) => { const marketAsset = useAppSelector(selectMarketAsset); @@ -29,7 +23,7 @@ const AmountContainer: FC = ({ position }) => { const side = positionDetails?.side === 'long' ? PositionSide.LONG : PositionSide.SHORT; const pnlPct = positionDetails?.pnlPct.mul(100); - const amount = () => { + const amount = useMemo(() => { if (pnlPct) { return pnlPct.gt(0) ? `+${pnlPct.toNumber().toFixed(2)}%` @@ -37,30 +31,33 @@ const AmountContainer: FC = ({ position }) => { ? `+0.00%` : `${pnlPct.toNumber().toFixed(2)}%`; } - }; + }, [pnlPct]); return ( - <> - - - - {marketName} - {`|`} - {side.toUpperCase()} - {`|`} - {`${leverage}`} - - {amount()} - - + + + + {marketName} + | + {side.toUpperCase()} + | + {leverage} + + {amount} + ); }; +const StyledCurrencyIcon = styled(CurrencyIcon)` + height: 1.94vw; + width: auto; + margin: -0.3vw 0.5vw 0vw 0vw; +`; + const StyledPositionLeverage = styled.div` display: flex; flex-direction: column; color: ${(props) => props.theme.colors.common.primaryGold}; - font-size: 1.07vw; `; diff --git a/sections/futures/Trade/DelayedOrderConfirmationModal.tsx b/sections/futures/Trade/DelayedOrderConfirmationModal.tsx index 81b08fd6f7..1bd26dad5e 100644 --- a/sections/futures/Trade/DelayedOrderConfirmationModal.tsx +++ b/sections/futures/Trade/DelayedOrderConfirmationModal.tsx @@ -4,7 +4,8 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import Error from 'components/Error'; +import Error from 'components/ErrorView'; +import { FlexDivCentered } from 'components/layout/flex'; import { ButtonLoader } from 'components/Loader/Loader'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import useSelectedPriceCurrency from 'hooks/useSelectedPriceCurrency'; @@ -27,7 +28,6 @@ import { } from 'state/futures/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; import { FetchStatus } from 'state/types'; -import { FlexDivCentered } from 'styles/common'; import { getKnownError } from 'utils/formatters/error'; import { zeroBN, @@ -69,12 +69,21 @@ const DelayedOrderConfirmationModal: FC = () => { ); }, [nativeSizeDelta, orderType, dispatch]); - const positionSize = position?.position?.size ?? zeroBN; + const positionSize = useMemo(() => { + const positionDetails = position?.position; + return positionDetails + ? positionDetails.size.mul(positionDetails.side === PositionSide.LONG ? 1 : -1) + : zeroBN; + }, [position]); const orderDetails = useMemo(() => { return { nativeSizeDelta, size: (positionSize ?? zeroBN).add(nativeSizeDelta).abs() }; }, [nativeSizeDelta, positionSize]); + const isClosing = useMemo(() => { + return orderDetails.size.eq(zeroBN); + }, [orderDetails]); + // TODO: check this deposit const totalDeposit = useMemo(() => { return (commitDeposit ?? zeroBN).add(marketInfo?.keeperDeposit ?? zeroBN); @@ -156,7 +165,7 @@ const DelayedOrderConfirmationModal: FC = () => { dispatch(setOpenModal(null)); }, [dispatch]); - const handleConfirmOrder = async () => { + const handleConfirmOrder = () => { dispatch( modifyIsolatedPosition({ sizeDelta: nativeSizeDelta, @@ -172,13 +181,17 @@ const DelayedOrderConfirmationModal: FC = () => { {dataRows.map((row, i) => ( - {row.value} + {row.value} ))} @@ -190,6 +203,8 @@ const DelayedOrderConfirmationModal: FC = () => { {submitting ? ( + ) : isClosing ? ( + t('futures.market.trade.confirmation.modal.close-order') ) : ( t('futures.market.trade.confirmation.modal.confirm-order') )} @@ -211,6 +226,8 @@ const DelayedOrderConfirmationModal: FC = () => { > {submitting ? ( + ) : isClosing ? ( + t('futures.market.trade.confirmation.modal.close-order') ) : ( t('futures.market.trade.confirmation.modal.confirm-order') )} diff --git a/sections/futures/Trade/FuturesUnsupported.tsx b/sections/futures/Trade/FuturesUnsupported.tsx index 538271d1f1..68a20cee46 100644 --- a/sections/futures/Trade/FuturesUnsupported.tsx +++ b/sections/futures/Trade/FuturesUnsupported.tsx @@ -10,12 +10,10 @@ const FuturesUnsupportedNetwork = () => { return ( {t('futures.page-title')} - <> - {t('common.l2-cta')} - -
{t('homepage.l2.cta-buttons.switch-l2')}
-
- + {t('common.l2-cta')} + +
{t('homepage.l2.cta-buttons.switch-l2')}
+
); }; diff --git a/sections/futures/Trade/ManagePosition.tsx b/sections/futures/Trade/ManagePosition.tsx index 22940e64df..ae8c5ac462 100644 --- a/sections/futures/Trade/ManagePosition.tsx +++ b/sections/futures/Trade/ManagePosition.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; -import Error from 'components/Error'; +import Error from 'components/ErrorView'; import { useFuturesContext } from 'contexts/FuturesContext'; import { previewErrorI18n } from 'queries/futures/constants'; import { PositionSide } from 'sdk/types/futures'; @@ -86,11 +86,14 @@ const ManagePosition: React.FC = () => { const leverageValid = useMemo(() => { if (selectedAccountType === 'cross_margin') return true; - const leverageNum = Number(leverage || 0); - return leverageNum > 0 && leverageNum < maxLeverageValue.toNumber(); + return leverage.gt(0) && leverage.lt(maxLeverageValue); }, [selectedAccountType, maxLeverageValue, leverage]); const placeOrderDisabledReason = useMemo(() => { + if (!leverageValid) return 'invalid_leverage'; + if (marketInfo?.isSuspended) return 'market_suspended'; + if (isMarketCapReached) return 'market_cap_reached'; + const invalidReason = orderPriceInvalidLabel( orderPrice, leverageSide, @@ -98,9 +101,6 @@ const ManagePosition: React.FC = () => { orderType ); - if (!leverageValid) return 'invalid_leverage'; - if (marketInfo?.isSuspended) return 'market_suspended'; - if (isMarketCapReached) return 'market_cap_reached'; if ((orderType === 'limit' || orderType === 'stop market') && !!invalidReason) return invalidReason; if (susdSize.gt(maxUsdInputAmount)) return 'max_size_exceeded'; diff --git a/sections/futures/Trade/MarketsDropdownOption.tsx b/sections/futures/Trade/MarketsDropdownOption.tsx index 1a02591612..a804d35acc 100644 --- a/sections/futures/Trade/MarketsDropdownOption.tsx +++ b/sections/futures/Trade/MarketsDropdownOption.tsx @@ -3,7 +3,7 @@ import styled, { css } from 'styled-components'; import MarketBadge from 'components/Badge/MarketBadge'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; -import { FlexDivCentered } from 'styles/common'; +import { FlexDivCentered } from 'components/layout/flex'; import { MarketsCurrencyOption } from './MarketsDropdown'; import { CurrencyLabel, SingleValueContainer } from './MarketsDropdownSingleValue'; diff --git a/sections/futures/Trade/MarketsDropdownSingleValue.tsx b/sections/futures/Trade/MarketsDropdownSingleValue.tsx index 4a77bb0d4f..ee638b1d1a 100644 --- a/sections/futures/Trade/MarketsDropdownSingleValue.tsx +++ b/sections/futures/Trade/MarketsDropdownSingleValue.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import MarketBadge from 'components/Badge/MarketBadge'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; -import { FlexDivCentered } from 'styles/common'; +import { FlexDivCentered } from 'components/layout/flex'; import { MarketKeyByAsset } from 'utils/futures'; import { MarketsCurrencyOption } from './MarketsDropdown'; diff --git a/sections/futures/Trade/TradeConfirmationModal.tsx b/sections/futures/Trade/TradeConfirmationModal.tsx index ae93dc9c11..a6bd4a337d 100644 --- a/sections/futures/Trade/TradeConfirmationModal.tsx +++ b/sections/futures/Trade/TradeConfirmationModal.tsx @@ -6,7 +6,8 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import ErrorView from 'components/Error'; +import ErrorView from 'components/ErrorView'; +import { FlexDivCentered } from 'components/layout/flex'; import { ButtonLoader } from 'components/Loader/Loader'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import { MIN_MARGIN_AMOUNT } from 'constants/futures'; @@ -19,7 +20,6 @@ import { selectTradePreview, } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; -import { FlexDivCentered } from 'styles/common'; import { zeroBN, formatCurrency, diff --git a/sections/futures/Trade/TradeIsolatedMargin.tsx b/sections/futures/Trade/TradeIsolatedMargin.tsx index 94ab6140e2..17cffd9c6f 100644 --- a/sections/futures/Trade/TradeIsolatedMargin.tsx +++ b/sections/futures/Trade/TradeIsolatedMargin.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import Error from 'components/Error'; +import Error from 'components/ErrorView'; import SegmentedControl from 'components/SegmentedControl'; import { DEFAULT_DELAYED_LEVERAGE_CAP, ISOLATED_MARGIN_ORDER_TYPES } from 'constants/futures'; import { setOpenModal } from 'state/app/reducer'; diff --git a/sections/futures/Trade/TransferIsolatedMarginModal.tsx b/sections/futures/Trade/TransferIsolatedMarginModal.tsx index e042788056..85e2f12951 100644 --- a/sections/futures/Trade/TransferIsolatedMarginModal.tsx +++ b/sections/futures/Trade/TransferIsolatedMarginModal.tsx @@ -5,8 +5,9 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import Error from 'components/Error'; +import Error from 'components/ErrorView'; import CustomInput from 'components/Input/CustomInput'; +import { FlexDivRowCentered } from 'components/layout/flex'; import SegmentedControl from 'components/SegmentedControl'; import Spacer from 'components/Spacer'; import { MIN_MARGIN_AMOUNT } from 'constants/futures'; @@ -18,7 +19,6 @@ import { selectPosition, } from 'state/futures/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; -import { FlexDivRowCentered } from 'styles/common'; import { formatDollars, zeroBN } from 'utils/formatters/number'; type Props = { diff --git a/sections/futures/TradeCrossMargin/CreateAccount.tsx b/sections/futures/TradeCrossMargin/CreateAccount.tsx index 5ca9d11552..40fc01cbf2 100644 --- a/sections/futures/TradeCrossMargin/CreateAccount.tsx +++ b/sections/futures/TradeCrossMargin/CreateAccount.tsx @@ -77,5 +77,5 @@ const CreateAccountButton = styled(Button)` const Questions = styled.div` margin-top: 10px; - border-top: ${(props) => `${props.theme.colors.selectedTheme.border}`}; + border-top: ${(props) => props.theme.colors.selectedTheme.border}; `; diff --git a/sections/futures/TradeCrossMargin/CrossMarginInfoBox.tsx b/sections/futures/TradeCrossMargin/CrossMarginInfoBox.tsx index c5ecae4803..ef4a9ca4a2 100644 --- a/sections/futures/TradeCrossMargin/CrossMarginInfoBox.tsx +++ b/sections/futures/TradeCrossMargin/CrossMarginInfoBox.tsx @@ -4,7 +4,6 @@ import styled from 'styled-components'; import WithdrawArrow from 'assets/svg/futures/withdraw-arrow.svg'; import InfoBox from 'components/InfoBox'; -import { MiniLoader } from 'components/Loader'; import PreviewArrow from 'components/PreviewArrow'; import { useFuturesContext } from 'contexts/FuturesContext'; import { FuturesPotentialTradeDetails } from 'sdk/types/futures'; @@ -152,8 +151,9 @@ function MarginInfoBox({ editingLeverage }: Props) { - {isLoading ? : formatDollars(previewTradeData.freeAccountMargin)} + {formatDollars(previewTradeData.freeAccountMargin)} ), } @@ -161,16 +161,16 @@ function MarginInfoBox({ editingLeverage }: Props) { 'Market Margin': { value: formatDollars(position?.remainingMargin || 0), valueNode: ( - - {isLoading ? : formatDollars(previewTradeData.totalMargin)} + + {formatDollars(previewTradeData.totalMargin)} ), }, 'Margin Usage': { value: formatPercent(marginUsage), valueNode: ( - - {isLoading ? : formatPercent(previewTradeData?.marginUsage)} + + {formatPercent(previewTradeData?.marginUsage)} ), }, @@ -209,8 +209,8 @@ function MarginInfoBox({ editingLeverage }: Props) { ), valueNode: ( - - {isLoading ? : formatNumber(previewTradeData.leverage || 0) + 'x'} + + {formatNumber(previewTradeData.leverage || 0) + 'x'} ), }, diff --git a/sections/futures/TradeCrossMargin/DepositWithdrawCrossMargin.tsx b/sections/futures/TradeCrossMargin/DepositWithdrawCrossMargin.tsx index 871b836193..776591355a 100644 --- a/sections/futures/TradeCrossMargin/DepositWithdrawCrossMargin.tsx +++ b/sections/futures/TradeCrossMargin/DepositWithdrawCrossMargin.tsx @@ -5,8 +5,9 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import ErrorView from 'components/Error'; +import ErrorView from 'components/ErrorView'; import CustomInput from 'components/Input/CustomInput'; +import { FlexDivRowCentered } from 'components/layout/flex'; import Loader from 'components/Loader'; import SegmentedControl from 'components/SegmentedControl'; import { MIN_MARGIN_AMOUNT } from 'constants/futures'; @@ -19,7 +20,6 @@ import { selectIsSubmittingCrossTransfer, } from 'state/futures/selectors'; import { useAppDispatch, useAppSelector } from 'state/hooks'; -import { FlexDivRowCentered } from 'styles/common'; import { formatDollars, zeroBN } from 'utils/formatters/number'; import logError from 'utils/logError'; diff --git a/sections/futures/TradeCrossMargin/EditCrossMarginLeverageModal.tsx b/sections/futures/TradeCrossMargin/EditCrossMarginLeverageModal.tsx index 21356af7d4..9af3e5c0b0 100644 --- a/sections/futures/TradeCrossMargin/EditCrossMarginLeverageModal.tsx +++ b/sections/futures/TradeCrossMargin/EditCrossMarginLeverageModal.tsx @@ -6,8 +6,9 @@ import styled from 'styled-components'; import BaseModal from 'components/BaseModal'; import Button from 'components/Button'; -import ErrorView from 'components/Error'; +import ErrorView from 'components/ErrorView'; import CustomInput from 'components/Input/CustomInput'; +import { FlexDivRow, FlexDivRowCentered } from 'components/layout/flex'; import Loader from 'components/Loader'; import Spacer from 'components/Spacer'; import { NumberSpan } from 'components/Text/NumberLabel'; @@ -33,7 +34,6 @@ import { selectTradePreviewError, } from 'state/futures/selectors'; import { useAppSelector, useAppDispatch } from 'state/hooks'; -import { FlexDivRow, FlexDivRowCentered } from 'styles/common'; import { isUserDeniedError } from 'utils/formatters/error'; import { formatDollars, zeroBN } from 'utils/formatters/number'; import logError from 'utils/logError'; diff --git a/sections/futures/TradeCrossMargin/ManageKeeperBalanceModal.tsx b/sections/futures/TradeCrossMargin/ManageKeeperBalanceModal.tsx index efad7164b3..435a01f65d 100644 --- a/sections/futures/TradeCrossMargin/ManageKeeperBalanceModal.tsx +++ b/sections/futures/TradeCrossMargin/ManageKeeperBalanceModal.tsx @@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import ErrorView from 'components/Error'; +import ErrorView from 'components/ErrorView'; import CustomInput from 'components/Input/CustomInput'; import Loader from 'components/Loader'; import SegmentedControl from 'components/SegmentedControl'; diff --git a/sections/futures/Trades/TimeDisplay.tsx b/sections/futures/Trades/TimeDisplay.tsx index af13ca3a22..9710bbaf32 100644 --- a/sections/futures/Trades/TimeDisplay.tsx +++ b/sections/futures/Trades/TimeDisplay.tsx @@ -1,29 +1,31 @@ import { format } from 'date-fns'; -import { FC, useCallback, useState } from 'react'; +import { FC, useCallback, useMemo, useState, memo } from 'react'; import styled, { css } from 'styled-components'; import getLocale from 'utils/formatters/getLocale'; type TimeDisplayProps = { - cellPropsValue: any; + value: any; horizontal?: boolean; }; -const TimeDisplay: FC = ({ cellPropsValue, horizontal }) => { - const [show12hr, setShow12h] = useState(false); +const TimeDisplay: FC = memo(({ value, horizontal }) => { + const [show12hr, setShow12h] = useState(false); const handleOnClick = useCallback(() => { - setShow12h(!show12hr); - }, [show12hr]); + setShow12h((current) => !current); + }, []); - const date = format( - new Date(cellPropsValue), - getLocale().formatLong?.date({ width: 'short' }) ?? 'MM/dd/yy' + const locale = useMemo(() => getLocale(), []); + + const date = useMemo( + () => format(new Date(value), locale.formatLong?.date({ width: 'short' }) ?? 'MM/dd/yy'), + [value, locale] ); - const time12hr = new Date(cellPropsValue).toLocaleTimeString(getLocale().code); - const time24hr = format(new Date(cellPropsValue), 'HH:mm:ss', { - locale: getLocale(), - }); + + const time12hr = useMemo(() => new Date(value).toLocaleTimeString(locale.code), [value, locale]); + + const time24hr = useMemo(() => format(new Date(value), 'HH:mm:ss', { locale }), [value, locale]); return ( @@ -31,7 +33,7 @@ const TimeDisplay: FC = ({ cellPropsValue, horizontal }) => {
{show12hr ? time12hr : time24hr}
); -}; +}); const TimeDisplayContainer = styled.div<{ horizontal?: boolean }>` ${(props) => @@ -42,7 +44,7 @@ const TimeDisplayContainer = styled.div<{ horizontal?: boolean }>` margin-right: 5px; } div:last-child { - color: ${(props) => props.theme.colors.common.secondaryGray}; + color: ${props.theme.colors.common.secondaryGray}; } `} `; diff --git a/sections/futures/Trades/Trades.tsx b/sections/futures/Trades/Trades.tsx index 7aa8d959dc..c8cdb30b60 100644 --- a/sections/futures/Trades/Trades.tsx +++ b/sections/futures/Trades/Trades.tsx @@ -5,14 +5,15 @@ import styled, { css } from 'styled-components'; import LinkIcon from 'assets/svg/app/link-blue.svg'; import Card from 'components/Card'; -import Table, { TableNoResults } from 'components/Table'; +import { GridDivCenteredRow } from 'components/layout/grid'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; import { DEFAULT_CRYPTO_DECIMALS } from 'constants/defaults'; import { ETH_UNIT } from 'constants/network'; import { blockExplorer } from 'containers/Connector/Connector'; import useIsL2 from 'hooks/useIsL2'; import useNetworkSwitcher from 'hooks/useNetworkSwitcher'; import { FuturesTrade } from 'queries/futures/types'; -import { ExternalLink, GridDivCenteredRow } from 'styles/common'; +import { ExternalLink } from 'styles/common'; import { formatCryptoCurrency, formatDollars } from 'utils/formatters/number'; import { PositionSide, TradeStatus } from '../types'; @@ -54,22 +55,18 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss highlightRowsOnHover columns={[ { - Header: ( - {t('futures.market.user.trades.table.date')} - ), + Header: {t('futures.market.user.trades.table.date')}, accessor: 'time', Cell: (cellProps: CellProps) => ( - + ), width: 90, sortable: true, }, { - Header: ( - {t('futures.market.user.trades.table.side')} - ), + Header: {t('futures.market.user.trades.table.side')}, accessor: 'side', sortType: 'basic', Cell: (cellProps: CellProps) => ( @@ -81,9 +78,7 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss sortable: true, }, { - Header: ( - {t('futures.market.user.trades.table.price')} - ), + Header: {t('futures.market.user.trades.table.price')}, accessor: 'value', sortType: 'basic', Cell: (cellProps: CellProps) => { @@ -98,11 +93,7 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss sortable: true, }, { - Header: ( - - {t('futures.market.user.trades.table.trade-size')} - - ), + Header: {t('futures.market.user.trades.table.trade-size')}, accessor: 'amount', sortType: 'basic', Cell: (cellProps: CellProps) => ( @@ -112,9 +103,7 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss sortable: true, }, { - Header: ( - {t('futures.market.user.trades.table.fees')} - ), + Header: {t('futures.market.user.trades.table.fees')}, sortType: 'basic', accessor: 'feesPaid', Cell: (cellProps: CellProps) => ( @@ -124,11 +113,7 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss sortable: true, }, { - Header: ( - - {t('futures.market.user.trades.table.order-type')} - - ), + Header: {t('futures.market.user.trades.table.order-type')}, accessor: 'type', sortType: 'basic', Cell: (cellProps: CellProps) => <>{cellProps.value}, @@ -167,11 +152,6 @@ const Trades: React.FC = ({ history, isLoading, isLoaded, marketAss export default Trades; -const StyledTableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - text-transform: capitalize; -`; - const StyledPositionSide = styled.div<{ side: PositionSide }>` text-transform: uppercase; ${(props) => diff --git a/sections/futures/TradingHistory/SkewInfo.tsx b/sections/futures/TradingHistory/SkewInfo.tsx index 135760b7ed..98836c1c5f 100644 --- a/sections/futures/TradingHistory/SkewInfo.tsx +++ b/sections/futures/TradingHistory/SkewInfo.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import Tooltip from 'components/Tooltip/Tooltip'; import { selectMarketAsset, selectMarketInfo } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; import { CapitalizedText, NumericValue } from 'styles/common'; @@ -93,7 +93,7 @@ const WithCursor = styled.div<{ cursor: 'help' }>` cursor: ${(props) => props.cursor}; `; -const SkewTooltip = styled(StyledTooltip)<{ isNumber?: boolean }>` +const SkewTooltip = styled(Tooltip)<{ isNumber?: boolean }>` left: -30px; z-index: 2; padding: 10px; diff --git a/sections/futures/TradingHistory/TradesHistoryTable.tsx b/sections/futures/TradingHistory/TradesHistoryTable.tsx index 1b39c0eb83..5bb3ea020d 100644 --- a/sections/futures/TradingHistory/TradesHistoryTable.tsx +++ b/sections/futures/TradingHistory/TradesHistoryTable.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { CellProps } from 'react-table'; import styled, { css } from 'styled-components'; -import Table from 'components/Table'; +import Table, { TableHeader } from 'components/Table'; import { DEFAULT_CRYPTO_DECIMALS } from 'constants/defaults'; import { NO_VALUE } from 'constants/placeholder'; import { blockExplorer } from 'containers/Connector/Connector'; @@ -242,11 +242,6 @@ const StyledTable = styled(Table)<{ mobile?: boolean }>` } `; -const TableHeader = styled(CapitalizedText)` - font-size: 13px; - font-family: ${(props) => props.theme.fonts.regular}; -`; - const PriceValue = styled(NumericValue)` font-size: 13px; color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; diff --git a/sections/futures/Transfers/Transfers.tsx b/sections/futures/Transfers/Transfers.tsx index 439a37ceae..1590a4eaca 100644 --- a/sections/futures/Transfers/Transfers.tsx +++ b/sections/futures/Transfers/Transfers.tsx @@ -2,7 +2,7 @@ import { FC, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; -import Table, { TableNoResults } from 'components/Table'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; import { blockExplorer } from 'containers/Connector/Connector'; import useIsL2 from 'hooks/useIsL2'; import useNetworkSwitcher from 'hooks/useNetworkSwitcher'; @@ -29,17 +29,13 @@ const Transfers: FC = ({ marginTransfers, isLoading, isLoaded }) highlightRowsOnHover columns={[ { - Header: ( - {t('futures.market.user.transfers.table.action')} - ), + Header: {t('futures.market.user.transfers.table.action')}, accessor: 'action', Cell: (cellProps: any) => {cellProps.value}, width: 50, }, { - Header: ( - {t('futures.market.user.transfers.table.amount')} - ), + Header: {t('futures.market.user.transfers.table.amount')}, accessor: 'amount', sortType: 'basic', Cell: (cellProps: any) => ( @@ -51,9 +47,7 @@ const Transfers: FC = ({ marginTransfers, isLoading, isLoaded }) width: 50, }, { - Header: ( - {t('futures.market.user.transfers.table.date')} - ), + Header: {t('futures.market.user.transfers.table.date')}, accessor: 'timestamp', Cell: (cellProps: any) => ( {timePresentation(cellProps.value, t)} @@ -61,11 +55,7 @@ const Transfers: FC = ({ marginTransfers, isLoading, isLoaded }) width: 50, }, { - Header: ( - - {t('futures.market.user.transfers.table.transaction')} - - ), + Header: {t('futures.market.user.transfers.table.transaction')}, accessor: 'txHash', Cell: (cellProps: any) => { return ( @@ -130,8 +120,3 @@ const StyledAmountCell = styled(DefaultCell)<{ isPositive: boolean }>` ? props.theme.colors.selectedTheme.green : props.theme.colors.selectedTheme.red}; `; - -const StyledTableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - text-transform: capitalize; -`; diff --git a/sections/futures/UserInfo/OpenOrdersTable.tsx b/sections/futures/UserInfo/OpenOrdersTable.tsx index 6deedbb35b..f82e160a3a 100644 --- a/sections/futures/UserInfo/OpenOrdersTable.tsx +++ b/sections/futures/UserInfo/OpenOrdersTable.tsx @@ -6,7 +6,7 @@ import styled, { css } from 'styled-components'; import Badge from 'components/Badge'; import Currency from 'components/Currency'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; -import Table, { TableNoResults } from 'components/Table'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; import { DEFAULT_DELAYED_EXECUTION_BUFFER } from 'constants/defaults'; import useIsL2 from 'hooks/useIsL2'; import useNetworkSwitcher from 'hooks/useNetworkSwitcher'; @@ -144,9 +144,7 @@ const OpenOrdersTable: React.FC = () => { columns={[ { Header: ( - - {t('futures.market.user.open-orders.table.market-type')} - + {t('futures.market.user.open-orders.table.market-type')} ), accessor: 'market', Cell: (cellProps: CellProps) => { @@ -171,11 +169,7 @@ const OpenOrdersTable: React.FC = () => { width: 60, }, { - Header: ( - - {t('futures.market.user.open-orders.table.side')} - - ), + Header: {t('futures.market.user.open-orders.table.side')}, accessor: 'side', Cell: (cellProps: CellProps) => { return ( @@ -188,11 +182,7 @@ const OpenOrdersTable: React.FC = () => { width: 40, }, { - Header: ( - - {t('futures.market.user.open-orders.table.size')} - - ), + Header: {t('futures.market.user.open-orders.table.size')}, accessor: 'size', Cell: (cellProps: CellProps) => { return ( @@ -206,9 +196,9 @@ const OpenOrdersTable: React.FC = () => { }, { Header: ( - + {t('futures.market.user.open-orders.table.commit-deposit')} - + ), accessor: 'marginDelta', Cell: (cellProps: CellProps) => { @@ -220,9 +210,7 @@ const OpenOrdersTable: React.FC = () => { }, { Header: ( - - {t('futures.market.user.open-orders.table.status')} - + {t('futures.market.user.open-orders.table.status')} ), accessor: 'actions', Cell: (cellProps: CellProps) => { @@ -266,9 +254,7 @@ const OpenOrdersTable: React.FC = () => { columns={[ { Header: ( - - {t('futures.market.user.open-orders.table.side-type')} - + {t('futures.market.user.open-orders.table.side-type')} ), accessor: 'side/type', Cell: (cellProps: CellProps) => ( @@ -282,11 +268,7 @@ const OpenOrdersTable: React.FC = () => { width: 100, }, { - Header: ( - - {t('futures.market.user.open-orders.table.size')} - - ), + Header: {t('futures.market.user.open-orders.table.size')}, accessor: 'size', Cell: (cellProps: CellProps) => { return ( @@ -313,11 +295,6 @@ const StyledTable = styled(Table)` margin-bottom: 20px; `; -const StyledTableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - text-transform: capitalize; -`; - const StyledCurrencyIcon = styled(Currency.Icon)` width: 30px; height: 30px; diff --git a/sections/futures/MobileTrade/common.ts b/sections/futures/mobile.ts similarity index 94% rename from sections/futures/MobileTrade/common.ts rename to sections/futures/mobile.ts index 67755d029c..c17f22be38 100644 --- a/sections/futures/MobileTrade/common.ts +++ b/sections/futures/mobile.ts @@ -12,7 +12,6 @@ export const SectionTitle = styled.div` color: ${(props) => props.theme.colors.selectedTheme.yellow}; text-transform: uppercase; font-size: 13px; - text-shadow: 0px 1px 3px rgb(242, 242, 242); `; export const SectionSubTitle = styled.div` diff --git a/sections/homepage/Assets/Assets.tsx b/sections/homepage/Assets.tsx similarity index 90% rename from sections/homepage/Assets/Assets.tsx rename to sections/homepage/Assets.tsx index 998acefc56..3fdf2933d5 100644 --- a/sections/homepage/Assets/Assets.tsx +++ b/sections/homepage/Assets.tsx @@ -1,6 +1,5 @@ import { wei } from '@synthetixio/wei'; import { ColorType, createChart, UTCTimestamp } from 'lightweight-charts'; -import isNil from 'lodash/isNil'; import values from 'lodash/values'; import router from 'next/router'; import React, { useEffect, useMemo, useRef, useState } from 'react'; @@ -14,10 +13,10 @@ import GridSvg from 'assets/svg/app/grid.svg'; import Button from 'components/Button'; import ChangePercent from 'components/ChangePercent'; import Currency from 'components/Currency'; +import { FlexDiv, FlexDivColCentered, FlexDivRow } from 'components/layout/flex'; import { TabPanel } from 'components/Tab'; import { CurrencyKey } from 'constants/currency'; import Connector from 'containers/Connector'; -import { Price } from 'queries/rates/types'; import { requestCandlesticks } from 'queries/rates/useCandlesticksQuery'; import useGetSynthsTradingVolumeForAllMarkets from 'queries/synths/useGetSynthsTradingVolumeForAllMarkets'; import { selectMarketVolumes } from 'state/futures/selectors'; @@ -26,13 +25,7 @@ import { selectOptimismMarkets } from 'state/home/selectors'; import { useAppSelector, usePollAction } from 'state/hooks'; import { selectPrices } from 'state/prices/selectors'; import { pastRatesState } from 'store/futures'; -import { - FlexDiv, - FlexDivColCentered, - FlexDivRow, - SmallGoldenHeader, - WhiteHeader, -} from 'styles/common'; +import { SmallGoldenHeader, WhiteHeader } from 'styles/common'; import media, { Media } from 'styles/media'; import { getSynthDescription } from 'utils/futures'; @@ -149,7 +142,7 @@ export const PriceChart = ({ asset }: PriceChartProps) => { const Assets = () => { const { t } = useTranslation(); const { l2SynthsMap, l2Provider } = Connector.useContainer(); - const [activeMarketsTab, setActiveMarketsTab] = useState(MarketsTab.FUTURES); + const [activeMarketsTab, setActiveMarketsTab] = useState(MarketsTab.FUTURES); const prices = useAppSelector(selectPrices); const futuresMarkets = useAppSelector(selectOptimismMarkets); @@ -188,7 +181,7 @@ const Assets = () => { const frozenSynthsQuery = queryCache.find(['synths', 'frozenSynths', 10]); const unfrozenSynths = - frozenSynthsQuery && frozenSynthsQuery.state.status === 'success' + frozenSynthsQuery?.state.status === 'success' ? synths.filter( (synth) => !(frozenSynthsQuery.state.data as Set).has(synth.name) ) @@ -198,30 +191,27 @@ const Assets = () => { const synthVolumesQuery = useGetSynthsTradingVolumeForAllMarkets(yesterday); const PERPS = useMemo(() => { - return ( - futuresMarkets?.map((market) => { - const marketPrice = - prices[market.asset]?.offChain ?? prices[market.asset]?.onChain ?? wei(0); - const description = getSynthDescription(market.asset, l2SynthsMap, t); - const volume = futuresVolumes[market.assetHex]?.volume?.toNumber() ?? 0; - const pastPrice = pastRates.find( - (price: Price) => price.synth === market.asset || price.synth === market.asset.slice(1) - ); - return { - key: market.asset, - name: market.asset[0] === 's' ? market.asset.slice(1) : market.asset, - description: description.split(' ')[0], - price: marketPrice.toNumber(), - volume, - priceChange: - (marketPrice.toNumber() - (pastPrice?.price ?? 0)) / marketPrice.toNumber() || 0, - image: , - icon: ( - - ), - }; - }) ?? [] - ); + return futuresMarkets.map((market) => { + const marketPrice = prices[market.asset]?.offChain ?? prices[market.asset]?.onChain ?? wei(0); + const description = getSynthDescription(market.asset, l2SynthsMap, t); + const volume = futuresVolumes[market.assetHex]?.volume?.toNumber() ?? 0; + const pastPrice = pastRates.find( + (price) => price.synth === market.asset || price.synth === market.asset.slice(1) + ); + return { + key: market.asset, + name: market.asset[0] === 's' ? market.asset.slice(1) : market.asset, + description: description.split(' ')[0], + price: marketPrice.toNumber(), + volume, + priceChange: + (marketPrice.toNumber() - (pastPrice?.price ?? 0)) / marketPrice.toNumber() || 0, + image: , + icon: ( + + ), + }; + }); // eslint-disable-next-line }, [futuresMarkets, l2SynthsMap, pastRates, futuresVolumes, t]); @@ -234,10 +224,10 @@ const Assets = () => { currencyName: synth.description, }) : ''; - const rate = prices && (prices[synth.name]?.onChain || prices[synth.name]?.offChain); - const price = isNil(rate) ? 0 : rate.toNumber(); + const rate = prices?.[synth.name]?.onChain || prices?.[synth.name]?.offChain; + const price = rate?.toNumber() ?? 0; - const pastPrice = pastRates.find((price: Price) => { + const pastPrice = pastRates.find((price) => { return price.synth === synth.asset || price.synth === synth.name; }); @@ -247,7 +237,7 @@ const Assets = () => { description: description.slice(10), price, change: price !== 0 ? (price - (pastPrice?.price ?? 0)) / price || 0 : 0, - volume: !isNil(synthVolumes[synth.name]) ? Number(synthVolumes[synth.name]) ?? 0 : 0, + volume: synthVolumes[synth.name]?.toNumber() ?? 0, image: , icon: ( @@ -310,9 +300,9 @@ const Assets = () => { {image} @@ -331,9 +321,9 @@ const Assets = () => { <>- ) : ( @@ -370,9 +360,9 @@ const Assets = () => { {image} @@ -391,9 +381,9 @@ const Assets = () => { <>- ) : ( @@ -440,9 +430,9 @@ const Assets = () => { {image} @@ -461,9 +451,9 @@ const Assets = () => { <>- ) : ( @@ -499,9 +489,9 @@ const Assets = () => { {image} @@ -520,9 +510,9 @@ const Assets = () => { <>- ) : ( diff --git a/sections/homepage/Assets/index.ts b/sections/homepage/Assets/index.ts deleted file mode 100644 index f7e0f87fd6..0000000000 --- a/sections/homepage/Assets/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Assets'; diff --git a/sections/homepage/Earning/Earning.tsx b/sections/homepage/Earning.tsx similarity index 93% rename from sections/homepage/Earning/Earning.tsx rename to sections/homepage/Earning.tsx index d037816a15..4714ac3030 100644 --- a/sections/homepage/Earning/Earning.tsx +++ b/sections/homepage/Earning.tsx @@ -5,19 +5,18 @@ import styled from 'styled-components'; import StakeNEarnIcon from 'assets/svg/earn/stake-n-earn.svg'; import TradeNEarnIcon from 'assets/svg/earn/trade-n-earn.svg'; import VoteNGovernIcon from 'assets/svg/earn/vote-n-govern.svg'; +import { StackSection } from 'sections/homepage/section'; +import { Copy, Title } from 'sections/homepage/text'; import { FlexDivCentered, FlexDivCol, FlexDivColCentered, FlexDivRow, - GridDiv, - SmallGoldenHeader, - WhiteHeader, -} from 'styles/common'; +} from 'components/layout/flex'; +import { GridDiv } from 'components/layout/grid'; +import { SmallGoldenHeader, WhiteHeader } from 'styles/common'; import media, { Media } from 'styles/media'; -import { Copy, StackSection, Title } from '../common'; - const EARNINGS = [ { id: 'vote-and-govern', diff --git a/sections/homepage/Earning/index.ts b/sections/homepage/Earning/index.ts deleted file mode 100644 index 2706892636..0000000000 --- a/sections/homepage/Earning/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Earning'; diff --git a/sections/homepage/Features/Features.tsx b/sections/homepage/Features.tsx similarity index 97% rename from sections/homepage/Features/Features.tsx rename to sections/homepage/Features.tsx index 440283ad43..dee4d54546 100644 --- a/sections/homepage/Features/Features.tsx +++ b/sections/homepage/Features.tsx @@ -23,14 +23,12 @@ import { FlexDivCol, FlexDivColCentered, FlexDivRow, - GridDivCentered, - SmallGoldenHeader, - WhiteHeader, -} from 'styles/common'; +} from 'components/layout/flex'; +import { GridDivCentered } from 'components/layout/grid'; +import { Copy, Title } from 'sections/homepage/text'; +import { SmallGoldenHeader, WhiteHeader } from 'styles/common'; import media from 'styles/media'; -import { Copy, Title } from '../common'; - const FEATURES = [ { key: 'blazing-fast', diff --git a/sections/homepage/Features/index.ts b/sections/homepage/Features/index.ts deleted file mode 100644 index b5fde73644..0000000000 --- a/sections/homepage/Features/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Features'; diff --git a/sections/homepage/Hero/Hero.tsx b/sections/homepage/Hero.tsx similarity index 88% rename from sections/homepage/Hero/Hero.tsx rename to sections/homepage/Hero.tsx index 02d93c2532..ce6769759e 100644 --- a/sections/homepage/Hero/Hero.tsx +++ b/sections/homepage/Hero.tsx @@ -5,15 +5,16 @@ import styled from 'styled-components'; import MarketOrderPreview from 'assets/png/marketing/market-order-preview.png'; import Button from 'components/Button'; +import { StackSection } from 'sections/homepage/section'; +import { FlexDivColCentered } from 'components/layout/flex'; +import { GridDiv } from 'components/layout/grid'; import PoweredBySynthetix from 'components/PoweredBySynthetix'; +import * as Text from 'components/Text'; import Webp from 'components/Webp'; import { DEFAULT_FUTURES_MARGIN_TYPE } from 'constants/defaults'; import ROUTES from 'constants/routes'; -import { FlexDivColCentered, GridDiv, Paragraph } from 'styles/common'; import media from 'styles/media'; -import { StackSection } from '../common'; - const Hero = () => { const { t } = useTranslation(); @@ -53,8 +54,7 @@ const Emphasis = styled.b` color: ${(props) => props.theme.colors.common.primaryWhite}; `; -const Header = styled(Paragraph)` - font-family: ${(props) => props.theme.fonts.monoBold}; +const Header = styled(Text.Body).attrs({ variant: 'bold', mono: true })` max-width: 636px; font-size: 80px; line-height: 85%; @@ -68,8 +68,7 @@ const Header = styled(Paragraph)` `} `; -const ProductDescription = styled(Paragraph)` - font-family: ${(props) => props.theme.fonts.regular}; +const ProductDescription = styled(Text.Body)` max-width: 530px; font-size: 24px; line-height: 120%; diff --git a/sections/homepage/Hero/index.ts b/sections/homepage/Hero/index.ts deleted file mode 100644 index 9c292bc06d..0000000000 --- a/sections/homepage/Hero/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Hero'; diff --git a/sections/homepage/ShortList/ShortList.tsx b/sections/homepage/ShortList.tsx similarity index 95% rename from sections/homepage/ShortList/ShortList.tsx rename to sections/homepage/ShortList.tsx index 3c1f37ebdc..bdf2dd7254 100644 --- a/sections/homepage/ShortList/ShortList.tsx +++ b/sections/homepage/ShortList.tsx @@ -7,18 +7,19 @@ import styled from 'styled-components'; import GridSvg from 'assets/svg/app/grid.svg'; import Button from 'components/Button'; import Currency from 'components/Currency'; +import { FlexDivColCentered, FlexDivRow } from 'components/layout/flex'; import Loader from 'components/Loader'; -import Table from 'components/Table'; +import Table, { TableHeader } from 'components/Table'; import ROUTES from 'constants/routes'; import useENS from 'hooks/useENS'; import useGetFuturesCumulativeStats from 'queries/futures/useGetFuturesCumulativeStats'; import useGetStats from 'queries/futures/useGetStats'; -import { FlexDivColCentered, FlexDivRow, SmallGoldenHeader, WhiteHeader } from 'styles/common'; +import { StackSection } from 'sections/homepage/section'; +import { Title } from 'sections/homepage/text'; +import { SmallGoldenHeader, WhiteHeader } from 'styles/common'; import media, { Media } from 'styles/media'; import { formatDollars, formatNumber, zeroBN } from 'utils/formatters/number'; -import { StackSection, Title } from '../common'; - const ShortList = () => { const { t } = useTranslation(); @@ -134,9 +135,9 @@ const ShortList = () => { accessor: 'pnl', Cell: (cellProps: CellProps) => ( ), @@ -197,9 +198,9 @@ const ShortList = () => { accessor: 'pnl', Cell: (cellProps: CellProps) => ( ), @@ -343,12 +344,6 @@ const Container = styled(FlexDivColCentered)` justify-content: center; `; -const TableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.common.secondaryGray}; - font-size: 13px; -`; - const StyledOrderType = styled.div` color: ${(props) => props.theme.colors.white}; text-align: center; diff --git a/sections/homepage/ShortList/index.ts b/sections/homepage/ShortList/index.ts deleted file mode 100644 index 1bd07f9f9f..0000000000 --- a/sections/homepage/ShortList/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ShortList'; diff --git a/sections/homepage/TradeNow/TradeNow.tsx b/sections/homepage/TradeNow.tsx similarity index 92% rename from sections/homepage/TradeNow/TradeNow.tsx rename to sections/homepage/TradeNow.tsx index a557623e3c..33dd8e1d15 100644 --- a/sections/homepage/TradeNow/TradeNow.tsx +++ b/sections/homepage/TradeNow.tsx @@ -4,9 +4,11 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import Button from 'components/Button'; +import { FlexDivColCentered } from 'components/layout/flex'; +import * as Text from 'components/Text'; import { DEFAULT_FUTURES_MARGIN_TYPE } from 'constants/defaults'; import ROUTES from 'constants/routes'; -import { FlexDivColCentered, Paragraph, SmallGoldenHeader, WhiteHeader } from 'styles/common'; +import { SmallGoldenHeader, WhiteHeader } from 'styles/common'; import media from 'styles/media'; const TradeNow = () => { @@ -68,7 +70,7 @@ const Container = styled.div` `}; `; -const GrayDescription = styled(Paragraph)` +const GrayDescription = styled(Text.Body)` color: ${(props) => props.theme.colors.common.secondaryGray}; font-size: 24px; line-height: 120%; diff --git a/sections/homepage/TradeNow/index.ts b/sections/homepage/TradeNow/index.ts deleted file mode 100644 index 47d8ab1321..0000000000 --- a/sections/homepage/TradeNow/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TradeNow'; diff --git a/sections/homepage/containers/SmoothScroll/SmoothScroll.tsx b/sections/homepage/containers/SmoothScroll/SmoothScroll.tsx deleted file mode 100644 index 72db4ca4b4..0000000000 --- a/sections/homepage/containers/SmoothScroll/SmoothScroll.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { MutableRefObject, useRef } from 'react'; -import { createContainer } from 'unstated-next'; - -const useSmoothScroll = () => { - const whyKwentaRef = useRef(null); - const howItWorksRef = useRef(null); - const faqRef = useRef(null); - - const scrollToRef = (ref: MutableRefObject) => { - if (ref && ref.current) { - ref.current.scrollIntoView({ - behavior: 'smooth', - }); - } - }; - - return { - whyKwentaRef, - howItWorksRef, - faqRef, - scrollToRef, - }; -}; - -const SmoothScroll = createContainer(useSmoothScroll); - -export default SmoothScroll; diff --git a/sections/homepage/containers/SmoothScroll/index.tsx b/sections/homepage/containers/SmoothScroll/index.tsx deleted file mode 100644 index 29d4e373ae..0000000000 --- a/sections/homepage/containers/SmoothScroll/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SmoothScroll'; diff --git a/sections/homepage/containers/index.tsx b/sections/homepage/containers/index.tsx deleted file mode 100644 index 4029c1c5e5..0000000000 --- a/sections/homepage/containers/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React, { FC } from 'react'; - -import SmoothScroll from './SmoothScroll'; - -type WithHomepageContainersProps = { - children: React.ReactNode; -}; - -export const WithHomepageContainers: FC = ({ children }) => ( - {children} -); - -export default WithHomepageContainers; diff --git a/sections/homepage/common.tsx b/sections/homepage/section.ts similarity index 50% rename from sections/homepage/common.tsx rename to sections/homepage/section.ts index d50ddba040..17e6b091b3 100644 --- a/sections/homepage/common.tsx +++ b/sections/homepage/section.ts @@ -1,6 +1,7 @@ import styled from 'styled-components'; -import { FlexDivColCentered, GridDiv, Paragraph } from 'styles/common'; +import { FlexDivColCentered } from 'components/layout/flex'; +import { GridDiv } from 'components/layout/grid'; import media from 'styles/media'; export const StackSection = styled(FlexDivColCentered)` @@ -19,18 +20,3 @@ export const GridContainer = styled(GridDiv)` grid-template-columns: 1fr; `} `; - -export const Title = styled(Paragraph)` - font-size: 16px; - font-family: ${(props) => props.theme.fonts.bold}; - text-align: left; - color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; -`; - -export const Copy = styled(Paragraph)` - font-size: 16px; - font-style: normal; - line-height: 24px; - text-align: left; - color: ${(props) => props.theme.colors.silver}; -`; diff --git a/sections/homepage/text.ts b/sections/homepage/text.ts new file mode 100644 index 0000000000..7aef0b1b1a --- /dev/null +++ b/sections/homepage/text.ts @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +import { Body } from 'components/Text'; + +export const Title = styled(Body).attrs({ variant: 'bold' })` + font-size: 16px; + text-align: left; + color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; +`; + +export const Copy = styled(Body)` + font-size: 16px; + font-style: normal; + line-height: 24px; + text-align: left; + color: ${(props) => props.theme.colors.silver}; +`; diff --git a/sections/leaderboard/AllTime/AllTime.tsx b/sections/leaderboard/AllTime.tsx similarity index 93% rename from sections/leaderboard/AllTime/AllTime.tsx rename to sections/leaderboard/AllTime.tsx index c213395e06..e5bebb2804 100644 --- a/sections/leaderboard/AllTime/AllTime.tsx +++ b/sections/leaderboard/AllTime.tsx @@ -5,13 +5,13 @@ import styled from 'styled-components'; import Currency from 'components/Currency'; import { MobileHiddenView, MobileOnlyView } from 'components/Media'; -import Table from 'components/Table'; +import Table, { TableHeader } from 'components/Table'; import { DEFAULT_LEADERBOARD_ROWS } from 'constants/defaults'; import Connector from 'containers/Connector'; import useENSAvatar from 'hooks/useENSAvatar'; import { AccountStat } from 'queries/futures/types'; - -import { getMedal, StyledTrader } from '../common'; +import { StyledTrader } from 'sections/leaderboard/trader'; +import { getMedal } from 'utils/competition'; type AllTimeProps = { stats: AccountStat[]; @@ -34,7 +34,7 @@ const AllTime: FC = ({ const { staticMainnetProvider, walletAddress } = Connector.useContainer(); if (compact) { - const ownPosition = stats.findIndex((i: { account: string }) => { + const ownPosition = stats.findIndex((i) => { return i.account.toLowerCase() === walletAddress?.toLowerCase(); }); @@ -146,9 +146,9 @@ const AllTime: FC = ({ accessor: 'totalVolume', Cell: (cellProps: CellProps) => ( ), @@ -159,9 +159,9 @@ const AllTime: FC = ({ accessor: 'pnl', Cell: (cellProps: CellProps) => ( ), @@ -230,7 +230,7 @@ const AllTime: FC = ({ Header: () => {t('leaderboard.leaderboard.table.pnl')}, accessor: 'pnl', Cell: (cellProps: CellProps) => ( - + ), width: 125, }, @@ -267,11 +267,6 @@ const TitleText = styled.div` text-transform: capitalize; `; -const TableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.gray}; -`; - const StyledOrderType = styled.div` color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; display: flex; diff --git a/sections/leaderboard/AllTime/index.tsx b/sections/leaderboard/AllTime/index.tsx deleted file mode 100644 index 021d28694d..0000000000 --- a/sections/leaderboard/AllTime/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AllTime'; diff --git a/sections/leaderboard/Competition/Competition.tsx b/sections/leaderboard/Competition.tsx similarity index 92% rename from sections/leaderboard/Competition/Competition.tsx rename to sections/leaderboard/Competition.tsx index 553a17c7f4..61f9d864a7 100644 --- a/sections/leaderboard/Competition/Competition.tsx +++ b/sections/leaderboard/Competition.tsx @@ -6,17 +6,17 @@ import styled from 'styled-components'; import Currency from 'components/Currency'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; -import Table, { TableNoResults } from 'components/Table'; +import Table, { TableHeader, TableNoResults } from 'components/Table'; +import { CompetitionRound, PIN, Tier } from 'constants/competition'; import Connector from 'containers/Connector'; import useENSs from 'hooks/useENSs'; import useGetFile from 'queries/files/useGetFile'; import { AccountStat } from 'queries/futures/types'; +import { StyledTrader } from 'sections/leaderboard/trader'; +import { getMedal, getCompetitionDataLocation } from 'utils/competition'; import { formatPercent } from 'utils/formatters/number'; import { truncateAddress } from 'utils/formatters/string'; -import { CompetitionRound, getMedal, PIN, StyledTrader, Tier } from '../common'; -import { getCompetitionDataLocation } from './constants'; - type CompetitionProps = { round: CompetitionRound; activeTier: Tier; @@ -45,10 +45,7 @@ const Competition: FC = ({ }, [walletAddress, competitionQuery]); const traders = useMemo( - () => - competitionQuery?.data?.map((stat: AccountStat) => { - return stat.account; - }) ?? [], + () => competitionQuery?.data?.map((stat: AccountStat) => stat.account) ?? [], [competitionQuery?.data] ); @@ -86,10 +83,7 @@ const Competition: FC = ({ const pinRow = cleanCompetitionData .filter((trader) => trader.account.toLowerCase() === walletAddress?.toLowerCase()) - .map((trader) => ({ - ...trader, - rankText: `${trader.rank}${PIN}`, - })); + .map((trader) => ({ ...trader, rankText: `${trader.rank}${PIN}` })); return [...pinRow, ...cleanCompetitionData]; }, [competitionQuery, ensInfo, searchTerm, activeTier, walletAddress, walletTier, compact]); @@ -169,9 +163,9 @@ const Competition: FC = ({ sortType: 'basic', Cell: (cellProps: CellProps) => ( ), @@ -183,11 +177,11 @@ const Competition: FC = ({ accessor: 'pnlNumber', sortType: 'basic', Cell: (cellProps: CellProps) => ( - + {cellProps.row.original.pnlPct} @@ -237,9 +231,9 @@ const Competition: FC = ({ Cell: (cellProps: CellProps) => ( {cellProps.row.original.pnlPct} @@ -269,11 +263,6 @@ const TitleText = styled.a` color: ${(props) => props.theme.colors.selectedTheme.gray}; `; -const TableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.gray}; -`; - const PnlContainer = styled.div<{ direction: 'row' | 'column' }>` display: flex; flex-direction: ${(props) => props.direction}; diff --git a/sections/leaderboard/Competition/constants.tsx b/sections/leaderboard/Competition/constants.tsx deleted file mode 100644 index 68d26b4df6..0000000000 --- a/sections/leaderboard/Competition/constants.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { CompetitionRound } from '../common'; - -export const getCompetitionDataLocation = (round: CompetitionRound) => { - return `crossmargin_competition_${round}/leaderboard_latest.json`; -}; diff --git a/sections/leaderboard/Competition/index.tsx b/sections/leaderboard/Competition/index.tsx deleted file mode 100644 index b2263d9773..0000000000 --- a/sections/leaderboard/Competition/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Competition'; diff --git a/sections/leaderboard/Leaderboard/Leaderboard.tsx b/sections/leaderboard/Leaderboard.tsx similarity index 87% rename from sections/leaderboard/Leaderboard/Leaderboard.tsx rename to sections/leaderboard/Leaderboard.tsx index 435bc9fdb0..0a038e8786 100644 --- a/sections/leaderboard/Leaderboard/Leaderboard.tsx +++ b/sections/leaderboard/Leaderboard.tsx @@ -4,20 +4,20 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import TabButton from 'components/Button/TabButton'; +import { FlexDivCol } from 'components/layout/flex'; import Search from 'components/Table/Search'; +import { CompetitionRound, COMPETITION_TIERS, PIN, Tier } from 'constants/competition'; import ROUTES from 'constants/routes'; import useENS from 'hooks/useENS'; import useENSs from 'hooks/useENSs'; import { AccountStat } from 'queries/futures/types'; import useLeaderboard, { DEFAULT_LEADERBOARD_DATA } from 'queries/futures/useLeaderboard'; import { CompetitionBanner } from 'sections/shared/components/CompetitionBanner'; -import { FlexDivCol } from 'styles/common'; import media from 'styles/media'; -import AllTime from '../AllTime'; -import { CompetitionRound, COMPETITION_TIERS, PIN, Tier } from '../common'; -import Competition from '../Competition'; -import TraderHistory from '../TraderHistory'; +import AllTime from './AllTime'; +import Competition from './Competition'; +import TraderHistory from './TraderHistory'; type LeaderboardProps = { compact?: boolean; @@ -31,8 +31,8 @@ enum LeaderboardTab { const LEADERBOARD_TABS = [LeaderboardTab.Top, LeaderboardTab.Bottom]; -const Leaderboard: FC = ({ compact, mobile }: LeaderboardProps) => { - const [activeTab, setActiveTab] = useState(LeaderboardTab.Top); +const Leaderboard: FC = ({ compact, mobile }) => { + const [activeTab, setActiveTab] = useState(LeaderboardTab.Top); const [activeTier, setActiveTier] = useState('bronze'); const [competitionRound, setCompetitionRound] = useState(); const [searchInput, setSearchInput] = useState(''); @@ -47,24 +47,16 @@ const Leaderboard: FC = ({ compact, mobile }: LeaderboardProps leaderboardQuery, ]); - const traders = useMemo( - () => - leaderboardData.all?.map((stat: AccountStat) => { - return stat.account; - }) ?? [], - [leaderboardData] - ); + const traders = useMemo(() => leaderboardData.all?.map((stat) => stat.account) ?? [], [ + leaderboardData, + ]); const ensInfoQuery = useENSs(traders); const ensInfo = useMemo(() => ensInfoQuery.data ?? {}, [ensInfoQuery]); - const pinRow: AccountStat[] = useMemo(() => { + const pinRow = useMemo(() => { return leaderboardData.wallet - ? leaderboardData.wallet.map((trader) => ({ - ...trader, - rank: 0, - rankText: PIN, - })) + ? leaderboardData.wallet.map((trader) => ({ ...trader, rank: 0, rankText: PIN })) : []; }, [leaderboardData.wallet]); @@ -85,7 +77,7 @@ const Leaderboard: FC = ({ compact, mobile }: LeaderboardProps return null; }, [router.query, router.asPath]); - const onChangeSearch = async (text: string) => { + const onChangeSearch = (text: string) => { setSearchInput(text?.toLowerCase()); if (isAddress(text)) { @@ -119,16 +111,11 @@ const Leaderboard: FC = ({ compact, mobile }: LeaderboardProps }; useEffect(() => { - setSearchAddress( - searchEns.ensAddress ? searchEns.ensAddress : isAddress(searchTerm) ? searchTerm : '' - ); + setSearchAddress(searchEns.ensAddress ?? (isAddress(searchTerm) ? searchTerm : '')); }, [searchTerm, searchEns]); const mapEnsName = useCallback( - (stat: AccountStat) => ({ - ...stat, - traderEns: ensInfo[stat.account] ?? null, - }), + (stat: AccountStat) => ({ ...stat, traderEns: ensInfo[stat.account] ?? null }), [ensInfo] ); diff --git a/sections/leaderboard/Leaderboard/index.tsx b/sections/leaderboard/Leaderboard/index.tsx deleted file mode 100644 index 7e4f019461..0000000000 --- a/sections/leaderboard/Leaderboard/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Leaderboard'; diff --git a/sections/leaderboard/TraderHistory.tsx b/sections/leaderboard/TraderHistory.tsx new file mode 100644 index 0000000000..5528b897e6 --- /dev/null +++ b/sections/leaderboard/TraderHistory.tsx @@ -0,0 +1,368 @@ +import { wei, WeiSource } from '@synthetixio/wei'; +import router from 'next/router'; +import { FC, memo, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { CellProps } from 'react-table'; +import styled, { css } from 'styled-components'; + +import Currency from 'components/Currency'; +import CurrencyIcon from 'components/Currency/CurrencyIcon'; +import { FlexDiv } from 'components/layout/flex'; +import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; +import FuturesIcon from 'components/Nav/FuturesIcon'; +import Table, { TableHeader } from 'components/Table'; +import ROUTES from 'constants/routes'; +import { FuturesAccountTypes } from 'queries/futures/types'; +import useGetFuturesPositionHistoryForAccount from 'queries/futures/useGetFuturesPositionHistoryForAccount'; +import TimeDisplay from 'sections/futures/Trades/TimeDisplay'; +import { ExternalLink } from 'styles/common'; +import { getMarketName } from 'utils/futures'; + +type TraderHistoryProps = { + trader: string; + ensInfo: Record; + resetSelection: Function; + compact?: boolean; + searchTerm?: string | undefined; +}; + +const TraderHistory: FC = memo( + ({ trader, ensInfo, resetSelection, compact, searchTerm }) => { + const { t } = useTranslation(); + const positionsQuery = useGetFuturesPositionHistoryForAccount(trader); + const positions = useMemo(() => { + const positionData = positionsQuery.data; + return positionData + ? [ + ...positionData[FuturesAccountTypes.ISOLATED_MARGIN], + ...positionData[FuturesAccountTypes.CROSS_MARGIN], + ] + : []; + }, [positionsQuery]); + const traderENSName = useMemo(() => ensInfo[trader] ?? null, [trader, ensInfo]); + + let data = useMemo(() => { + return positions + .sort((a, b) => b.timestamp - a.timestamp) + .map((stat, i) => { + return { + ...stat, + rank: i + 1, + currencyIconKey: stat.asset ? (stat.asset[0] !== 's' ? 's' : '') + stat.asset : '', + marketShortName: getMarketName(stat.asset), + status: stat.isOpen ? 'Open' : stat.isLiquidated ? 'Liquidated' : 'Closed', + pnl: stat.pnlWithFeesPaid, + pnlPct: `(${stat.pnlWithFeesPaid + .div(stat.initialMargin.add(stat.totalDeposits)) + .mul(100) + .toNumber() + .toFixed(2)}%)`, + }; + }) + .filter((i) => + searchTerm?.length + ? i.marketShortName.toLowerCase().includes(searchTerm) || + i.status.toLowerCase().includes(searchTerm) + : true + ); + }, [positions, searchTerm]); + + return ( + <> + + + { + resetSelection(); + }} + > + {t('leaderboard.trader-history.table.back')} + + > + + {traderENSName ?? trader} + + + ), + accessor: 'title', + columns: [ + { + Header: ( + {t('leaderboard.trader-history.table.timestamp')} + ), + accessor: 'openTimestamp', + Cell: (cellProps: CellProps) => { + return ( + + + + ); + }, + sortType: 'basic', + sortable: true, + width: compact ? 40 : 100, + }, + { + Header: ( + {t('leaderboard.trader-history.table.market')} + ), + accessor: 'asset', + Cell: (cellProps: CellProps) => ( + + + {cellProps.row.original.marketShortName} + + + ), + width: compact ? 40 : 100, + }, + { + Header: ( + {t('leaderboard.trader-history.table.status')} + ), + accessor: 'status', + Cell: (cellProps: CellProps) => { + return {cellProps.row.original.status}; + }, + width: compact ? 40 : 100, + }, + { + Header: ( + + {t('leaderboard.trader-history.table.total-trades')} + + ), + accessor: 'trades', + width: compact ? 40 : 100, + sortType: 'basic', + sortable: true, + }, + { + Header: ( + + {t('leaderboard.trader-history.table.total-volume')} + + ), + accessor: 'totalVolume', + Cell: (cellProps: CellProps) => ( + + ), + width: compact ? 40 : 100, + sortType: 'basic', + sortable: true, + }, + { + Header: ( + {t('leaderboard.trader-history.table.total-pnl')} + ), + accessor: 'pnl', + Cell: (cellProps: CellProps) => ( + + + + {cellProps.row.original.pnlPct} + + + ), + width: compact ? 40 : 100, + sortType: 'basic', + sortable: true, + }, + ], + }, + ]} + /> + + + + { + resetSelection(); + router.push(ROUTES.Leaderboard.Home); + }} + > + {t('leaderboard.leaderboard.table.title')} + + > + + {traderENSName ?? trader} + + + ), + accessor: 'title', + columns: [ + { + Header: ( + {t('leaderboard.trader-history.table.market')} + ), + accessor: 'asset', + Cell: (cellProps: CellProps) => ( + + + {cellProps.row.original.marketShortName} + + + ), + width: 50, + }, + { + Header: ( + {t('leaderboard.trader-history.table.status')} + ), + accessor: 'status', + Cell: (cellProps: CellProps) => { + return {cellProps.row.original.status}; + }, + width: 30, + }, + { + Header: ( + {t('leaderboard.trader-history.table.total-pnl')} + ), + accessor: 'pnl', + Cell: (cellProps: CellProps) => ( + + + + {cellProps.row.original.pnlPct} + + + ), + width: 40, + sortType: 'basic', + sortable: true, + }, + ], + }, + ]} + /> + + + ); + } +); + +const StyledTable = styled(Table)<{ compact?: boolean }>` + margin-top: ${({ compact }) => (compact ? '0' : '15px')}; +`; + +const TableTitle = styled.div` + width: 100%; + display: flex; + justify-content: flex-start; +`; + +const TitleText = styled.a` + font-family: ${(props) => props.theme.fonts.regular}; + color: ${(props) => props.theme.colors.selectedTheme.gray}; + + &:hover { + text-decoration: underline; + } +`; + +const StyledCell = styled.div` + color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; + display: flex; +`; + +const TitleSeparator = styled.div` + margin-left: 10px; + margin-right: 10px; + font-family: ${(props) => props.theme.fonts.regular}; + color: ${(props) => props.theme.colors.selectedTheme.gray}; +`; + +const StyledCurrencyIcon = styled(CurrencyIcon)` + width: 30px; + height: 30px; + margin-right: 5px; +`; + +const CurrencyInfo = styled(FlexDiv)` + align-items: center; +`; + +const StyledSubtitle = styled.div` + font-family: ${(props) => props.theme.fonts.regular}; + font-size: 13px; + color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; + text-transform: capitalize; +`; + +const PnlContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +const valueColor = css<{ $value: WeiSource }>` + color: ${(props) => + wei(props.$value).gt(0) + ? props.theme.colors.selectedTheme.green + : wei(props.$value).lt(0) + ? props.theme.colors.selectedTheme.red + : props.theme.colors.selectedTheme.button.text.primary}; +`; + +const ColorCodedPrice = styled(Currency.Price)<{ $value: WeiSource }>` + align-items: right; + ${valueColor} +`; + +const StyledValue = styled.div<{ $value: WeiSource }>` + font-family: ${(props) => props.theme.fonts.mono}; + font-size: 13px; + margin: 0; + text-align: end; + ${valueColor} +`; + +const StyledFuturesIcon = styled(FuturesIcon)` + margin-left: 5px; +`; + +export default TraderHistory; diff --git a/sections/leaderboard/TraderHistory/TraderHistory.tsx b/sections/leaderboard/TraderHistory/TraderHistory.tsx deleted file mode 100644 index 61c3ad37ef..0000000000 --- a/sections/leaderboard/TraderHistory/TraderHistory.tsx +++ /dev/null @@ -1,390 +0,0 @@ -import router from 'next/router'; -import { FC, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { CellProps } from 'react-table'; -import styled from 'styled-components'; - -import Currency from 'components/Currency'; -import CurrencyIcon from 'components/Currency/CurrencyIcon'; -import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; -import FuturesIcon from 'components/Nav/FuturesIcon'; -import Table from 'components/Table'; -import ROUTES from 'constants/routes'; -import { FuturesAccountTypes, PositionHistory } from 'queries/futures/types'; -import useGetFuturesPositionHistoryForAccount from 'queries/futures/useGetFuturesPositionHistoryForAccount'; -import TimeDisplay from 'sections/futures/Trades/TimeDisplay'; -import { FlexDiv } from 'styles/common'; -import { getMarketName } from 'utils/futures'; - -type TraderHistoryProps = { - trader: string; - ensInfo: Record; - resetSelection: Function; - compact?: boolean; - searchTerm?: string | undefined; -}; - -const TraderHistory: FC = ({ - trader, - ensInfo, - resetSelection, - compact, - searchTerm, -}: TraderHistoryProps) => { - const { t } = useTranslation(); - const positionsQuery = useGetFuturesPositionHistoryForAccount(trader); - const positions = useMemo(() => { - const positionData = positionsQuery.data; - return positionData - ? [ - ...positionData[FuturesAccountTypes.ISOLATED_MARGIN], - ...positionData[FuturesAccountTypes.CROSS_MARGIN], - ] - : []; - }, [positionsQuery]); - const traderENSName = useMemo(() => ensInfo[trader] ?? null, [trader, ensInfo]); - - let data = useMemo(() => { - return positions - .sort((a: PositionHistory, b: PositionHistory) => b.timestamp - a.timestamp) - .map((stat: PositionHistory, i: number) => { - return { - ...stat, - rank: i + 1, - currencyIconKey: stat.asset ? (stat.asset[0] !== 's' ? 's' : '') + stat.asset : '', - marketShortName: getMarketName(stat.asset), - status: stat.isOpen ? 'Open' : stat.isLiquidated ? 'Liquidated' : 'Closed', - pnl: stat.pnlWithFeesPaid, - pnlPct: `(${stat.pnlWithFeesPaid - .div(stat.initialMargin.add(stat.totalDeposits)) - .mul(100) - .toNumber() - .toFixed(2)}%)`, - }; - }) - .filter((i: { marketShortName: string; status: string }) => - searchTerm?.length - ? i.marketShortName.toLowerCase().includes(searchTerm) || - i.status.toLowerCase().includes(searchTerm) - : true - ); - }, [positions, searchTerm]); - - return ( - <> - - - { - resetSelection(); - }} - > - {t('leaderboard.trader-history.table.back')} - - > - - {traderENSName ?? trader} - - - ), - accessor: 'title', - columns: [ - { - Header: ( - {t('leaderboard.trader-history.table.timestamp')} - ), - accessor: 'openTimestamp', - Cell: (cellProps: CellProps) => { - return ( - - - - ); - }, - sortType: 'basic', - sortable: true, - width: compact ? 40 : 100, - }, - { - Header: {t('leaderboard.trader-history.table.market')}, - accessor: 'asset', - Cell: (cellProps: CellProps) => ( - - - {cellProps.row.original.marketShortName} - - - ), - width: compact ? 40 : 100, - }, - { - Header: {t('leaderboard.trader-history.table.status')}, - accessor: 'status', - Cell: (cellProps: CellProps) => { - return {cellProps.row.original.status}; - }, - width: compact ? 40 : 100, - }, - { - Header: ( - {t('leaderboard.trader-history.table.total-trades')} - ), - accessor: 'trades', - width: compact ? 40 : 100, - sortType: 'basic', - sortable: true, - }, - { - Header: ( - {t('leaderboard.trader-history.table.total-volume')} - ), - accessor: 'totalVolume', - Cell: (cellProps: CellProps) => ( - - ), - width: compact ? 40 : 100, - sortType: 'basic', - sortable: true, - }, - { - Header: ( - {t('leaderboard.trader-history.table.total-pnl')} - ), - accessor: 'pnl', - Cell: (cellProps: CellProps) => ( - - - - {cellProps.row.original.pnlPct} - - - ), - width: compact ? 40 : 100, - sortType: 'basic', - sortable: true, - }, - ], - }, - ]} - /> - - - - { - resetSelection(); - router.push(ROUTES.Leaderboard.Home); - }} - > - {t('leaderboard.leaderboard.table.title')} - - > - - {traderENSName ?? trader} - - - ), - accessor: 'title', - columns: [ - { - Header: {t('leaderboard.trader-history.table.market')}, - accessor: 'asset', - Cell: (cellProps: CellProps) => ( - - - {cellProps.row.original.marketShortName} - - - ), - width: 50, - }, - { - Header: {t('leaderboard.trader-history.table.status')}, - accessor: 'status', - Cell: (cellProps: CellProps) => { - return {cellProps.row.original.status}; - }, - width: 30, - }, - { - Header: ( - {t('leaderboard.trader-history.table.total-pnl')} - ), - accessor: 'pnl', - Cell: (cellProps: CellProps) => ( - - - - {cellProps.row.original.pnlPct} - - - ), - width: 40, - sortType: 'basic', - sortable: true, - }, - ], - }, - ]} - /> - - - ); -}; - -const StyledTable = styled(Table)<{ compact: boolean | undefined }>` - margin-top: ${({ compact }) => (compact ? '0' : '15px')}; -`; - -const TableTitle = styled.div` - width: 100%; - display: flex; - justify-content: flex-start; -`; - -const TitleText = styled.a` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.gray}; - - &:hover { - text-decoration: underline; - cursor: pointer; - } -`; - -const StyledCell = styled.div` - color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - display: flex; -`; - -const TitleSeparator = styled.div` - margin-left: 10px; - margin-right: 10px; - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.gray}; -`; - -const TraderText = styled.a` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - - &:hover { - text-decoration: underline; - } -`; - -const TableHeader = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - color: ${(props) => props.theme.colors.selectedTheme.gray}; -`; - -const StyledCurrencyIcon = styled(CurrencyIcon)` - width: 30px; - height: 30px; - margin-right: 5px; -`; - -const CurrencyInfo = styled(FlexDiv)` - align-items: center; -`; - -const StyledSubtitle = styled.div` - font-family: ${(props) => props.theme.fonts.regular}; - font-size: 13px; - color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - text-transform: capitalize; -`; - -const PnlContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; -`; - -const ColorCodedPrice = styled(Currency.Price)` - align-items: right; - color: ${(props) => - props.price > 0 - ? props.theme.colors.selectedTheme.green - : props.price < 0 - ? props.theme.colors.selectedTheme.red - : props.theme.colors.selectedTheme.button.text.primary}; -`; - -const StyledValue = styled.div` - font-family: ${(props) => props.theme.fonts.mono}; - font-size: 13px; - color: ${(props) => - props.color === 'green' - ? props.theme.colors.selectedTheme.green - : props.color === 'red' - ? props.theme.colors.selectedTheme.red - : props.theme.colors.selectedTheme.button.text.primary}; - margin: 0; - text-align: end; -`; - -const StyledFuturesIcon = styled(FuturesIcon)` - margin-left: 5px; -`; - -export default TraderHistory; diff --git a/sections/leaderboard/TraderHistory/index.tsx b/sections/leaderboard/TraderHistory/index.tsx deleted file mode 100644 index 5564828bc7..0000000000 --- a/sections/leaderboard/TraderHistory/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TraderHistory'; diff --git a/sections/leaderboard/common.tsx b/sections/leaderboard/common.tsx deleted file mode 100644 index 40d99d6cde..0000000000 --- a/sections/leaderboard/common.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import styled from 'styled-components'; - -export type Tier = 'gold' | 'silver' | 'bronze' | null; -export type CompetitionRound = '1' | '2' | null; - -export const getMedal = (position: number) => { - switch (position) { - case 1: - return 🥇; - case 2: - return 🥈; - case 3: - return 🥉; - } -}; - -export const COMPETITION_TIERS: Tier[] = ['bronze', 'silver', 'gold']; - -export const PIN = ' 📌'; - -const Medal = styled.span` - font-size: 16px; - margin-left: 4px; -`; - -export const StyledTrader = styled.a` - color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; - display: flex; - - &:hover { - text-decoration: underline; - cursor: pointer; - } -`; diff --git a/sections/leaderboard/medal.ts b/sections/leaderboard/medal.ts new file mode 100644 index 0000000000..00aacff2d3 --- /dev/null +++ b/sections/leaderboard/medal.ts @@ -0,0 +1,6 @@ +import styled from 'styled-components'; + +export const Medal = styled.span` + font-size: 16px; + margin-left: 4px; +`; diff --git a/sections/leaderboard/trader.ts b/sections/leaderboard/trader.ts new file mode 100644 index 0000000000..5f1f89ba34 --- /dev/null +++ b/sections/leaderboard/trader.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export const StyledTrader = styled.a` + color: ${(props) => props.theme.colors.selectedTheme.button.text.primary}; + display: flex; + + &:hover { + text-decoration: underline; + cursor: pointer; + } +`; diff --git a/sections/shared/Layout/AppLayout/AppLayout.tsx b/sections/shared/Layout/AppLayout/AppLayout.tsx index b8e269cb14..6c851ad2b7 100644 --- a/sections/shared/Layout/AppLayout/AppLayout.tsx +++ b/sections/shared/Layout/AppLayout/AppLayout.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, memo } from 'react'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import NotificationContainer from 'constants/NotificationContainer'; @@ -12,7 +12,7 @@ type AppLayoutProps = { children: React.ReactNode; }; -const AppLayout: FC = ({ children }) => ( +const AppLayout: FC = memo(({ children }) => ( @@ -28,6 +28,6 @@ const AppLayout: FC = ({ children }) => ( -); +)); export default AppLayout; diff --git a/sections/shared/Layout/AppLayout/GitHashID/GitHashID.tsx b/sections/shared/Layout/AppLayout/GitHashID.tsx similarity index 100% rename from sections/shared/Layout/AppLayout/GitHashID/GitHashID.tsx rename to sections/shared/Layout/AppLayout/GitHashID.tsx diff --git a/sections/shared/Layout/AppLayout/GitHashID/index.ts b/sections/shared/Layout/AppLayout/GitHashID/index.ts deleted file mode 100644 index 55569aeaf0..0000000000 --- a/sections/shared/Layout/AppLayout/GitHashID/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './GitHashID'; diff --git a/sections/shared/Layout/AppLayout/Header/BalanceActions.tsx b/sections/shared/Layout/AppLayout/Header/BalanceActions.tsx index 3ec75a92ce..ded5d194db 100644 --- a/sections/shared/Layout/AppLayout/Header/BalanceActions.tsx +++ b/sections/shared/Layout/AppLayout/Header/BalanceActions.tsx @@ -1,11 +1,12 @@ import { useRouter } from 'next/router'; -import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { FC, memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { components } from 'react-select'; -import styled, { useTheme } from 'styled-components'; +import styled from 'styled-components'; import Button from 'components/Button'; import CurrencyIcon from 'components/Currency/CurrencyIcon'; +import { FlexDivRow, FlexDivRowCentered } from 'components/layout/flex'; import Select from 'components/Select'; import { FuturesAccountTypes } from 'queries/futures/types'; import { FuturesPosition } from 'sdk/types/futures'; @@ -17,7 +18,6 @@ import { selectIsolatedMarginPositions, } from 'state/futures/selectors'; import { useAppSelector, useAppDispatch } from 'state/hooks'; -import { FlexDivRow, FlexDivRowCentered } from 'styles/common'; import { zeroBN, formatDollars } from 'utils/formatters/number'; import { getMarketName, MarketKeyByAsset } from 'utils/futures'; @@ -28,10 +28,38 @@ type ReactSelectOptionProps = { onClick?: () => {}; }; +const GetUsdButton = memo(() => { + const { t } = useTranslation(); + const router = useRouter(); + + return ( + router.push(`/exchange/?quote=sUSD`)}> + {t('header.balance.get-more-susd')} + + ); +}); + +const Group: FC = memo(({ children, ...props }) => ( + + {children} + + +)); + +const NoOptionsMessage: FC = memo((props) => { + const { t } = useTranslation(); + + return ( + + {t('header.balance.no-accessible-margin')} + + + ); +}); + const BalanceActions: FC = () => { const [balanceLabel, setBalanceLabel] = useState(''); const { t } = useTranslation(); - const theme = useTheme(); const router = useRouter(); const crossPositions = useAppSelector(selectCrossMarginPositions); @@ -41,22 +69,20 @@ const BalanceActions: FC = () => { const dispatch = useAppDispatch(); const setMarketConfig = useCallback( - (position: FuturesPosition, accountType: FuturesAccountTypes): ReactSelectOptionProps => { - return { - label: getMarketName(position.asset), - synthIcon: MarketKeyByAsset[position.asset], - marketRemainingMargin: formatDollars(position.remainingMargin), - onClick: () => { - // TODO: Remove eventually - dispatch(setFuturesAccountType(accountType)); - return router.push(`/market/?asset=${position.asset}&accountType=${accountType}`); - }, - }; - }, + (position: FuturesPosition, accountType: FuturesAccountTypes) => ({ + label: getMarketName(position.asset), + synthIcon: MarketKeyByAsset[position.asset], + marketRemainingMargin: formatDollars(position.remainingMargin), + onClick: () => { + // TODO: Remove eventually + dispatch(setFuturesAccountType(accountType)); + return router.push(`/market/?asset=${position.asset}&accountType=${accountType}`); + }, + }), [dispatch, router] ); - const OPTIONS = useMemo(() => { + const options = useMemo(() => { const isolatedPositionsFiltered = isolatedPositions .filter((position) => position.remainingMargin.gt(zeroBN)) .map((position) => setMarketConfig(position, FuturesAccountTypes.ISOLATED_MARGIN)); @@ -75,16 +101,14 @@ const BalanceActions: FC = () => { const OptionsGroupLabel: FC<{ label: string; totalAvailableMargin?: string }> = ({ label, totalAvailableMargin, - }) => { - return ( - - {t(label)} - {totalAvailableMargin} - - ); - }; + }) => ( + + {t(label)} + {totalAvailableMargin} + + ); - const formatOptionLabel = ({ + const formatOptionLabel: FC = ({ label, synthIcon, marketRemainingMargin, @@ -93,34 +117,12 @@ const BalanceActions: FC = () => { {synthIcon && } - {t(label)} + {t(label)} {marketRemainingMargin} ); - const GetUsdButton = () => ( - router.push(`/exchange/?quote=sUSD`)}> - {t('header.balance.get-more-susd')} - - ); - - const Group: FC = ({ children, ...props }) => ( - - {children} - - - ); - - const NoOptionsMessage: FC = (props) => { - return ( - - {t('header.balance.no-accessible-margin')} - - - ); - }; - useEffect(() => { setBalanceLabel(formatDollars(susdWalletBalance, { sign: '$' })); }, [balanceLabel, susdWalletBalance]); @@ -131,13 +133,14 @@ const BalanceActions: FC = () => { return ( - {susdWalletBalance.eq(zeroBN) && OPTIONS.length === 0 ? ( + {susdWalletBalance.eq(zeroBN) && options.length === 0 ? ( router.push(`/exchange/?quote=sUSD`)} noOutline + mono > - + {t('header.balance.get-susd')} ) : ( @@ -145,12 +148,11 @@ const BalanceActions: FC = () => { formatOptionLabel={formatOptionLabel} formatGroupLabel={OptionsGroupLabel} controlHeight={41} - options={OPTIONS} + options={options} value={{ label: balanceLabel, synthIcon: 'sUSD' }} menuWidth={290} maxMenuHeight={500} - optionPadding={'0px'} //override default padding to 0 - optionBorderBottom={theme.colors.selectedTheme.border} + optionPadding="0px" components={{ Group, NoOptionsMessage, @@ -159,7 +161,7 @@ const BalanceActions: FC = () => { }} isSearchable={false} variant="flat" - > + /> )} ); @@ -198,6 +200,10 @@ const BalanceSelect = styled(Select)<{ value: { label: string } }>` .react-select__menu-notice--no-options { padding: 15px; } + + .react-select__option { + border-bottom: ${(props) => props.theme.colors.selectedTheme.border}; + } `; const StyledOptions = styled.div` @@ -211,7 +217,7 @@ const StyledCurrencyIcon = styled(CurrencyIcon)` width: 20px; `; -const StyledLabel = styled.div<{ noPadding: boolean }>` +const StyledLabel = styled.div` white-space: nowrap; `; @@ -236,7 +242,6 @@ const StyledButton = styled(Button)` const StyledWidgetButton = styled(Button)` height: 41px; font-size: 13px; - font-family: ${(props) => props.theme.fonts.mono}; padding: 10px; white-space: nowrap; display: flex; diff --git a/sections/shared/Layout/AppLayout/Header/ConnectionDot.tsx b/sections/shared/Layout/AppLayout/Header/ConnectionDot.tsx index 24c4d19626..25fcf46707 100644 --- a/sections/shared/Layout/AppLayout/Header/ConnectionDot.tsx +++ b/sections/shared/Layout/AppLayout/Header/ConnectionDot.tsx @@ -46,6 +46,7 @@ const Dot = styled.span<{ background: string }>` height: 8px; border-radius: 100%; background-color: ${(props) => props.background}; + margin-right: 6px; `; export default ConnectionDot; diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileMenuModal.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileMenuModal.tsx index 548729c199..8c87b48016 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileMenuModal.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileMenuModal.tsx @@ -13,7 +13,7 @@ import Logo from 'sections/shared/Layout/Logo'; import { currentThemeState } from 'store/ui'; import { HOMEPAGE_MENU_LINKS, MOBILE_NAV_LINKS } from '../constants'; -import { MenuButton } from './common'; +import { MenuButton } from './menu'; import MobileSubMenu from './MobileSubMenu'; type MobileMenuModalProps = { diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSettingsModal.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSettingsModal.tsx index b084952eaf..9b9d3fce01 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSettingsModal.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSettingsModal.tsx @@ -14,6 +14,7 @@ import MoonIcon from 'assets/svg/app/moon.svg'; import SunIcon from 'assets/svg/app/sun.svg'; import FullScreenModal from 'components/FullScreenModal'; import { EXTERNAL_LINKS } from 'constants/links'; +import { languageIcon } from 'constants/menu'; import ROUTES from 'constants/routes'; import usePersistedRecoilState from 'hooks/usePersistedRecoilState'; import Logo from 'sections/shared/Layout/Logo'; @@ -21,7 +22,6 @@ import { languageState } from 'store/app'; import { currentThemeState } from 'store/ui'; import colors from 'styles/theme/colors'; -import { languageIcon } from './common'; import MobileSubMenu from './MobileSubMenu'; type MobileSettingsModalProps = { diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSubMenu.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSubMenu.tsx index b93f9462f4..57b7895bef 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSubMenu.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileSubMenu.tsx @@ -1,5 +1,6 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useRecoilValue } from 'recoil'; import styled, { css } from 'styled-components'; @@ -12,7 +13,7 @@ import { currentThemeState } from 'store/ui'; import { ThemeName } from 'styles/theme'; import { SubMenuLink } from '../constants'; -import { MenuButton } from './common'; +import { MenuButton } from './menu'; type MobileSubMenuOption = { label: string; @@ -32,71 +33,64 @@ type MobileSubMenuProps = { onToggle(): void; }; -const MobileSubMenu: React.FC = ({ - i18nLabel, - active, - options, - links, - onDismiss, - onToggle, -}) => { - const { t } = useTranslation(); - const { asPath } = useRouter(); - - const currentTheme = useRecoilValue(currentThemeState); - - return ( - <> - - {t(i18nLabel)} - {active ? : } - - {active && ( - - {links - ? links.map(({ i18nLabel, link: subLink, badge }) => ( - - · - - -
- {t(i18nLabel)}{' '} - {badge && - badge.map(({ i18nLabel, color }) => ( +const MobileSubMenu: React.FC = memo( + ({ i18nLabel, active, options, links, onDismiss, onToggle }) => { + const { t } = useTranslation(); + const { asPath } = useRouter(); + const currentTheme = useRecoilValue(currentThemeState); + + return ( + <> + + {t(i18nLabel)} + {active ? : } + + {active && ( + + {links + ? links.map(({ i18nLabel, link: subLink, badge }) => ( + + · + + +
+ {t(i18nLabel)}{' '} + {badge?.map(({ i18nLabel, color }) => ( {t(i18nLabel)} ))} -
-
-
-
- )) - : options?.map(({ label, icon, onClick, selected, externalLink }) => ( - - {icon ?? '·'} - {externalLink ? ( - - - {label} +
- - ) : ( - - - {label} - - - )} -
- ))} -
- )} - - ); -}; + + + )) + : options?.map(({ label, icon, onClick, selected, externalLink }) => ( + + {icon ?? '·'} + {externalLink ? ( + + + {label} + + + ) : ( + + + {label} + + + )} + + ))} + + )} + + ); + } +); const SubMenuButton = styled(MenuButton)` ${(props) => diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileUserMenu.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileUserMenu.tsx index c38b32af1f..4f92acf9c3 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileUserMenu.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileUserMenu.tsx @@ -29,13 +29,7 @@ const MobileUserMenu: FC = () => { const toggleModal = (modal: 'menu' | 'settings') => () => { setIsOpen((s) => { if (!!s) { - if (s === modal) { - return undefined; - } else if (s === 'menu') { - return 'settings'; - } else { - return 'menu'; - } + return s === modal ? undefined : s === 'menu' ? 'settings' : 'menu'; } else { return modal; } diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletActions.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletActions.tsx index 09fa670eb4..2bf97f9dba 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletActions.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletActions.tsx @@ -28,17 +28,13 @@ export const MobileWalletActions: FC = ({ toggleModal } {ensAvatar ? ( ) : ( - + )} {walletLabel} ); }; -const StyledConnectionDot = styled(ConnectionDot)` - margin-right: 6px; -`; - const StyledButton = styled(Button)` font-size: 13px; text-transform: lowercase; diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletButton.tsx b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletButton.tsx index ef6d0f41d4..527ff61aa3 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletButton.tsx +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/MobileWalletButton.tsx @@ -16,13 +16,11 @@ type MobileWalletButtonProps = { closeModal(): void; }; -const MobileWalletButton: React.FC = ({ toggleModal }) => { +const MobileConnectButton = () => { const { t } = useTranslation(); - const { network, isWalletConnected } = Connector.useContainer(); const { openConnectModal: connectWallet } = useConnectModal(); - const { openChainModal } = useChainModal(); - const walletIsNotConnected = ( + return ( = ({ toggleModal }) data-testid="connect-wallet" mono > - + {t('common.wallet.connect-wallet')} ); +}; + +const MobileUnsupportedButton = () => { + const { t } = useTranslation(); + const { openChainModal } = useChainModal(); - const walletIsConnectedButNotSupported = ( + return ( = ({ toggleModal }) mono onClick={openChainModal} > - + {t('common.wallet.unsupported-network')} ); +}; - const walletIsConnectedAndSupported = ; +const MobileWalletButton: React.FC = ({ toggleModal }) => { + const { network, isWalletConnected } = Connector.useContainer(); - return isWalletConnected - ? isSupportedNetworkId(network?.id as NetworkId) - ? walletIsConnectedAndSupported - : walletIsConnectedButNotSupported - : walletIsNotConnected; + if (!isWalletConnected) { + return ; + } else if (isSupportedNetworkId(network?.id as NetworkId)) { + return ; + } else { + return ; + } }; -const StyledConnectionDot = styled(ConnectionDot)` - margin-right: 6px; -`; - const ConnectButton = styled(Button)` font-size: 13px; `; diff --git a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/common.ts b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/menu.ts similarity index 62% rename from sections/shared/Layout/AppLayout/Header/MobileUserMenu/common.ts rename to sections/shared/Layout/AppLayout/Header/MobileUserMenu/menu.ts index 54dd4a0e60..bfc3b2a980 100644 --- a/sections/shared/Layout/AppLayout/Header/MobileUserMenu/common.ts +++ b/sections/shared/Layout/AppLayout/Header/MobileUserMenu/menu.ts @@ -1,6 +1,5 @@ import styled, { css } from 'styled-components'; -import { EXTERNAL_LINKS } from 'constants/links'; import ROUTES from 'constants/routes'; import type { ThemeName } from 'styles/theme'; @@ -32,21 +31,3 @@ export const MenuButton = styled.div<{ } `} `; - -export const SUB_MENUS = { - [ROUTES.Dashboard.Overview]: [ - { label: 'Overview', link: '/dashboard/overview' }, - // { label: 'Positions', link: '/positions' }, - // { label: 'Rewards', link: '/rewards' }, - { label: 'Markets', link: '/dashboard/markets' }, - // { label: 'Governance', link: '/governance' }, - ], - [ROUTES.Home.Root]: [ - { label: 'Overview', link: EXTERNAL_LINKS.Docs.Governance }, - { label: 'KIPs', link: EXTERNAL_LINKS.Governance.Kips }, - ], -}; - -export const languageIcon = { - en: '🌐', -}; diff --git a/sections/shared/Layout/AppLayout/Header/Nav/Nav.tsx b/sections/shared/Layout/AppLayout/Header/Nav.tsx similarity index 86% rename from sections/shared/Layout/AppLayout/Header/Nav/Nav.tsx rename to sections/shared/Layout/AppLayout/Header/Nav.tsx index 393481c295..277e2a68d0 100644 --- a/sections/shared/Layout/AppLayout/Header/Nav/Nav.tsx +++ b/sections/shared/Layout/AppLayout/Header/Nav.tsx @@ -1,6 +1,6 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; -import { FC, FunctionComponent } from 'react'; +import { FC, FunctionComponent, memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -12,7 +12,7 @@ import { selectMarketAsset } from 'state/futures/selectors'; import { useAppSelector } from 'state/hooks'; import { linkCSS } from 'styles/common'; -import { DESKTOP_NAV_LINKS, Badge as BadgeType } from '../constants'; +import { DESKTOP_NAV_LINKS, Badge as BadgeType } from './constants'; type ReactSelectOptionProps = { i18nLabel: string; @@ -23,14 +23,17 @@ type ReactSelectOptionProps = { Icon: FunctionComponent; }; -const Nav: FC = () => { +const Nav: FC = memo(() => { const { t } = useTranslation(); const { asPath } = useRouter(); const marketAsset = useAppSelector(selectMarketAsset); - function getLink(link: string) { - return link.slice(0, 7) === '/market' ? `/market/?asset=${marketAsset}` : link; - } + const getLink = useCallback( + (link: string) => { + return link.indexOf('/market') === 0 ? `/market/?asset=${marketAsset}` : link; + }, + [marketAsset] + ); const formatOptionLabel = ({ i18nLabel, @@ -39,19 +42,22 @@ const Nav: FC = () => { link, isActive, }: ReactSelectOptionProps) => { - if (i18nLabel === 'header.nav.markets' || i18nLabel === 'header.nav.leaderboard') + if (i18nLabel === 'header.nav.markets' || i18nLabel === 'header.nav.leaderboard') { return ( {t(i18nLabel)} ); + } + return ( {t(i18nLabel)} - {badge && - badge.map(({ i18nLabel, color }) => {t(i18nLabel)})} + {badge?.map(({ i18nLabel, color }) => ( + {t(i18nLabel)} + ))} {Icon && } @@ -66,17 +72,13 @@ const Nav: FC = () => { const routeBase = asPath.split('/')[1]; const linkBase = link.split('/')[1]?.split('?')[0]; const isActive = routeBase === linkBase; - const url = getLink(link); + if (!links) { return ( - + + {t(i18nLabel)} + ); } @@ -97,7 +99,7 @@ const Nav: FC = () => { ); -}; +}); const MenuLinks = styled.ul` display: flex; diff --git a/sections/shared/Layout/AppLayout/Header/Nav/index.ts b/sections/shared/Layout/AppLayout/Header/Nav/index.ts deleted file mode 100644 index 13fa327162..0000000000 --- a/sections/shared/Layout/AppLayout/Header/Nav/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Nav'; diff --git a/sections/shared/Layout/AppLayout/Header/NetworksSwitcher.tsx b/sections/shared/Layout/AppLayout/Header/NetworksSwitcher.tsx index 6ffa9f1d9b..b25f262719 100644 --- a/sections/shared/Layout/AppLayout/Header/NetworksSwitcher.tsx +++ b/sections/shared/Layout/AppLayout/Header/NetworksSwitcher.tsx @@ -28,8 +28,8 @@ type ReactSelectOptionProps = { const NetworksSwitcher: FC = () => { const { network: activeChain } = Connector.useContainer(); - const { openChainModal } = useChainModal(); const { t } = useTranslation(); + const { openChainModal } = useChainModal(); const isL2 = useIsL2(); const network = activeChain?.id === chain.optimismGoerli.id ? 'testnet' : 'mainnet'; const networkLabel = 'header.networks-switcher.optimism-' + network; @@ -95,11 +95,11 @@ const NetworksSwitcher: FC = () => { options={OPTIMISM_OPTIONS} value={{ label: networkLabel, prefixIcon: 'Optimism' }} menuWidth={240} - optionPadding={'0px'} //override default padding to 0 + optionPadding="0px" components={{ IndicatorSeparator, DropdownIndicator }} isSearchable={false} variant="flat" - > + />
); }; diff --git a/sections/shared/Layout/AppLayout/Header/WalletActions.tsx b/sections/shared/Layout/AppLayout/Header/WalletActions.tsx index 96ce5c861f..65ffc17cea 100644 --- a/sections/shared/Layout/AppLayout/Header/WalletActions.tsx +++ b/sections/shared/Layout/AppLayout/Header/WalletActions.tsx @@ -1,5 +1,5 @@ import { useAccountModal } from '@rainbow-me/rainbowkit'; -import { FC, useEffect, useState } from 'react'; +import { FC, useMemo } from 'react'; import styled, { css } from 'styled-components'; import { useEnsAvatar, useEnsName } from 'wagmi'; @@ -18,12 +18,11 @@ export const WalletActions: FC = ({ isMobile }) => { const { data: ensAvatar } = useEnsAvatar({ address: walletAddress!, chainId: 1 }); const { data: ensName } = useEnsName({ address: walletAddress!, chainId: 1 }); - const [walletLabel, setWalletLabel] = useState(''); const truncatedWalletAddress = truncateAddress(walletAddress ?? ''); const { openAccountModal } = useAccountModal(); - useEffect(() => { - setWalletLabel(ensName || truncatedWalletAddress!); + const walletLabel = useMemo(() => { + return ensName || truncatedWalletAddress!; }, [ensName, truncatedWalletAddress]); return ( @@ -45,7 +44,7 @@ export const WalletActions: FC = ({ isMobile }) => { style={{ borderRadius: '50%', marginRight: '8px' }} /> ) : ( - + )} {walletLabel} @@ -53,10 +52,6 @@ export const WalletActions: FC = ({ isMobile }) => { ); }; -const StyledConnectionDot = styled(ConnectionDot)` - margin-right: 6px; -`; - const Container = styled.div<{ isMobile?: boolean }>` font-size: 12px; font-family: ${(props) => props.theme.fonts.mono}; diff --git a/sections/shared/Layout/AppLayout/Header/WalletButtons.tsx b/sections/shared/Layout/AppLayout/Header/WalletButtons.tsx index 093bcdb30d..45d4967723 100644 --- a/sections/shared/Layout/AppLayout/Header/WalletButtons.tsx +++ b/sections/shared/Layout/AppLayout/Header/WalletButtons.tsx @@ -42,7 +42,7 @@ const WalletButtons: React.FC = () => { data-testid="connect-wallet" mono > - + {t('common.wallet.connect-wallet')} @@ -54,7 +54,7 @@ const WalletButtons: React.FC = () => { {t('homepage.l2.cta-buttons.switch-networks')} - + {t('common.wallet.unsupported-network')} @@ -88,10 +88,6 @@ const Container = styled.div` grid-auto-flow: column; `; -const StyledConnectionDot = styled(ConnectionDot)` - margin-right: 6px; -`; - const MenuButton = styled(Button)` display: grid; place-items: center; diff --git a/sections/shared/Layout/HomeLayout/Background.tsx b/sections/shared/Layout/HomeLayout/Background.tsx index abf949e8b1..d69559b29a 100644 --- a/sections/shared/Layout/HomeLayout/Background.tsx +++ b/sections/shared/Layout/HomeLayout/Background.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import { memo } from 'react'; import styled, { keyframes } from 'styled-components'; -const Background = () => { +const Background = memo(() => { return (
@@ -9,7 +9,7 @@ const Background = () => {
); -}; +}); const drop = keyframes` from { @@ -19,6 +19,7 @@ const drop = keyframes` top:100%; } `; + const Container = styled.div` background-color: transparent; width: 100vw; diff --git a/sections/shared/Layout/HomeLayout/Banner.tsx b/sections/shared/Layout/HomeLayout/Banner.tsx index 9c2ae0018d..6e1d14787c 100644 --- a/sections/shared/Layout/HomeLayout/Banner.tsx +++ b/sections/shared/Layout/HomeLayout/Banner.tsx @@ -1,17 +1,13 @@ +import { memo } from 'react'; import styled from 'styled-components'; import { DesktopOnlyView, MobileOrTabletView } from 'components/Media'; import { BANNER_ENABLED, BANNER_LINK_URL, BANNER_TEXT } from 'constants/announcement'; import media from 'styles/media'; -const Banner = () => { +const Banner = memo(() => { if (!BANNER_ENABLED) return null; - const linkProps = BANNER_LINK_URL - ? { href: BANNER_LINK_URL, target: '_blank' } - : { as: 'p' as const }; - const bannerLink = {BANNER_TEXT}; - return ( <> @@ -24,7 +20,7 @@ const Banner = () => { ); -}; +}); const FuturesLink = styled.a` margin-right: 5px; @@ -33,6 +29,12 @@ const FuturesLink = styled.a` border-radius: 20px; `; +const linkProps = BANNER_LINK_URL + ? { href: BANNER_LINK_URL, target: '_blank' } + : { as: 'p' as const }; + +const bannerLink = {BANNER_TEXT}; + const FuturesBannerContainer = styled.div` height: 70px; width: 100%; @@ -42,12 +44,9 @@ const FuturesBannerContainer = styled.div` ${media.lessThan('md')` position: relative; - width: 100%; - display: flex; margin-bottom: 0px; flex-direction: column; justify-content: center; - align-items: center; text-align: center; background: transaparent; padding: 22px 10px; diff --git a/sections/shared/Layout/HomeLayout/Footer.tsx b/sections/shared/Layout/HomeLayout/Footer.tsx index 27ec35d749..62eb9b806d 100644 --- a/sections/shared/Layout/HomeLayout/Footer.tsx +++ b/sections/shared/Layout/HomeLayout/Footer.tsx @@ -1,20 +1,21 @@ -import React from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled, { ThemeProvider } from 'styled-components'; import TwitterLogo from 'assets/svg/marketing/twitter-icon.svg'; import DiscordLogo from 'assets/svg/social/discord.svg'; import MirrorLogo from 'assets/svg/social/mirror.svg'; +import { GridContainer } from 'sections/homepage/section'; +import { FlexDivCentered } from 'components/layout/flex'; import PoweredBySynthetix from 'components/PoweredBySynthetix'; import { EXTERNAL_LINKS } from 'constants/links'; -import { GridContainer } from 'sections/homepage/common'; -import { FlexDivCentered, ExternalLink } from 'styles/common'; +import { ExternalLink } from 'styles/common'; import media from 'styles/media'; import { themes } from 'styles/theme'; import Logo from '../Logo'; -const Footer: React.FC = () => { +const Footer = memo(() => { const { t } = useTranslation(); const DOC_LINKS = [ { @@ -97,7 +98,7 @@ const Footer: React.FC = () => { }, ]; return ( - + @@ -132,7 +133,7 @@ const Footer: React.FC = () => { ); -}; +}); const StyledLink = styled.a` cursor: pointer; diff --git a/sections/shared/Layout/HomeLayout/Header.tsx b/sections/shared/Layout/HomeLayout/Header.tsx index 01520ad5a4..f342c18a13 100644 --- a/sections/shared/Layout/HomeLayout/Header.tsx +++ b/sections/shared/Layout/HomeLayout/Header.tsx @@ -1,6 +1,6 @@ import Link from 'next/link'; import router from 'next/router'; -import { FC, useMemo } from 'react'; +import { useMemo, memo } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -10,18 +10,19 @@ import TwitterLogo from 'assets/svg/marketing/twitter-icon.svg'; import DiscordLogo from 'assets/svg/social/discord.svg'; import MirrorLogo from 'assets/svg/social/mirror.svg'; import Button from 'components/Button'; +import { FlexDivRow, FlexDivRowCentered } from 'components/layout/flex'; +import { GridDivCenteredCol } from 'components/layout/grid'; import { MobileHiddenView, MobileOnlyView } from 'components/Media'; import { DEFAULT_FUTURES_MARGIN_TYPE } from 'constants/defaults'; import { EXTERNAL_LINKS } from 'constants/links'; import ROUTES from 'constants/routes'; -import { FlexDivRow, FlexDivRowCentered, GridDivCenteredCol } from 'styles/common'; import MobileUserMenu from '../AppLayout/Header/MobileUserMenu'; import Logo from '../Logo'; export type TPages = 'landing-page' | 'stats-page'; -const Header: FC = () => { +const Header = memo(() => { const { t } = useTranslation(); const LINKS = useMemo( @@ -59,7 +60,6 @@ const Header: FC = () => { onClick: () => window.open(EXTERNAL_LINKS.Docs.DocsRoot, '_blank'), }, ], - // eslint-disable-next-line [t] ); @@ -148,7 +148,7 @@ const Header: FC = () => { ); -}; +}); const MobileContainer = styled(FlexDivRow)` justify-content: center; diff --git a/sections/shared/Layout/HomeLayout/HomeLayout.tsx b/sections/shared/Layout/HomeLayout/HomeLayout.tsx index 6e9bb2760c..7f898bf49f 100644 --- a/sections/shared/Layout/HomeLayout/HomeLayout.tsx +++ b/sections/shared/Layout/HomeLayout/HomeLayout.tsx @@ -16,7 +16,7 @@ type HomeLayoutProps = { }; const HomeLayout: FC = ({ children }) => ( - + diff --git a/sections/shared/Layout/Logo/Logo.tsx b/sections/shared/Layout/Logo.tsx similarity index 88% rename from sections/shared/Layout/Logo/Logo.tsx rename to sections/shared/Layout/Logo.tsx index 661ec06a39..016cf3ba7c 100644 --- a/sections/shared/Layout/Logo/Logo.tsx +++ b/sections/shared/Layout/Logo.tsx @@ -1,5 +1,5 @@ import Link from 'next/link'; -import { FC } from 'react'; +import { FC, memo } from 'react'; import { useRecoilValue } from 'recoil'; import styled from 'styled-components'; @@ -8,7 +8,7 @@ import LogoSvg from 'assets/svg/brand/logo.svg'; import ROUTES from 'constants/routes'; import { currentThemeState } from 'store/ui'; -const SvgLogo = () => { +const SvgLogo = memo(() => { const currentTheme = useRecoilValue(currentThemeState); if (window.location.pathname === ROUTES.Home.Root) { @@ -20,9 +20,9 @@ const SvgLogo = () => { } return ; -}; +}); -const Logo: FC = () => { +const Logo: FC = memo(() => { return ( @@ -30,7 +30,7 @@ const Logo: FC = () => { ); -}; +}); const LogoContainer = styled.span` display: flex; diff --git a/sections/shared/Layout/Logo/index.ts b/sections/shared/Layout/Logo/index.ts deleted file mode 100644 index a5be7785e1..0000000000 --- a/sections/shared/Layout/Logo/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Logo'; diff --git a/sections/shared/SystemStatus/SystemStatus.tsx b/sections/shared/SystemStatus.tsx similarity index 94% rename from sections/shared/SystemStatus/SystemStatus.tsx rename to sections/shared/SystemStatus.tsx index 368be0aed3..17ad440504 100644 --- a/sections/shared/SystemStatus/SystemStatus.tsx +++ b/sections/shared/SystemStatus.tsx @@ -8,16 +8,12 @@ import SystemDownIcon from 'assets/svg/app/system-down.svg'; import DiscordIcon from 'assets/svg/social/discord.svg'; import GithubIcon from 'assets/svg/social/github.svg'; import TwitterIcon from 'assets/svg/social/twitter.svg'; +import { FlexDivColCentered } from 'components/layout/flex'; +import { GridDivCenteredCol } from 'components/layout/grid'; import { EXTERNAL_LINKS, PROD_HOSTNAME } from 'constants/links'; import { HEADER_HEIGHT } from 'constants/ui'; import Logo from 'sections/shared/Layout/Logo'; -import { - FlexDivColCentered, - PageContent, - FullScreenContainer, - ExternalLink, - GridDivCenteredCol, -} from 'styles/common'; +import { PageContent, FullScreenContainer, ExternalLink } from 'styles/common'; import media from 'styles/media'; type SystemStatusProps = { diff --git a/sections/shared/SystemStatus/index.ts b/sections/shared/SystemStatus/index.ts deleted file mode 100644 index fa51f4e496..0000000000 --- a/sections/shared/SystemStatus/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SystemStatus'; diff --git a/sections/shared/components/CompetitionBanner/CompetitionBanner.tsx b/sections/shared/components/CompetitionBanner.tsx similarity index 77% rename from sections/shared/components/CompetitionBanner/CompetitionBanner.tsx rename to sections/shared/components/CompetitionBanner.tsx index 519a24f977..fb96c4c19f 100644 --- a/sections/shared/components/CompetitionBanner/CompetitionBanner.tsx +++ b/sections/shared/components/CompetitionBanner.tsx @@ -1,8 +1,9 @@ -import React, { FC } from 'react'; +import { memo, FC } from 'react'; import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import CompetitionBannerBg from 'assets/svg/app/competition-banner-bg.svg'; +import * as Text from 'components/Text'; import { COMPETITION_DATES, COMPETITION_ENABLED } from 'constants/competition'; import { EXTERNAL_LINKS } from 'constants/links'; import { ExternalLink } from 'styles/common'; @@ -16,19 +17,15 @@ type CompetitionBannerProps = { hideBanner?: boolean; }; -export const CompetitionBanner: FC = ({ - compact, - hideBanner, -}: CompetitionBannerProps) => { +const formatedStartDate = formatDateWithoutYear(COMPETITION_DATES.START_DATE); +const formatedEndDate = formatDateWithoutYear(COMPETITION_DATES.END_DATE); +const competitionPeriod = `${formatedStartDate}-${formatedEndDate.split(' ')[1]}`; + +export const CompetitionBanner: FC = memo(({ compact, hideBanner }) => { const { t } = useTranslation(); if (!COMPETITION_ENABLED) return null; - const formatedStartDate = formatDateWithoutYear(COMPETITION_DATES.START_DATE); - const formatedEndDate = formatDateWithoutYear(COMPETITION_DATES.END_DATE); - - const competitionPeriod = `${formatedStartDate}-${formatedEndDate.split(' ')[1]}`; - return ( {competitionPeriod} @@ -38,12 +35,9 @@ export const CompetitionBanner: FC = ({ ); -}; +}); -const BannerContainer = styled.div<{ - compact: boolean | undefined; - hideBanner: boolean | undefined; -}>` +const BannerContainer = styled.div<{ compact?: boolean; hideBanner?: boolean }>` position: relative; width: 100%; display: ${({ hideBanner }) => (hideBanner ? 'none' : 'flex')}; @@ -62,13 +56,11 @@ const BannerContainer = styled.div<{ gap: 10px; `; -const CompetitionPeriod = styled.p` - font-family: ${(props) => props.theme.fonts.monoBold}; +const CompetitionPeriod = styled(Text.Body).attrs({ mono: true, variant: 'bold' })` font-style: normal; font-size: 13px; line-height: 10px; color: ${(props) => props.theme.colors.selectedTheme.gray}; - // clear UA style. margin: 0; `; @@ -97,7 +89,7 @@ const StyledBg = styled(CompetitionBannerBg)` width: 100%; height: 100%; - // prevent background-image from covering the text. + /* prevent background-image from covering the text. */ z-index: -1; position: absolute; diff --git a/sections/shared/components/CompetitionBanner/index.ts b/sections/shared/components/CompetitionBanner/index.ts deleted file mode 100644 index 15de7a0688..0000000000 --- a/sections/shared/components/CompetitionBanner/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './CompetitionBanner'; diff --git a/sections/shared/components/CompetitionBanner/CompetitionState.tsx b/sections/shared/components/CompetitionState.tsx similarity index 98% rename from sections/shared/components/CompetitionBanner/CompetitionState.tsx rename to sections/shared/components/CompetitionState.tsx index d433424a62..62d2e1ef78 100644 --- a/sections/shared/components/CompetitionBanner/CompetitionState.tsx +++ b/sections/shared/components/CompetitionState.tsx @@ -12,7 +12,6 @@ const Container = styled.p` line-height: 25px; text-align: center; color: ${(props) => props.theme.colors.selectedTheme.competitionBanner.state.text}; - // clear UA style. margin: 0; `; diff --git a/sections/shared/components/FeeCostSummary/FeeCostSummary.tsx b/sections/shared/components/FeeCostSummary.tsx similarity index 96% rename from sections/shared/components/FeeCostSummary/FeeCostSummary.tsx rename to sections/shared/components/FeeCostSummary.tsx index e04f93d023..dd7b68467c 100644 --- a/sections/shared/components/FeeCostSummary/FeeCostSummary.tsx +++ b/sections/shared/components/FeeCostSummary.tsx @@ -2,11 +2,10 @@ import Wei from '@synthetixio/wei'; import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { SummaryItem, SummaryItemValue, SummaryItemLabel } from 'sections/exchange/summary'; import { NO_VALUE } from 'constants/placeholder'; import { formatDollars } from 'utils/formatters/number'; -import { SummaryItem, SummaryItemValue, SummaryItemLabel } from '../common'; - type FeeRateSummaryItemProps = { feeCost?: Wei; }; diff --git a/sections/shared/components/FeeCostSummary/index.ts b/sections/shared/components/FeeCostSummary/index.ts deleted file mode 100644 index 51251c5ef4..0000000000 --- a/sections/shared/components/FeeCostSummary/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FeeCostSummary'; diff --git a/sections/shared/components/FeeRateSummary/FeeRateSummary.tsx b/sections/shared/components/FeeRateSummary.tsx similarity index 72% rename from sections/shared/components/FeeRateSummary/FeeRateSummary.tsx rename to sections/shared/components/FeeRateSummary.tsx index cecace59fa..c16a2b78cb 100644 --- a/sections/shared/components/FeeRateSummary/FeeRateSummary.tsx +++ b/sections/shared/components/FeeRateSummary.tsx @@ -3,14 +3,13 @@ import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import TimerIcon from 'assets/svg/app/timer.svg'; -import StyledTooltip from 'components/Tooltip/StyledTooltip'; +import { SummaryItem, SummaryItemValue, SummaryItemLabel } from 'sections/exchange/summary'; +import Tooltip from 'components/Tooltip/Tooltip'; import { NO_VALUE } from 'constants/placeholder'; import { selectExchangeFeeRateWei, selectBaseFeeRateWei } from 'state/exchange/selectors'; import { useAppSelector } from 'state/hooks'; import { formatPercent } from 'utils/formatters/number'; -import { SummaryItem, SummaryItemValue, SummaryItemLabel } from '../common'; - const FeeRateSummaryItem: FC = memo(() => { const { t } = useTranslation(); @@ -29,25 +28,23 @@ const FeeRateSummaryItem: FC = memo(() => { ? formatPercent(exchangeFeeRate, { minDecimals: 2 }) : NO_VALUE} - {!!exchangeFeeRate && !!baseFeeRate ? ( - exchangeFeeRate.sub(baseFeeRate).gt(0) ? ( - <> - + - - - - {formatPercent(exchangeFeeRate.sub(baseFeeRate), { - minDecimals: 2, - })} - - - - - - ) : null + {exchangeFeeRate.sub(baseFeeRate).gt(0) ? ( + <> + + + + + + {formatPercent(exchangeFeeRate.sub(baseFeeRate), { + minDecimals: 2, + })} + + + + + ) : null} @@ -79,7 +76,7 @@ export const DynamicFeeRateItem = styled.span` } `; -const CustomStyledTooltip = styled(StyledTooltip)` +const CustomStyledTooltip = styled(Tooltip)` width: 300px; padding: 0px 4px; text-align: center; diff --git a/sections/shared/components/FeeRateSummary/index.ts b/sections/shared/components/FeeRateSummary/index.ts deleted file mode 100644 index 53dd71b045..0000000000 --- a/sections/shared/components/FeeRateSummary/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FeeRateSummary'; diff --git a/sections/shared/components/GasPriceSelect/GasPriceSelect.tsx b/sections/shared/components/GasPriceSelect.tsx similarity index 72% rename from sections/shared/components/GasPriceSelect/GasPriceSelect.tsx rename to sections/shared/components/GasPriceSelect.tsx index 55a12d01a1..7fea2bb36b 100644 --- a/sections/shared/components/GasPriceSelect/GasPriceSelect.tsx +++ b/sections/shared/components/GasPriceSelect.tsx @@ -4,6 +4,7 @@ import { FC, useMemo, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useRecoilValue } from 'recoil'; +import { SummaryItem, SummaryItemValue, SummaryItemLabel } from 'sections/exchange/summary'; import { NO_VALUE } from 'constants/placeholder'; import { parseGasPriceObject } from 'hooks/useGas'; import useIsL1 from 'hooks/useIsL1'; @@ -11,21 +12,21 @@ import useIsL2 from 'hooks/useIsL2'; import { customGasPriceState, gasSpeedState } from 'store/wallet'; import { formatNumber, formatDollars } from 'utils/formatters/number'; -import { SummaryItem, SummaryItemValue, SummaryItemLabel } from '../common'; - type GasPriceSelectProps = { gasPrices: GasPrices | undefined; transactionFee?: Wei | number | null; className?: string; }; -const GasPriceSelect: FC = memo(({ gasPrices, transactionFee, ...rest }) => { - const { t } = useTranslation(); +type GasPriceItemProps = { + gasPrices: GasPrices | undefined; + transactionFee?: Wei | number | null; +}; + +const GasPriceItem: FC = memo(({ gasPrices, transactionFee }) => { + const isL2 = useIsL2(); const gasSpeed = useRecoilValue(gasSpeedState); const customGasPrice = useRecoilValue(customGasPriceState); - const isL2 = useIsL2(); - const isMainnet = useIsL1(); - const formattedTransactionFee = useMemo(() => { return transactionFee ? formatDollars(transactionFee, { maxDecimals: 1 }) : NO_VALUE; }, [transactionFee]); @@ -33,18 +34,22 @@ const GasPriceSelect: FC = memo(({ gasPrices, transactionFe const hasCustomGasPrice = customGasPrice !== ''; const gasPrice = gasPrices ? parseGasPriceObject(gasPrices[gasSpeed]) : null; - const gasPriceItem = useMemo( - () => ( - - {isL2 - ? formattedTransactionFee - : `${formatNumber(hasCustomGasPrice ? +customGasPrice : gasPrice ?? 0, { - minDecimals: 2, - })} Gwei`} - - ), - [isL2, formattedTransactionFee, hasCustomGasPrice, customGasPrice, gasPrice] + if (!gasPrice) return <>{NO_VALUE}; + + return ( + + {isL2 + ? formattedTransactionFee + : `${formatNumber(hasCustomGasPrice ? +customGasPrice : gasPrice ?? 0, { + minDecimals: 2, + })} Gwei`} + ); +}); + +const GasPriceSelect: FC = memo(({ gasPrices, transactionFee, ...rest }) => { + const { t } = useTranslation(); + const isMainnet = useIsL1(); return ( @@ -53,7 +58,9 @@ const GasPriceSelect: FC = memo(({ gasPrices, transactionFe ? t('common.summary.gas-prices.max-fee') : t('common.summary.gas-prices.gas-price')} - {gasPrice != null ? gasPriceItem : NO_VALUE} + + + ); }); diff --git a/sections/shared/components/GasPriceSelect/index.ts b/sections/shared/components/GasPriceSelect/index.ts deleted file mode 100644 index 5a274f0fed..0000000000 --- a/sections/shared/components/GasPriceSelect/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './GasPriceSelect'; diff --git a/sections/shared/components/PriceCurrencySelect/PriceCurrencySelect.tsx b/sections/shared/components/PriceCurrencySelect/PriceCurrencySelect.tsx deleted file mode 100644 index e83e2d2d73..0000000000 --- a/sections/shared/components/PriceCurrencySelect/PriceCurrencySelect.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useMemo, FC } from 'react'; - -import Select from 'components/Select'; -import Connector from 'containers/Connector'; -import usePersistedRecoilState from 'hooks/usePersistedRecoilState'; -import { priceCurrencyState, PRICE_CURRENCIES } from 'store/app'; - -export const PriceCurrencySelect: FC = () => { - const [priceCurrency, setPriceCurrency] = usePersistedRecoilState(priceCurrencyState); - - const { synthsMap, network } = Connector.useContainer(); - - const currencyOptions = useMemo(() => { - if (network != null && synthsMap != null) { - return PRICE_CURRENCIES.filter((currencyKey) => synthsMap![currencyKey]).map( - (currencyKey) => { - const synth = synthsMap![currencyKey]!; - return { label: synth.asset, value: synth }; - } - ); - } - return []; - }, [network, synthsMap]); - - return ( -