Merge branch 'main' into env-list
This commit is contained in:
Generated
+6
-8
@@ -27,8 +27,8 @@ dependencies:
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@dydxprotocol/abacus':
|
||||
specifier: file:/Users/jaredvu/Documents/v4-abacus/build/packages/dydxprotocol-abacus-0.3.7.tgz
|
||||
version: file:../v4-abacus/build/packages/dydxprotocol-abacus-0.3.7.tgz
|
||||
specifier: ^0.3.7
|
||||
version: 0.3.7
|
||||
'@dydxprotocol/v4-client':
|
||||
specifier: ^0.29.0
|
||||
version: 0.29.0
|
||||
@@ -1143,6 +1143,10 @@ packages:
|
||||
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
||||
dev: true
|
||||
|
||||
/@dydxprotocol/abacus@0.3.7:
|
||||
resolution: {integrity: sha512-wYGdsFNnVulwVqsNpMrS3j02lOyw/qg5QrB2DdlWtj4YeNZqvdM/vHC6HgU+U4McdVJW4STiEKW2Fl0rF/qbhQ==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/dydxjs@0.3.0:
|
||||
resolution: {integrity: sha512-ygNeBs0f3H7sJk1qLUjfNwaXgc5TmjD+qZf7BFDbi7+boHJI9xuOWrGpjfBo7OTUZxS6O5jZG323CgU5XqMSPw==}
|
||||
dependencies:
|
||||
@@ -15836,12 +15840,6 @@ packages:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
dev: true
|
||||
|
||||
file:../v4-abacus/build/packages/dydxprotocol-abacus-0.3.7.tgz:
|
||||
resolution: {integrity: sha512-omUiVHcT/tHWeXKgZTk1WW8LDVHI+2yxXNM6+B756liRY/t1JwUkRzwplp09U2+mNo/FenejHFtWZ0qd+W79iw==, tarball: file:../v4-abacus/build/packages/dydxprotocol-abacus-0.3.7.tgz}
|
||||
name: '@dydxprotocol/abacus'
|
||||
version: 0.3.7
|
||||
dev: false
|
||||
|
||||
github.com/release-it/conventional-changelog/a4acfeac76369937a6566d698a5ae9180eceb413(release-it@15.11.0):
|
||||
resolution: {tarball: https://codeload.github.com/release-it/conventional-changelog/tar.gz/a4acfeac76369937a6566d698a5ae9180eceb413}
|
||||
id: github.com/release-it/conventional-changelog/a4acfeac76369937a6566d698a5ae9180eceb413
|
||||
|
||||
+15
-13
@@ -10,10 +10,10 @@ import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
|
||||
import { useBreakpoints, useInitializePage, useShouldShowFooter, useAnalytics } from '@/hooks';
|
||||
import { DydxProvider } from '@/hooks/useDydxClient';
|
||||
import { AccountsProvider } from '@/hooks/useAccounts';
|
||||
import { SubaccountProvider } from './hooks/useSubaccount';
|
||||
import { DialogAreaProvider, useDialogArea } from './hooks/useDialogArea';
|
||||
import { LocaleProvider } from './hooks/useLocaleSeparators';
|
||||
import { NotificationsProvider } from './hooks/useNotifications';
|
||||
|
||||
import { SubaccountProvider } from './hooks/useSubaccount';
|
||||
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
|
||||
|
||||
import MarketsPage from '@/pages/markets/Markets';
|
||||
@@ -100,17 +100,19 @@ const App = () => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<GrazProvider>
|
||||
<WagmiConfig config={config}>
|
||||
<DydxProvider>
|
||||
<AccountsProvider>
|
||||
<SubaccountProvider>
|
||||
<NotificationsProvider>
|
||||
<DialogAreaProvider>
|
||||
<Content />
|
||||
</DialogAreaProvider>
|
||||
</NotificationsProvider>
|
||||
</SubaccountProvider>
|
||||
</AccountsProvider>
|
||||
</DydxProvider>
|
||||
<LocaleProvider>
|
||||
<DydxProvider>
|
||||
<AccountsProvider>
|
||||
<SubaccountProvider>
|
||||
<NotificationsProvider>
|
||||
<DialogAreaProvider>
|
||||
<Content />
|
||||
</DialogAreaProvider>
|
||||
</NotificationsProvider>
|
||||
</SubaccountProvider>
|
||||
</AccountsProvider>
|
||||
</DydxProvider>
|
||||
</LocaleProvider>
|
||||
</WagmiConfig>
|
||||
</GrazProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Story } from '@ladle/react';
|
||||
|
||||
import { CopyButton, type CopyButtonProps } from '@/components/CopyButton';
|
||||
|
||||
import { StoryWrapper } from '.ladle/components';
|
||||
|
||||
export const CopyButtonStory: Story<CopyButtonProps> = (args) => (
|
||||
<StoryWrapper>
|
||||
<CopyButton {...args} />
|
||||
</StoryWrapper>
|
||||
);
|
||||
|
||||
CopyButtonStory.args = {
|
||||
value: 'some text to copy',
|
||||
};
|
||||
|
||||
CopyButtonStory.argTypes = {
|
||||
shownAsText: {
|
||||
options: [true, false],
|
||||
control: { type: 'select' },
|
||||
defaultValue: false,
|
||||
},
|
||||
children: {
|
||||
options: ['some text to copy'],
|
||||
control: { type: 'select' },
|
||||
defaultValue: undefined,
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { css, type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { Button, ButtonProps } from './Button';
|
||||
import { Icon, IconName } from './Icon';
|
||||
|
||||
export type CopyButtonProps = {
|
||||
value?: string;
|
||||
shownAsText?: boolean;
|
||||
children?: React.ReactNode;
|
||||
} & ButtonProps;
|
||||
|
||||
export const CopyButton = ({ value, shownAsText, children, ...buttonProps }: CopyButtonProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = () => {
|
||||
if (!value) return;
|
||||
|
||||
setCopied(true);
|
||||
navigator.clipboard.writeText(value);
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
return shownAsText ? (
|
||||
<Styled.InlineRow onClick={onCopy} copied={copied}>
|
||||
{children}
|
||||
<Icon iconName={IconName.Copy} />
|
||||
</Styled.InlineRow>
|
||||
) : (
|
||||
<Button
|
||||
{...buttonProps}
|
||||
action={copied ? ButtonAction.Create : ButtonAction.Primary}
|
||||
onClick={onCopy}
|
||||
>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{children ?? stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.InlineRow = styled.div<{ copied: boolean }>`
|
||||
${layoutMixins.inlineRow}
|
||||
cursor: pointer;
|
||||
|
||||
${({ copied }) =>
|
||||
copied
|
||||
? css`
|
||||
filter: brightness(0.8);
|
||||
`
|
||||
: css`
|
||||
&:hover {
|
||||
filter: brightness(1.1);
|
||||
text-decoration: underline;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
@@ -119,6 +119,8 @@ export type SubaccountFill = Abacus.exchange.dydx.abacus.output.SubaccountFill;
|
||||
export type SubaccountFundingPayment = Abacus.exchange.dydx.abacus.output.SubaccountFundingPayment;
|
||||
export type SubaccountFundingPayments =
|
||||
Abacus.exchange.dydx.abacus.output.SubaccountFundingPayment[];
|
||||
export type SubaccountTransfer = Abacus.exchange.dydx.abacus.output.SubaccountTransfer;
|
||||
export type SubaccountTransfers = Abacus.exchange.dydx.abacus.output.SubaccountTransfer[];
|
||||
|
||||
// ------ Historical PnL ------ //
|
||||
export type SubAccountHistoricalPNL = Abacus.exchange.dydx.abacus.output.SubaccountHistoricalPNL;
|
||||
|
||||
@@ -177,6 +177,7 @@ export const APP_STRING_KEYS = {
|
||||
RECEIVE: 'GENERAL.RECEIVE',
|
||||
RECENT: 'GENERAL.RECENT',
|
||||
RECENT_TRADES_SHORT: 'GENERAL.RECENT_TRADES_SHORT',
|
||||
RECIPIENT: 'GENERAL.RECIPIENT',
|
||||
REFERRAL_CODE: 'GENERAL.REFERRAL_CODE',
|
||||
REFERRALS: 'GENERAL.REFERRALS',
|
||||
REFERRER_PERCENT_OFF: 'GENERAL.REFERRER_PERCENT_OFF',
|
||||
@@ -188,6 +189,7 @@ export const APP_STRING_KEYS = {
|
||||
SELECT_NETWORK: 'GENERAL.SELECT_NETWORK',
|
||||
SELL: 'GENERAL.SELL',
|
||||
SEND: 'GENERAL.SEND',
|
||||
SENDER: 'GENERAL.SENDER',
|
||||
SHARE: 'GENERAL.SHARE',
|
||||
SHORT_POSITION_SHORT: 'GENERAL.SHORT_POSITION_SHORT',
|
||||
SIDE: 'GENERAL.SIDE',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { DEFAULT_MARKETID } from './markets';
|
||||
|
||||
export enum AppRoute {
|
||||
Markets = '/markets',
|
||||
Portfolio = '/portfolio',
|
||||
@@ -5,7 +7,7 @@ export enum AppRoute {
|
||||
Profile = '/profile',
|
||||
Alerts = '/alerts',
|
||||
Settings = '/settings',
|
||||
Rewards = '/DYDX',
|
||||
Rewards = '/DV4TNT',
|
||||
}
|
||||
|
||||
export enum PortfolioRoute {
|
||||
@@ -31,7 +33,7 @@ export enum MobileSettingsRoute {
|
||||
export const TRADE_ROUTE = `${AppRoute.Trade}/:market`;
|
||||
export const PORTFOLIO_ROUTE = `${AppRoute.Portfolio}/:subroute`;
|
||||
export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:subroute`;
|
||||
export const DEFAULT_TRADE_ROUTE = `${AppRoute.Trade}/ETH-USD`;
|
||||
export const DEFAULT_TRADE_ROUTE = `${AppRoute.Trade}/${DEFAULT_MARKETID}`;
|
||||
export const SETTINGS_ROUTE = `${AppRoute.Settings}/*`;
|
||||
export const DEFAULT_DOCUMENT_TITLE = 'dYdX';
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
|
||||
|
||||
export enum DydxChainAsset {
|
||||
USDC = 'USDC',
|
||||
DYDX = 'DYDX',
|
||||
DYDX = 'Dv4TNT',
|
||||
}
|
||||
|
||||
export const DYDX_CHAIN_ASSET_COIN_DENOM: Record<DydxChainAsset, string> = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { useMatch, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { LocalStorageKey } from '@/constants/localStorage';
|
||||
@@ -13,6 +13,7 @@ import { setCurrentMarketId } from '@/state/perpetuals';
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
|
||||
import { useLocalStorage } from './useLocalStorage';
|
||||
import { getMarketIds } from '@/state/perpetualsSelectors';
|
||||
|
||||
export const useCurrentMarketId = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -20,26 +21,27 @@ export const useCurrentMarketId = () => {
|
||||
const { marketId } = match?.params ?? {};
|
||||
const dispatch = useDispatch();
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
const marketIds = useSelector(getMarketIds, shallowEqual);
|
||||
const [lastViewedMarket, setLastViewedMarket] = useLocalStorage({
|
||||
key: LocalStorageKey.LastViewedMarket,
|
||||
defaultValue: DEFAULT_MARKETID,
|
||||
});
|
||||
|
||||
const validId = useMemo(() => {
|
||||
if (marketIds.length === 0) return marketId ?? lastViewedMarket;
|
||||
if (!marketIds.includes(marketId)) return DEFAULT_MARKETID;
|
||||
return marketId ?? lastViewedMarket;
|
||||
}, [marketIds, marketId]);
|
||||
|
||||
useEffect(() => {
|
||||
setLastViewedMarket(marketId ?? DEFAULT_MARKETID);
|
||||
dispatch(setCurrentMarketId(marketId ?? DEFAULT_MARKETID));
|
||||
setLastViewedMarket(validId);
|
||||
dispatch(setCurrentMarketId(validId));
|
||||
dispatch(closeDialogInTradeBox());
|
||||
|
||||
if (!marketId) {
|
||||
navigate(lastViewedMarket ? `${AppRoute.Trade}/${lastViewedMarket}` : DEFAULT_TRADE_ROUTE, {
|
||||
replace: true,
|
||||
});
|
||||
} else {
|
||||
navigate(`${AppRoute.Trade}/${marketId}`, {
|
||||
replace: true,
|
||||
});
|
||||
}
|
||||
}, [marketId]);
|
||||
navigate(`${AppRoute.Trade}/${validId}`, {
|
||||
replace: true,
|
||||
});
|
||||
}, [validId]);
|
||||
|
||||
useEffect(() => {
|
||||
abacusStateManager.setMarket(marketId ?? DEFAULT_MARKETID);
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
setFundingPayments,
|
||||
setHistoricalPnl,
|
||||
setSubaccount,
|
||||
setTransfers,
|
||||
setWallet,
|
||||
} from '@/state/account';
|
||||
|
||||
@@ -113,6 +114,11 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
|
||||
dispatch(setFundingPayments(fundingPayments));
|
||||
}
|
||||
|
||||
if (changes.has(Changes.transfers)) {
|
||||
const transfers = updatedState.subaccountTransfers(subaccountId)?.toArray() || [];
|
||||
dispatch(setTransfers(transfers));
|
||||
}
|
||||
|
||||
if (changes.has(Changes.historicalPnl)) {
|
||||
const historicalPnl =
|
||||
updatedState.subaccountHistoricalPnl(subaccountId)?.toArray() || [];
|
||||
|
||||
@@ -182,6 +182,7 @@
|
||||
"RECEIVE": "Receive",
|
||||
"RECENT": "Recent",
|
||||
"RECENT_TRADES_SHORT": "Trades",
|
||||
"RECIPIENT": "Recipient",
|
||||
"REFERRAL_CODE": "Referral Code",
|
||||
"REFERRALS": "Referrals",
|
||||
"REFERRER_PERCENT_OFF": "{DISCOUNT}% off",
|
||||
@@ -193,6 +194,7 @@
|
||||
"SELECT_NETWORK": "Select Network",
|
||||
"SELL": "Sell",
|
||||
"SEND": "Send",
|
||||
"SENDER": "Sender",
|
||||
"SHARE": "Share",
|
||||
"SHORT_POSITION_SHORT": "Short",
|
||||
"SIDE": "Side",
|
||||
|
||||
+2
-5
@@ -1,5 +1,5 @@
|
||||
import './polyfills';
|
||||
import { Fragment, StrictMode } from 'react';
|
||||
import { StrictMode } from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { HashRouter } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
@@ -11,15 +11,12 @@ import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
import './index.css';
|
||||
|
||||
import App from './App';
|
||||
import { LocaleProvider } from './hooks/useLocaleSeparators';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<ErrorBoundary>
|
||||
<StrictMode>
|
||||
<Provider store={store}>
|
||||
<LocaleProvider>
|
||||
<HashRouter children={<App />} />
|
||||
</LocaleProvider>
|
||||
<HashRouter children={<App />} />
|
||||
</Provider>
|
||||
</StrictMode>
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -28,13 +28,14 @@ export const History = () => {
|
||||
label: <h3>{stringGetter({ key: STRING_KEYS.TRADES })}</h3>,
|
||||
href: HistoryRoute.Trades,
|
||||
},
|
||||
{
|
||||
value: HistoryRoute.Transfers,
|
||||
label: <h3>{stringGetter({ key: STRING_KEYS.TRANSFERS })}</h3>,
|
||||
href: HistoryRoute.Transfers,
|
||||
tag: 'USDC',
|
||||
},
|
||||
// TODO - TRCL-1693 -
|
||||
// {
|
||||
// value: HistoryRoute.Transfers,
|
||||
// label: <h3>{stringGetter({ key: STRING_KEYS.TRANSFERS })}</h3>,
|
||||
// href: HistoryRoute.Transfers,
|
||||
// },
|
||||
// {
|
||||
// value: HistoryRoute.Payments,
|
||||
// label: <h3>{stringGetter({ key: STRING_KEYS.PAYMENTS })}</h3>,
|
||||
// href: HistoryRoute.Payments,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks';
|
||||
|
||||
import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable';
|
||||
import { FundingPaymentsTable } from '@/views/tables/FundingPaymentsTable';
|
||||
import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { NavigationMenu } from '@/components/NavigationMenu';
|
||||
import { WithSidebar } from '@/components/WithSidebar';
|
||||
@@ -61,7 +62,10 @@ export default () => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path={HistoryRoute.Transfers} element={<div />} />
|
||||
<Route
|
||||
path={HistoryRoute.Transfers}
|
||||
element={<TransferHistoryTable withOuterBorder={isNotTablet} />}
|
||||
/>
|
||||
<Route
|
||||
path={HistoryRoute.Payments}
|
||||
element={<FundingPaymentsTable withOuterBorder={isNotTablet} />}
|
||||
@@ -118,8 +122,6 @@ export default () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
// TODO(aforaleka) Add back subitems when there are clearer designs
|
||||
// or when transfers and payments are ready
|
||||
]}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -40,12 +40,12 @@ export const PortfolioNavMobile = () => {
|
||||
label: stringGetter({ key: STRING_KEYS.TRADES }),
|
||||
description: stringGetter({ key: STRING_KEYS.TRADES_DESCRIPTION }),
|
||||
},
|
||||
// TODO: TRCL-1693 - re-enable when Payments and Transfers are ready
|
||||
// {
|
||||
// value: `${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Transfers}`,
|
||||
// label: stringGetter({ key: STRING_KEYS.TRANSFERS }),
|
||||
// description: stringGetter({ key: STRING_KEYS.TRANSFERS_DESCRIPTION }),
|
||||
// },
|
||||
{
|
||||
value: `${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Transfers}`,
|
||||
label: stringGetter({ key: STRING_KEYS.TRANSFERS }),
|
||||
description: stringGetter({ key: STRING_KEYS.TRANSFERS_DESCRIPTION }),
|
||||
},
|
||||
// TODO: TRCL-1693 - re-enable when Payments are ready
|
||||
// {
|
||||
// value: `${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Payments}`,
|
||||
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
|
||||
|
||||
@@ -36,8 +36,8 @@ export const DYDXBalancePanel = () => {
|
||||
slotHeader={
|
||||
<Styled.Header>
|
||||
<Styled.Title>
|
||||
<AssetIcon symbol="DYDX" />
|
||||
DYDX
|
||||
{/* <AssetIcon symbol="DYDX" /> */}
|
||||
Dv4TNT
|
||||
</Styled.Title>
|
||||
<Styled.ReceiveAndTransferButtons>
|
||||
{!canAccountTrade ? (
|
||||
@@ -106,7 +106,7 @@ export const DYDXBalancePanel = () => {
|
||||
{
|
||||
key: 'totalBalance',
|
||||
label: 'Total balance',
|
||||
value: <Output type={OutputType.Asset} value={nativeTokenBalance} tag="DYDX" />,
|
||||
value: <Output type={OutputType.Asset} value={nativeTokenBalance} tag="Dv4TNT" />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
SubaccountFundingPayments,
|
||||
Wallet,
|
||||
SubaccountOrder,
|
||||
SubaccountTransfers,
|
||||
HistoricalPnlPeriods,
|
||||
SubAccountHistoricalPNLs,
|
||||
} from '@/constants/abacus';
|
||||
@@ -22,6 +23,7 @@ import { getLocalStorage } from '@/lib/localStorage';
|
||||
export type AccountState = {
|
||||
fills?: SubaccountFills;
|
||||
fundingPayments?: SubaccountFundingPayments;
|
||||
transfers?: SubaccountTransfers;
|
||||
clearedOrderIds?: string[];
|
||||
uncommittedOrderClientIds?: number[];
|
||||
hasUnseenFillUpdates: boolean;
|
||||
@@ -38,6 +40,7 @@ export type AccountState = {
|
||||
const initialState: AccountState = {
|
||||
fills: undefined,
|
||||
fundingPayments: undefined,
|
||||
transfers: undefined,
|
||||
clearedOrderIds: undefined,
|
||||
uncommittedOrderClientIds: undefined,
|
||||
hasUnseenFillUpdates: false,
|
||||
@@ -81,6 +84,9 @@ export const accountSlice = createSlice({
|
||||
setFundingPayments: (state, action: PayloadAction<any>) => {
|
||||
state.fundingPayments = action.payload;
|
||||
},
|
||||
setTransfers: (state, action: PayloadAction<any>) => {
|
||||
state.transfers = action.payload;
|
||||
},
|
||||
clearOrder: (state, action: PayloadAction<string>) => ({
|
||||
...state,
|
||||
clearedOrderIds: [...(state.clearedOrderIds || []), action.payload],
|
||||
@@ -148,6 +154,7 @@ export const accountSlice = createSlice({
|
||||
export const {
|
||||
setFills,
|
||||
setFundingPayments,
|
||||
setTransfers,
|
||||
clearOrder,
|
||||
setOnboardingGuard,
|
||||
setOnboardingState,
|
||||
|
||||
@@ -193,6 +193,12 @@ export const getCurrentMarketFills = createSelector(
|
||||
!currentMarketId ? [] : marketFills[currentMarketId]
|
||||
);
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns list of transfers for the currently connected subaccount
|
||||
*/
|
||||
export const getSubaccountTransfers = (state: RootState) => state.account?.transfers;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns list of funding payments for the currently connected subaccount
|
||||
|
||||
@@ -5,7 +5,7 @@ export const headerMixins = {
|
||||
--trigger-backgroundColor: transparent;
|
||||
--trigger-textColor: var(--color-text-0);
|
||||
|
||||
--trigger-hover-backgroundColor: var(--color-layer-4);
|
||||
--trigger-hover-backgroundColor: var(--color-layer-3);
|
||||
--trigger-hover-textColor: var(--color-text-2);
|
||||
|
||||
--trigger-open-backgroundColor: var(--color-layer-1);
|
||||
|
||||
@@ -185,6 +185,7 @@ export const popoverMixins = {
|
||||
--item-checked-backgroundColor: var(--color-layer-2);
|
||||
--item-checked-textColor: currentColor;
|
||||
|
||||
--item-highlighted-backgroundColor: var(--color-layer-2);
|
||||
--item-highlighted-textColor: var(--color-text-2);
|
||||
|
||||
--item-radius: 0px;
|
||||
@@ -218,6 +219,7 @@ export const popoverMixins = {
|
||||
&[data-highlighted] // @radix-ui
|
||||
{
|
||||
filter: brightness(1.1);
|
||||
background-color: var(--item-highlighted-backgroundColor);
|
||||
color: var(--item-highlighted-textColor, var(--trigger-textColor, inherit)) !important;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -18,5 +18,9 @@ export const tradeViewMixins: Record<
|
||||
tbody {
|
||||
font: var(--font-small-book);
|
||||
}
|
||||
|
||||
thead tr {
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { AlertMessage } from '@/components/AlertMessage';
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { Checkbox } from '@/components/Checkbox';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
@@ -30,21 +30,12 @@ export const MnemonicExportDialog = ({ setIsOpen }: ElementProps) => {
|
||||
const [hasAcknowledged, setHasAcknowledged] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(MnemonicExportStep.AcknowledgeRisk);
|
||||
const [isShowing, setIsShowing] = useState(false);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const { hdKey } = useAccounts();
|
||||
const { mnemonic } = hdKey ?? {};
|
||||
|
||||
const onCopy = () => {
|
||||
setCopied(true);
|
||||
if (mnemonic) {
|
||||
navigator.clipboard.writeText(mnemonic);
|
||||
}
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
const title = {
|
||||
[MnemonicExportStep.AcknowledgeRisk]: stringGetter({ key: STRING_KEYS.REVEAL_SECRET_PHRASE }),
|
||||
[MnemonicExportStep.DisplayMnemonic]: stringGetter({ key: STRING_KEYS.EXPORT_SECRET_PHRASE }),
|
||||
@@ -116,10 +107,7 @@ export const MnemonicExportDialog = ({ setIsOpen }: ElementProps) => {
|
||||
</Styled.WordList>
|
||||
}
|
||||
>
|
||||
<Button action={copied ? ButtonAction.Create : ButtonAction.Primary} onClick={onCopy}>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })}
|
||||
</Button>
|
||||
<CopyButton value={mnemonic} />
|
||||
</WithReceipt>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { DydxChainAsset } from '@/constants/wallets';
|
||||
|
||||
@@ -10,9 +9,8 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { useAccounts, useStringGetter } from '@/hooks';
|
||||
|
||||
import { AssetIcon } from '@/components/AssetIcon';
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { QrCode } from '@/components/QrCode';
|
||||
import { SelectItem, SelectMenu } from '@/components/SelectMenu';
|
||||
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
||||
@@ -22,22 +20,15 @@ import { truncateAddress } from '@/lib/wallet';
|
||||
import { OnboardingTriggerButton } from './OnboardingTriggerButton';
|
||||
|
||||
type ElementProps = {
|
||||
selectedAsset?: DydxChainAsset;
|
||||
setIsOpen: (open: boolean) => void;
|
||||
};
|
||||
|
||||
export const ReceiveDialog = ({ setIsOpen }: ElementProps) => {
|
||||
export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.DYDX, setIsOpen }: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { dydxAddress } = useAccounts();
|
||||
|
||||
const [asset, setAsset] = useState(DydxChainAsset.DYDX);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = () => {
|
||||
if (!dydxAddress) return;
|
||||
setCopied(true);
|
||||
navigator.clipboard.writeText(dydxAddress);
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
const [asset, setAsset] = useState(selectedAsset);
|
||||
|
||||
const assetOptions = [
|
||||
{
|
||||
@@ -52,7 +43,8 @@ export const ReceiveDialog = ({ setIsOpen }: ElementProps) => {
|
||||
value: DydxChainAsset.DYDX,
|
||||
label: (
|
||||
<Styled.InlineRow>
|
||||
<AssetIcon symbol="DYDX" /> DYDX
|
||||
{/* <AssetIcon symbol="DYDX" /> */}
|
||||
Dv4TNT
|
||||
</Styled.InlineRow>
|
||||
),
|
||||
},
|
||||
@@ -87,10 +79,7 @@ export const ReceiveDialog = ({ setIsOpen }: ElementProps) => {
|
||||
>
|
||||
<QrCode hasLogo value={dydxAddress!} />
|
||||
</Styled.WithDetailsReceipt>
|
||||
<Button action={copied ? ButtonAction.Create : ButtonAction.Primary} onClick={onCopy}>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY_ADDRESS })}
|
||||
</Button>
|
||||
<CopyButton value={dydxAddress} />
|
||||
</>
|
||||
)}
|
||||
</Styled.Content>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { DydxChainAsset } from '@/constants/wallets';
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { TransferForm } from '@/views/forms/TransferForm';
|
||||
|
||||
type ElementProps = {
|
||||
selectedAsset?: DydxChainAsset;
|
||||
setIsOpen?: (open: boolean) => void;
|
||||
};
|
||||
|
||||
export const TransferDialog = ({ setIsOpen }: ElementProps) => {
|
||||
export const TransferDialog = ({ selectedAsset, setIsOpen }: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
return (
|
||||
<Styled.Dialog isOpen setIsOpen={setIsOpen} title={stringGetter({ key: STRING_KEYS.TRANSFER })}>
|
||||
<TransferForm onDone={() => setIsOpen?.(false)} />
|
||||
<TransferForm selectedAsset={selectedAsset} onDone={() => setIsOpen?.(false)} />
|
||||
</Styled.Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -109,6 +109,7 @@ export const AdvancedTradeOptions = () => {
|
||||
{executionOptions && (
|
||||
<Styled.SelectMenu
|
||||
value={execution}
|
||||
label={stringGetter({ key: STRING_KEYS.EXECUTION })}
|
||||
onValueChange={(selectedTimeInForceOption: string) =>
|
||||
abacusStateManager.setTradeValue({
|
||||
value: selectedTimeInForceOption,
|
||||
|
||||
@@ -48,6 +48,7 @@ import { MustBigNumber } from '@/lib/numbers';
|
||||
import { log } from '@/lib/telemetry';
|
||||
|
||||
type TransferFormProps = {
|
||||
selectedAsset?: DydxChainAsset;
|
||||
onDone?: () => void;
|
||||
className?: string;
|
||||
};
|
||||
@@ -74,7 +75,11 @@ const debouncedEstimateFee = debounce(
|
||||
{ trailing: true }
|
||||
);
|
||||
|
||||
export const TransferForm = ({ onDone, className }: TransferFormProps) => {
|
||||
export const TransferForm = ({
|
||||
selectedAsset = DydxChainAsset.DYDX,
|
||||
onDone,
|
||||
className,
|
||||
}: TransferFormProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||
const { dydxAddress } = useAccounts();
|
||||
@@ -84,7 +89,7 @@ export const TransferForm = ({ onDone, className }: TransferFormProps) => {
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
// User Input
|
||||
const [asset, setAsset] = useState<DydxChainAsset>(DydxChainAsset.DYDX);
|
||||
const [asset, setAsset] = useState<DydxChainAsset>(selectedAsset);
|
||||
|
||||
// Form states
|
||||
const [error, setError] = useState<Error | undefined>();
|
||||
@@ -214,7 +219,8 @@ export const TransferForm = ({ onDone, className }: TransferFormProps) => {
|
||||
value: DydxChainAsset.DYDX,
|
||||
label: (
|
||||
<Styled.InlineRow>
|
||||
<AssetIcon symbol="DYDX" /> DYDX
|
||||
{/* <AssetIcon symbol="DYDX" /> */}
|
||||
Dv4TNT
|
||||
</Styled.InlineRow>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { memo } from 'react';
|
||||
import styled, { AnyStyledComponent } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import type { Dispatch } from '@reduxjs/toolkit';
|
||||
|
||||
import { OnboardingState } from '@/constants/account';
|
||||
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS, TOOLTIP_STRING_KEYS } from '@/constants/localization';
|
||||
import { wallets } from '@/constants/wallets';
|
||||
import { DydxChainAsset, wallets } from '@/constants/wallets';
|
||||
|
||||
import { useAccounts, useBreakpoints, useStringGetter, useAccountBalance } from '@/hooks';
|
||||
|
||||
@@ -103,22 +105,28 @@ export const AccountMenu = () => {
|
||||
</Styled.AddressRow>
|
||||
<Styled.Balances>
|
||||
<div>
|
||||
<Styled.label>
|
||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'Dv4TNT' } })}
|
||||
{/* <AssetIcon symbol="DYDX" /> */}
|
||||
</Styled.label>
|
||||
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
||||
<div>
|
||||
<Styled.label>
|
||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'Dv4TNT' } })}
|
||||
{/* <AssetIcon symbol="DYDX" /> */}
|
||||
</Styled.label>
|
||||
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
||||
</div>
|
||||
<AssetActions asset={DydxChainAsset.DYDX} dispatch={dispatch} />
|
||||
</div>
|
||||
<div>
|
||||
<Styled.label>
|
||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'USDC' } })}
|
||||
<AssetIcon symbol="USDC" />
|
||||
</Styled.label>
|
||||
<Styled.BalanceOutput
|
||||
type={OutputType.Asset}
|
||||
value={freeCollateral?.current || 0}
|
||||
fractionDigits={2}
|
||||
/>
|
||||
<div>
|
||||
<Styled.label>
|
||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'USDC' } })}
|
||||
<AssetIcon symbol="USDC" />
|
||||
</Styled.label>
|
||||
<Styled.BalanceOutput
|
||||
type={OutputType.Asset}
|
||||
value={freeCollateral?.current || 0}
|
||||
fractionDigits={2}
|
||||
/>
|
||||
</div>
|
||||
<AssetActions asset={DydxChainAsset.USDC} dispatch={dispatch} />
|
||||
</div>
|
||||
</Styled.Balances>
|
||||
</Styled.AccountInfo>
|
||||
@@ -191,6 +199,29 @@ export const AccountMenu = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const AssetActions = memo(({ asset, dispatch }: { asset: DydxChainAsset; dispatch: Dispatch }) => (
|
||||
<Styled.InlineRow>
|
||||
{[
|
||||
// TODO(@rosepuppy): Add withdraw action for USDC
|
||||
{
|
||||
dialogType: DialogTypes.Receive,
|
||||
iconName: IconName.Qr,
|
||||
},
|
||||
{ dialogType: DialogTypes.Transfer, iconName: IconName.Send },
|
||||
].map(({ iconName, dialogType }) => (
|
||||
<IconButton
|
||||
key={dialogType}
|
||||
action={ButtonAction.Base}
|
||||
shape={ButtonShape.Square}
|
||||
iconName={iconName}
|
||||
onClick={() =>
|
||||
dispatch(openDialog({ type: dialogType, dialogProps: { selectedAsset: asset } }))
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Styled.InlineRow>
|
||||
));
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.AccountInfo = styled.div`
|
||||
@@ -204,6 +235,10 @@ Styled.Column = styled.div`
|
||||
${layoutMixins.column}
|
||||
`;
|
||||
|
||||
Styled.InlineRow = styled.div`
|
||||
${layoutMixins.inlineRow}
|
||||
`;
|
||||
|
||||
Styled.AddressRow = styled.div`
|
||||
${layoutMixins.row}
|
||||
|
||||
@@ -256,7 +291,7 @@ Styled.Balances = styled.div`
|
||||
gap: 2px;
|
||||
|
||||
> div {
|
||||
${layoutMixins.flexColumn}
|
||||
${layoutMixins.spacedRow}
|
||||
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import type { ColumnSize } from '@react-types/table';
|
||||
|
||||
import { type SubaccountTransfer } from '@/constants/abacus';
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS, StringGetterFunction } from '@/constants/localization';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { tradeViewMixins } from '@/styles/tradeViewMixins';
|
||||
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Icon } from '@/components/Icon';
|
||||
import { Link } from '@/components/Link';
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { Table, TableCell, TableColumnHeader, type ColumnDef } from '@/components/Table';
|
||||
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
||||
|
||||
import { getSubaccountTransfers } from '@/state/accountSelectors';
|
||||
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { truncateAddress } from '@/lib/wallet';
|
||||
|
||||
const MOBILE_TRANSFERS_PER_PAGE = 50;
|
||||
|
||||
export enum TransferHistoryTableColumnKey {
|
||||
Time = 'Time',
|
||||
Action = 'Action',
|
||||
SenderRecipient = 'Sender-Recipient',
|
||||
Amount = 'Amount',
|
||||
TxHash = 'TxHash',
|
||||
}
|
||||
|
||||
const getTransferHistoryTableColumnDef = ({
|
||||
key,
|
||||
stringGetter,
|
||||
width,
|
||||
}: {
|
||||
key: TransferHistoryTableColumnKey;
|
||||
isTablet?: boolean;
|
||||
stringGetter: StringGetterFunction;
|
||||
width?: ColumnSize;
|
||||
}): ColumnDef<SubaccountTransfer> => ({
|
||||
width,
|
||||
...(
|
||||
{
|
||||
[TransferHistoryTableColumnKey.Time]: {
|
||||
columnKey: TransferHistoryTableColumnKey.Time,
|
||||
getCellValue: (row) => row.updatedAtMilliseconds,
|
||||
label: stringGetter({ key: STRING_KEYS.TIME }),
|
||||
renderCell: ({ updatedAtMilliseconds }) => (
|
||||
<Styled.TimeOutput
|
||||
type={OutputType.RelativeTime}
|
||||
relativeTimeFormatOptions={{ format: 'singleCharacter' }}
|
||||
value={updatedAtMilliseconds}
|
||||
/>
|
||||
),
|
||||
},
|
||||
[TransferHistoryTableColumnKey.Action]: {
|
||||
columnKey: TransferHistoryTableColumnKey.Action,
|
||||
getCellValue: (row) => row.resources.typeStringKey,
|
||||
label: stringGetter({ key: STRING_KEYS.ACTION }),
|
||||
renderCell: ({ resources }) =>
|
||||
resources.typeStringKey && stringGetter({ key: resources.typeStringKey }),
|
||||
},
|
||||
[TransferHistoryTableColumnKey.SenderRecipient]: {
|
||||
columnKey: TransferHistoryTableColumnKey.SenderRecipient,
|
||||
getCellValue: (row) => `${row.fromAddress}-${row.toAddress}`,
|
||||
label: (
|
||||
<TableColumnHeader>
|
||||
<span>{stringGetter({ key: STRING_KEYS.SENDER })}</span>
|
||||
<span>{stringGetter({ key: STRING_KEYS.RECIPIENT })}</span>
|
||||
</TableColumnHeader>
|
||||
),
|
||||
renderCell: ({ fromAddress, toAddress }) => (
|
||||
<TableCell stacked>
|
||||
<CopyButton shownAsText value={fromAddress ?? undefined}>
|
||||
{fromAddress ? truncateAddress(fromAddress) : '-'}
|
||||
</CopyButton>{' '}
|
||||
<CopyButton shownAsText value={toAddress ?? undefined}>
|
||||
{toAddress ? truncateAddress(toAddress) : '-'}
|
||||
</CopyButton>
|
||||
</TableCell>
|
||||
),
|
||||
},
|
||||
[TransferHistoryTableColumnKey.Amount]: {
|
||||
columnKey: TransferHistoryTableColumnKey.Amount,
|
||||
getCellValue: (row) => row.amount,
|
||||
label: stringGetter({ key: STRING_KEYS.AMOUNT }),
|
||||
renderCell: ({ amount }) => <Output type={OutputType.Fiat} value={amount} />,
|
||||
},
|
||||
[TransferHistoryTableColumnKey.TxHash]: {
|
||||
columnKey: TransferHistoryTableColumnKey.TxHash,
|
||||
getCellValue: (row) => row.transactionHash,
|
||||
label: stringGetter({ key: STRING_KEYS.TRANSACTION }),
|
||||
renderCell: ({ transactionHash, resources }) =>
|
||||
transactionHash ? (
|
||||
<Styled.TxHash withIcon href={resources.blockExplorerUrl}>
|
||||
{truncateAddress(transactionHash, '')}
|
||||
</Styled.TxHash>
|
||||
) : (
|
||||
'-'
|
||||
),
|
||||
},
|
||||
} as Record<TransferHistoryTableColumnKey, ColumnDef<SubaccountTransfer>>
|
||||
)[key],
|
||||
});
|
||||
|
||||
type ElementProps = {
|
||||
columnKeys?: TransferHistoryTableColumnKey[];
|
||||
columnWidths?: Partial<Record<TransferHistoryTableColumnKey, ColumnSize>>;
|
||||
};
|
||||
|
||||
type StyleProps = {
|
||||
withOuterBorder?: boolean;
|
||||
withInnerBorders?: boolean;
|
||||
};
|
||||
|
||||
export const TransferHistoryTable = ({
|
||||
columnKeys = Object.values(TransferHistoryTableColumnKey),
|
||||
columnWidths,
|
||||
withOuterBorder,
|
||||
withInnerBorders = true,
|
||||
}: ElementProps & StyleProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const dispatch = useDispatch();
|
||||
const { isMobile, isTablet } = useBreakpoints();
|
||||
|
||||
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
||||
|
||||
const transfers = useSelector(getSubaccountTransfers, shallowEqual) ?? [];
|
||||
|
||||
return (
|
||||
<Styled.Table
|
||||
label="Transfers"
|
||||
data={isMobile ? transfers.slice(0, MOBILE_TRANSFERS_PER_PAGE) : transfers}
|
||||
getRowKey={(row: SubaccountTransfer) => row.id}
|
||||
columns={columnKeys.map((key: TransferHistoryTableColumnKey) =>
|
||||
getTransferHistoryTableColumnDef({
|
||||
key,
|
||||
isTablet,
|
||||
stringGetter,
|
||||
width: columnWidths?.[key],
|
||||
})
|
||||
)}
|
||||
slotEmpty={
|
||||
<>
|
||||
{stringGetter({ key: STRING_KEYS.TRANSFERS_EMPTY_STATE })}
|
||||
{canAccountTrade ? (
|
||||
<Button
|
||||
action={ButtonAction.Primary}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
|
||||
>
|
||||
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
|
||||
</Button>
|
||||
) : (
|
||||
<OnboardingTriggerButton />
|
||||
)}
|
||||
</>
|
||||
}
|
||||
selectionBehavior="replace"
|
||||
withOuterBorder={withOuterBorder}
|
||||
withInnerBorders={withInnerBorders}
|
||||
withScrollSnapColumns
|
||||
withScrollSnapRows
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Table = styled(Table)`
|
||||
${tradeViewMixins.horizontalTable}
|
||||
`;
|
||||
|
||||
Styled.InlineRow = styled.div`
|
||||
${layoutMixins.inlineRow}
|
||||
`;
|
||||
|
||||
Styled.Icon = styled(Icon)`
|
||||
font-size: 3em;
|
||||
`;
|
||||
|
||||
Styled.TimeOutput = styled(Output)`
|
||||
color: var(--color-text-0);
|
||||
`;
|
||||
|
||||
Styled.TxHash = styled(Link)`
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
Reference in New Issue
Block a user