Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbb6a42675 | ||
|
|
7cafc6e6cc | ||
|
|
cd56545042 | ||
|
|
b6e21f7265 | ||
|
|
b1979c4948 | ||
|
|
5e674b1bec | ||
|
|
a9ca215276 | ||
|
|
61a9eb2f5c | ||
|
|
bb47747501 | ||
|
|
5827b87f89 | ||
|
|
19b95832c4 | ||
|
|
48e4ab53a1 | ||
|
|
cefcff040f |
@@ -1,3 +1,4 @@
|
||||
import '../i18n';
|
||||
import {
|
||||
NetworkLoader,
|
||||
NodeFailure,
|
||||
@@ -28,20 +29,24 @@ function App() {
|
||||
);
|
||||
return (
|
||||
<TendermintWebsocketProvider>
|
||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||
<NodeGuard
|
||||
skeleton={<div>{t('Loading')}</div>}
|
||||
failure={<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
||||
>
|
||||
<Suspense fallback={splashLoading}>
|
||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||
</Suspense>
|
||||
</NodeGuard>
|
||||
<NodeSwitcherDialog
|
||||
open={nodeSwitcherOpen}
|
||||
setOpen={setNodeSwitcherOpen}
|
||||
/>
|
||||
</NetworkLoader>
|
||||
<Suspense fallback={splashLoading}>
|
||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||
<NodeGuard
|
||||
skeleton={<div>{t('Loading')}</div>}
|
||||
failure={
|
||||
<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />
|
||||
}
|
||||
>
|
||||
<Suspense fallback={splashLoading}>
|
||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||
</Suspense>
|
||||
</NodeGuard>
|
||||
<NodeSwitcherDialog
|
||||
open={nodeSwitcherOpen}
|
||||
setOpen={setNodeSwitcherOpen}
|
||||
/>
|
||||
</NetworkLoader>
|
||||
</Suspense>
|
||||
</TendermintWebsocketProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { AssetLink } from '../links';
|
||||
|
||||
export type AssetBalanceProps = {
|
||||
@@ -23,7 +23,7 @@ const AssetBalance = ({
|
||||
|
||||
const label =
|
||||
!loading && asset && asset.decimals
|
||||
? addDecimalsFixedFormatNumber(price, asset.decimals)
|
||||
? addDecimalsFormatNumber(price, asset.decimals)
|
||||
: price;
|
||||
|
||||
return (
|
||||
|
||||
@@ -120,6 +120,6 @@ describe('Order TX Summary component', () => {
|
||||
// After fetch renders formatted price and asset quotename
|
||||
expect(await res.findByText('3.33')).toBeInTheDocument();
|
||||
expect(await res.findByText('TEST')).toBeInTheDocument();
|
||||
expect(await res.getByText('0.10')).toBeInTheDocument();
|
||||
expect(await res.findByText('0.1')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('Price in Market component', () => {
|
||||
|
||||
it('Renders the formatted price when market data is fetched, using market decimals by default', async () => {
|
||||
const res = render(renderComponent('100', '123', [fullMock]));
|
||||
expect(await res.findByText('1.00')).toBeInTheDocument();
|
||||
expect(await res.findByText('1')).toBeInTheDocument();
|
||||
expect(await res.findByText('dai')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -69,6 +69,6 @@ describe('Size in Market component', () => {
|
||||
|
||||
it('Renders the formatted size when market data is fetched', async () => {
|
||||
const res = render(renderComponent('100', '123', [fullMock]));
|
||||
expect(await res.findByText('1.00')).toBeInTheDocument();
|
||||
expect(await res.findByText('1')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import { locales } from '@vegaprotocol/i18n';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
Object.defineProperty(window, 'ResizeObserver', {
|
||||
writable: false,
|
||||
@@ -13,3 +16,14 @@ Object.defineProperty(window, 'ResizeObserver', {
|
||||
disconnect: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
// Set up i18n instance so that components have the correct default
|
||||
// en translations
|
||||
i18n.use(initReactI18next).init({
|
||||
// we init with resources
|
||||
resources: locales,
|
||||
fallbackLng: 'en',
|
||||
nsSeparator: false,
|
||||
ns: ['explorer'],
|
||||
defaultNS: 'explorer',
|
||||
});
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../../libs/i18n/src/locales
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { Module } from 'i18next';
|
||||
import i18n from 'i18next';
|
||||
import HttpBackend from 'i18next-http-backend';
|
||||
import LocizeBackend from 'i18next-locize-backend';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
const isInDev = process.env.NODE_ENV === 'development';
|
||||
const useLocize = isInDev && !!process.env.NX_USE_LOCIZE;
|
||||
|
||||
const backend = useLocize
|
||||
? {
|
||||
projectId: '96ac1231-4bdd-455a-b9d7-f5322a2e7430',
|
||||
apiKey: process.env.NX_LOCIZE_API_KEY,
|
||||
referenceLng: 'en',
|
||||
}
|
||||
: {
|
||||
loadPath: '/assets/locales/{{lng}}/{{ns}}.json',
|
||||
};
|
||||
|
||||
const Backend: Module = useLocize ? LocizeBackend : HttpBackend;
|
||||
|
||||
i18n
|
||||
.use(Backend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
supportedLngs: ['en'],
|
||||
load: 'languageOnly',
|
||||
debug: isInDev,
|
||||
// have a common namespace used around the full app
|
||||
ns: ['explorer'],
|
||||
defaultNS: 'explorer',
|
||||
keySeparator: false, // we use content as keys
|
||||
nsSeparator: false,
|
||||
backend,
|
||||
saveMissing: useLocize && !!process.env.NX_LOCIZE_API_KEY,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
@@ -3,14 +3,14 @@ import { formatNumber } from './format-number';
|
||||
|
||||
describe('formatNumber and formatNumberPercentage', () => {
|
||||
it.each([
|
||||
{ v: new BigNumber(123), d: 3, o: '123.00' },
|
||||
{ v: new BigNumber(123), d: 3, o: '123.000' },
|
||||
{ v: new BigNumber(123.123), d: 3, o: '123.123' },
|
||||
{ v: new BigNumber(123.123), d: 6, o: '123.123' },
|
||||
{ v: new BigNumber(123.123), d: 6, o: '123.123000' },
|
||||
{ v: new BigNumber(123.123), d: 0, o: '123' },
|
||||
{ v: new BigNumber(123), d: undefined, o: '123.00' }, // it default to 2 decimal places
|
||||
{ v: new BigNumber(30000), d: undefined, o: '30,000.00' },
|
||||
{ v: new BigNumber(3.000001), d: undefined, o: '3.000001' },
|
||||
])(`formats given number with decimals correctly`, ({ v, d, o }) => {
|
||||
])(`formatNumber($v, $d) -> $o`, ({ v, d, o }) => {
|
||||
expect(formatNumber(v, d)).toStrictEqual(o);
|
||||
});
|
||||
});
|
||||
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
getProposalDialogIcon,
|
||||
getProposalDialogIntent,
|
||||
getProposalDialogTitle,
|
||||
useGetProposalDialogTitle,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import type { ProposalEventFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import type { DialogProps } from '@vegaprotocol/proposals';
|
||||
@@ -15,6 +15,7 @@ export const ProposalFormTransactionDialog = ({
|
||||
finalizedProposal,
|
||||
TransactionDialog,
|
||||
}: ProposalFormTransactionDialogProps) => {
|
||||
const title = useGetProposalDialogTitle(finalizedProposal?.state);
|
||||
// Render a custom complete UI if the proposal was rejected otherwise
|
||||
// pass undefined so that the default vega transaction dialog UI gets used
|
||||
const completeContent = finalizedProposal?.rejectionReason ? (
|
||||
@@ -24,7 +25,7 @@ export const ProposalFormTransactionDialog = ({
|
||||
return (
|
||||
<div data-testid="proposal-transaction-dialog">
|
||||
<TransactionDialog
|
||||
title={getProposalDialogTitle(finalizedProposal?.state)}
|
||||
title={title}
|
||||
intent={getProposalDialogIntent(finalizedProposal?.state)}
|
||||
icon={getProposalDialogIcon(finalizedProposal?.state)}
|
||||
content={{
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
doesValueEquateToParam,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||
import { validateJson } from '@vegaprotocol/utils';
|
||||
import { useValidateJson } from '@vegaprotocol/utils';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -41,6 +41,7 @@ export interface NewAssetProposalFormFields {
|
||||
const DOCS_LINK = '/new-asset-proposal';
|
||||
|
||||
export const ProposeNewAsset = () => {
|
||||
const validateJson = useValidateJson();
|
||||
const {
|
||||
params,
|
||||
loading: networkParamsLoading,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
doesValueEquateToParam,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||
import { validateJson } from '@vegaprotocol/utils';
|
||||
import { useValidateJson } from '@vegaprotocol/utils';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -39,6 +39,7 @@ export interface NewMarketProposalFormFields {
|
||||
const DOCS_LINK = '/new-market-proposal';
|
||||
|
||||
export const ProposeNewMarket = () => {
|
||||
const validateJson = useValidateJson();
|
||||
const {
|
||||
params,
|
||||
loading: networkParamsLoading,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
RoundedWrapper,
|
||||
TextArea,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { validateJson } from '@vegaprotocol/utils';
|
||||
import { useValidateJson } from '@vegaprotocol/utils';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -31,6 +31,7 @@ export interface RawProposalFormFields {
|
||||
}
|
||||
|
||||
export const ProposeRaw = () => {
|
||||
const validateJson = useValidateJson();
|
||||
const {
|
||||
params,
|
||||
loading: networkParamsLoading,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
doesValueEquateToParam,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||
import { validateJson } from '@vegaprotocol/utils';
|
||||
import { useValidateJson } from '@vegaprotocol/utils';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -39,6 +39,7 @@ export interface UpdateAssetProposalFormFields {
|
||||
const DOCS_LINK = '/update-asset-proposal';
|
||||
|
||||
export const ProposeUpdateAsset = () => {
|
||||
const validateJson = useValidateJson();
|
||||
const {
|
||||
params,
|
||||
loading: networkParamsLoading,
|
||||
|
||||
+3
-2
@@ -8,7 +8,7 @@ import {
|
||||
useProposalSubmit,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||
import { validateJson } from '@vegaprotocol/utils';
|
||||
import { useValidateJson } from '@vegaprotocol/utils';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
@@ -53,6 +53,7 @@ export interface UpdateMarketProposalFormFields {
|
||||
const DOCS_LINK = '/update-market-proposal';
|
||||
|
||||
export const ProposeUpdateMarket = () => {
|
||||
const validateJson = useValidateJson();
|
||||
const {
|
||||
params,
|
||||
loading: networkParamsLoading,
|
||||
@@ -260,7 +261,7 @@ export const ProposeUpdateMarket = () => {
|
||||
</FormGroup>
|
||||
|
||||
{selectedMarket && (
|
||||
<div className="mt-[-20px] mb-6">
|
||||
<div className="mb-6 mt-[-20px]">
|
||||
<KeyValueTable data-testid="update-market-details">
|
||||
<KeyValueTableRow>
|
||||
{t('MarketName')}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getNumberFormat } from '@vegaprotocol/utils';
|
||||
import { addDays } from 'date-fns';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import omit from 'lodash/omit';
|
||||
import { useReferralProgramQuery } from './__generated__/CurrentReferralProgram';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
|
||||
const STAKING_TIERS_MAPPING: Record<number, string> = {
|
||||
1: 'Tradestarter',
|
||||
@@ -85,9 +85,7 @@ export const useReferralProgram = () => {
|
||||
discountFactor: Number(t.referralDiscountFactor),
|
||||
discount: Number(t.referralDiscountFactor) * 100 + '%',
|
||||
minimumVolume: Number(t.minimumRunningNotionalTakerVolume),
|
||||
volume: getNumberFormat(0).format(
|
||||
Number(t.minimumRunningNotionalTakerVolume)
|
||||
),
|
||||
volume: addDecimalsFormatNumber(t.minimumRunningNotionalTakerVolume, 0),
|
||||
epochs: Number(t.minimumEpochs),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
getDateFormat,
|
||||
getDateTimeFormat,
|
||||
getNumberFormat,
|
||||
getUserLocale,
|
||||
removePaginationWrapper,
|
||||
} from '@vegaprotocol/utils';
|
||||
@@ -256,7 +255,7 @@ export const Statistics = ({
|
||||
})}
|
||||
description={<QUSDTooltip />}
|
||||
>
|
||||
{getNumberFormat(0).format(Number(totalCommissionValue))}
|
||||
{addDecimalsFormatNumber(totalCommissionValue.toString(), 0)}
|
||||
</StatTile>
|
||||
);
|
||||
|
||||
@@ -418,8 +417,8 @@ export const Statistics = ({
|
||||
)
|
||||
.map((r) => ({
|
||||
...r,
|
||||
volume: getNumberFormat(0).format(r.volume),
|
||||
commission: getNumberFormat(0).format(r.commission),
|
||||
volume: addDecimalsFormatNumber(r.volume, 0),
|
||||
commission: addDecimalsFormatNumber(r.commission, 0),
|
||||
}))
|
||||
.reverse()}
|
||||
/>
|
||||
|
||||
@@ -139,7 +139,7 @@ describe('RewardPot', () => {
|
||||
renderComponent(props);
|
||||
|
||||
expect(screen.getByTestId('total-rewards')).toHaveTextContent(
|
||||
`7.00 ${rewardAsset.symbol}`
|
||||
`7.0000 ${rewardAsset.symbol}`
|
||||
);
|
||||
|
||||
expect(screen.getByText(/Locked/).nextElementSibling).toHaveTextContent(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { AccountFields } from './accounts-data-provider';
|
||||
import { getAccountData } from './accounts-data-provider';
|
||||
@@ -123,11 +123,13 @@ describe('AccountsTable', () => {
|
||||
/>
|
||||
);
|
||||
|
||||
const cells = await screen.findAllByRole('gridcell');
|
||||
const expectedValues = ['tBTC', '1,256.00', '1,256.00', '2,512.00', ''];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
await assertCells({
|
||||
usedAmount: '1,256',
|
||||
usedPct: '0.00%',
|
||||
available: '1,256',
|
||||
total: '2,512',
|
||||
});
|
||||
|
||||
const rows = container.querySelector('.ag-center-cols-container');
|
||||
expect(rows?.childElementCount).toBe(1);
|
||||
});
|
||||
@@ -160,12 +162,13 @@ describe('AccountsTable', () => {
|
||||
/>
|
||||
);
|
||||
|
||||
const cells = await screen.findAllByRole('gridcell');
|
||||
const expectedValues = ['tBTC', '1,256.00', '1,256.00', '2,512.00', ''];
|
||||
expect(cells.length).toBe(expectedValues.length);
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
await assertCells({
|
||||
usedAmount: '1,256',
|
||||
usedPct: '0.00%',
|
||||
available: '1,256',
|
||||
total: '2,512',
|
||||
});
|
||||
|
||||
const rows = container.querySelector('.ag-center-cols-container');
|
||||
expect(rows?.childElementCount).toBe(1);
|
||||
});
|
||||
@@ -248,4 +251,36 @@ describe('AccountsTable', () => {
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
const assertCells = async ({
|
||||
usedAmount,
|
||||
usedPct,
|
||||
available,
|
||||
total,
|
||||
}: {
|
||||
usedAmount: string;
|
||||
usedPct: string;
|
||||
available: string;
|
||||
total: string;
|
||||
}) => {
|
||||
const cells = await screen.findAllByRole('gridcell');
|
||||
|
||||
const usedCell = within(
|
||||
cells.find(
|
||||
(cell) => cell.getAttribute('col-id') === 'used'
|
||||
) as HTMLElement
|
||||
);
|
||||
expect(usedCell.getByTestId('used-amount')).toHaveTextContent(usedAmount);
|
||||
expect(usedCell.getByTestId('used-pct')).toHaveTextContent(usedPct);
|
||||
|
||||
const availableCell = cells.find(
|
||||
(cell) => cell.getAttribute('col-id') === 'available'
|
||||
);
|
||||
expect(availableCell).toHaveTextContent(available);
|
||||
|
||||
const totalCell = cells.find(
|
||||
(cell) => cell.getAttribute('col-id') === 'total'
|
||||
);
|
||||
expect(totalCell).toHaveTextContent(total);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -178,20 +178,28 @@ export const AccountTable = ({
|
||||
|
||||
return data.breakdown ? (
|
||||
<>
|
||||
<span className="underline">{valueFormatted}</span>
|
||||
<span className="underline" data-testid="used-amount">
|
||||
{valueFormatted}
|
||||
</span>
|
||||
<span
|
||||
className={classNames(
|
||||
colorClass(percentageUsed),
|
||||
'ml-1 inline-block w-14'
|
||||
)}
|
||||
data-testid="used-pct"
|
||||
>
|
||||
{percentageUsed.toFixed(2)}%
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="underline">{valueFormatted}</span>
|
||||
<span className="inline-block ml-2 w-14 text-muted">
|
||||
<span className="underline" data-testid="used-amount">
|
||||
{valueFormatted}
|
||||
</span>
|
||||
<span
|
||||
className="inline-block ml-2 w-14 text-muted"
|
||||
data-testid="used-pct"
|
||||
>
|
||||
{(0).toFixed(2)}%
|
||||
</span>
|
||||
</>
|
||||
|
||||
@@ -63,9 +63,9 @@ describe('BreakdownTable', () => {
|
||||
const expectedValues = [
|
||||
'BTCUSD.MF21',
|
||||
'Margin',
|
||||
'1,256.00 (50%)',
|
||||
'1,256.00',
|
||||
'1,256.00',
|
||||
'1,256 (50%)',
|
||||
'1,256',
|
||||
'1,256',
|
||||
];
|
||||
cells.slice(0, -1).forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('MarginHealthChart', () => {
|
||||
it('should render correct values', async () => {
|
||||
render(<MarginHealthChart marketId="marketId" assetId="assetId" />);
|
||||
const chart = screen.getByTestId('margin-health-chart');
|
||||
expect(chart).toHaveTextContent('3.00 above maintenance level');
|
||||
expect(chart).toHaveTextContent('3 above maintenance level');
|
||||
const red = screen.getByTestId('margin-health-chart-red');
|
||||
const orange = screen.getByTestId('margin-health-chart-orange');
|
||||
const yellow = screen.getByTestId('margin-health-chart-yellow');
|
||||
@@ -121,7 +121,7 @@ describe('MarginHealthChartTooltip', () => {
|
||||
expect(value).toHaveTextContent(expectedLabels[i]);
|
||||
});
|
||||
const values = await screen.findAllByTestId('margin-health-tooltip-value');
|
||||
const expectedValues = ['4.00', '5.00', '6.00', '8.00', '10.00'];
|
||||
const expectedValues = ['4', '5', '6', '8', '10'];
|
||||
values.forEach((value, i) => {
|
||||
expect(value).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
@@ -137,7 +137,7 @@ describe('MarginHealthChartTooltip', () => {
|
||||
);
|
||||
|
||||
let values = await screen.findAllByTestId('margin-health-tooltip-value');
|
||||
expect(values[2]).toHaveTextContent('7.00');
|
||||
expect(values[2]).toHaveTextContent('7');
|
||||
|
||||
rerender(
|
||||
<MarginHealthChartTooltip
|
||||
@@ -149,6 +149,6 @@ describe('MarginHealthChartTooltip', () => {
|
||||
|
||||
values = await screen.findAllByTestId('margin-health-tooltip-value');
|
||||
expect(values.length).toBe(5);
|
||||
expect(values[3]).toHaveTextContent('9.00');
|
||||
expect(values[3]).toHaveTextContent('9');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import {
|
||||
maxSafe,
|
||||
required,
|
||||
vegaPublicKey,
|
||||
useMaxSafe,
|
||||
useRequired,
|
||||
useVegaPublicKey,
|
||||
addDecimal,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
@@ -67,6 +67,9 @@ export const TransferForm = ({
|
||||
minQuantumMultiple,
|
||||
}: TransferFormProps) => {
|
||||
const t = useT();
|
||||
const maxSafe = useMaxSafe();
|
||||
const required = useRequired();
|
||||
const vegaPublicKey = useVegaPublicKey();
|
||||
const {
|
||||
control,
|
||||
register,
|
||||
@@ -415,7 +418,7 @@ export const TransferForm = ({
|
||||
{accountBalance && (
|
||||
<button
|
||||
type="button"
|
||||
className="absolute top-0 right-0 ml-auto text-xs underline"
|
||||
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||
onClick={() =>
|
||||
setValue('amount', parseFloat(accountBalance).toString(), {
|
||||
shouldValidate: true,
|
||||
@@ -491,7 +494,7 @@ export const TransferFee = ({
|
||||
const totalValue = new BigNumber(transferAmount).plus(fee).toString();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col mb-4 text-xs gap-2">
|
||||
<div className="mb-4 flex flex-col gap-2 text-xs">
|
||||
<div className="flex flex-wrap items-center justify-between gap-1">
|
||||
<Tooltip
|
||||
description={t(
|
||||
@@ -560,7 +563,7 @@ export const AddressField = ({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onChange}
|
||||
className="absolute top-0 right-0 ml-auto text-xs underline"
|
||||
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||
>
|
||||
{isInput ? t('Select from wallet') : t('Enter manually')}
|
||||
</button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { memo } from 'react';
|
||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { NumericCell } from './numeric-cell';
|
||||
import { theme } from '@vegaprotocol/tailwindcss-config';
|
||||
|
||||
@@ -57,7 +57,7 @@ export const CumulativeVol = memo(
|
||||
(
|
||||
<NumericCell
|
||||
value={Number(indicativeVolume)}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
indicativeVolume,
|
||||
positionDecimalPlaces ?? 0
|
||||
)}
|
||||
@@ -69,7 +69,7 @@ export const CumulativeVol = memo(
|
||||
{ask ? (
|
||||
<NumericCell
|
||||
value={ask}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
ask,
|
||||
positionDecimalPlaces ?? 0
|
||||
)}
|
||||
@@ -79,7 +79,7 @@ export const CumulativeVol = memo(
|
||||
{bid ? (
|
||||
<NumericCell
|
||||
value={ask}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
bid,
|
||||
positionDecimalPlaces ?? 0
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { getDecimalSeparator, isNumeric } from '@vegaprotocol/utils';
|
||||
import { getNumberParts, isNumeric } from '@vegaprotocol/utils';
|
||||
|
||||
interface NumericCellProps {
|
||||
value: number | bigint | null | undefined;
|
||||
@@ -23,7 +23,7 @@ export const NumericCell = forwardRef<HTMLSpanElement, NumericCellProps>(
|
||||
);
|
||||
}
|
||||
|
||||
const decimalSeparator = getDecimalSeparator();
|
||||
const decimalSeparator = getNumberParts().decimalSeparator;
|
||||
const valueSplit: string[] = decimalSeparator
|
||||
? valueFormatted.split(decimalSeparator).map((v) => `${v}`)
|
||||
: [`${value}`];
|
||||
|
||||
@@ -10,12 +10,12 @@ describe('PriceChangeCell', () => {
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('-48.51%')).toBeInTheDocument();
|
||||
expect(screen.getByText('-22.10')).toBeInTheDocument();
|
||||
expect(screen.getByText('-22.100')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders correctly and calculates the price change without decimals', () => {
|
||||
render(<PriceChangeCell candles={['45556', '678678', '23456']} />);
|
||||
expect(screen.getByText('-48.51%')).toBeInTheDocument();
|
||||
expect(screen.getByText('-22,100.00')).toBeInTheDocument();
|
||||
expect(screen.getByText('-22,100.000')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller, type Control } from 'react-hook-form';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import type { OrderFormValues } from '../../hooks/use-form-values';
|
||||
import { toDecimal, validateAmount } from '@vegaprotocol/utils';
|
||||
import { toDecimal, useValidateAmount } from '@vegaprotocol/utils';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
@@ -28,6 +28,7 @@ export const DealTicketSizeIceberg = ({
|
||||
peakSize,
|
||||
}: DealTicketSizeIcebergProps) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||
|
||||
const renderPeakSizeError = () => {
|
||||
|
||||
@@ -136,7 +136,7 @@ describe('StopOrder', () => {
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '10');
|
||||
await userEvent.type(screen.getByTestId(priceInput), '10');
|
||||
expect(screen.getByTestId('deal-ticket-fee-notional')).toHaveTextContent(
|
||||
'Notional100.00 BTC'
|
||||
'Notional100 BTC'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -147,13 +147,13 @@ describe('StopOrder', () => {
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '10');
|
||||
// price trigger is selected but it's empty, calculate base on size and marketPrice prop
|
||||
expect(screen.getByTestId('deal-ticket-fee-notional')).toHaveTextContent(
|
||||
'Notional20.00 BTC'
|
||||
'Notional20 BTC'
|
||||
);
|
||||
|
||||
await userEvent.type(screen.getByTestId(triggerPriceInput), '3');
|
||||
// calculate base on size and price trigger
|
||||
expect(screen.getByTestId('deal-ticket-fee-notional')).toHaveTextContent(
|
||||
'Notional30.00 BTC'
|
||||
'Notional30 BTC'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
formatValue,
|
||||
removeDecimal,
|
||||
toDecimal,
|
||||
validateAmount,
|
||||
useValidateAmount,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { type Control, type UseFormWatch } from 'react-hook-form';
|
||||
import { useForm, Controller, useController } from 'react-hook-form';
|
||||
@@ -36,7 +36,6 @@ import {
|
||||
} from '@vegaprotocol/markets';
|
||||
import { ExpirySelector } from './expiry-selector';
|
||||
import { SideSelector } from './side-selector';
|
||||
import { timeInForceLabel } from '@vegaprotocol/orders';
|
||||
import {
|
||||
NoWalletWarning,
|
||||
REDUCE_ONLY_TOOLTIP,
|
||||
@@ -110,6 +109,7 @@ const Trigger = ({
|
||||
decimalPlaces: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
const triggerType = watch(oco ? 'ocoTriggerType' : 'triggerType');
|
||||
const triggerDirection = watch('triggerDirection');
|
||||
const isPriceTrigger = triggerType === 'price';
|
||||
@@ -342,6 +342,7 @@ const Size = ({
|
||||
assetUnit?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
return (
|
||||
<Controller
|
||||
name={oco ? 'ocoSize' : 'size'}
|
||||
@@ -402,6 +403,7 @@ const Price = ({
|
||||
oco?: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
if (watch(oco ? 'ocoType' : 'type') === Schema.OrderType.TYPE_MARKET) {
|
||||
return null;
|
||||
}
|
||||
@@ -479,13 +481,13 @@ const TimeInForce = ({
|
||||
key={Schema.OrderTimeInForce.TIME_IN_FORCE_IOC}
|
||||
value={Schema.OrderTimeInForce.TIME_IN_FORCE_IOC}
|
||||
>
|
||||
{timeInForceLabel(Schema.OrderTimeInForce.TIME_IN_FORCE_IOC)}
|
||||
{t(Schema.OrderTimeInForce.TIME_IN_FORCE_IOC)}
|
||||
</option>
|
||||
<option
|
||||
key={Schema.OrderTimeInForce.TIME_IN_FORCE_FOK}
|
||||
value={Schema.OrderTimeInForce.TIME_IN_FORCE_FOK}
|
||||
>
|
||||
{timeInForceLabel(Schema.OrderTimeInForce.TIME_IN_FORCE_FOK)}
|
||||
{t(Schema.OrderTimeInForce.TIME_IN_FORCE_FOK)}
|
||||
</option>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
@@ -1181,7 +1183,9 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
testId={'stop-order-warning-limit'}
|
||||
message={t(
|
||||
'There is a limit of {{maxNumberOfOrders}} active stop orders per market. Orders submitted above the limit will be immediately rejected.',
|
||||
{ maxNumberOfOrders: MAX_NUMBER_OF_ACTIVE_STOP_ORDERS.toString() }
|
||||
{
|
||||
maxNumberOfOrders: MAX_NUMBER_OF_ACTIVE_STOP_ORDERS.toString(),
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -495,12 +495,15 @@ describe('DealTicket', () => {
|
||||
Array.from(screen.getByTestId('order-tif').children).map(
|
||||
(o) => o.textContent
|
||||
)
|
||||
).toEqual(['Fill or Kill (FOK)', 'Immediate or Cancel (IOC)']);
|
||||
).toEqual([
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
]);
|
||||
|
||||
// IOC should be default
|
||||
// 7002-SORD-030
|
||||
expect(screen.getByTestId('order-tif')).toHaveDisplayValue(
|
||||
'Immediate or Cancel (IOC)'
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC
|
||||
);
|
||||
|
||||
// Select FOK - FOK should be selected
|
||||
@@ -509,7 +512,7 @@ describe('DealTicket', () => {
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK
|
||||
);
|
||||
expect(screen.getByTestId('order-tif')).toHaveDisplayValue(
|
||||
'Fill or Kill (FOK)'
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK
|
||||
);
|
||||
|
||||
// Switch to type limit order -> all TIF options should be shown
|
||||
|
||||
@@ -28,7 +28,7 @@ import { useOpenVolume } from '@vegaprotocol/positions';
|
||||
import {
|
||||
toBigNum,
|
||||
removeDecimal,
|
||||
validateAmount,
|
||||
useValidateAmount,
|
||||
toDecimal,
|
||||
formatForInput,
|
||||
formatValue,
|
||||
@@ -140,6 +140,7 @@ export const DealTicket = ({
|
||||
onDeposit,
|
||||
}: DealTicketProps) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const setType = useDealTicketFormValues((state) => state.setType);
|
||||
const storedFormValues = useDealTicketFormValues(
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
SimpleGrid,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { timeInForceLabel } from '@vegaprotocol/orders';
|
||||
import { compileGridData } from '../trading-mode-tooltip';
|
||||
import { MarketModeValidationType } from '../../constants';
|
||||
import type { Market, StaticMarketData } from '@vegaprotocol/markets';
|
||||
@@ -119,9 +118,7 @@ export const TimeInForceSelector = ({
|
||||
hasError={!!errorMessage}
|
||||
>
|
||||
{options.map(([key, value]) => (
|
||||
<option key={key} value={value}>
|
||||
{timeInForceLabel(value)}
|
||||
</option>
|
||||
<TimeInForceOption key={key} value={value} />
|
||||
))}
|
||||
</TradingSelect>
|
||||
{errorMessage && (
|
||||
@@ -133,3 +130,8 @@ export const TimeInForceSelector = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TimeInForceOption = ({ value }: { value: Schema.OrderTimeInForce }) => {
|
||||
const t = useT();
|
||||
return <option value={value}>{t(value)}</option>;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Asset, AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { AssetOption } from '@vegaprotocol/assets';
|
||||
import {
|
||||
ethereumAddress,
|
||||
required,
|
||||
vegaPublicKey,
|
||||
minSafe,
|
||||
maxSafe,
|
||||
useEthereumAddress,
|
||||
useRequired,
|
||||
useVegaPublicKey,
|
||||
useMinSafe,
|
||||
useMaxSafe,
|
||||
addDecimal,
|
||||
isAssetTypeERC20,
|
||||
formatNumber,
|
||||
@@ -85,6 +85,11 @@ export const DepositForm = ({
|
||||
isFaucetable,
|
||||
}: DepositFormProps) => {
|
||||
const t = useT();
|
||||
const ethereumAddress = useEthereumAddress();
|
||||
const required = useRequired();
|
||||
const vegaPublicKey = useVegaPublicKey();
|
||||
const minSafe = useMinSafe();
|
||||
const maxSafe = useMaxSafe();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const openDialog = useWeb3ConnectStore((store) => store.open);
|
||||
const { isActive, account } = useWeb3React();
|
||||
@@ -459,7 +464,7 @@ const UseButton = (props: UseButtonProps) => {
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
className="absolute top-0 right-0 ml-auto text-sm underline"
|
||||
className="absolute right-0 top-0 ml-auto text-sm underline"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -519,7 +524,7 @@ export const AddressField = ({
|
||||
setIsInput((curr) => !curr);
|
||||
onChange();
|
||||
}}
|
||||
className="absolute top-0 right-0 ml-auto text-sm underline"
|
||||
className="absolute right-0 top-0 ml-auto text-sm underline"
|
||||
data-testid="enter-pubkey-manually"
|
||||
>
|
||||
{isInput ? t('Select from wallet') : t('Enter manually')}
|
||||
|
||||
@@ -84,11 +84,11 @@ describe('FillsTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market?.tradableInstrument.instrument.code || '',
|
||||
'+3.00',
|
||||
'1.00 BTC',
|
||||
'+3',
|
||||
'1 BTC',
|
||||
'3.00 BTC',
|
||||
'Maker',
|
||||
'2.00 BTC',
|
||||
'2 BTC',
|
||||
'0.27 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
'', // action column
|
||||
@@ -121,8 +121,8 @@ describe('FillsTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market?.tradableInstrument.instrument.code || '',
|
||||
'-3.00',
|
||||
'1.00 BTC',
|
||||
'-3',
|
||||
'1 BTC',
|
||||
'3.00 BTC',
|
||||
'Taker',
|
||||
'0.03 BTC',
|
||||
@@ -158,8 +158,8 @@ describe('FillsTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market?.tradableInstrument.instrument.code || '',
|
||||
'-3.00',
|
||||
'1.00 BTC',
|
||||
'-3',
|
||||
'1 BTC',
|
||||
'3.00 BTC',
|
||||
'-',
|
||||
'0.03 BTC',
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('FundingPaymentsTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
fundingPayment.market?.tradableInstrument.instrument.code || '',
|
||||
'1.00 BTC',
|
||||
'1 BTC',
|
||||
getDateTimeFormat().format(new Date(fundingPayment.timestamp)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
@@ -77,7 +77,7 @@ describe('FundingPaymentsTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
fundingPayment.market?.tradableInstrument.instrument.code || '',
|
||||
'-1.00 BTC',
|
||||
'-1 BTC',
|
||||
getDateTimeFormat().format(new Date(fundingPayment.timestamp)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './lib/i18n';
|
||||
|
||||
import en_accounts from './locales/en/accounts.json';
|
||||
import en_assets from './locales/en/assets.json';
|
||||
import en_candles_chart from './locales/en/candles-chart.json';
|
||||
@@ -12,6 +13,10 @@ import en_governance from './locales/en/governance.json';
|
||||
import en_trading from './locales/en/trading.json';
|
||||
import en_markets from './locales/en/markets.json';
|
||||
import en_web3 from './locales/en/web3.json';
|
||||
import en_proposals from './locales/en/proposals.json';
|
||||
import en_positions from './locales/en/positions.json';
|
||||
import en_trades from './locales/en/trading.json';
|
||||
import en_ui_toolkit from './locales/en/ui-toolkit.json';
|
||||
|
||||
export const locales = {
|
||||
en: {
|
||||
@@ -28,5 +33,9 @@ export const locales = {
|
||||
trading: en_trading,
|
||||
markets: en_markets,
|
||||
web3: en_web3,
|
||||
positions: en_positions,
|
||||
proposals: en_proposals,
|
||||
trades: en_trades,
|
||||
'ui-toolkit': en_ui_toolkit,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -128,5 +128,11 @@
|
||||
"You need to connect your own wallet to start trading on this market": "You need to connect your own wallet to start trading on this market",
|
||||
"You need to provide a minimum visible size": "You need to provide a minimum visible size",
|
||||
"You need to provide a peak size": "You need to provide a peak size",
|
||||
"You need to provide a size": "You need to provide a size"
|
||||
"You need to provide a size": "You need to provide a size",
|
||||
"TIME_IN_FORCE_FOK": "Fill or Kill (FOK)",
|
||||
"TIME_IN_FORCE_GFA": "Good for Auction (GFA)",
|
||||
"TIME_IN_FORCE_GFN": "Good for Normal (GFN)",
|
||||
"TIME_IN_FORCE_GTC": "Good 'til Cancelled (GTC)",
|
||||
"TIME_IN_FORCE_GTT": "Good 'til Time (GTT)",
|
||||
"TIME_IN_FORCE_IOC": "Immediate or Cancel (IOC)"
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"Last traded price": "Last traded price",
|
||||
"No open orders": "No open orders",
|
||||
"Spread": "Spread"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"{{tifLabel}}. Post Only": "{{tifLabel}}. Post Only",
|
||||
"{{tifLabel}}. Reduce only": "{{tifLabel}}. Reduce only",
|
||||
"Cancel": "Cancel",
|
||||
"Cancel all": "Cancel all",
|
||||
"Cancel order": "Cancel order",
|
||||
"Cancels": "Cancels",
|
||||
"Copy": "Copy",
|
||||
"Copy order ID": "Copy order ID",
|
||||
"Created": "Created",
|
||||
"Edit order": "Edit order",
|
||||
"Expires": "Expires",
|
||||
"Expires at": "Expires at",
|
||||
"Filled": "Filled",
|
||||
"Iceberg order": "Iceberg order",
|
||||
"Liquidity provision": "Liquidity provision",
|
||||
"Market": "Market",
|
||||
"MAX": "MAX",
|
||||
"Minimum size": "Minimum size",
|
||||
"No orders": "No orders",
|
||||
"No stop orders": "No stop orders",
|
||||
"One Cancels the Other": "One Cancels the Other",
|
||||
"Order details": "Order details",
|
||||
"Order ID": "Order ID",
|
||||
"Peak size": "Peak size",
|
||||
"Pegged": "Pegged",
|
||||
"Post only": "Post only",
|
||||
"Price": "Price",
|
||||
"Reduce only": "Reduce only",
|
||||
"Remaining": "Remaining",
|
||||
"Reserved remaining": "Reserved remaining",
|
||||
"Side": "Side",
|
||||
"Size": "Size",
|
||||
"Something went wrong: {{errorMessage}}": "Something went wrong: {{errorMessage}}",
|
||||
"Status": "Status",
|
||||
"Submit": "Submit",
|
||||
"The maximum volume that can be traded at once. Must be less than the total size of the order.": "The maximum volume that can be traded at once. Must be less than the total size of the order.",
|
||||
"The price cannot be negative": "The price cannot be negative",
|
||||
"The size cannot be negative": "The size cannot be negative",
|
||||
"Trigger": "Trigger",
|
||||
"Type": "Type",
|
||||
"Update": "Update",
|
||||
"Updated": "Updated",
|
||||
"View order details": "View order details",
|
||||
"When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.": "When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.",
|
||||
"Yes": "Yes",
|
||||
"You need to provide a price": "You need to provide a price",
|
||||
"You need to provide a size": "You need to provide a size"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Best case": "Best case",
|
||||
"Close position": "Close position",
|
||||
"Entry / Mark": "Entry / Mark",
|
||||
"Lifetime loss socialisation deductions: {{losses}}": "Lifetime loss socialisation deductions: {{losses}}",
|
||||
"Maintained by network": "Maintained by network",
|
||||
"Margin / Leverage": "Margin / Leverage",
|
||||
"Market": "Market",
|
||||
"No positions": "No positions",
|
||||
"Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.": "Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.",
|
||||
"Read more about loss socialisation": "Read more about loss socialisation",
|
||||
"Read more about position resolution": "Read more about position resolution",
|
||||
"Realised PNL": "Realised PNL",
|
||||
"Realised PNL: {{value}}": "Realised PNL: {{value}}",
|
||||
"Size / Notional": "Size / Notional",
|
||||
"Status: {{status}}": "Status: {{status}}",
|
||||
"The position was distressed, but could not be closed out - orders were removed from the book, and the open volume will be closed out once there is sufficient volume on the book.": "The position was distressed, but could not be closed out - orders were removed from the book, and the open volume will be closed out once there is sufficient volume on the book.",
|
||||
"The position was distressed, but removing open orders from the book brought the margin level back to a point where the open position could be maintained.": "The position was distressed, but removing open orders from the book brought the margin level back to a point where the open position could be maintained.",
|
||||
"Unrealised PNL": "Unrealised PNL",
|
||||
"Unrealised profit is the current profit on your open position. Margin is still allocated to your position.": "Unrealised profit is the current profit on your open position. Margin is still allocated to your position.",
|
||||
"Vega key": "Vega key",
|
||||
"View settlement asset details": "View settlement asset details",
|
||||
"Worst case": "Worst case",
|
||||
"Worst case liquidation price": "Worst case liquidation price",
|
||||
"You did not have enough {{assetSymbol}} collateral to meet the maintenance margin requirements for your position, so it was closed by the network.": "You did not have enough {{assetSymbol}} collateral to meet the maintenance margin requirements for your position, so it was closed by the network.",
|
||||
"You received less {{assetSymbol}} in gains that you should have when the market moved in your favour. This occurred because one or more other trader(s) were closed out and did not have enough funds to cover their losses, and the market's insurance pool was empty.": "You received less {{assetSymbol}} in gains that you should have when the market moved in your favour. This occurred because one or more other trader(s) were closed out and did not have enough funds to cover their losses, and the market's insurance pool was empty.",
|
||||
"Your open orders were cancelled.": "Your open orders were cancelled.",
|
||||
"Your position is distressed.": "Your position is distressed.",
|
||||
"Your position was closed.": "Your position was closed."
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"[This is {{network}} transaction only]": "[This is {{network}} transaction only]",
|
||||
"{{proposalChange}} proposal {{proposalState}}": "{{proposalChange}} proposal {{proposalState}}",
|
||||
"<0>{{count}}</0> blocks": "<0>{{count}}</0> blocks",
|
||||
"Awaiting network confirmation": "Awaiting network confirmation",
|
||||
"blocks": "blocks",
|
||||
"Changes have been proposed for this asset.": "Changes have been proposed for this asset.",
|
||||
"Changes have been proposed for this market.": "Changes have been proposed for this market.",
|
||||
"Closing date": "Closing date",
|
||||
"Confirm transaction in wallet": "Confirm transaction in wallet",
|
||||
"Enactment date: {{date}}": "Enactment date: {{date}}",
|
||||
"Enactment date": "Enactment date",
|
||||
"estimated time to protocol upgrade": "estimated time to protocol upgrade",
|
||||
"estimating...": "estimating...",
|
||||
"Market": "Market",
|
||||
"Network upgrade in {{countdown}}": "Network upgrade in {{countdown}}",
|
||||
"No proposed markets": "No proposed markets",
|
||||
"Parent market": "Parent market",
|
||||
"Please open your wallet application and confirm or reject the transaction": "Please open your wallet application and confirm or reject the transaction",
|
||||
"Please wait for your transaction to be confirmed": "Please wait for your transaction to be confirmed",
|
||||
"Proposal declined": "Proposal declined",
|
||||
"Proposal enacted": "Proposal enacted",
|
||||
"Proposal failed": "Proposal failed",
|
||||
"Proposal passed": "Proposal passed",
|
||||
"Proposal rejected": "Proposal rejected",
|
||||
"Proposal submitted": "Proposal submitted",
|
||||
"Proposal waiting for node vote": "Proposal waiting for node vote",
|
||||
"Rejection reason: {{reason}}": "Rejection reason: {{reason}}",
|
||||
"Settlement asset": "Settlement asset",
|
||||
"State": "State",
|
||||
"Submission failed": "Submission failed",
|
||||
"The network is being upgraded to {{vegaReleaseTag}}": "The network is being upgraded to {{vegaReleaseTag}}",
|
||||
"The network will upgrade to {{vegaReleaseTag}} in {{countdown}}": "The network will upgrade to {{vegaReleaseTag}} in {{countdown}}",
|
||||
"Trading activity will be interrupted, manage your risk appropriately.": "Trading activity will be interrupted, manage your risk appropriately.",
|
||||
"Trading and other network activity has stopped until the upgrade is complete.": "Trading and other network activity has stopped until the upgrade is complete.",
|
||||
"Transaction complete": "Transaction complete",
|
||||
"Transaction failed": "Transaction failed",
|
||||
"Unknown proposal {{proposalState}}": "Unknown proposal {{proposalState}}",
|
||||
"Update <0>{{key}}</0> to {{value}}": "Update <0>{{key}}</0> to {{value}}",
|
||||
"View details": "View details",
|
||||
"View in block explorer": "View in block explorer",
|
||||
"View proposal details": "View proposal details",
|
||||
"View proposal": "View proposal",
|
||||
"Voting": "Voting",
|
||||
"Your transaction has been confirmed": "Your transaction has been confirmed"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"Created at": "Created at",
|
||||
"No trades": "No trades",
|
||||
"Price": "Price",
|
||||
"Size": "Size"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"{{fee}} Fee": "{{fee}} Fee",
|
||||
"Auction Trigger stake {{trigger}}": "Auction Trigger stake {{trigger}}",
|
||||
"Collapse": "Collapse",
|
||||
"Copied": "Copied",
|
||||
"Dark mode": "Dark mode",
|
||||
"Dismiss all toasts": "Dismiss all toasts",
|
||||
"Dismiss all": "Dismiss all",
|
||||
"Exit view as": "Exit view as",
|
||||
"Expand": "Expand",
|
||||
"Light mode": "Light mode",
|
||||
"Loading...": "Loading...",
|
||||
"No data": "No data",
|
||||
"Providers greater than 2x target stake not shown": "Providers greater than 2x target stake not shown",
|
||||
"Show more": "Show more",
|
||||
"Something went wrong: {{errorMessage}}": "Something went wrong: {{errorMessage}}",
|
||||
"Target stake {{target}}": "Target stake {{target}}",
|
||||
"This is an example of a toast notification": "This is an example of a toast notification",
|
||||
"Try again": "Try again",
|
||||
"Viewing as Vega user: {{pubKey}}": "Viewing as Vega user: {{pubKey}}"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Expired on {{date}}": "Expired on {{date}}",
|
||||
"Not time-based": "Not time-based",
|
||||
"Expired": "Expired",
|
||||
"Mark": "Mark",
|
||||
"Required": "Required",
|
||||
"Invalid Ethereum address": "Invalid Ethereum address",
|
||||
"Invalid Vega key": "Invalid Vega key",
|
||||
"Value is below minimum": "Value is below minimum",
|
||||
"Value is above maximum": "Value is above maximum",
|
||||
"Must be valid JSON": "Must be valid JSON",
|
||||
"{{field}} must be a multiple of {{step}} for this market": "{{field}} must be a multiple of {{step}} for this market",
|
||||
"{{field}} must be whole numbers for this market": "{{field}} must be whole numbers for this market",
|
||||
"{{field}} accepts up to {{decimals}} decimal places": "{{field}} accepts up to {{decimals}} decimal places"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export const useTranslation = () => ({
|
||||
t: (label: string, replacements?: Record<string, string>) => {
|
||||
const replace =
|
||||
replacements?.replace && typeof replacements === 'object'
|
||||
? replacements?.replace
|
||||
: replacements;
|
||||
let translatedLabel = replacements?.defaultValue || label;
|
||||
if (typeof replace === 'object' && replace !== null) {
|
||||
Object.keys(replace).forEach((key) => {
|
||||
translatedLabel = translatedLabel.replace(`{{${key}}}`, replace[key]);
|
||||
});
|
||||
}
|
||||
return translatedLabel;
|
||||
},
|
||||
});
|
||||
@@ -1,8 +1,7 @@
|
||||
import { DepthChart } from 'pennant';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { addDecimal, getNumberFormat } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { addDecimal, addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketDepthProvider } from './market-depth-provider';
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
} from './__generated__/MarketDepth';
|
||||
import { type DepthChartProps } from 'pennant';
|
||||
import { parseLevel, updateLevels } from './depth-chart-utils';
|
||||
import { useT } from './use-t';
|
||||
|
||||
interface DepthChartManagerProps {
|
||||
marketId: string;
|
||||
@@ -39,6 +39,7 @@ const getMidPrice = (
|
||||
type DepthData = Pick<DepthChartProps, 'data' | 'midPrice'>;
|
||||
|
||||
export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
||||
const t = useT();
|
||||
const { theme } = useThemeSwitcher();
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const [depthData, setDepthData] = useState<DepthData | null>(null);
|
||||
@@ -215,13 +216,13 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
||||
|
||||
const volumeFormat = useCallback(
|
||||
(volume: number) =>
|
||||
getNumberFormat(market?.positionDecimalPlaces || 0).format(volume),
|
||||
addDecimalsFormatNumber(volume, market?.positionDecimalPlaces || 0),
|
||||
[market?.positionDecimalPlaces]
|
||||
);
|
||||
|
||||
const priceFormat = useCallback(
|
||||
(price: number) =>
|
||||
getNumberFormat(market?.decimalPlaces || 0).format(price),
|
||||
addDecimalsFormatNumber(price, market?.decimalPlaces || 0),
|
||||
[market?.decimalPlaces]
|
||||
);
|
||||
|
||||
|
||||
@@ -102,12 +102,7 @@ export const OrderbookControls = ({
|
||||
};
|
||||
|
||||
export const formatResolution = (r: number, decimalPlaces: number) => {
|
||||
let num = addDecimalsFormatNumber(r, decimalPlaces);
|
||||
|
||||
// Remove trailing zeroes
|
||||
num = num.replace(/\.?0+$/, '');
|
||||
|
||||
return num;
|
||||
return addDecimalsFormatNumber(r, decimalPlaces);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { addDecimal, addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimal, addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { NumericCell } from '@vegaprotocol/datagrid';
|
||||
import { VolumeType } from './orderbook-data';
|
||||
import classNames from 'classnames';
|
||||
@@ -55,7 +55,7 @@ export const OrderbookRow = memo(
|
||||
<NumericCell
|
||||
testId={`price-${price}`}
|
||||
value={BigInt(price)}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
price,
|
||||
decimalPlaces,
|
||||
priceFormatDecimalPlaces
|
||||
@@ -76,7 +76,7 @@ export const OrderbookRow = memo(
|
||||
<NumericCell
|
||||
testId={`${txtId}-vol-${price}`}
|
||||
value={volume}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
volume,
|
||||
positionDecimalPlaces ?? 0
|
||||
)}
|
||||
@@ -94,7 +94,7 @@ export const OrderbookRow = memo(
|
||||
<NumericCell
|
||||
testId={`cumulative-vol-${price}`}
|
||||
value={cumulativeVolume}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
valueFormatted={addDecimalsFormatNumber(
|
||||
cumulativeVolume,
|
||||
positionDecimalPlaces
|
||||
)}
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('Orderbook', () => {
|
||||
);
|
||||
expect(
|
||||
screen.getByTestId(`last-traded-${params.lastTradedPrice}`)
|
||||
).toHaveTextContent('122.90');
|
||||
).toHaveTextContent('122.9');
|
||||
});
|
||||
|
||||
it('should format correctly the numbers on resolution change', async () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import ReactVirtualizedAutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { usePrevious } from '@vegaprotocol/react-helpers';
|
||||
import { OrderbookRow } from './orderbook-row';
|
||||
import type { OrderbookRowData } from './orderbook-data';
|
||||
@@ -10,6 +9,7 @@ import { Splash, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { PriceLevelFieldsFragment } from './__generated__/MarketDepth';
|
||||
import { OrderbookControls } from './orderbook-controls';
|
||||
import { useT } from './use-t';
|
||||
|
||||
// Sets row height, will be used to calculate number of rows that can be
|
||||
// displayed each side of the book without overflow
|
||||
@@ -85,6 +85,7 @@ export const OrderbookMid = ({
|
||||
bestAskPrice: string;
|
||||
bestBidPrice: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const previousLastTradedPrice = usePrevious(lastTradedPrice);
|
||||
const priceChangeRef = useRef<'up' | 'down' | 'none'>('none');
|
||||
const spread = (BigInt(bestAskPrice) - BigInt(bestBidPrice)).toString();
|
||||
@@ -153,6 +154,7 @@ export const Orderbook = ({
|
||||
bids,
|
||||
assetSymbol,
|
||||
}: OrderbookProps) => {
|
||||
const t = useT();
|
||||
const [resolution, setResolution] = useState(1);
|
||||
|
||||
const groupedAsks = useMemo(() => {
|
||||
@@ -170,8 +172,9 @@ export const Orderbook = ({
|
||||
|
||||
// we'll want to only display a relevant number of dps based on the
|
||||
// current resolution selection
|
||||
const priceFormatDecimalPlaces = Math.ceil(
|
||||
decimalPlaces - Math.log10(resolution)
|
||||
const priceFormatDecimalPlaces = Math.max(
|
||||
0,
|
||||
Math.ceil(decimalPlaces - Math.log10(resolution))
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const useT = () => useTranslation('market-depth').t;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useHasAmendableOrder } from '../../order-hooks';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const OpenOrdersMenu = () => {
|
||||
const { isReadOnly } = useVegaWallet();
|
||||
@@ -28,8 +28,11 @@ export const OpenOrdersMenu = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => (
|
||||
<TradingButton size="extra-small" onClick={onClick} data-testid="cancelAll">
|
||||
{t('Cancel all')}
|
||||
</TradingButton>
|
||||
);
|
||||
const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<TradingButton size="extra-small" onClick={onClick} data-testid="cancelAll">
|
||||
{t('Cancel all')}
|
||||
</TradingButton>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useCallback, useRef, useState, useEffect } from 'react';
|
||||
import { type AgGridReact } from 'ag-grid-react';
|
||||
import { Pagination, type useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
@@ -12,6 +11,7 @@ import { type Order } from '../order-data-provider';
|
||||
import { OrderViewDialog } from '../order-list/order-view-dialog';
|
||||
import { OrderListTable } from '../order-list';
|
||||
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export enum Filter {
|
||||
'Open' = 'Open',
|
||||
@@ -38,6 +38,7 @@ export const OrderListManager = ({
|
||||
gridProps,
|
||||
noRowsMessage,
|
||||
}: OrderListManagerProps) => {
|
||||
const t = useT();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const [editOrder, setEditOrder] = useState<Order | null>(null);
|
||||
const [viewOrder, setViewOrder] = useState<Order | null>(null);
|
||||
@@ -85,7 +86,13 @@ export const OrderListManager = ({
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <Splash>{t(`Something went wrong: ${error.message}`)}</Splash>;
|
||||
return (
|
||||
<Splash>
|
||||
{t(`Something went wrong: {{errorMessage}}`, {
|
||||
errorMessage: error.message,
|
||||
})}
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { OrderEditDialog } from './order-edit-dialog';
|
||||
@@ -7,16 +7,14 @@ import { limitOrder } from '../mocks';
|
||||
describe('OrderEditDialog', () => {
|
||||
it('must be warned (pre-submit) if the input price has too many digits after the decimal place for the market', async () => {
|
||||
// 7003-MORD-013
|
||||
await act(async () => {
|
||||
render(
|
||||
<OrderEditDialog
|
||||
order={limitOrder}
|
||||
onChange={jest.fn()}
|
||||
isOpen={true}
|
||||
onSubmit={jest.fn()}
|
||||
/>
|
||||
);
|
||||
});
|
||||
render(
|
||||
<OrderEditDialog
|
||||
order={limitOrder}
|
||||
onChange={jest.fn()}
|
||||
isOpen={true}
|
||||
onSubmit={jest.fn()}
|
||||
/>
|
||||
);
|
||||
const editOrder = await screen.findByTestId('edit-order');
|
||||
const limitPrice = within(editOrder).getByLabelText('Price');
|
||||
await userEvent.type(limitPrice, '0.111111');
|
||||
|
||||
@@ -3,9 +3,8 @@ import {
|
||||
getDateTimeFormat,
|
||||
addDecimal,
|
||||
addDecimalsFormatNumber,
|
||||
validateAmount,
|
||||
useValidateAmount,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Size } from '@vegaprotocol/datagrid';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
@@ -19,6 +18,7 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { Order } from '../order-data-provider';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
interface OrderEditDialogProps {
|
||||
isOpen: boolean;
|
||||
@@ -38,6 +38,8 @@ export const OrderEditDialog = ({
|
||||
order,
|
||||
onSubmit,
|
||||
}: OrderEditDialogProps) => {
|
||||
const t = useT();
|
||||
const validateAmount = useValidateAmount();
|
||||
const headerClassName = 'text-xs font-bold text-black dark:text-white';
|
||||
const {
|
||||
register,
|
||||
@@ -60,7 +62,7 @@ export const OrderEditDialog = ({
|
||||
title={t('Edit order')}
|
||||
icon={<VegaIcon name={VegaIconNames.EDIT} />}
|
||||
>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-4">
|
||||
{order.market && (
|
||||
<div className="md:col-span-2">
|
||||
<p className={headerClassName}>{t(`Market`)}</p>
|
||||
@@ -99,10 +101,10 @@ export const OrderEditDialog = ({
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
data-testid="edit-order"
|
||||
className="w-full mt-4"
|
||||
className="mt-4 w-full"
|
||||
noValidate
|
||||
>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<div className="flex flex-col gap-4 md:flex-row">
|
||||
<TradingFormGroup
|
||||
label={t('Price')}
|
||||
labelFor="limitPrice"
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('OrderListTable', () => {
|
||||
const expectedValues: string[] = [
|
||||
marketOrder.market?.tradableInstrument.instrument.code || '',
|
||||
'0.05',
|
||||
'0.10',
|
||||
'0.1',
|
||||
Schema.OrderTypeMapping[marketOrder.type as Schema.OrderType] || '',
|
||||
Schema.OrderStatusMapping[marketOrder.status],
|
||||
'-',
|
||||
@@ -102,7 +102,7 @@ describe('OrderListTable', () => {
|
||||
const expectedValues: string[] = [
|
||||
limitOrder.market?.tradableInstrument.instrument.code || '',
|
||||
'0.05',
|
||||
'0.10',
|
||||
'0.1',
|
||||
Schema.OrderTypeMapping[limitOrder.type || Schema.OrderType.TYPE_LIMIT],
|
||||
Schema.OrderStatusMapping[limitOrder.status],
|
||||
'-',
|
||||
@@ -135,8 +135,8 @@ describe('OrderListTable', () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues: string[] = [
|
||||
icebergOrder.market?.tradableInstrument.instrument.code || '',
|
||||
'0.00',
|
||||
'+1.00',
|
||||
'0',
|
||||
'+1',
|
||||
Schema.OrderTypeMapping[
|
||||
icebergOrder.type || Schema.OrderType.TYPE_LIMIT
|
||||
] + ' (Iceberg)',
|
||||
@@ -277,7 +277,7 @@ describe('OrderListTable', () => {
|
||||
|
||||
const amendCell = getAmendCell();
|
||||
const typeCell = screen.getAllByRole('gridcell')[3];
|
||||
expect(typeCell).toHaveTextContent('Mid - 10.0 Peg limit');
|
||||
expect(typeCell).toHaveTextContent('Mid - 10 Peg limit');
|
||||
expect(amendCell.queryByTestId('edit')).toBeInTheDocument();
|
||||
expect(amendCell.queryByTestId('cancel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
isNumeric,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
ActionsDropdown,
|
||||
@@ -30,10 +29,11 @@ import {
|
||||
type VegaValueFormatterParams,
|
||||
type VegaValueGetterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGridReact } from 'ag-grid-react';
|
||||
import { type AgGridReact } from 'ag-grid-react';
|
||||
import { type Order } from '../order-data-provider';
|
||||
import { Filter } from '../order-list-manager/order-list-manager';
|
||||
import { type ColDef } from 'ag-grid-community';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
const defaultColDef = {
|
||||
resizable: true,
|
||||
@@ -68,6 +68,7 @@ export const OrderListTable = memo<
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const t = useT();
|
||||
const showAllActions = props.isReadOnly
|
||||
? false
|
||||
: filter === undefined || filter === Filter.Open
|
||||
@@ -252,11 +253,14 @@ export const OrderListTable = memo<
|
||||
}
|
||||
|
||||
const tifLabel = value ? Schema.OrderTimeInForceCode[value] : '';
|
||||
const label = `${tifLabel}${
|
||||
data?.postOnly ? t('. Post Only') : ''
|
||||
}${data?.reduceOnly ? t('. Reduce only') : ''}`;
|
||||
if (data?.postOnly) {
|
||||
return t('{{tifLabel}}. Post Only', { tifLabel });
|
||||
}
|
||||
if (data?.reduceOnly) {
|
||||
return t('{{tifLabel}}. Reduce only', { tifLabel });
|
||||
}
|
||||
|
||||
return label;
|
||||
return tifLabel;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -336,6 +340,7 @@ export const OrderListTable = memo<
|
||||
onOrderTypeClick,
|
||||
props.isReadOnly,
|
||||
showAllActions,
|
||||
t,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -162,17 +162,15 @@ describe('OrderViewDialog', () => {
|
||||
expect(screen.getByTestId('order-type-label')).toHaveTextContent('Type');
|
||||
expect(screen.getByTestId('order-type-value')).toHaveTextContent('Limit');
|
||||
expect(screen.getByTestId('order-price-label')).toHaveTextContent('Price');
|
||||
expect(screen.getByTestId('order-price-value')).toHaveTextContent('150.00');
|
||||
expect(screen.getByTestId('order-price-value')).toHaveTextContent('150');
|
||||
expect(screen.getByTestId('order-size-label')).toHaveTextContent('Size');
|
||||
expect(screen.getByTestId('order-size-value')).toHaveTextContent('+10.00');
|
||||
expect(screen.getByTestId('order-size-value')).toHaveTextContent('+10');
|
||||
expect(screen.getByTestId('order-remaining-label')).toHaveTextContent(
|
||||
'Remaining'
|
||||
);
|
||||
expect(screen.getByTestId('order-remaining-value')).toHaveTextContent(
|
||||
'+5.00'
|
||||
);
|
||||
expect(screen.getByTestId('order-remaining-value')).toHaveTextContent('+5');
|
||||
expect(
|
||||
screen.getByTestId('order-iceberg-order-reserved-remaining-value')
|
||||
).toHaveTextContent('5.00');
|
||||
).toHaveTextContent('5');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
getDateTimeFormat,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Size } from '@vegaprotocol/datagrid';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
@@ -19,6 +18,7 @@ import type { Order } from '../order-data-provider';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
interface OrderViewDialogProps {
|
||||
isOpen: boolean;
|
||||
@@ -33,6 +33,7 @@ export const OrderViewDialog = ({
|
||||
onChange,
|
||||
onMarketClick,
|
||||
}: OrderViewDialogProps) => {
|
||||
const t = useT();
|
||||
const [, setCopied] = useCopyTimeout();
|
||||
return (
|
||||
<Dialog open={isOpen} title={t('Order details')} onChange={onChange}>
|
||||
@@ -184,21 +185,21 @@ export const OrderViewDialog = ({
|
||||
<KeyValueTableRow key={'order-post-only'}>
|
||||
<div data-testid={'order-post-only-label'}>{t('Post only')}</div>
|
||||
<div data-testid={`order-post-only-value`}>
|
||||
{order.postOnly ? t('Yes') : t('-')}
|
||||
{order.postOnly ? t('Yes') : '-'}
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
|
||||
<KeyValueTableRow key={'order-reduce-only'}>
|
||||
<div data-testid={'order-reduce-only-label'}>{t('Reduce only')}</div>
|
||||
<div data-testid={`order-reduce-only-value`}>
|
||||
{order.reduceOnly ? t('Yes') : t('-')}
|
||||
{order.reduceOnly ? t('Yes') : '-'}
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
|
||||
<KeyValueTableRow key={'order-pegged'}>
|
||||
<div data-testid={'order-pegged-label'}>{t('Pegged')}</div>
|
||||
<div data-testid={`order-pegged-value`}>
|
||||
{order.peggedOrder ? t('Yes') : t('-')}
|
||||
{order.peggedOrder ? t('Yes') : '-'}
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
|
||||
@@ -207,7 +208,7 @@ export const OrderViewDialog = ({
|
||||
{t('Liquidity provision')}
|
||||
</div>
|
||||
<div data-testid={`order-liquidity-provision-value`}>
|
||||
{order.liquidityProvision ? t('Yes') : t('-')}
|
||||
{order.liquidityProvision ? t('Yes') : '-'}
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
@@ -217,7 +218,7 @@ export const OrderViewDialog = ({
|
||||
{t('Iceberg order')}
|
||||
</div>
|
||||
<div data-testid={`order-iceberg-order-value`}>
|
||||
{order.icebergOrder ? t('Yes') : t('-')}
|
||||
{order.icebergOrder ? t('Yes') : '-'}
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
{order.icebergOrder && (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { StopOrdersTable } from '../stop-orders-table/stop-orders-table';
|
||||
import { type useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
type StopOrdersQueryVariables,
|
||||
} from '../order-data-provider';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export interface StopOrdersManagerProps {
|
||||
partyId: string;
|
||||
@@ -27,6 +27,7 @@ export const StopOrdersManager = ({
|
||||
isReadOnly,
|
||||
gridProps,
|
||||
}: StopOrdersManagerProps) => {
|
||||
const t = useT();
|
||||
const create = useVegaTransactionStore((state) => state.create);
|
||||
const [viewOrder, setViewOrder] = useState<Order | null>(null);
|
||||
const variables: StopOrdersQueryVariables = {
|
||||
|
||||
@@ -140,8 +140,8 @@ describe('StopOrdersTable', () => {
|
||||
const cells = grid.querySelectorAll('.ag-body [col-id="trigger"]');
|
||||
|
||||
const expectedValues: string[] = [
|
||||
'Mark < 8.0',
|
||||
'Mark > 9.0',
|
||||
'Mark < 8',
|
||||
'Mark > 9',
|
||||
'Mark +10.0%',
|
||||
'Mark -20.0%',
|
||||
];
|
||||
@@ -173,7 +173,7 @@ describe('StopOrdersTable', () => {
|
||||
const grid = screen.getByRole('treegrid');
|
||||
const cells = grid.querySelectorAll('.ag-body [col-id="submission.size"]');
|
||||
|
||||
const expectedValues: string[] = ['+1.00', '-1.10'];
|
||||
const expectedValues: string[] = ['+1', '-1.1'];
|
||||
expectedValues.forEach((expectedValue, i) =>
|
||||
expect(cells[i]).toHaveTextContent(expectedValue)
|
||||
);
|
||||
@@ -191,6 +191,7 @@ describe('StopOrdersTable', () => {
|
||||
expect(cells[i]).toHaveTextContent(expectedValue)
|
||||
);
|
||||
});
|
||||
|
||||
it('formats status column', async () => {
|
||||
await act(async () => {
|
||||
render(generateJsx({ rowData }));
|
||||
@@ -218,7 +219,7 @@ describe('StopOrdersTable', () => {
|
||||
const grid = screen.getByRole('treegrid');
|
||||
const cells = grid.querySelectorAll('.ag-body [col-id="submission.price"]');
|
||||
|
||||
const expectedValues: string[] = ['12.0', '-'];
|
||||
const expectedValues: string[] = ['12', '-'];
|
||||
expectedValues.forEach((expectedValue, i) =>
|
||||
expect(cells[i]).toHaveTextContent(expectedValue)
|
||||
);
|
||||
@@ -260,14 +261,13 @@ describe('StopOrdersTable', () => {
|
||||
await act(async () => {
|
||||
render(generateJsx({ rowData, onView }));
|
||||
});
|
||||
const dropdownMenuButtons = screen.getByTestId('dropdown-menu');
|
||||
dropdownMenuButtons.click();
|
||||
await user.click(dropdownMenuButtons as HTMLButtonElement);
|
||||
const menuItems = screen.getAllByRole('menuitem');
|
||||
const button = screen.getByTestId('icon-kebab');
|
||||
await user.click(button);
|
||||
const menuItems = await screen.findAllByRole('menuitem');
|
||||
expect(menuItems).toHaveLength(2);
|
||||
expect(menuItems[0]).toHaveTextContent('Copy order ID');
|
||||
expect(menuItems[1]).toHaveTextContent('View order details');
|
||||
menuItems[1].click();
|
||||
await user.click(menuItems[1]);
|
||||
expect(onView).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,9 +3,8 @@ import {
|
||||
getDateTimeFormat,
|
||||
isNumeric,
|
||||
toBigNum,
|
||||
formatTrigger,
|
||||
useFormatTrigger,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
ActionsDropdown,
|
||||
@@ -35,6 +34,7 @@ import type {
|
||||
import type { StopOrder } from '../order-data-provider/stop-orders-data-provider';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import type { Order } from '../order-data-provider';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
const defaultColDef = {
|
||||
resizable: true,
|
||||
@@ -51,6 +51,8 @@ export type StopOrdersTableProps = TypedDataAgGrid<StopOrder> & {
|
||||
|
||||
export const StopOrdersTable = memo(
|
||||
({ onCancel, onMarketClick, onView, ...props }: StopOrdersTableProps) => {
|
||||
const t = useT();
|
||||
const formatTrigger = useFormatTrigger();
|
||||
const showAllActions = !props.isReadOnly;
|
||||
const columnDefs: ColDef[] = useMemo(
|
||||
() => [
|
||||
@@ -176,7 +178,7 @@ export const StopOrdersTable = memo(
|
||||
{data.ocoLinkId && (
|
||||
<Pill
|
||||
size="xxs"
|
||||
className="uppercase ml-0.5"
|
||||
className="ml-0.5 uppercase"
|
||||
title={t('One Cancels the Other')}
|
||||
>
|
||||
OCO
|
||||
@@ -281,7 +283,15 @@ export const StopOrdersTable = memo(
|
||||
},
|
||||
},
|
||||
],
|
||||
[onCancel, onMarketClick, onView, props.isReadOnly, showAllActions]
|
||||
[
|
||||
onCancel,
|
||||
onMarketClick,
|
||||
onView,
|
||||
props.isReadOnly,
|
||||
showAllActions,
|
||||
t,
|
||||
formatTrigger,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from './components';
|
||||
export * from './order-hooks';
|
||||
export * from './utils';
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const useT = () => useTranslation('orders').t;
|
||||
@@ -1,28 +0,0 @@
|
||||
import { timeInForceLabel } from './utils';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
describe('utils', () => {
|
||||
describe('timeInForceLabel', () => {
|
||||
it('should return the correct label for time in force', () => {
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_FOK)).toBe(
|
||||
`Fill or Kill (FOK)`
|
||||
);
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GTC)).toBe(
|
||||
`Good 'til Cancelled (GTC)`
|
||||
);
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_IOC)).toBe(
|
||||
`Immediate or Cancel (IOC)`
|
||||
);
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GTT)).toBe(
|
||||
`Good 'til Time (GTT)`
|
||||
);
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GFA)).toBe(
|
||||
`Good for Auction (GFA)`
|
||||
);
|
||||
expect(timeInForceLabel(Types.OrderTimeInForce.TIME_IN_FORCE_GFN)).toBe(
|
||||
`Good for Normal (GFN)`
|
||||
);
|
||||
expect(timeInForceLabel('')).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
// More detail in https://docs.vega.xyz/mainnet/graphql/enums/order-time-in-force
|
||||
export const timeInForceLabel = (tif: string) => {
|
||||
switch (tif) {
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_GTC:
|
||||
return t(`Good 'til Cancelled (GTC)`);
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_IOC:
|
||||
return t('Immediate or Cancel (IOC)');
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_FOK:
|
||||
return t('Fill or Kill (FOK)');
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_GTT:
|
||||
return t(`Good 'til Time (GTT)`);
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_GFN:
|
||||
return t('Good for Normal (GFN)');
|
||||
case Schema.OrderTimeInForce.TIME_IN_FORCE_GFA:
|
||||
return t('Good for Auction (GFA)');
|
||||
default:
|
||||
return t(tif);
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEstimatePositionQuery } from './__generated__/Positions';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const LiquidationPrice = ({
|
||||
marketId,
|
||||
@@ -14,6 +14,7 @@ export const LiquidationPrice = ({
|
||||
collateralAvailable: string;
|
||||
decimalPlaces: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { data: currentData, previousData } = useEstimatePositionQuery({
|
||||
variables: {
|
||||
marketId,
|
||||
@@ -43,11 +44,11 @@ export const LiquidationPrice = ({
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t('Worst case')}</th>
|
||||
<td className="pl-2 font-mono text-right">{worstCase}</td>
|
||||
<td className="pl-2 text-right font-mono">{worstCase}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t('Best case')}</th>
|
||||
<td className="pl-2 font-mono text-right">{bestCase}</td>
|
||||
<td className="pl-2 text-right font-mono">{bestCase}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ActionsDropdown,
|
||||
TradingDropdownItem,
|
||||
@@ -6,8 +5,10 @@ import {
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const PositionActionsDropdown = ({ assetId }: { assetId: string }) => {
|
||||
const t = useT();
|
||||
const open = useAssetDetailsDialogStore((store) => store.open);
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { PositionsTable } from './positions-table';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
positionsMetricsProvider,
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
} from './positions-data-providers';
|
||||
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
interface PositionsManagerProps {
|
||||
partyIds: string[];
|
||||
@@ -27,6 +27,7 @@ export const PositionsManager = ({
|
||||
gridProps,
|
||||
showClosed = false,
|
||||
}: PositionsManagerProps) => {
|
||||
const t = useT();
|
||||
const { pubKeys, pubKey } = useVegaWallet();
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
const onClose = useCallback(
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('Positions', () => {
|
||||
'+100'
|
||||
);
|
||||
expect(within(cell).getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||
'1,230.0'
|
||||
'1,230'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ describe('Positions', () => {
|
||||
'-100'
|
||||
);
|
||||
expect(within(cell).getByTestId('stack-cell-secondary')).toHaveTextContent(
|
||||
'1,230.0'
|
||||
'1,230'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -334,7 +334,7 @@ describe('Positions', () => {
|
||||
const tooltip = within(await screen.findByRole('tooltip'));
|
||||
expect(tooltip.getByText('Realised PNL: 1.23')).toBeInTheDocument();
|
||||
expect(
|
||||
tooltip.getByText('Lifetime loss socialisation deductions: 5.00')
|
||||
tooltip.getByText('Lifetime loss socialisation deductions: 5')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
tooltip.getByText(
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
addDecimalsFormatNumberQuantum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { type Position } from './positions-data-providers';
|
||||
import {
|
||||
MarketTradingMode,
|
||||
@@ -38,6 +37,7 @@ import {
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { PositionActionsDropdown } from './position-actions-dropdown';
|
||||
import { LiquidationPrice } from './liquidation-price';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
interface Props extends TypedDataAgGrid<Position> {
|
||||
onClose?: (data: Position) => void;
|
||||
@@ -81,6 +81,7 @@ export const PositionsTable = ({
|
||||
pubKey,
|
||||
...props
|
||||
}: Props) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<AgGrid
|
||||
overlayNoRowsTemplate={t('No positions')}
|
||||
@@ -193,8 +194,8 @@ export const PositionsTable = ({
|
||||
switch (args.data.status) {
|
||||
case PositionStatus.POSITION_STATUS_CLOSED_OUT:
|
||||
secondaryTooltip = t(
|
||||
`You did not have enough %s collateral to meet the maintenance margin requirements for your position, so it was closed by the network.`,
|
||||
args.data.assetSymbol
|
||||
`You did not have enough {{assetSymbol}} collateral to meet the maintenance margin requirements for your position, so it was closed by the network.`,
|
||||
{ assetSymbol: args.data.assetSymbol }
|
||||
);
|
||||
break;
|
||||
case PositionStatus.POSITION_STATUS_ORDERS_CLOSED:
|
||||
@@ -218,10 +219,12 @@ export const PositionsTable = ({
|
||||
<p className="mb-2">{primaryTooltip}</p>
|
||||
<p className="mb-2">{secondaryTooltip}</p>
|
||||
<p className="mb-2">
|
||||
{t(
|
||||
'Status: %s',
|
||||
PositionStatusMapping[args.data.status]
|
||||
)}
|
||||
{t('Status: {{status}}', {
|
||||
nsSeparator: '*',
|
||||
replace: {
|
||||
status: PositionStatusMapping[args.data.status],
|
||||
},
|
||||
})}
|
||||
</p>
|
||||
{POSITION_RESOLUTION_LINK && (
|
||||
<ExternalLink href={POSITION_RESOLUTION_LINK}>
|
||||
@@ -386,18 +389,26 @@ export const PositionsTable = ({
|
||||
value={
|
||||
<>
|
||||
<p className="mb-2">
|
||||
{t('Realised PNL: %s', args.value)}
|
||||
{t('Realised PNL: {{value}}', {
|
||||
nsSeparator: '*',
|
||||
replace: { value: args.value },
|
||||
})}
|
||||
</p>
|
||||
<p className="mb-2">
|
||||
{t(
|
||||
'Lifetime loss socialisation deductions: %s',
|
||||
lossesFormatted
|
||||
'Lifetime loss socialisation deductions: {{losses}}',
|
||||
{
|
||||
nsSeparator: '*',
|
||||
replace: {
|
||||
losses: lossesFormatted,
|
||||
},
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-2">
|
||||
{t(
|
||||
`You received less %s in gains that you should have when the market moved in your favour. This occurred because one or more other trader(s) were closed out and did not have enough funds to cover their losses, and the market's insurance pool was empty.`,
|
||||
args.data.assetSymbol
|
||||
`You received less {{assetSymbol}} in gains that you should have when the market moved in your favour. This occurred because one or more other trader(s) were closed out and did not have enough funds to cover their losses, and the market's insurance pool was empty.`,
|
||||
{ assetSymbol: args.data.assetSymbol }
|
||||
)}
|
||||
</p>
|
||||
{LOSS_SOCIALIZATION_LINK && (
|
||||
@@ -481,7 +492,15 @@ export const PositionsTable = ({
|
||||
return columnDefs.filter<ColDef>(
|
||||
(colDef: ColDef | null): colDef is ColDef => colDef !== null
|
||||
);
|
||||
}, [isReadOnly, multipleKeys, onClose, onMarketClick, pubKey, pubKeys])}
|
||||
}, [
|
||||
isReadOnly,
|
||||
multipleKeys,
|
||||
onClose,
|
||||
onMarketClick,
|
||||
pubKey,
|
||||
pubKeys,
|
||||
t,
|
||||
])}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import { locales } from '@vegaprotocol/i18n';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
// Set up i18n instance so that components have the correct default
|
||||
// en translations
|
||||
i18n.use(initReactI18next).init({
|
||||
// we init with resources
|
||||
resources: locales,
|
||||
fallbackLng: 'en',
|
||||
ns: ['positions'],
|
||||
defaultNS: 'positions',
|
||||
});
|
||||
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const ns = 'positions';
|
||||
export const useT = () => useTranslation(ns).t;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit';
|
||||
import { useUpdateProposal } from '../lib';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
type AssetProposalNotificationProps = {
|
||||
assetId?: string;
|
||||
@@ -10,6 +10,7 @@ type AssetProposalNotificationProps = {
|
||||
export const AssetProposalNotification = ({
|
||||
assetId,
|
||||
}: AssetProposalNotificationProps) => {
|
||||
const t = useT();
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const { data: proposal } = useUpdateProposal({
|
||||
id: assetId,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit';
|
||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||
import { useUpdateProposal } from '../lib';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
type MarketProposalNotificationProps = {
|
||||
marketId?: string;
|
||||
@@ -10,6 +10,7 @@ type MarketProposalNotificationProps = {
|
||||
export const MarketProposalNotification = ({
|
||||
marketId,
|
||||
}: MarketProposalNotificationProps) => {
|
||||
const t = useT();
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const { data: proposal } = useUpdateProposal({
|
||||
id: marketId,
|
||||
@@ -29,7 +30,7 @@ export const MarketProposalNotification = ({
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="border-l border-default pl-1 pr-1 pb-1 min-w-min whitespace-nowrap">
|
||||
<div className="border-default min-w-min whitespace-nowrap border-l pb-1 pl-1 pr-1">
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
message={message}
|
||||
|
||||
@@ -5,10 +5,11 @@ import {
|
||||
Link,
|
||||
ActionsDropdown,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const ProposalActionsDropdown = ({ id }: { id: string }) => {
|
||||
const t = useT();
|
||||
const linkCreator = useLinks(DApp.Governance);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { FC } from 'react';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { useProposalsListQuery } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { useColumnDefs } from './use-column-defs';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
|
||||
data.filter((proposal) =>
|
||||
@@ -30,6 +30,7 @@ interface ProposalListProps {
|
||||
}
|
||||
|
||||
export const ProposalsList = ({ cellRenderers }: ProposalListProps) => {
|
||||
const t = useT();
|
||||
const { data } = useProposalsListQuery({
|
||||
variables: {
|
||||
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import compact from 'lodash/compact';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
@@ -19,8 +18,11 @@ import {
|
||||
} from '@vegaprotocol/types';
|
||||
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { ProposalActionsDropdown } from '../proposal-actions-dropdown';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const useColumnDefs = () => {
|
||||
const t = useT();
|
||||
|
||||
const columnDefs: ColDef[] = useMemo(() => {
|
||||
return compact([
|
||||
{
|
||||
@@ -124,7 +126,7 @@ export const useColumnDefs = () => {
|
||||
},
|
||||
},
|
||||
]);
|
||||
}, []);
|
||||
}, [t]);
|
||||
|
||||
return columnDefs;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useNextProtocolUpgradeProposal, useTimeToUpgrade } from '../lib';
|
||||
import { convertToCountdownString } from '@vegaprotocol/utils';
|
||||
import classNames from 'classnames';
|
||||
@@ -9,6 +8,8 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment';
|
||||
import { useContext } from 'react';
|
||||
import { useT } from '../use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
export enum ProtocolUpgradeCountdownMode {
|
||||
IN_BLOCKS,
|
||||
@@ -21,6 +22,7 @@ type ProtocolUpgradeCountdownProps = {
|
||||
export const ProtocolUpgradeCountdown = ({
|
||||
mode = ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING,
|
||||
}: ProtocolUpgradeCountdownProps) => {
|
||||
const t = useT();
|
||||
const { theme } = useContext(NavigationContext);
|
||||
const { data, lastBlockHeight } = useNextProtocolUpgradeProposal();
|
||||
|
||||
@@ -45,12 +47,13 @@ export const ProtocolUpgradeCountdown = ({
|
||||
switch (mode) {
|
||||
case ProtocolUpgradeCountdownMode.IN_BLOCKS:
|
||||
countdown = (
|
||||
<>
|
||||
<span className={emphasis}>
|
||||
{Number(data.upgradeBlockHeight) - Number(lastBlockHeight)}
|
||||
</span>{' '}
|
||||
{t('blocks')}
|
||||
</>
|
||||
<Trans
|
||||
defaults="<0>{{count}}</0> blocks"
|
||||
components={[<span className={emphasis}>count</span>]}
|
||||
values={{
|
||||
count: Number(data.upgradeBlockHeight) - Number(lastBlockHeight),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING:
|
||||
@@ -61,7 +64,7 @@ export const ProtocolUpgradeCountdown = ({
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
className={classNames('italic lowercase text-vega-orange-600', {
|
||||
className={classNames('text-vega-orange-600 lowercase italic', {
|
||||
'!text-black': theme === 'yellow',
|
||||
})}
|
||||
>
|
||||
@@ -80,20 +83,19 @@ export const ProtocolUpgradeCountdown = ({
|
||||
<div
|
||||
data-testid="protocol-upgrade-counter"
|
||||
className={classNames(
|
||||
'flex flex-nowrap gap-1 items-center text-xs py-1 px-2 lg:px-4 h-8',
|
||||
'border rounded',
|
||||
'flex h-8 flex-nowrap items-center gap-1 px-2 py-1 text-xs lg:px-4',
|
||||
'rounded border',
|
||||
'border-vega-orange-500 dark:border-vega-orange-500',
|
||||
'bg-vega-orange-300 dark:bg-vega-orange-700',
|
||||
'text-default',
|
||||
{
|
||||
'!bg-transparent !border-black': theme === 'yellow',
|
||||
'!border-black !bg-transparent': theme === 'yellow',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.EXCLAIMATION_MARK} size={12} />{' '}
|
||||
<span className="flex gap-1 flex-nowrap whitespace-nowrap">
|
||||
<span>{t('Network upgrade in')} </span>
|
||||
{countdown}
|
||||
<span className="flex flex-nowrap gap-1 whitespace-nowrap">
|
||||
<span>{t('Network upgrade in {{countdown}}', { countdown })} </span>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment';
|
||||
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
} from '../lib';
|
||||
import { useLocalStorageSnapshot } from '@vegaprotocol/react-helpers';
|
||||
import { useBlockRising } from '../lib/protocol-upgrade-proposals/use-block-rising';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
/**
|
||||
* A flag determining whether to get the upgrade proposal data from local
|
||||
@@ -22,6 +22,7 @@ import { useBlockRising } from '../lib/protocol-upgrade-proposals/use-block-risi
|
||||
const ALLOW_STORED_PROPOSAL_DATA = true;
|
||||
|
||||
export const ProtocolUpgradeInProgressNotification = () => {
|
||||
const t = useT();
|
||||
const { data, error } = useNextProtocolUpgradeProposal(undefined, true);
|
||||
const [nextUpgrade] = useLocalStorageSnapshot(
|
||||
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT
|
||||
@@ -71,7 +72,9 @@ export const ProtocolUpgradeInProgressNotification = () => {
|
||||
return (
|
||||
<NotificationBanner intent={Intent.Danger} className={SHORT}>
|
||||
<div className="uppercase">
|
||||
{t('The network is being upgraded to %s', vegaReleaseTag)}
|
||||
{t('The network is being upgraded to {{vegaReleaseTag}}', {
|
||||
vegaReleaseTag,
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
|
||||
@@ -4,11 +4,12 @@ import {
|
||||
NotificationBanner,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useNextProtocolUpgradeProposal, useTimeToUpgrade } from '../lib';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment';
|
||||
import { ProtocolUpgradeCountdownMode } from './protocol-upgrade-countdown';
|
||||
import { convertToCountdownString } from '@vegaprotocol/utils';
|
||||
import { useState } from 'react';
|
||||
import { useT } from '../use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
type ProtocolUpgradeProposalNotificationProps = {
|
||||
mode?: ProtocolUpgradeCountdownMode;
|
||||
@@ -16,6 +17,7 @@ type ProtocolUpgradeProposalNotificationProps = {
|
||||
export const ProtocolUpgradeProposalNotification = ({
|
||||
mode = ProtocolUpgradeCountdownMode.IN_BLOCKS,
|
||||
}: ProtocolUpgradeProposalNotificationProps) => {
|
||||
const t = useT();
|
||||
const [visible, setVisible] = useState(true);
|
||||
const { data, lastBlockHeight } = useNextProtocolUpgradeProposal();
|
||||
const detailsLink = useProtocolUpgradeProposalLink();
|
||||
@@ -40,10 +42,13 @@ export const ProtocolUpgradeProposalNotification = ({
|
||||
switch (mode) {
|
||||
case ProtocolUpgradeCountdownMode.IN_BLOCKS:
|
||||
countdown = (
|
||||
<>
|
||||
<span className="text-vega-orange-500">{blocksLeft}</span>{' '}
|
||||
{t('blocks')}
|
||||
</>
|
||||
<Trans
|
||||
defaults="<0>{{count}}</0> blocks"
|
||||
components={[<span className="text-vega-orange-500">count</span>]}
|
||||
values={{
|
||||
count: blocksLeft,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING:
|
||||
@@ -72,10 +77,13 @@ export const ProtocolUpgradeProposalNotification = ({
|
||||
}}
|
||||
>
|
||||
<div className="uppercase ">
|
||||
{t('The network will upgrade to %s in ', [data.vegaReleaseTag])}
|
||||
{countdown}
|
||||
{t('The network will upgrade to {{vegaReleaseTag}} in {{countdown}}', {
|
||||
vegaReleaseTag: data.vegaReleaseTag,
|
||||
countdown,
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Trans />
|
||||
{t(
|
||||
'Trading activity will be interrupted, manage your risk appropriately.'
|
||||
)}{' '}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Dialog, Icon, Intent, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import { WalletClientError } from '@vegaprotocol/wallet-client';
|
||||
import type { VegaTxState } from '../../lib/proposals-hooks/use-vega-transaction';
|
||||
import { VegaTxStatus } from '../../lib/proposals-hooks/use-vega-transaction';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export type VegaTransactionContentMap = {
|
||||
[C in VegaTxStatus]?: JSX.Element;
|
||||
@@ -28,8 +28,9 @@ export const VegaTransactionDialog = ({
|
||||
icon,
|
||||
content,
|
||||
}: VegaTransactionDialogProps) => {
|
||||
const t = useT();
|
||||
const computedIntent = intent ? intent : getIntent(transaction);
|
||||
const computedTitle = title ? title : getTitle(transaction);
|
||||
const computedTitle = title ? title : getTitle(transaction, t);
|
||||
const computedIcon = icon ? icon : getIcon(transaction);
|
||||
|
||||
return (
|
||||
@@ -86,6 +87,7 @@ interface VegaDialogProps {
|
||||
* Default dialog content
|
||||
*/
|
||||
export const VegaDialog = ({ transaction }: VegaDialogProps) => {
|
||||
const t = useT();
|
||||
const { links, network } = useVegaWallet();
|
||||
|
||||
let content = null;
|
||||
@@ -99,7 +101,7 @@ export const VegaDialog = ({ transaction }: VegaDialogProps) => {
|
||||
</p>
|
||||
{network !== 'MAINNET' && (
|
||||
<p data-testid="testnet-transaction-info">
|
||||
{t('[This is %s transaction only]').replace('%s', network)}
|
||||
{t('[This is {{network}} transaction only]', { network })}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
@@ -176,7 +178,7 @@ const getIntent = (transaction: VegaTxState) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getTitle = (transaction: VegaTxState) => {
|
||||
const getTitle = (transaction: VegaTxState, t: ReturnType<typeof useT>) => {
|
||||
switch (transaction.status) {
|
||||
case VegaTxStatus.Requested:
|
||||
return t('Confirm transaction in wallet');
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ProposalChangeMapping,
|
||||
ProposalRejectionReasonMapping,
|
||||
@@ -16,6 +15,8 @@ import {
|
||||
useOnProposalSubscription,
|
||||
type OnProposalFragmentFragment,
|
||||
} from './__generated__/Proposal';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const PROPOSAL_STATES_TO_TOAST = [
|
||||
ProposalState.STATE_DECLINED,
|
||||
@@ -27,6 +28,7 @@ const CLOSE_AFTER = 0;
|
||||
type Proposal = OnProposalFragmentFragment;
|
||||
|
||||
const ProposalDetails = ({ proposal }: { proposal: Proposal }) => {
|
||||
const t = useT();
|
||||
const change = proposal.terms.change;
|
||||
switch (change.__typename) {
|
||||
case 'UpdateNetworkParameter':
|
||||
@@ -43,8 +45,10 @@ const ProposalDetails = ({ proposal }: { proposal: Proposal }) => {
|
||||
{proposal.state === ProposalState.STATE_REJECTED &&
|
||||
proposal.rejectionReason ? (
|
||||
<p data-testid="proposal-toast-rejection-reason">
|
||||
{t('Rejection reason:')}{' '}
|
||||
{ProposalRejectionReasonMapping[proposal.rejectionReason]}
|
||||
{t('Rejection reason: {{reason}}', {
|
||||
reason:
|
||||
ProposalRejectionReasonMapping[proposal.rejectionReason],
|
||||
})}
|
||||
</p>
|
||||
) : null}
|
||||
</>
|
||||
@@ -61,24 +65,30 @@ const UpdateNetworkParameterDetails = ({
|
||||
if (change.__typename !== 'UpdateNetworkParameter') return null;
|
||||
return (
|
||||
<p data-testid="proposal-toast-network-param" className="italic">
|
||||
'{t('Update ')}
|
||||
<span className="break-all">{change.networkParameter.key}</span>
|
||||
{t(' to ')}
|
||||
<span>{change.networkParameter.value}</span>'
|
||||
<Trans
|
||||
defaults="Update <0>{{key}}</0> to {{value}}"
|
||||
values={change.networkParameter}
|
||||
components={[<span className="break-all">key</span>]}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export const ProposalToastContent = ({ proposal }: { proposal: Proposal }) => {
|
||||
const t = useT();
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const change = proposal.terms.change;
|
||||
|
||||
// Generates toast's title,
|
||||
// e.g. Update market proposal enacted, New transfer proposal open, ...
|
||||
const title = t('%s proposal %s', [
|
||||
change.__typename ? ProposalChangeMapping[change.__typename] : 'Unknown',
|
||||
ProposalStateMapping[proposal.state].toLowerCase(),
|
||||
]);
|
||||
const title = change.__typename
|
||||
? t('{{proposalChange}} proposal {{proposalState}}', {
|
||||
proposalChange: ProposalChangeMapping[change.__typename],
|
||||
proposalState: ProposalStateMapping[proposal.state].toLowerCase(),
|
||||
})
|
||||
: t('Unknown proposal {{proposalState}}', {
|
||||
proposalState: ProposalStateMapping[proposal.state].toLowerCase(),
|
||||
});
|
||||
|
||||
const enactment = Date.parse(proposal.terms.enactmentDatetime);
|
||||
|
||||
@@ -88,7 +98,9 @@ export const ProposalToastContent = ({ proposal }: { proposal: Proposal }) => {
|
||||
<ProposalDetails proposal={proposal} />
|
||||
{!isNaN(enactment) && (
|
||||
<p>
|
||||
{t('Enactment date:')} {getDateTimeFormat().format(enactment)}
|
||||
{t('Enactment date: {{date}}', {
|
||||
date: getDateTimeFormat().format(enactment),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import '@testing-library/jest-dom';
|
||||
import { locales } from '@vegaprotocol/i18n';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
// Set up i18n instance so that components have the correct default
|
||||
// en translations
|
||||
i18n.use(initReactI18next).init({
|
||||
// we init with resources
|
||||
resources: locales,
|
||||
fallbackLng: 'en',
|
||||
ns: ['proposals'],
|
||||
defaultNS: 'proposals',
|
||||
});
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const ns = 'proposals';
|
||||
export const useT = () => useTranslation(ns).t;
|
||||
@@ -1,11 +1,12 @@
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Icon, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
export const getProposalDialogTitle = (
|
||||
export const useGetProposalDialogTitle = (
|
||||
status?: ProposalState
|
||||
): string | undefined => {
|
||||
const t = useT();
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ import type { BigNumber } from 'bignumber.js';
|
||||
import { toNumberParts } from '@vegaprotocol/utils';
|
||||
|
||||
export const useNumberParts = (
|
||||
value: BigNumber | null | undefined,
|
||||
decimals: number
|
||||
value: BigNumber | null | undefined
|
||||
): [integers: string, decimalPlaces: string, separator: string | undefined] => {
|
||||
return useMemo(() => toNumberParts(value, decimals), [decimals, value]);
|
||||
return useMemo(() => toNumberParts(value), [value]);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const useTranslation = () => ({
|
||||
t: (label: string) => label,
|
||||
});
|
||||
@@ -2,8 +2,8 @@ import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { tradesWithMarketProvider } from './trades-data-provider';
|
||||
import { TradesTable } from './trades-table';
|
||||
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { useT } from './use-t';
|
||||
|
||||
interface TradesContainerProps {
|
||||
marketId: string;
|
||||
@@ -14,6 +14,7 @@ export const TradesManager = ({
|
||||
marketId,
|
||||
gridProps,
|
||||
}: TradesContainerProps) => {
|
||||
const t = useT();
|
||||
const update = useDealTicketFormValues((state) => state.updateAll);
|
||||
|
||||
const { data, error } = useDataProvider({
|
||||
|
||||
@@ -41,8 +41,8 @@ describe('TradesTable', () => {
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
'1,111,222.00',
|
||||
'20.00',
|
||||
'1,111,222',
|
||||
'20',
|
||||
getTimeFormat().format(new Date(trade.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
getTimeFormat,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
type ColDef,
|
||||
type CellClassParams,
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
import { type AgGridReactProps } from 'ag-grid-react';
|
||||
import { type Trade } from './trades-data-provider';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { useT } from './use-t';
|
||||
|
||||
export const BUY_CLASS = 'text-market-green-600 dark:text-market-green';
|
||||
export const SELL_CLASS = 'text-market-red dark:text-market-red';
|
||||
@@ -51,6 +51,7 @@ interface Props extends AgGridReactProps {
|
||||
}
|
||||
|
||||
export const TradesTable = ({ onClick, ...props }: Props) => {
|
||||
const t = useT();
|
||||
const columnDefs = useMemo<ColDef[]>(
|
||||
() => [
|
||||
{
|
||||
@@ -118,7 +119,7 @@ export const TradesTable = ({ onClick, ...props }: Props) => {
|
||||
},
|
||||
},
|
||||
],
|
||||
[onClick]
|
||||
[onClick, t]
|
||||
);
|
||||
return (
|
||||
<AgGrid
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const ns = 'trades';
|
||||
export const useT = () => useTranslation(ns).t;
|
||||
@@ -0,0 +1,14 @@
|
||||
export const useTranslation = () => ({
|
||||
t: (label: string, replacements?: Record<string, string>) => {
|
||||
let translatedLabel = label;
|
||||
if (typeof replacements === 'object' && replacements !== null) {
|
||||
Object.keys(replacements).forEach((key) => {
|
||||
translatedLabel = translatedLabel.replace(
|
||||
`{{${key}}}`,
|
||||
replacements[key]
|
||||
);
|
||||
});
|
||||
}
|
||||
return translatedLabel;
|
||||
},
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Splash } from '../splash';
|
||||
import type { ReactNode } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Button } from '../button';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
interface AsyncRendererProps<T> {
|
||||
loading: boolean;
|
||||
@@ -28,15 +28,18 @@ export function AsyncRenderer<T = object>({
|
||||
render,
|
||||
reload,
|
||||
}: AsyncRendererProps<T>) {
|
||||
const t = useT();
|
||||
if (error) {
|
||||
if (!data || (Array.isArray(data) && !data.length)) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center">
|
||||
<div className="h-12 flex flex-col items-center">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="flex h-12 flex-col items-center">
|
||||
<Splash>
|
||||
{errorMessage
|
||||
? errorMessage
|
||||
: t(`Something went wrong: ${error.message}`)}
|
||||
: t('Something went wrong: {{errorMessage}}', {
|
||||
errorMessage: error.message,
|
||||
})}
|
||||
</Splash>
|
||||
{reload && error.message === 'Timeout exceeded' && (
|
||||
<Button
|
||||
@@ -77,6 +80,7 @@ export function AsyncRendererInline<T>({
|
||||
render,
|
||||
reload,
|
||||
}: AsyncRendererProps<T>) {
|
||||
const t = useT();
|
||||
const wrapperClasses = 'text-sm';
|
||||
if (error) {
|
||||
if (!data) {
|
||||
@@ -85,7 +89,9 @@ export function AsyncRendererInline<T>({
|
||||
<p>
|
||||
{errorMessage
|
||||
? errorMessage
|
||||
: t(`Something went wrong: ${error.message}`)}
|
||||
: t('Something went wrong: {{errorMessage}}', {
|
||||
errorMessage: error.message,
|
||||
})}
|
||||
</p>
|
||||
{reload && error.message === 'Timeout exceeded' && (
|
||||
<Button
|
||||
|
||||
@@ -5,7 +5,7 @@ import { forwardRef } from 'react';
|
||||
import { VegaIcon, VegaIconNames } from '../icon';
|
||||
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
const itemClass = classNames(
|
||||
'relative flex gap-2 items-center rounded-sm p-2 text-sm',
|
||||
@@ -214,6 +214,7 @@ export const DropdownMenuCopyItem = ({
|
||||
value: string;
|
||||
text: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const [copied, setCopied] = useCopyTimeout();
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,14 +3,14 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { getIntentBackground, Intent } from '../../utils/intent';
|
||||
import { Indicator } from '../indicator';
|
||||
import { Tooltip } from '../tooltip';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
const Remainder = () => (
|
||||
<div className="bg-greys-light-200 h-[inherit] relative flex-1" />
|
||||
<div className="bg-greys-light-200 relative h-[inherit] flex-1" />
|
||||
);
|
||||
|
||||
const Target = ({
|
||||
@@ -22,6 +22,7 @@ const Target = ({
|
||||
target: string;
|
||||
decimals: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
@@ -30,20 +31,22 @@ const Target = ({
|
||||
<Indicator variant={Intent.None} />
|
||||
</div>
|
||||
<span>
|
||||
{t('Target stake')} {addDecimalsFormatNumber(target, decimals)}
|
||||
{t('Target stake {{target}}', {
|
||||
target: addDecimalsFormatNumber(target, decimals),
|
||||
})}{' '}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute top-1/2 left-1/2 -translate-x-2/4 -translate-y-1/2 px-1.5 group'
|
||||
'group absolute left-1/2 top-1/2 -translate-x-2/4 -translate-y-1/2 px-1.5'
|
||||
)}
|
||||
style={{ left: '50%' }}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'health-target w-0.5 bg-vega-dark-100 dark:bg-vega-light-100 group-hover:scale-x-150 group-hover:scale-y-108',
|
||||
'health-target bg-vega-dark-100 dark:bg-vega-light-100 group-hover:scale-y-108 w-0.5 group-hover:scale-x-150',
|
||||
{
|
||||
'h-6': !isLarge,
|
||||
'h-12': isLarge,
|
||||
@@ -66,6 +69,7 @@ const AuctionTarget = ({
|
||||
rangeLimit: number;
|
||||
decimals: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const leftPosition = new BigNumber(trigger).div(rangeLimit).multipliedBy(100);
|
||||
return (
|
||||
<Tooltip
|
||||
@@ -75,15 +79,16 @@ const AuctionTarget = ({
|
||||
<Indicator variant={Intent.None} />
|
||||
</div>
|
||||
<span>
|
||||
{t('Auction Trigger stake')}{' '}
|
||||
{addDecimalsFormatNumber(trigger, decimals)}
|
||||
{t('Auction Trigger stake {{trigger}}', {
|
||||
trigger: addDecimalsFormatNumber(trigger, decimals),
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute top-1/2 left-1/2 -translate-x-2/4 -translate-y-1/2 px-1.5 group'
|
||||
'group absolute left-1/2 top-1/2 -translate-x-2/4 -translate-y-1/2 px-1.5'
|
||||
)}
|
||||
style={{
|
||||
left: `${leftPosition}%`,
|
||||
@@ -91,7 +96,7 @@ const AuctionTarget = ({
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'health-target w-0.5 group-hover:scale-x-150 group-hover:scale-y-108 dashed-background',
|
||||
'health-target group-hover:scale-y-108 dashed-background w-0.5 group-hover:scale-x-150',
|
||||
{
|
||||
'h-6': !isLarge,
|
||||
'h-12': isLarge,
|
||||
@@ -120,6 +125,7 @@ const Level = ({
|
||||
decimals: number;
|
||||
intent: Intent;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const width = new BigNumber(commitmentAmount)
|
||||
.div(rangeLimit)
|
||||
.multipliedBy(100)
|
||||
@@ -134,9 +140,7 @@ const Level = ({
|
||||
<div className="mt-1.5 inline-flex">
|
||||
<Indicator variant={intent} />
|
||||
</div>
|
||||
<span>
|
||||
{formattedFee} {t('Fee')}
|
||||
</span>
|
||||
<span>{t('{{fee}} Fee', { fee: formattedFee })}</span>
|
||||
<div className="flex flex-col">
|
||||
<span>
|
||||
{prevLevel ? addDecimalsFormatNumber(prevLevel, decimals) : '0'} -{' '}
|
||||
@@ -149,14 +153,14 @@ const Level = ({
|
||||
return (
|
||||
<Tooltip description={tooltipContent}>
|
||||
<div
|
||||
className={classNames(`relative h-[inherit] w-full group min-w-[1px]`)}
|
||||
className="group relative h-[inherit] w-full min-w-[1px]"
|
||||
style={{
|
||||
width: `${width}%`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'relative w-full h-[inherit] group-hover:scale-y-150',
|
||||
'relative h-[inherit] w-full group-hover:scale-y-150',
|
||||
getIntentBackground(intent)
|
||||
)}
|
||||
style={{ opacity }}
|
||||
@@ -167,7 +171,7 @@ const Level = ({
|
||||
};
|
||||
|
||||
const Full = () => (
|
||||
<div className="bg-transparent w-full h-[inherit] absolute bottom-0 left-0" />
|
||||
<div className="absolute bottom-0 left-0 h-[inherit] w-full bg-transparent" />
|
||||
);
|
||||
|
||||
interface Levels {
|
||||
@@ -190,6 +194,7 @@ export const HealthBar = ({
|
||||
intent: Intent;
|
||||
triggerRatio?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const targetNumber = parseInt(target, 10);
|
||||
const rangeLimit = targetNumber * 2;
|
||||
|
||||
@@ -220,7 +225,7 @@ export const HealthBar = ({
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={classNames('health-inner relative w-full flex', {
|
||||
className={classNames('health-inner relative flex w-full', {
|
||||
'h-4': !isLarge,
|
||||
'h-8': isLarge,
|
||||
})}
|
||||
@@ -228,8 +233,8 @@ export const HealthBar = ({
|
||||
<Full />
|
||||
|
||||
<div
|
||||
className="health-bars h-[inherit] flex w-full
|
||||
gap-0.5 outline outline-vega-light-200 dark:outline-vega-dark-200"
|
||||
className="health-bars outline-vega-light-200 dark:outline-vega-dark-200 flex
|
||||
h-[inherit] w-full gap-0.5 outline"
|
||||
>
|
||||
{levels.map((p, index) => {
|
||||
const { commitmentAmount, fee } = p;
|
||||
@@ -253,11 +258,11 @@ export const HealthBar = ({
|
||||
<Tooltip
|
||||
description={
|
||||
<div className="text-vega-dark-100 dark:text-vega-light-200">
|
||||
t( 'Providers greater than 2x target stake not shown' )
|
||||
{t('Providers greater than 2x target stake not shown')}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="h-[inherit] relative flex-1 leading-4">...</div>
|
||||
<div className="relative h-[inherit] flex-1 leading-4">...</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import classNames from 'classnames';
|
||||
import { useRef, useState, useEffect } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Button } from '../button';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
type ShowMoreProps = {
|
||||
children: ReactNode;
|
||||
@@ -15,6 +15,7 @@ export const ShowMore = ({
|
||||
closedMaxHeightPx = 125,
|
||||
overlayColourOverrides,
|
||||
}: ShowMoreProps) => {
|
||||
const t = useT();
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { SunIcon, MoonIcon } from './icons';
|
||||
import { Toggle } from '../toggle';
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const ThemeSwitcher = ({
|
||||
className,
|
||||
@@ -10,6 +10,7 @@ export const ThemeSwitcher = ({
|
||||
className?: string;
|
||||
withMobile?: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { theme, setTheme } = useThemeSwitcher();
|
||||
const button = (
|
||||
<button
|
||||
@@ -35,7 +36,7 @@ export const ThemeSwitcher = ({
|
||||
];
|
||||
return withMobile ? (
|
||||
<>
|
||||
<div className="flex grow gap-6 md:hidden whitespace-nowrap justify-between">
|
||||
<div className="flex grow justify-between gap-6 whitespace-nowrap md:hidden">
|
||||
{button}{' '}
|
||||
<Toggle
|
||||
name="theme-switch"
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import classNames from 'classnames';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { Icon } from '../icon';
|
||||
import { ToastPosition, useToastsConfiguration, useToasts } from './use-toasts';
|
||||
import { useCallback } from 'react';
|
||||
import { Intent } from '../../utils/intent';
|
||||
|
||||
const TEST_TOAST = {
|
||||
id: 'test-toast',
|
||||
intent: Intent.Primary,
|
||||
content: <>{t('This is an example of a toast notification')}</>,
|
||||
onClose: () => useToasts.getState().remove('test-toast'),
|
||||
};
|
||||
import { useT } from '../../use-t';
|
||||
|
||||
export const ToastPositionSetter = () => {
|
||||
const t = useT();
|
||||
const setPostion = useToastsConfiguration((store) => store.setPosition);
|
||||
const position = useToastsConfiguration((store) => store.position);
|
||||
const setToast = useToasts((store) => store.setToast);
|
||||
const handleChange = useCallback(
|
||||
(position: ToastPosition) => {
|
||||
setPostion(position);
|
||||
setToast(TEST_TOAST);
|
||||
setToast({
|
||||
id: 'test-toast',
|
||||
intent: Intent.Primary,
|
||||
content: <>{t('This is an example of a toast notification')}</>,
|
||||
onClose: () => useToasts.getState().remove('test-toast'),
|
||||
});
|
||||
},
|
||||
[setToast, setPostion]
|
||||
[setToast, setPostion, t]
|
||||
);
|
||||
const buttonCssClasses =
|
||||
'flex items-center px-1 py-1 relative rounded bg-vega-clight-400 dark:bg-vega-cdark-400';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user