Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7318d6088a | ||
|
|
8e898cfd78 | ||
|
|
f377e07996 | ||
|
|
090d340364 | ||
|
|
6d32fa7362 | ||
|
|
1a7682c3c9 | ||
|
|
3294c0cabe | ||
|
|
c10084d441 | ||
|
|
96658134ee | ||
|
|
a070504d2e | ||
|
|
f891caf08b |
+2
-2
@@ -48,12 +48,12 @@ cypress.env.json
|
||||
# Next.js
|
||||
.next
|
||||
|
||||
#cypress
|
||||
# cypress
|
||||
/apps/**/cypress/reports/
|
||||
/apps/**/cypress/downloads/
|
||||
/apps/**/fixtures/wallet/node**
|
||||
|
||||
#console-test
|
||||
# apps/trading/e2e
|
||||
__pycache__/
|
||||
apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Add files here to ignore them from prettier formatting
|
||||
|
||||
/dist
|
||||
/dist-result
|
||||
/coverage
|
||||
__generated__
|
||||
__generated___
|
||||
@@ -13,3 +14,10 @@ apps/static/src/assets/testnet-tranches.json
|
||||
/apps/**/cypress/downloads/
|
||||
|
||||
/.nx/cache
|
||||
|
||||
# apps/trading/e2e
|
||||
__pycache__/
|
||||
apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
apps/trading/e2e/traces/
|
||||
.pytest_cache/
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
@@ -74,15 +74,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/explorer/netlify.toml netlify.toml",
|
||||
"nx build explorer"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": [],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||
import { AssetLink } from '../links';
|
||||
|
||||
export type AssetBalanceProps = {
|
||||
@@ -23,12 +23,12 @@ const AssetBalance = ({
|
||||
|
||||
const label =
|
||||
!loading && asset && asset.decimals
|
||||
? addDecimalsFormatNumber(price, asset.decimals)
|
||||
? addDecimalsFixedFormatNumber(price, asset.decimals)
|
||||
: price;
|
||||
|
||||
return (
|
||||
<div className="inline-block">
|
||||
<span>{label}</span>{' '}
|
||||
<span className="font-mono">{label}</span>{' '}
|
||||
{showAssetLink && asset?.id ? (
|
||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
||||
) : null}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { type AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||
import {
|
||||
useAssetTypeMapping,
|
||||
useAssetStatusMapping,
|
||||
type AssetFieldsFragment,
|
||||
} from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { type AgGridReact } from 'ag-grid-react';
|
||||
@@ -15,6 +18,8 @@ type AssetsTableProps = {
|
||||
data: AssetFieldsFragment[] | null;
|
||||
};
|
||||
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
const assetTypeMapping = useAssetTypeMapping();
|
||||
const assetStatusMapping = useAssetStatusMapping();
|
||||
const navigate = useNavigate();
|
||||
const ref = useRef<AgGridReact>(null);
|
||||
const showColumnsOnDesktop = () => {
|
||||
@@ -47,14 +52,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
field: 'source.__typename',
|
||||
hide: window.innerWidth < BREAKPOINT_MD,
|
||||
valueFormatter: ({ value }: { value?: string }) =>
|
||||
value ? AssetTypeMapping[value].value : '',
|
||||
value ? assetTypeMapping[value].value : '',
|
||||
},
|
||||
{
|
||||
headerName: t('Status'),
|
||||
field: 'status',
|
||||
hide: window.innerWidth < BREAKPOINT_MD,
|
||||
valueFormatter: ({ value }: { value?: string }) =>
|
||||
value ? AssetStatusMapping[value].value : '',
|
||||
value ? assetStatusMapping[value].value : '',
|
||||
},
|
||||
{
|
||||
colId: 'actions',
|
||||
@@ -69,7 +74,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||
value ? (
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
onClick={() => {
|
||||
navigate(value);
|
||||
}}
|
||||
>
|
||||
@@ -80,7 +85,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
),
|
||||
},
|
||||
],
|
||||
[navigate]
|
||||
[navigate, assetStatusMapping, assetTypeMapping]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -15,6 +15,7 @@ import isUndefined from 'lodash/isUndefined';
|
||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||
import { TxDetailsContractCall } from './tx-contract-call';
|
||||
|
||||
interface ChainEventProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -38,7 +39,7 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { builtin, erc20, erc20Multisig, stakingEvent } =
|
||||
const { builtin, erc20, erc20Multisig, stakingEvent, contractCall } =
|
||||
txData.command.chainEvent;
|
||||
|
||||
// Builtin Asset events
|
||||
@@ -140,6 +141,10 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (contractCall) {
|
||||
return <TxDetailsContractCall contractCall={contractCall} />;
|
||||
}
|
||||
|
||||
// If we hit this return, tx-shared-details should give a basic overview
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { decodeEthCallResult } from './tx-contract-call';
|
||||
import { base64 } from 'ethers/lib/utils';
|
||||
import { defaultAbiCoder } from '@ethersproject/abi';
|
||||
import { BigNumber } from '@ethersproject/bignumber';
|
||||
|
||||
describe('decodeEthCallResult', () => {
|
||||
it('should decode contractData correctly (mocked)', () => {
|
||||
const mockContractData = base64.encode(
|
||||
defaultAbiCoder.encode(['int256'], [BigNumber.from(123)])
|
||||
);
|
||||
const result = decodeEthCallResult(mockContractData);
|
||||
expect(result).toBe('123');
|
||||
});
|
||||
|
||||
it('should decode contractData correctly (known data)', () => {
|
||||
const mockContractData = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH8cueyY=';
|
||||
const result = decodeEthCallResult(mockContractData);
|
||||
expect(result).toBe('3435020581670');
|
||||
});
|
||||
|
||||
it('should return "-" when an error occurs', () => {
|
||||
const mockContractData = 'invalid_data';
|
||||
const result = decodeEthCallResult(mockContractData);
|
||||
expect(result).toBe('-');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import { TableCell, TableRow } from '../../../table';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
EthExplorerLink,
|
||||
EthExplorerLinkTypes,
|
||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
||||
import { BigNumber } from 'ethers';
|
||||
import OracleLink from '../../../links/oracle-link/oracle-link';
|
||||
import { useExplorerOracleSpecByIdQuery } from '../../../../routes/oracles/__generated__/Oracles';
|
||||
import { OracleEthSource } from '../../../../routes/oracles/components/oracle-eth-source';
|
||||
|
||||
/**
|
||||
* Decodes the b64/ABIcoded result from an eth cal
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export function decodeEthCallResult(contractData: string): string {
|
||||
try {
|
||||
const rawResult = defaultAbiCoder.decode(
|
||||
['int256'],
|
||||
base64.decode(contractData)
|
||||
);
|
||||
|
||||
// Finally, convert the resulting BigNumber in to a string
|
||||
const res = BigNumber.from(rawResult[0]).toString();
|
||||
return res;
|
||||
} catch (e) {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
interface TxDetailsContractCallProps {
|
||||
contractCall: components['schemas']['vegaEthContractCallEvent'];
|
||||
}
|
||||
|
||||
export const TxDetailsContractCall = ({
|
||||
contractCall,
|
||||
}: TxDetailsContractCallProps) => {
|
||||
const { data } = useExplorerOracleSpecByIdQuery({
|
||||
variables: {
|
||||
id: contractCall.specId || '1',
|
||||
},
|
||||
});
|
||||
|
||||
if (!contractCall || !contractCall.result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{contractCall.specId && (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Oracle')}</TableCell>
|
||||
<TableCell>
|
||||
<OracleLink
|
||||
id={contractCall.specId}
|
||||
hasSeenOracleReports={true}
|
||||
status={data?.oracleSpec?.dataSourceSpec.spec.status || '-'}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{contractCall.blockHeight && (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('ETH block')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={contractCall.blockHeight}
|
||||
type={EthExplorerLinkTypes.block}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{data?.oracleSpec?.dataSourceSpec && (
|
||||
<OracleEthSource
|
||||
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Result')}</TableCell>
|
||||
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,51 +1,11 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableWithTbody } from '../../table';
|
||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
||||
import { ChainEvent } from './chain-events';
|
||||
import { BigNumber } from 'ethers';
|
||||
|
||||
import type { AbiType } from '../../../lib/encoders/abis/abi-types';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
|
||||
interface AbiOutput {
|
||||
type: AbiType;
|
||||
internalType: AbiType;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the b64/ABIcoded result from an eth cal
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export function decodeEthCallResult(
|
||||
data: BlockExplorerTransactionResult
|
||||
): string {
|
||||
const ethResult = data.command.chainEvent?.contractCall.result;
|
||||
|
||||
try {
|
||||
// Decode the result string: base64 => uint8array
|
||||
const data = base64.decode(ethResult);
|
||||
|
||||
// Parse the escaped ABI in to an object
|
||||
const abi = JSON.parse(
|
||||
'[{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]'
|
||||
);
|
||||
// Pull the expected types out of the Oracles ABI
|
||||
const types: AbiType[] = abi[0].outputs.map((o: AbiOutput) => o.type);
|
||||
|
||||
const rawResult = defaultAbiCoder.decode(types, data);
|
||||
|
||||
// Finally, convert the resulting BigNumber in to a string
|
||||
const res = BigNumber.from(rawResult[0]).toString();
|
||||
return res;
|
||||
} catch (e) {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
interface TxDetailsChainEventProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AccountManager } from '@vegaprotocol/accounts';
|
||||
import { useCallback } from 'react';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { useExplorerPartyAssetsQuery } from '../__generated__/Party-assets';
|
||||
import { AssetLink, MarketLink } from '../../../../components/links';
|
||||
import AssetBalance from '../../../../components/asset-balance/asset-balance';
|
||||
import { AccountTypeMapping } from '@vegaprotocol/types';
|
||||
|
||||
interface PartyAccountsProps {
|
||||
partyId: string;
|
||||
@@ -12,21 +13,71 @@ interface PartyAccountsProps {
|
||||
* appearing first and... tbd
|
||||
*/
|
||||
export const PartyAccounts = ({ partyId }: PartyAccountsProps) => {
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const onClickAsset = useCallback(
|
||||
(assetId?: string) => {
|
||||
assetId && openAssetDetailsDialog(assetId);
|
||||
},
|
||||
[openAssetDetailsDialog]
|
||||
);
|
||||
const { data } = useExplorerPartyAssetsQuery({
|
||||
variables: { partyId },
|
||||
});
|
||||
|
||||
const party = data?.partiesConnection?.edges[0]?.node;
|
||||
const accounts =
|
||||
party?.accountsConnection?.edges?.filter((edge) => edge?.node) || [];
|
||||
|
||||
return (
|
||||
<div className="block min-h-44 h-60 4 w-full border-red-800 relative">
|
||||
<AccountManager
|
||||
partyId={partyId}
|
||||
onClickAsset={onClickAsset}
|
||||
isReadOnly={true}
|
||||
/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="text-right px-4">Balance</th>
|
||||
<th className="text-left px-4">Type</th>
|
||||
<th className="text-left px-4">Market</th>
|
||||
<th className="text-left px-4">Asset</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{accounts
|
||||
.sort((a, b) => {
|
||||
// Sort by asset id, then market id, with general accounts first
|
||||
if (!a) {
|
||||
return 1;
|
||||
}
|
||||
if (!b) {
|
||||
return -1;
|
||||
}
|
||||
if (a.node.asset.id !== b.node.asset.id) {
|
||||
return a.node.asset.id.localeCompare(b.node.asset.id);
|
||||
}
|
||||
if (a.node.type === 'ACCOUNT_TYPE_GENERAL') return -1;
|
||||
if (b.node.type === 'ACCOUNT_TYPE_GENERAL') return 1;
|
||||
if (a.node.market && b.node.market) {
|
||||
return a.node.market.id.localeCompare(b.node.market.id);
|
||||
} else {
|
||||
return a.node.type.localeCompare(b.node.type);
|
||||
}
|
||||
})
|
||||
.map((e) => {
|
||||
if (!e) return null;
|
||||
const { type, asset, balance, market } = e.node;
|
||||
|
||||
return (
|
||||
<tr className="border-t border-neutral-300 dark:border-neutral-600">
|
||||
<td className="px-4 text-right">
|
||||
<AssetBalance
|
||||
assetId={asset.id}
|
||||
price={balance}
|
||||
showAssetSymbol={true}
|
||||
/>
|
||||
</td>
|
||||
<td className="px-4">{AccountTypeMapping[type]}</td>
|
||||
<td className="px-4">
|
||||
{market?.id ? <MarketLink id={market.id} /> : '-'}
|
||||
</td>
|
||||
<td className="px-4">
|
||||
<AssetLink assetId={asset.id} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -302,14 +302,17 @@ context(
|
||||
|
||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||
.contains(name)
|
||||
.parent()
|
||||
.siblings(txTimeout)
|
||||
.should((elementAmount) => {
|
||||
const displayedAmount = parseFloat(elementAmount.text());
|
||||
// @ts-ignore clash between jest and cypress
|
||||
expect(displayedAmount).be.gte(expectedAmount);
|
||||
.parent() // back to currency-title
|
||||
.parent() // back to container
|
||||
.within(() => {
|
||||
cy.get(
|
||||
'[data-account-type="account_type_general"] [data-value]'
|
||||
).should((elementAmount) => {
|
||||
const displayedAmount = parseFloat(elementAmount.text());
|
||||
// @ts-ignore clash between jest and cypress
|
||||
expect(displayedAmount).be.gte(expectedAmount);
|
||||
});
|
||||
});
|
||||
|
||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||
.contains(name)
|
||||
.parent()
|
||||
|
||||
@@ -256,10 +256,7 @@ export function validateWalletCurrency(
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getByTestId('currency-value', txTimeout).should(
|
||||
'have.text',
|
||||
expectedAmount
|
||||
);
|
||||
cy.get('[data-value]', txTimeout).should('have.text', expectedAmount);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -49,10 +49,6 @@ There are a few different configuration options offered for this app:
|
||||
| `NX_ETH_WALLET_MNEMONIC` (optional) | The mnemonic to be used to sign transactions with in browser |
|
||||
| `NX_LOCAL_PROVIDER_URL` (optional) | The local node to use to send transaction to when signing in browser |
|
||||
|
||||
## Example configs:
|
||||
|
||||
For example configurations, check out our [netlify.toml](./netlify.toml).
|
||||
|
||||
## Testing
|
||||
|
||||
To run the minimal set of unit tests, run the following:
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
@@ -69,15 +69,6 @@
|
||||
"jestConfig": "apps/governance/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/governance/netlify.toml netlify.toml",
|
||||
"nx build token"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": [],
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
|
||||
import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SplashError } from './components/splash-error';
|
||||
@@ -164,13 +164,14 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
return (
|
||||
<Splash>
|
||||
<SplashLoader />
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
const loading = (
|
||||
<Splash>
|
||||
<SplashLoader />
|
||||
</Splash>
|
||||
);
|
||||
|
||||
return children;
|
||||
if (!loaded) {
|
||||
return loading;
|
||||
}
|
||||
return <Suspense fallback={loading}>{children}</Suspense>;
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
useNodeSwitcherStore,
|
||||
DocsLinks,
|
||||
NodeFailure,
|
||||
AppLoader as Loader,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { ENV } from './config';
|
||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||
@@ -352,9 +353,11 @@ function App() {
|
||||
useInitializeEnv();
|
||||
|
||||
return (
|
||||
<NetworkLoader cache={cache}>
|
||||
<AppContainer />
|
||||
</NetworkLoader>
|
||||
<React.Suspense fallback={<Loader />}>
|
||||
<NetworkLoader cache={cache}>
|
||||
<AppContainer />
|
||||
</NetworkLoader>
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../../libs/i18n/src/locales
|
||||
@@ -114,6 +114,16 @@ export const usePollForDelegations = () => {
|
||||
isAssetTypeERC20(a.asset) &&
|
||||
a.asset.source.contractAddress === vegaToken.address;
|
||||
|
||||
const isVesting =
|
||||
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
||||
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS;
|
||||
|
||||
let icon = noIcon;
|
||||
if (isVega) {
|
||||
if (isVesting) icon = vegaVesting;
|
||||
else icon = vegaBlack;
|
||||
}
|
||||
|
||||
return {
|
||||
isVega,
|
||||
name: a.asset.name,
|
||||
@@ -124,14 +134,7 @@ export const usePollForDelegations = () => {
|
||||
balance: new BigNumber(
|
||||
addDecimal(a.balance, a.asset.decimals)
|
||||
),
|
||||
image: isVega
|
||||
? vegaBlack
|
||||
: a.type ===
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
||||
a.type ===
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS
|
||||
? vegaVesting
|
||||
: noIcon,
|
||||
image: icon,
|
||||
border: isVega,
|
||||
address: isAssetTypeERC20(a.asset)
|
||||
? a.asset.source.contractAddress
|
||||
|
||||
@@ -11,7 +11,10 @@ import { BigNumber } from '../../lib/bignumber';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
import Routes from '../../routes/routes';
|
||||
import { BulletHeader } from '../bullet-header';
|
||||
import type { WalletCardAssetProps } from '../wallet-card';
|
||||
import type {
|
||||
WalletCardAssetProps,
|
||||
WalletCardAssetWithMultipleBalancesProps,
|
||||
} from '../wallet-card';
|
||||
import {
|
||||
WalletCard,
|
||||
WalletCardActions,
|
||||
@@ -27,6 +30,7 @@ import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { toBigNum } from '@vegaprotocol/utils';
|
||||
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
|
||||
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
|
||||
import omit from 'lodash/omit';
|
||||
|
||||
export const VegaWallet = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -99,12 +103,29 @@ const VegaWalletAssetList = ({ accounts }: VegaWalletAssetsListProps) => {
|
||||
if (!accounts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const groupedByAsset = accounts.reduce((all, a) => {
|
||||
const foundIndex = all.findIndex((acc) => acc.assetId === a.assetId);
|
||||
if (foundIndex > -1) {
|
||||
const found = all[foundIndex];
|
||||
all[foundIndex] = {
|
||||
...found,
|
||||
balances: [...found.balances, { balance: a.balance, type: a.type }],
|
||||
};
|
||||
return all;
|
||||
}
|
||||
const acc = {
|
||||
...omit(a, 'balance', 'type'),
|
||||
balances: [{ balance: a.balance, type: a.type }],
|
||||
};
|
||||
return [...all, acc];
|
||||
}, [] as WalletCardAssetWithMultipleBalancesProps[]);
|
||||
return (
|
||||
<>
|
||||
<WalletCardHeader>
|
||||
<BulletHeader tag="h2">{t('assets')}</BulletHeader>
|
||||
</WalletCardHeader>
|
||||
{accounts.map((a, i) => (
|
||||
{groupedByAsset.map((a, i) => (
|
||||
<WalletCardAsset key={i} {...a} />
|
||||
))}
|
||||
</>
|
||||
@@ -182,6 +203,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
subheading={t('Associated')}
|
||||
symbol="VEGA"
|
||||
balance={currentStakeAvailable}
|
||||
allowZeroBalance={true}
|
||||
/>
|
||||
{totalPending.eq(0) ? null : (
|
||||
<>
|
||||
@@ -192,6 +214,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
subheading={t('Pending association')}
|
||||
symbol="VEGA"
|
||||
balance={totalPending}
|
||||
allowZeroBalance={true}
|
||||
/>
|
||||
<WalletCardAsset
|
||||
image={vegaWhite}
|
||||
@@ -200,6 +223,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
subheading={t('Total associated after pending')}
|
||||
symbol="VEGA"
|
||||
balance={pendingStakeAmount}
|
||||
allowZeroBalance={true}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -103,7 +103,7 @@ export const WalletCardActions = ({
|
||||
return <div className="flex justify-end gap-2 mb-4">{children}</div>;
|
||||
};
|
||||
|
||||
export interface WalletCardAssetProps {
|
||||
export type WalletCardAssetProps = {
|
||||
image: string;
|
||||
name: string;
|
||||
symbol: string;
|
||||
@@ -113,42 +113,61 @@ export interface WalletCardAssetProps {
|
||||
border?: boolean;
|
||||
subheading?: string;
|
||||
type?: Schema.AccountType;
|
||||
}
|
||||
allowZeroBalance?: boolean;
|
||||
};
|
||||
|
||||
export type WalletCardAssetWithMultipleBalancesProps = Omit<
|
||||
WalletCardAssetProps,
|
||||
'balance' | 'type'
|
||||
> & {
|
||||
balances: { balance: BigNumber; type?: Schema.AccountType }[];
|
||||
};
|
||||
|
||||
export const WalletCardAsset = ({
|
||||
image,
|
||||
name,
|
||||
symbol,
|
||||
balance,
|
||||
decimals,
|
||||
assetId,
|
||||
border,
|
||||
subheading,
|
||||
type,
|
||||
}: WalletCardAssetProps) => {
|
||||
const [integers, decimalsPlaces, separator] = useNumberParts(
|
||||
balance,
|
||||
decimals
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const consoleLink = useLinks(DApp.Console);
|
||||
const transferAssetLink = (assetId: string) =>
|
||||
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
|
||||
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
|
||||
allowZeroBalance = false,
|
||||
...props
|
||||
}: WalletCardAssetProps | WalletCardAssetWithMultipleBalancesProps) => {
|
||||
const balance = 'balance' in props ? props.balance : undefined;
|
||||
const type = 'type' in props ? props.type : undefined;
|
||||
const balances =
|
||||
'balances' in props
|
||||
? props.balances
|
||||
: balance
|
||||
? [{ balance, type }]
|
||||
: undefined;
|
||||
|
||||
const isRedeemable =
|
||||
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
|
||||
const values =
|
||||
balances &&
|
||||
balances.length > 0 &&
|
||||
balances
|
||||
.filter((b) => allowZeroBalance || !b.balance.isZero())
|
||||
.sort((a, b) => {
|
||||
const order = [
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS,
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
undefined,
|
||||
];
|
||||
return order.indexOf(a.type) - order.indexOf(b.type);
|
||||
})
|
||||
.map(({ balance, type }, i) => (
|
||||
<CurrencyValue
|
||||
key={i}
|
||||
balance={balance}
|
||||
decimals={decimals}
|
||||
type={type}
|
||||
assetId={assetId}
|
||||
/>
|
||||
));
|
||||
|
||||
const accountTypeTooltip = useMemo(() => {
|
||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
|
||||
return t('VestedRewardsTooltip');
|
||||
}
|
||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
|
||||
return t('VestingRewardsTooltip', { baseRate });
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [baseRate, t, type]);
|
||||
if (!values || values.length === 0) return;
|
||||
|
||||
return (
|
||||
<div className="flex flex-nowrap gap-2 mt-2 mb-4">
|
||||
@@ -169,35 +188,92 @@ export const WalletCardAsset = ({
|
||||
{subheading || symbol}
|
||||
</div>
|
||||
</div>
|
||||
{type ? (
|
||||
<div className="mb-[2px] flex gap-2 items-baseline">
|
||||
<Tooltip description={accountTypeTooltip}>
|
||||
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
|
||||
{Schema.AccountTypeMapping[type]}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{isRedeemable ? (
|
||||
<Tooltip description={t('RedeemRewardsTooltip')}>
|
||||
<AnchorButton
|
||||
variant="primary"
|
||||
size="xs"
|
||||
href={transferAssetLink(assetId)}
|
||||
target="_blank"
|
||||
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
|
||||
>
|
||||
{t('Redeem')}
|
||||
</AnchorButton>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="basis-full font-mono" data-testid="currency-value">
|
||||
<span>
|
||||
{integers}
|
||||
{separator}
|
||||
</span>
|
||||
<span className="text-neutral-400">{decimalsPlaces}</span>
|
||||
{values}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useAccountTypeTooltip = (type?: Schema.AccountType) => {
|
||||
const { t } = useTranslation();
|
||||
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
|
||||
const accountTypeTooltip = useMemo(() => {
|
||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
|
||||
return t('VestedRewardsTooltip');
|
||||
}
|
||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
|
||||
return t('VestingRewardsTooltip', { baseRate });
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [baseRate, t, type]);
|
||||
|
||||
return accountTypeTooltip;
|
||||
};
|
||||
|
||||
const CurrencyValue = ({
|
||||
balance,
|
||||
decimals,
|
||||
type,
|
||||
assetId,
|
||||
}: {
|
||||
balance: BigNumber;
|
||||
decimals: number;
|
||||
type?: Schema.AccountType;
|
||||
assetId?: string;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const consoleLink = useLinks(DApp.Console);
|
||||
const transferAssetLink = (assetId: string) =>
|
||||
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
|
||||
|
||||
const [integers, decimalsPlaces, separator] = useNumberParts(
|
||||
balance,
|
||||
decimals
|
||||
);
|
||||
const accountTypeTooltip = useAccountTypeTooltip(type);
|
||||
|
||||
const accountType = type && (
|
||||
<Tooltip description={accountTypeTooltip}>
|
||||
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
|
||||
{Schema.AccountTypeMapping[type]}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
const isRedeemable =
|
||||
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
|
||||
const redeemBtn = isRedeemable ? (
|
||||
<Tooltip description={t('RedeemRewardsTooltip')}>
|
||||
<AnchorButton
|
||||
variant="primary"
|
||||
size="xs"
|
||||
href={transferAssetLink(assetId)}
|
||||
target="_blank"
|
||||
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
|
||||
>
|
||||
{t('Redeem')}
|
||||
</AnchorButton>
|
||||
</Tooltip>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="basis-full font-mono mb-1"
|
||||
data-account-type={type?.toLowerCase() || 'unspecified'}
|
||||
data-testid="currency-value"
|
||||
>
|
||||
{type && (
|
||||
<div data-type className="flex gap-1">
|
||||
{accountType}
|
||||
{redeemBtn}
|
||||
</div>
|
||||
)}
|
||||
<div data-value>
|
||||
<span>
|
||||
{integers}
|
||||
{separator}
|
||||
</span>
|
||||
<span className="text-neutral-400">{decimalsPlaces}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,29 +1,42 @@
|
||||
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';
|
||||
|
||||
import dev from './translations/dev.json';
|
||||
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({
|
||||
// we init with resources
|
||||
resources: {
|
||||
en: {
|
||||
translations: {
|
||||
...dev,
|
||||
},
|
||||
},
|
||||
},
|
||||
lng: undefined,
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
supportedLngs: ['en'],
|
||||
load: 'languageOnly',
|
||||
debug: isInDev,
|
||||
// have a common namespace used around the full app
|
||||
ns: ['translations'],
|
||||
defaultNS: 'translations',
|
||||
ns: ['governance'],
|
||||
defaultNS: 'governance',
|
||||
keySeparator: false, // we use content as keys
|
||||
|
||||
nsSeparator: false,
|
||||
backend,
|
||||
saveMissing: useLocize && !!process.env.NX_LOCIZE_API_KEY,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import dev from './i18n/translations/dev.json';
|
||||
import { locales } from '@vegaprotocol/i18n';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
@@ -12,16 +12,10 @@ import ResizeObserver from 'resize-observer-polyfill';
|
||||
// en translations
|
||||
i18n.use(initReactI18next).init({
|
||||
// we init with resources
|
||||
resources: {
|
||||
en: {
|
||||
translations: {
|
||||
...dev,
|
||||
},
|
||||
},
|
||||
},
|
||||
resources: locales,
|
||||
fallbackLng: 'en',
|
||||
ns: ['translations'],
|
||||
defaultNS: 'translations',
|
||||
ns: ['governance'],
|
||||
defaultNS: 'governance',
|
||||
});
|
||||
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
@@ -82,15 +82,6 @@
|
||||
"jestConfig": "apps/liquidity-provision-dashboard/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/liquidity-provision-dashboard/netlify.toml netlify.toml",
|
||||
"nx build liquidity-provision-dashboard"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": [],
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
@@ -66,15 +66,6 @@
|
||||
"jestConfig": "apps/multisig-signer/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/multisig-signer/netlify.toml netlify.toml",
|
||||
"nx build multisig-signer"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": [],
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
Access-Control-Allow-Origin = "*"
|
||||
@@ -46,15 +46,6 @@
|
||||
"buildTarget": "static:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/static/netlify.toml netlify.toml",
|
||||
"nx build static"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { Links } from '../../lib/links';
|
||||
import classNames from 'classnames';
|
||||
import { NavLink, Outlet } from 'react-router-dom';
|
||||
|
||||
export const Assets = () => {
|
||||
const t = useT();
|
||||
const linkClasses = ({ isActive }: { isActive: boolean }) => {
|
||||
return classNames('border-b-2 border-transparent', {
|
||||
'border-vega-yellow': isActive,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { GetStartedCheckList } from '../../components/welcome-dialog';
|
||||
import {
|
||||
@@ -8,8 +7,10 @@ import {
|
||||
} from '../../components/welcome-dialog/use-get-onboarding-step';
|
||||
import { Links } from '../../lib/links';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const DepositGetStarted = () => {
|
||||
const t = useT();
|
||||
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const step = useGetOnboardingStep();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const Disclaimer = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<>
|
||||
<h1 className="text-4xl uppercase xl:text-5xl font-alpha calt">
|
||||
@@ -8,37 +9,44 @@ export const Disclaimer = () => {
|
||||
</h1>
|
||||
<p className="mt-10 mb-6">
|
||||
{t(
|
||||
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
|
||||
'DISCLAIMER_P1',
|
||||
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-6">
|
||||
{t(
|
||||
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
|
||||
'DISCLAIMER_P2',
|
||||
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-6">
|
||||
{t(
|
||||
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
|
||||
'DISCLAIMER_P3',
|
||||
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'DISCLAIMER_P4',
|
||||
'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
|
||||
'DISCLAIMER_P5',
|
||||
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
|
||||
'DISCLAIMER_P6',
|
||||
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
|
||||
'DISCLAIMER_P7',
|
||||
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { FeesContainer } from '../../components/fees-container';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const Fees = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<div className="container p-4 mx-auto">
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Fees')}</h1>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
SidebarButton,
|
||||
@@ -6,8 +5,10 @@ import {
|
||||
ViewType,
|
||||
} from '../../components/sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const LiquiditySidebar = () => {
|
||||
const t = useT();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { matchFilter, lpAggregatedDataProvider } from '@vegaprotocol/liquidity';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { Tab, Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { LiquidityContainer } from '../../components/liquidity-container';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const enum LiquidityTabs {
|
||||
Active = 'active',
|
||||
@@ -24,6 +24,7 @@ export const LiquidityViewContainer = ({
|
||||
}: {
|
||||
marketId: string | undefined;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const [tab, setTab] = useState<string | undefined>(undefined);
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
export const NO_MARKET = t('No market');
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
getExpiryDate,
|
||||
getMarketExpiryDate,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Last24hPriceChange,
|
||||
Last24hVolume,
|
||||
@@ -31,12 +30,14 @@ import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { PriceCell } from '@vegaprotocol/datagrid';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
interface MarketHeaderStatsProps {
|
||||
market: Market;
|
||||
}
|
||||
|
||||
export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
||||
const t = useT();
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
|
||||
@@ -234,6 +235,7 @@ const useFormatCountdown = (
|
||||
startTime?: number,
|
||||
every?: number
|
||||
) => {
|
||||
const t = useT();
|
||||
if (startTime && every) {
|
||||
const diff = every - ((now - startTime) % every);
|
||||
const hours = (diff / 3.6e6) | 0;
|
||||
@@ -276,6 +278,7 @@ const ExpiryTooltipContent = ({
|
||||
market,
|
||||
explorerUrl,
|
||||
}: ExpiryTooltipContentProps) => {
|
||||
const t = useT();
|
||||
if (market.marketTimestamps.close === null) {
|
||||
const oracleId =
|
||||
market.tradableInstrument.instrument.product.__typename === 'Future'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { ExternalLink, Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -12,6 +11,8 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Links } from '../../lib/links';
|
||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||
return markPrice && decimalPlaces
|
||||
@@ -57,6 +58,7 @@ const TitleUpdater = ({
|
||||
};
|
||||
|
||||
export const MarketPage = () => {
|
||||
const t = useT();
|
||||
const { marketId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
@@ -111,10 +113,18 @@ export const MarketPage = () => {
|
||||
{t('This market URL is not available any more.')}
|
||||
</p>
|
||||
<p className="justify-center text-sm">
|
||||
{t(`Please choose another market from the`)}{' '}
|
||||
<ExternalLink onClick={() => navigate(Links.MARKETS())}>
|
||||
{t('market list')}
|
||||
</ExternalLink>
|
||||
<Trans
|
||||
defaults="Please choose another market from the <0>market list<0>"
|
||||
ns={ns}
|
||||
components={[
|
||||
<ExternalLink
|
||||
onClick={() => navigate(Links.MARKETS())}
|
||||
key="link"
|
||||
>
|
||||
market list
|
||||
</ExternalLink>,
|
||||
]}
|
||||
/>
|
||||
</p>
|
||||
</span>
|
||||
</Splash>
|
||||
|
||||
@@ -4,10 +4,8 @@ import { LayoutPriority } from 'allotment';
|
||||
import classNames from 'classnames';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { OracleBanner, useMarket } from '@vegaprotocol/markets';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { Filter } from '@vegaprotocol/orders';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
ResizableGrid,
|
||||
@@ -21,6 +19,7 @@ import {
|
||||
MarketTerminationBanner,
|
||||
} from '../../components/market-banner';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
interface TradeGridProps {
|
||||
market: Market | null;
|
||||
@@ -35,6 +34,7 @@ const MainGrid = memo(
|
||||
marketId: string;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { data: market } = useMarket(marketId);
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'top' });
|
||||
const [sizesMiddle, handleOnMiddleLayoutChange] = usePaneLayout({
|
||||
@@ -125,13 +125,13 @@ const MainGrid = memo(
|
||||
name={t('Open')}
|
||||
menu={<TradingViews.activeOrders.menu />}
|
||||
>
|
||||
<TradingViews.orders.component filter={Filter.Open} />
|
||||
<TradingViews.activeOrders.component />
|
||||
</Tab>
|
||||
<Tab id="closed-orders" name={t('Closed')}>
|
||||
<TradingViews.orders.component filter={Filter.Closed} />
|
||||
<TradingViews.closedOrders.component />
|
||||
</Tab>
|
||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||
<TradingViews.orders.component filter={Filter.Rejected} />
|
||||
<TradingViews.rejectedOrders.component />
|
||||
</Tab>
|
||||
<Tab
|
||||
id="orders"
|
||||
|
||||
@@ -4,8 +4,6 @@ import { OracleBanner } from '@vegaprotocol/markets';
|
||||
import type { TradingView } from './trade-views';
|
||||
import { TradingViews } from './trade-views';
|
||||
import { useState } from 'react';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { NO_MARKET } from './constants';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
@@ -14,6 +12,8 @@ import {
|
||||
MarketTerminationBanner,
|
||||
} from '../../components/market-banner';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface TradePanelsProps {
|
||||
market: Market | null;
|
||||
@@ -30,8 +30,10 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
throw new Error(`No component for view: ${view}`);
|
||||
}
|
||||
|
||||
if (!market) return <Splash>{NO_MARKET}</Splash>;
|
||||
if (!market) return <NoMarketSplash />;
|
||||
|
||||
// Watch out here, we don't know what component is being rendered
|
||||
// so watch out for clashes in props
|
||||
return <Component marketId={market?.id} pinnedAsset={pinnedAsset} />;
|
||||
};
|
||||
|
||||
@@ -74,33 +76,89 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<div className="flex flex-nowrap overflow-x-auto max-w-full border-t border-default">
|
||||
{Object.keys(TradingViews).map((key) => {
|
||||
const isActive = view === key;
|
||||
const className = classNames(
|
||||
'py-2 px-4 min-w-[100px] capitalize text-sm',
|
||||
{
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
|
||||
{Object.keys(TradingViews)
|
||||
// filter to control available views for the current market
|
||||
// eg only perps should get the funding views
|
||||
.filter((_key) => {
|
||||
const key = _key as TradingView;
|
||||
const perpOnlyViews = ['funding', 'fundingPayments'];
|
||||
|
||||
if (
|
||||
market?.tradableInstrument.instrument.product.__typename ===
|
||||
'Perpetual'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
if (
|
||||
market?.tradableInstrument.instrument.product.__typename !==
|
||||
'Perpetual' &&
|
||||
(key === 'funding' || key === 'fundingPayments')
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<button
|
||||
data-testid={key}
|
||||
onClick={() => setView(key as TradingView)}
|
||||
className={className}
|
||||
key={key}
|
||||
>
|
||||
{TradingViews[key as keyof typeof TradingViews].label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
if (perpOnlyViews.includes(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.map((_key) => {
|
||||
const key = _key as TradingView;
|
||||
const isActive = view === key;
|
||||
return (
|
||||
<ViewButton
|
||||
key={key}
|
||||
view={key}
|
||||
isActive={isActive}
|
||||
onClick={() => setView(key)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const NoMarketSplash = () => {
|
||||
const t = useT();
|
||||
return <Splash>{t('No market')}</Splash>;
|
||||
};
|
||||
|
||||
const ViewButton = ({
|
||||
view,
|
||||
isActive,
|
||||
onClick,
|
||||
}: {
|
||||
view: TradingView;
|
||||
isActive: boolean;
|
||||
onClick: () => void;
|
||||
}) => {
|
||||
const label = useViewLabel(view);
|
||||
const className = classNames('py-2 px-4 min-w-[100px] capitalize text-sm', {
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
|
||||
});
|
||||
|
||||
return (
|
||||
<button data-testid={view} onClick={onClick} className={className}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const useViewLabel = (view: TradingView) => {
|
||||
const t = useT();
|
||||
|
||||
const labels = {
|
||||
candles: t('Candles'),
|
||||
depth: t('Depth'),
|
||||
liquidity: t('Liquidity'),
|
||||
funding: t('Funding'),
|
||||
fundingPayments: t('Funding Payments'),
|
||||
orderbook: t('Orderbook'),
|
||||
trades: t('Trades'),
|
||||
positions: t('Positions'),
|
||||
activeOrders: t('Active'),
|
||||
closedOrders: t('Closed'),
|
||||
rejectedOrders: t('Rejected'),
|
||||
orders: t('All'),
|
||||
stopOrders: t('Stop'),
|
||||
collateral: t('Collateral'),
|
||||
fills: t('Fills'),
|
||||
};
|
||||
|
||||
return labels[view];
|
||||
};
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||
import {
|
||||
CandlesChartContainer,
|
||||
CandlesMenu,
|
||||
} from '@vegaprotocol/candles-chart';
|
||||
import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders';
|
||||
import { NO_MARKET } from './constants';
|
||||
import { TradesContainer } from '../../components/trades-container';
|
||||
import { OrderbookContainer } from '../../components/orderbook-container';
|
||||
import { FillsContainer } from '../../components/fills-container';
|
||||
@@ -15,96 +12,60 @@ import { AccountsContainer } from '../../components/accounts-container';
|
||||
import { LiquidityContainer } from '../../components/liquidity-container';
|
||||
import { FundingContainer } from '../../components/funding-container';
|
||||
import { FundingPaymentsContainer } from '../../components/funding-payments-container';
|
||||
import type { OrderContainerProps } from '../../components/orders-container';
|
||||
import { OrdersContainer } from '../../components/orders-container';
|
||||
import { StopOrdersContainer } from '../../components/stop-orders-container';
|
||||
import { AccountsMenu } from '../../components/accounts-menu';
|
||||
import { PositionsMenu } from '../../components/positions-menu';
|
||||
|
||||
type MarketDependantView =
|
||||
| typeof CandlesChartContainer
|
||||
| typeof DepthChartContainer
|
||||
| typeof OrderbookContainer
|
||||
| typeof TradesContainer;
|
||||
|
||||
type MarketDependantViewProps = ComponentProps<MarketDependantView>;
|
||||
|
||||
const requiresMarket = (View: MarketDependantView) => {
|
||||
const WrappedComponent = (props: MarketDependantViewProps) =>
|
||||
props.marketId ? <View {...props} /> : <Splash>{NO_MARKET}</Splash>;
|
||||
WrappedComponent.displayName = `RequiresMarket(${View.name})`;
|
||||
return WrappedComponent;
|
||||
};
|
||||
|
||||
export type TradingView = keyof typeof TradingViews;
|
||||
|
||||
export const TradingViews = {
|
||||
candles: {
|
||||
label: 'Candles',
|
||||
component: requiresMarket(CandlesChartContainer),
|
||||
component: CandlesChartContainer,
|
||||
menu: CandlesMenu,
|
||||
},
|
||||
depth: {
|
||||
label: 'Depth',
|
||||
component: requiresMarket(DepthChartContainer),
|
||||
component: DepthChartContainer,
|
||||
},
|
||||
liquidity: {
|
||||
label: 'Liquidity',
|
||||
component: requiresMarket(LiquidityContainer),
|
||||
component: LiquidityContainer,
|
||||
},
|
||||
funding: {
|
||||
label: 'Funding',
|
||||
component: requiresMarket(FundingContainer),
|
||||
component: FundingContainer,
|
||||
},
|
||||
fundingPayments: {
|
||||
label: 'Funding Payments',
|
||||
component: FundingPaymentsContainer,
|
||||
},
|
||||
orderbook: {
|
||||
label: 'Orderbook',
|
||||
component: requiresMarket(OrderbookContainer),
|
||||
component: OrderbookContainer,
|
||||
},
|
||||
trades: {
|
||||
label: 'Trades',
|
||||
component: requiresMarket(TradesContainer),
|
||||
component: TradesContainer,
|
||||
},
|
||||
positions: {
|
||||
label: 'Positions',
|
||||
component: PositionsContainer,
|
||||
menu: PositionsMenu,
|
||||
},
|
||||
activeOrders: {
|
||||
label: 'Active',
|
||||
component: (props: OrderContainerProps) => (
|
||||
<OrdersContainer {...props} filter={Filter.Open} />
|
||||
),
|
||||
component: () => <OrdersContainer filter={Filter.Open} />,
|
||||
menu: OpenOrdersMenu,
|
||||
},
|
||||
closedOrders: {
|
||||
label: 'Closed',
|
||||
component: (props: OrderContainerProps) => (
|
||||
<OrdersContainer {...props} filter={Filter.Closed} />
|
||||
),
|
||||
component: () => <OrdersContainer filter={Filter.Closed} />,
|
||||
},
|
||||
rejectedOrders: {
|
||||
label: 'Rejected',
|
||||
component: (props: OrderContainerProps) => (
|
||||
<OrdersContainer {...props} filter={Filter.Rejected} />
|
||||
),
|
||||
component: () => <OrdersContainer filter={Filter.Rejected} />,
|
||||
},
|
||||
orders: {
|
||||
label: 'All',
|
||||
component: OrdersContainer,
|
||||
menu: OpenOrdersMenu,
|
||||
},
|
||||
stopOrders: {
|
||||
label: 'Stop',
|
||||
component: StopOrdersContainer,
|
||||
},
|
||||
collateral: {
|
||||
label: 'Collateral',
|
||||
component: AccountsContainer,
|
||||
menu: AccountsMenu,
|
||||
},
|
||||
fills: { label: 'Fills', component: FillsContainer },
|
||||
};
|
||||
fills: { component: FillsContainer },
|
||||
} as const;
|
||||
|
||||
@@ -8,7 +8,6 @@ import type {
|
||||
import { AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { Asset } from '@vegaprotocol/types';
|
||||
import type { ProductType } from '@vegaprotocol/types';
|
||||
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||
@@ -24,6 +23,7 @@ import { SettlementDateCell } from './settlement-date-cell';
|
||||
import { SettlementPriceCell } from './settlement-price-cell';
|
||||
import { MarketCodeCell } from './market-code-cell';
|
||||
import { MarketActionsDropdown } from './market-table-actions';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
type SettlementAsset = Pick<
|
||||
Asset,
|
||||
@@ -127,6 +127,7 @@ const ClosedMarketsDataGrid = ({
|
||||
rowData: Row[];
|
||||
error: Error | undefined;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const handleOnSelect = useMarketClickHandler();
|
||||
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
|
||||
|
||||
@@ -274,7 +275,7 @@ const ClosedMarketsDataGrid = ({
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [openAssetDialog]);
|
||||
}, [openAssetDialog, t]);
|
||||
|
||||
return (
|
||||
<AgGrid
|
||||
|
||||
@@ -2,7 +2,7 @@ import compact from 'lodash/compact';
|
||||
import type { ProductType } from '@vegaprotocol/types';
|
||||
import { ProductTypeMapping, ProductTypeShortName } from '@vegaprotocol/types';
|
||||
import { StackedCell } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export interface MarketCodeCellProps {
|
||||
value: string | undefined; // market code
|
||||
@@ -14,6 +14,7 @@ export interface MarketCodeCellProps {
|
||||
}
|
||||
|
||||
export const MarketCodeCell = ({ value, data }: MarketCodeCellProps) => {
|
||||
const t = useT();
|
||||
if (!value || !data || !data.productType) return null;
|
||||
|
||||
const infoSpanClasses =
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingDropdownItem,
|
||||
TradingDropdownCopyItem,
|
||||
@@ -11,6 +10,7 @@ import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketActionsDropdown = ({
|
||||
marketId,
|
||||
@@ -23,6 +23,7 @@ export const MarketActionsDropdown = ({
|
||||
successorMarketID: string | null | undefined;
|
||||
parentMarketID: string | null | undefined;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const navigate = useNavigate();
|
||||
const open = useAssetDetailsDialogStore((store) => store.open);
|
||||
const linkCreator = useLinks(DApp.Explorer);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
LocalStoragePersistTabs as Tabs,
|
||||
Tab,
|
||||
@@ -15,8 +14,10 @@ import {
|
||||
TOKEN_NEW_MARKET_PROPOSAL,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketsPage = () => {
|
||||
const t = useT();
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
@@ -25,8 +26,8 @@ export const MarketsPage = () => {
|
||||
const externalLink = governanceLink(TOKEN_NEW_MARKET_PROPOSAL);
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy(['Markets']));
|
||||
}, [updateTitle]);
|
||||
updateTitle(titlefy([t('Markets')]));
|
||||
}, [updateTitle, t]);
|
||||
|
||||
return (
|
||||
<div className="h-full pt-0.5 pb-3 px-1.5">
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Route, Routes, useParams } from 'react-router-dom';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useMarket } from '@vegaprotocol/markets';
|
||||
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
@@ -9,8 +8,10 @@ import {
|
||||
ViewType,
|
||||
} from '../../components/sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketsSidebar = () => {
|
||||
const t = useT();
|
||||
const { marketId } = useParams();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const { data } = useMarket(marketId);
|
||||
|
||||
@@ -2,16 +2,17 @@ import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||
import { marketListProvider } from '@vegaprotocol/markets';
|
||||
import { useEffect } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { CellClickedEvent } from 'ag-grid-community';
|
||||
import MarketListTable from './market-list-table';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { Interval } from '@vegaprotocol/types';
|
||||
import { useYesterday } from '@vegaprotocol/react-helpers';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const POLLING_TIME = 2000;
|
||||
|
||||
export const OpenMarkets = () => {
|
||||
const t = useT();
|
||||
const handleOnSelect = useMarketClickHandler();
|
||||
const yesterday = useYesterday();
|
||||
const { data, error, reload } = useDataProvider({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DApp, EXPLORER_ORACLE, useLinks } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { formatDistanceToNowStrict, isAfter } from 'date-fns';
|
||||
|
||||
export interface SettlementDataCellProps {
|
||||
@@ -18,6 +18,7 @@ export const SettlementDateCell = ({
|
||||
closeTimestamp,
|
||||
marketState,
|
||||
}: SettlementDataCellProps) => {
|
||||
const t = useT();
|
||||
const linkCreator = useLinks(DApp.Explorer);
|
||||
const date = closeTimestamp ? new Date(closeTimestamp) : metaDate;
|
||||
|
||||
@@ -31,12 +32,12 @@ export const SettlementDateCell = ({
|
||||
|
||||
if (expiryHasPassed) {
|
||||
if (marketState !== MarketState.STATE_SETTLED) {
|
||||
text = t('Expected %s ago', distance);
|
||||
text = t('Expected {{distance}} ago', { distance });
|
||||
} else {
|
||||
text = t('%s ago', distance);
|
||||
text = t('{{distance}} ago', { distance });
|
||||
}
|
||||
} else {
|
||||
text = t('Expected in %s', distance);
|
||||
text = t('Expected in {{distance}}', { distance });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { DApp, EXPLORER_ORACLE, useLinks } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { DataSourceFilterFragment } from '@vegaprotocol/markets';
|
||||
import { useOracleSpecBindingData } from '@vegaprotocol/markets';
|
||||
import { PropertyKeyType } from '@vegaprotocol/types';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export interface SettlementPriceCellProps {
|
||||
oracleSpecId: string | undefined;
|
||||
@@ -17,6 +17,7 @@ export const SettlementPriceCell = ({
|
||||
settlementDataSpecBinding,
|
||||
filter,
|
||||
}: SettlementPriceCellProps) => {
|
||||
const t = useT();
|
||||
const linkCreator = useLinks(DApp.Explorer);
|
||||
const { property, loading } = useOracleSpecBindingData(
|
||||
oracleSpecId,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
@@ -18,10 +17,12 @@ import type {
|
||||
import { MarketActionsDropdown } from './market-table-actions';
|
||||
import { calcCandleVolume, getAsset } from '@vegaprotocol/markets';
|
||||
import { MarketCodeCell } from './market-code-cell';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const { MarketTradingMode, AuctionTrigger } = Schema;
|
||||
|
||||
export const useColumnDefs = () => {
|
||||
const t = useT();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
return useMemo<ColDef[]>(
|
||||
() => [
|
||||
@@ -216,6 +217,6 @@ export const useColumnDefs = () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
[openAssetDetailsDialog]
|
||||
[openAssetDetailsDialog, t]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { SidebarButton, ViewType } from '../../components/sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const PortfolioSidebar = () => {
|
||||
const t = useT();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { LayoutPriority } from 'allotment';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useIncompleteWithdrawals } from '@vegaprotocol/withdraws';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
@@ -25,6 +24,7 @@ import { AccountsMenu } from '../../components/accounts-menu';
|
||||
import { DepositsMenu } from '../../components/deposits-menu';
|
||||
import { WithdrawalsMenu } from '../../components/withdrawals-menu';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const WithdrawalsIndicator = () => {
|
||||
const { ready } = useIncompleteWithdrawals();
|
||||
@@ -39,6 +39,7 @@ const WithdrawalsIndicator = () => {
|
||||
};
|
||||
|
||||
export const Portfolio = () => {
|
||||
const t = useT();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const { getView, setViews } = useSidebar();
|
||||
const view = getView(currentRouteId);
|
||||
@@ -49,7 +50,7 @@ export const Portfolio = () => {
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([t('Portfolio')]));
|
||||
}, [updateTitle]);
|
||||
}, [updateTitle, t]);
|
||||
|
||||
// Make transfer sidebar open by default
|
||||
useEffect(() => {
|
||||
|
||||
@@ -16,13 +16,13 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { useReferral } from './hooks/use-referral';
|
||||
import { Routes } from '../../lib/links';
|
||||
import { useTransactionEventSubscription } from '@vegaprotocol/web3';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Statistics, useStats } from './referral-statistics';
|
||||
import { useReferralProgram } from './hooks/use-referral-program';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const RELOAD_DELAY = 3000;
|
||||
|
||||
const validateCode = (value: string) => {
|
||||
const validateCode = (value: string, t: ReturnType<typeof useT>) => {
|
||||
const number = +`0x${value}`;
|
||||
if (!value || value.length !== 64) {
|
||||
return t('Code must be 64 characters in length');
|
||||
@@ -33,6 +33,7 @@ const validateCode = (value: string) => {
|
||||
};
|
||||
|
||||
export const ApplyCodeForm = () => {
|
||||
const t = useT();
|
||||
const program = useReferralProgram();
|
||||
const navigate = useNavigate();
|
||||
const openWalletDialog = useVegaWalletDialogStore(
|
||||
@@ -59,7 +60,7 @@ export const ApplyCodeForm = () => {
|
||||
|
||||
const codeField = watch('code');
|
||||
const { data: previewData, loading: previewLoading } = useReferral({
|
||||
code: validateCode(codeField) ? codeField : undefined,
|
||||
code: validateCode(codeField, t) ? codeField : undefined,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -223,7 +224,7 @@ export const ApplyCodeForm = () => {
|
||||
hasError={Boolean(errors.code)}
|
||||
{...register('code', {
|
||||
required: t('You have to provide a code to apply it.'),
|
||||
validate: validateCode,
|
||||
validate: (value) => validateCode(value, t),
|
||||
})}
|
||||
placeholder="Enter a code"
|
||||
className="mb-2 bg-vega-clight-900 dark:bg-vega-cdark-700"
|
||||
|
||||
@@ -24,13 +24,14 @@ import {
|
||||
DISCLAIMER_REFERRAL_DOCS_LINK,
|
||||
} from './constants';
|
||||
import { useReferral } from './hooks/use-referral';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const CreateCodeContainer = () => {
|
||||
return <CreateCodeForm />;
|
||||
};
|
||||
|
||||
export const CreateCodeForm = () => {
|
||||
const t = useT();
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const openWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
@@ -81,6 +82,7 @@ const CreateCodeDialog = ({
|
||||
}: {
|
||||
setDialogOpen: (open: boolean) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const createLink = useLinks(DApp.Governance);
|
||||
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
|
||||
const { refetch } = useReferral({ pubKey, role: 'referrer' });
|
||||
@@ -93,6 +95,11 @@ const CreateCodeDialog = ({
|
||||
const { stakeAvailable: currentStakeAvailable, requiredStake } =
|
||||
useStakeAvailable();
|
||||
|
||||
const { data: referralSets } = useReferral({
|
||||
pubKey,
|
||||
role: 'referrer',
|
||||
});
|
||||
|
||||
const onSubmit = () => {
|
||||
if (isReadOnly || !pubKey) {
|
||||
setErr('Not connected');
|
||||
@@ -170,10 +177,14 @@ const CreateCodeDialog = ({
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<p>
|
||||
{t('You need at least')}{' '}
|
||||
{addDecimalsFormatNumber(requiredStake.toString(), 18)}{' '}
|
||||
{t(
|
||||
'VEGA staked to generate a referral code and participate in the referral program.'
|
||||
'You need at least {{requiredStake}} VEGA staked to generate a referral code and participate in the referral program.',
|
||||
{
|
||||
requiredStake: addDecimalsFormatNumber(
|
||||
requiredStake.toString(),
|
||||
18
|
||||
),
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
<TradingAnchorButton
|
||||
@@ -187,6 +198,68 @@ const CreateCodeDialog = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (!referralSets) {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
<>
|
||||
{
|
||||
<p>
|
||||
{t(
|
||||
'There is currently no referral program active, are you sure you want to create a code?'
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
{status === 'success' && code && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{code}
|
||||
</p>
|
||||
</div>
|
||||
<CopyWithTooltip text={code}>
|
||||
<TradingButton
|
||||
className="text-sm no-underline"
|
||||
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
||||
>
|
||||
<span>{t('Copy')}</span>
|
||||
</TradingButton>
|
||||
</CopyWithTooltip>
|
||||
</div>
|
||||
)}
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => onSubmit()}
|
||||
{...getButtonProps()}
|
||||
></TradingButton>
|
||||
{status === 'idle' && (
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
refetch();
|
||||
setDialogOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('No')}
|
||||
</TradingButton>
|
||||
)}
|
||||
{err && <InputError>{err}</InputError>}
|
||||
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
||||
<ExternalLink href={ABOUT_REFERRAL_DOCS_LINK}>
|
||||
{t('About the referral program')}
|
||||
</ExternalLink>
|
||||
<ExternalLink href={DISCLAIMER_REFERRAL_DOCS_LINK}>
|
||||
{t('Disclaimer')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
|
||||
@@ -3,21 +3,22 @@ import { RainbowButton } from './buttons';
|
||||
import { AnimatedDudeWithWire } from './graphics/dude';
|
||||
import { LayoutWithSky } from './layout';
|
||||
import { Routes } from '../../lib/links';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const ErrorBoundary = () => {
|
||||
const t = useT();
|
||||
const error = useRouteError();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const title = isRouteErrorResponse(error)
|
||||
? `${error.status} ${error.statusText}`
|
||||
: 'Something went wrong';
|
||||
: t('Something went wrong');
|
||||
|
||||
const code = isRouteErrorResponse(error) ? error.status : 0;
|
||||
|
||||
const messages: Record<number, string> = {
|
||||
0: 'An unknown error occurred.',
|
||||
404: "The page you're looking for doesn't exists.",
|
||||
0: t('An unknown error occurred.'),
|
||||
404: t("The page you're looking for doesn't exists."),
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -48,6 +49,7 @@ export const ErrorBoundary = () => {
|
||||
};
|
||||
|
||||
export const NotFound = () => {
|
||||
const t = useT();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,63 +1,66 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { Table } from './table';
|
||||
|
||||
export const HowItWorksTable = () => (
|
||||
<Table
|
||||
className="bg-none bg-vega-clight-800 dark:bg-vega-cdark-800"
|
||||
noHeader
|
||||
noCollapse
|
||||
columns={[{ name: 'number', className: 'pr-0' }, { name: 'step' }]}
|
||||
data={[
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
1
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Referrers generate a code assigned to their key via an on chain transaction'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
2
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
3
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Discounts are applied automatically during trading based on the key(s) used'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
4
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Referrers earn commission based on a percentage of the taker fees their referees pay'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
5
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee'
|
||||
),
|
||||
},
|
||||
]}
|
||||
></Table>
|
||||
);
|
||||
export const HowItWorksTable = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Table
|
||||
className="bg-none bg-vega-clight-800 dark:bg-vega-cdark-800"
|
||||
noHeader
|
||||
noCollapse
|
||||
columns={[{ name: 'number', className: 'pr-0' }, { name: 'step' }]}
|
||||
data={[
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
1
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Referrers generate a code assigned to their key via an on chain transaction'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
2
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
3
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Discounts are applied automatically during trading based on the key(s) used'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
4
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'Referrers earn commission based on a percentage of the taker fees their referees pay'
|
||||
),
|
||||
},
|
||||
{
|
||||
number: (
|
||||
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
5
|
||||
</span>
|
||||
),
|
||||
step: t(
|
||||
'The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee'
|
||||
),
|
||||
},
|
||||
]}
|
||||
></Table>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import classNames from 'classnames';
|
||||
import { AnimatedDudeWithWire } from './graphics/dude';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const LandingBanner = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<div className={classNames('relative mb-20')}>
|
||||
<div className="">
|
||||
|
||||
@@ -28,9 +28,10 @@ import sortBy from 'lodash/sortBy';
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCurrentEpochInfoQuery } from './hooks/__generated__/Epoch';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import maxBy from 'lodash/maxBy';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
export const ReferralStatistics = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
@@ -152,6 +153,7 @@ export const Statistics = ({
|
||||
program: ReturnType<typeof useReferralProgram>;
|
||||
as: 'referrer' | 'referee';
|
||||
}) => {
|
||||
const t = useT();
|
||||
const {
|
||||
baseCommissionValue,
|
||||
runningVolumeValue,
|
||||
@@ -185,10 +187,15 @@ export const Statistics = ({
|
||||
const baseCommissionTile = (
|
||||
<StatTile
|
||||
title={t('Base commission rate')}
|
||||
description={t('(Combined set volume %s over last %s epochs)', [
|
||||
compactNumFormat.format(runningVolumeValue),
|
||||
(details?.windowLength || DEFAULT_AGGREGATION_DAYS).toString(),
|
||||
])}
|
||||
description={t(
|
||||
'(Combined set volume {{runningVolume}} over last {{epochs}} epochs)',
|
||||
{
|
||||
runningVolume: compactNumFormat.format(runningVolumeValue),
|
||||
epochs: (
|
||||
details?.windowLength || DEFAULT_AGGREGATION_DAYS
|
||||
).toString(),
|
||||
}
|
||||
)}
|
||||
>
|
||||
{baseCommissionValue * 100}%
|
||||
</StatTile>
|
||||
@@ -196,10 +203,9 @@ export const Statistics = ({
|
||||
const stakingMultiplierTile = (
|
||||
<StatTile
|
||||
title={t('Staking multiplier')}
|
||||
description={`(${addDecimalsFormatNumber(
|
||||
stakeAvailable?.toString() || 0,
|
||||
18
|
||||
)} $VEGA staked)`}
|
||||
description={t('{{amount}} $VEGA staked', {
|
||||
amount: addDecimalsFormatNumber(stakeAvailable?.toString() || 0, 18),
|
||||
})}
|
||||
>
|
||||
{multiplier || t('None')}
|
||||
</StatTile>
|
||||
@@ -232,10 +238,9 @@ export const Statistics = ({
|
||||
|
||||
const referrerVolumeTile = (
|
||||
<StatTile
|
||||
title={t(
|
||||
'My volume (last %s epochs)',
|
||||
(details?.windowLength || DEFAULT_AGGREGATION_DAYS).toString()
|
||||
)}
|
||||
title={t('My volume (last {{count}} epochs)', {
|
||||
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
|
||||
})}
|
||||
>
|
||||
{compactNumFormat.format(referrerVolumeValue)}
|
||||
</StatTile>
|
||||
@@ -246,10 +251,9 @@ export const Statistics = ({
|
||||
.reduce((all, r) => all.plus(r), new BigNumber(0));
|
||||
const totalCommissionTile = (
|
||||
<StatTile
|
||||
title={t(
|
||||
'Total commission (last %s epochs)',
|
||||
(details?.windowLength || DEFAULT_AGGREGATION_DAYS).toString()
|
||||
)}
|
||||
title={t('Total commission (last {{count}}} epochs)', {
|
||||
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
|
||||
})}
|
||||
description={<QUSDTooltip />}
|
||||
>
|
||||
{getNumberFormat(0).format(Number(totalCommissionValue))}
|
||||
@@ -290,10 +294,9 @@ export const Statistics = ({
|
||||
);
|
||||
const runningVolumeTile = (
|
||||
<StatTile
|
||||
title={t(
|
||||
'Combined volume (last %s epochs)',
|
||||
details?.windowLength.toString()
|
||||
)}
|
||||
title={t('Combined volume (last {{count}} epochs)', {
|
||||
count: details?.windowLength,
|
||||
})}
|
||||
>
|
||||
{compactNumFormat.format(runningVolumeValue)}
|
||||
</StatTile>
|
||||
@@ -381,25 +384,22 @@ export const Statistics = ({
|
||||
{ name: 'joined', displayName: t('Date Joined') },
|
||||
{
|
||||
name: 'volume',
|
||||
displayName: t(
|
||||
'Volume (last %s epochs)',
|
||||
(
|
||||
details?.windowLength || DEFAULT_AGGREGATION_DAYS
|
||||
).toString()
|
||||
),
|
||||
displayName: t('Volume (last {{count}} epochs)', {
|
||||
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: 'commission',
|
||||
displayName: (
|
||||
<>
|
||||
{t('Commission earned in')} <QUSDTooltip />{' '}
|
||||
{t(
|
||||
'(last %s epochs)',
|
||||
(
|
||||
details?.windowLength || DEFAULT_AGGREGATION_DAYS
|
||||
).toString()
|
||||
)}
|
||||
</>
|
||||
<Trans
|
||||
i18nKey="referral-statistics-commission"
|
||||
defaults="Commission earned in <0>qUSD</0> (last {{count}} epochs)"
|
||||
values={{
|
||||
count:
|
||||
details?.windowLength || DEFAULT_AGGREGATION_DAYS,
|
||||
}}
|
||||
ns={ns}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
@@ -430,24 +430,27 @@ export const Statistics = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const QUSDTooltip = () => (
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'qUSD provides a rough USD equivalent of balances across all assets using the value of "Quantum" for that asset'
|
||||
export const QUSDTooltip = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'qUSD provides a rough USD equivalent of balances across all assets using the value of "Quantum" for that asset'
|
||||
)}
|
||||
</p>
|
||||
{DocsLinks && (
|
||||
<ExternalLink href={DocsLinks.QUANTUM}>
|
||||
{t('Find out more')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</p>
|
||||
{DocsLinks && (
|
||||
<ExternalLink href={DocsLinks.QUANTUM}>
|
||||
{t('Find out more')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
underline={true}
|
||||
>
|
||||
<span>{t('qUSD')}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
</>
|
||||
}
|
||||
underline={true}
|
||||
>
|
||||
<span>{t('qUSD')}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,18 +17,22 @@ import classNames from 'classnames';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { useEffect } from 'react';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const Nav = () => (
|
||||
<div className="flex justify-center border-b border-vega-cdark-500">
|
||||
<TabLink end to={Routes.REFERRALS}>
|
||||
{t('I want a code')}
|
||||
</TabLink>
|
||||
<TabLink to={Routes.REFERRALS_APPLY_CODE}>{t('I have a code')}</TabLink>
|
||||
</div>
|
||||
);
|
||||
const Nav = () => {
|
||||
const t = useT();
|
||||
return (
|
||||
<div className="flex justify-center border-b border-vega-cdark-500">
|
||||
<TabLink end to={Routes.REFERRALS}>
|
||||
{t('I want a code')}
|
||||
</TabLink>
|
||||
<TabLink to={Routes.REFERRALS_APPLY_CODE}>{t('I have a code')}</TabLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Referrals = () => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
const {
|
||||
@@ -58,7 +62,7 @@ export const Referrals = () => {
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([t('Referrals')]));
|
||||
}, [updateTitle]);
|
||||
}, [updateTitle, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,8 +6,14 @@ import { BORDER_COLOR, GRADIENT } from './constants';
|
||||
import { Tag } from './tag';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { DApp, TOKEN_PROPOSALS, useLinks } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
DApp,
|
||||
DocsLinks,
|
||||
TOKEN_PROPOSALS,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
const Loading = ({ variant }: { variant: 'large' | 'inline' }) => (
|
||||
<div
|
||||
@@ -31,6 +37,7 @@ const StakingTier = ({
|
||||
referralRewardMultiplier: string;
|
||||
minimumStakedTokens: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const color: Record<number, ComponentProps<typeof Tag>['color']> = {
|
||||
1: 'green',
|
||||
2: 'blue',
|
||||
@@ -62,7 +69,9 @@ const StakingTier = ({
|
||||
<Tag color={color[tier]}>Multiplier {referralRewardMultiplier}x</Tag>
|
||||
<h3 className="mt-1 mb-1 text-base">{label}</h3>
|
||||
<p className="text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
{t('Stake a minimum of')} {minimumStakedTokens} {t('$VEGA tokens')}
|
||||
{t('Stake a minimum of {{minimumStakedTokens}} $VEGA tokens', {
|
||||
minimumStakedTokens,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,6 +79,7 @@ const StakingTier = ({
|
||||
};
|
||||
|
||||
export const TiersContainer = () => {
|
||||
const t = useT();
|
||||
const { benefitTiers, stakingTiers, details, loading, error } =
|
||||
useReferralProgram();
|
||||
|
||||
@@ -82,13 +92,24 @@ export const TiersContainer = () => {
|
||||
if ((!loading && !details) || error) {
|
||||
return (
|
||||
<div className="text-base px-5 py-10 text-center">
|
||||
{t(
|
||||
"We're sorry but we don't have an active referral programme currently running. You can propose a new programme"
|
||||
)}{' '}
|
||||
<ExternalLink href={governanceLink(TOKEN_PROPOSALS)}>
|
||||
{t('here')}
|
||||
</ExternalLink>
|
||||
.
|
||||
<Trans
|
||||
defaults="There are currently no active referral programs. Check the <0>Governance App</0> to see if there are any proposals in progress and vote."
|
||||
components={[
|
||||
<ExternalLink href={governanceLink(TOKEN_PROPOSALS)} key="link">
|
||||
{t('Governance App')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
/>
|
||||
<Trans
|
||||
defaults="You can propose a new program via the <0>Docs</0>."
|
||||
components={[
|
||||
<ExternalLink href={DocsLinks?.REFERRALS} key="link">
|
||||
{t('Docs')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -174,6 +195,7 @@ const TiersTable = ({
|
||||
}>;
|
||||
windowLength?: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Table
|
||||
columns={[
|
||||
@@ -186,12 +208,9 @@ const TiersTable = ({
|
||||
{ name: 'discount', displayName: t('Referrer trading discount') },
|
||||
{
|
||||
name: 'volume',
|
||||
displayName: t(
|
||||
'Min. trading volume %s',
|
||||
windowLength
|
||||
? t('(last %s epochs)', windowLength.toString())
|
||||
: undefined
|
||||
),
|
||||
displayName: t('Min. trading volume (last {{count}} epochs)', {
|
||||
count: windowLength,
|
||||
}),
|
||||
},
|
||||
{ name: 'epochs', displayName: t('Min. epochs') },
|
||||
]}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import classNames from 'classnames';
|
||||
import type { HTMLAttributes, ReactNode } from 'react';
|
||||
import { Button } from './buttons';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const Tile = ({
|
||||
className,
|
||||
@@ -62,10 +62,13 @@ export const CodeTile = ({
|
||||
createdAt?: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<StatTile
|
||||
title={t('Your referral code')}
|
||||
description={createdAt ? t('(Created at: %s)', createdAt) : undefined}
|
||||
description={
|
||||
createdAt ? t('(Created at: {{createdAt}})', { createdAt }) : undefined
|
||||
}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<Tooltip
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { Rewards } from './rewards';
|
||||
@@ -0,0 +1,11 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { RewardsContainer } from '../../components/rewards-container';
|
||||
|
||||
export const Rewards = () => {
|
||||
return (
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Rewards')}</h1>
|
||||
<RewardsContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { TransferContainer } from '@vegaprotocol/accounts';
|
||||
import { GetStarted } from '../../components/welcome-dialog';
|
||||
import { GetStarted } from '../../components/welcome-dialog/get-started';
|
||||
|
||||
export const Transfer = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { GetStarted } from '../../components/welcome-dialog';
|
||||
import { GetStarted } from '../../components/welcome-dialog/get-started';
|
||||
import { WithdrawContainer } from '../../components/withdraw-container';
|
||||
|
||||
export const Withdraw = () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useCallback } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
@@ -13,12 +12,14 @@ import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const AccountsContainer = ({
|
||||
pinnedAsset,
|
||||
}: {
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const AccountsMenu = () => {
|
||||
const t = useT();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
|
||||
|
||||
@@ -8,12 +8,13 @@ import {
|
||||
NodeGuard,
|
||||
useEnvironment,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import type { ReactNode } from 'react';
|
||||
import { Web3Provider } from './web3-provider';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||
const t = useT();
|
||||
const {
|
||||
error,
|
||||
VEGA_URL,
|
||||
@@ -45,12 +46,16 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||
>
|
||||
<NodeGuard
|
||||
skeleton={<AppLoader />}
|
||||
failure={<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
||||
failure={
|
||||
<NodeFailure
|
||||
title={t('Node: {{VEGA_URL}} is unsuitable', { VEGA_URL })}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Web3Provider
|
||||
skeleton={<AppLoader />}
|
||||
failure={
|
||||
<AppFailure title={t(`Could not configure web3 provider`)} />
|
||||
<AppFailure title={t('Could not configure web3 provider')} />
|
||||
}
|
||||
>
|
||||
<VegaWalletProvider
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { HTMLProps, ReactNode } from 'react';
|
||||
|
||||
export const Card = ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
loading = false,
|
||||
highlight = false,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
title: string;
|
||||
className?: string;
|
||||
loading?: boolean;
|
||||
highlight?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto',
|
||||
'rounded-lg',
|
||||
{
|
||||
'bg-rainbow': highlight,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="bg-vega-clight-800 dark:bg-vega-cdark-800 h-full w-full rounded p-4">
|
||||
<h2 className="mb-3">{title}</h2>
|
||||
{loading ? <CardLoader /> : children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CardLoader = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="bg-vega-clight-600 dark:bg-vega-cdark-600 h-5 w-full" />
|
||||
<div className="bg-vega-clight-600 dark:bg-vega-cdark-600 h-6 w-3/4" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CardStat = ({
|
||||
value,
|
||||
text,
|
||||
highlight,
|
||||
description,
|
||||
testId,
|
||||
}: {
|
||||
value: ReactNode;
|
||||
text?: string;
|
||||
highlight?: boolean;
|
||||
description?: ReactNode;
|
||||
testId?: string;
|
||||
}) => {
|
||||
const val = (
|
||||
<span
|
||||
className={classNames('inline-block text-3xl leading-none', {
|
||||
'bg-rainbow bg-clip-text text-transparent': highlight,
|
||||
'cursor-help': description,
|
||||
})}
|
||||
data-testid={testId}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<p className="leading-none">
|
||||
{description ? <Tooltip description={description}>{val}</Tooltip> : val}
|
||||
{text && (
|
||||
<small className="text-muted mt-0.5 block text-xs">{text}</small>
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export const CardTable = (props: HTMLProps<HTMLTableElement>) => {
|
||||
return (
|
||||
<table {...props} className="text-muted mt-0.5 w-full text-xs">
|
||||
<tbody>{props.children}</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export const CardTableTH = (props: HTMLProps<HTMLTableHeaderCellElement>) => {
|
||||
return (
|
||||
<th
|
||||
{...props}
|
||||
className={classNames('text-left font-normal', props.className)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const CardTableTD = (props: HTMLProps<HTMLTableCellElement>) => {
|
||||
return (
|
||||
<td {...props} className={classNames('text-right', props.className)} />
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { Card, CardStat, CardTable, CardTableTH, CardTableTD } from './card';
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { DepositsTable } from '@vegaprotocol/deposits';
|
||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const DepositsContainer = () => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data, error } = useDataProvider({
|
||||
dataProvider: depositsProvider,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const DepositsMenu = () => {
|
||||
const t = useT();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export const FeeCard = ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
loading = false,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
title: string;
|
||||
className?: string;
|
||||
loading?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'p-4 bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full lg:col-auto',
|
||||
'rounded-lg',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<h2 className="mb-3">{title}</h2>
|
||||
{loading ? <FeeCardLoader /> : children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const FeeCardLoader = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="w-full h-5 bg-vega-clight-600 dark:bg-vega-cdark-600" />
|
||||
<div className="w-3/4 h-6 bg-vega-clight-600 dark:bg-vega-cdark-600" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import maxBy from 'lodash/maxBy';
|
||||
import minBy from 'lodash/minBy';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
useNetworkParams,
|
||||
@@ -9,9 +8,8 @@ import {
|
||||
import { useMarketList } from '@vegaprotocol/markets';
|
||||
import { formatNumber, formatNumberRounded } from '@vegaprotocol/utils';
|
||||
import { useDiscountProgramsQuery, useFeesQuery } from './__generated__/Fees';
|
||||
import { FeeCard } from './fees-card';
|
||||
import { Card, CardStat, CardTable, CardTableTD, CardTableTH } from '../card';
|
||||
import { MarketFees } from './market-fees';
|
||||
import { Stat } from './stat';
|
||||
import { useVolumeStats } from './use-volume-stats';
|
||||
import { useReferralStats } from './use-referral-stats';
|
||||
import { formatPercentage, getAdjustedFee } from './utils';
|
||||
@@ -25,8 +23,10 @@ import {
|
||||
VegaIconNames,
|
||||
truncateMiddle,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const FeesContainer = () => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { params, loading: paramsLoading } = useNetworkParams([
|
||||
NetworkParams.market_fee_factors_makerFee,
|
||||
@@ -87,7 +87,7 @@ export const FeesContainer = () => {
|
||||
<div className="grid auto-rows-min grid-cols-4 gap-3">
|
||||
{isConnected && (
|
||||
<>
|
||||
<FeeCard
|
||||
<Card
|
||||
title={t('My trading fees')}
|
||||
className="sm:col-span-2"
|
||||
loading={loading}
|
||||
@@ -98,8 +98,8 @@ export const FeesContainer = () => {
|
||||
referralDiscount={referralDiscount}
|
||||
volumeDiscount={volumeDiscount}
|
||||
/>
|
||||
</FeeCard>
|
||||
<FeeCard
|
||||
</Card>
|
||||
<Card
|
||||
title={t('Total discount')}
|
||||
className="sm:col-span-2"
|
||||
loading={loading}
|
||||
@@ -110,8 +110,8 @@ export const FeesContainer = () => {
|
||||
isReferralProgramRunning={isReferralProgramRunning}
|
||||
isVolumeDiscountProgramRunning={isVolumeDiscountProgramRunning}
|
||||
/>
|
||||
</FeeCard>
|
||||
<FeeCard
|
||||
</Card>
|
||||
<Card
|
||||
title={t('My current volume')}
|
||||
className="sm:col-span-2"
|
||||
loading={loading}
|
||||
@@ -124,12 +124,12 @@ export const FeesContainer = () => {
|
||||
windowLength={volumeDiscountWindowLength}
|
||||
/>
|
||||
) : (
|
||||
<p className="pt-3 text-sm text-muted">
|
||||
<p className="text-muted pt-3 text-sm">
|
||||
{t('No volume discount program active')}
|
||||
</p>
|
||||
)}
|
||||
</FeeCard>
|
||||
<FeeCard
|
||||
</Card>
|
||||
<Card
|
||||
title={t('Referral benefits')}
|
||||
className="sm:col-span-2"
|
||||
loading={loading}
|
||||
@@ -143,14 +143,14 @@ export const FeesContainer = () => {
|
||||
epochs={referralDiscountWindowLength}
|
||||
/>
|
||||
) : (
|
||||
<p className="pt-3 text-sm text-muted">
|
||||
<p className="text-muted pt-3 text-sm">
|
||||
{t('No referral program active')}
|
||||
</p>
|
||||
)}
|
||||
</FeeCard>
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
<FeeCard
|
||||
<Card
|
||||
title={t('Volume discount')}
|
||||
className="lg:col-span-full xl:col-span-2"
|
||||
loading={loading}
|
||||
@@ -161,8 +161,8 @@ export const FeesContainer = () => {
|
||||
lastEpochVolume={volumeInWindow}
|
||||
windowLength={volumeDiscountWindowLength}
|
||||
/>
|
||||
</FeeCard>
|
||||
<FeeCard
|
||||
</Card>
|
||||
<Card
|
||||
title={t('Referral discount')}
|
||||
className="lg:col-span-full xl:col-span-2"
|
||||
loading={loading}
|
||||
@@ -173,8 +173,8 @@ export const FeesContainer = () => {
|
||||
epochsInSet={epochsInSet}
|
||||
referralVolumeInWindow={referralVolumeInWindow}
|
||||
/>
|
||||
</FeeCard>
|
||||
<FeeCard
|
||||
</Card>
|
||||
<Card
|
||||
title={t('Fees by market')}
|
||||
className="lg:col-span-full"
|
||||
loading={marketsLoading}
|
||||
@@ -184,7 +184,7 @@ export const FeesContainer = () => {
|
||||
referralDiscount={referralDiscount}
|
||||
volumeDiscount={volumeDiscount}
|
||||
/>
|
||||
</FeeCard>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -203,6 +203,7 @@ export const TradingFees = ({
|
||||
referralDiscount: number;
|
||||
volumeDiscount: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const referralDiscountBigNum = new BigNumber(referralDiscount);
|
||||
const volumeDiscountBigNum = new BigNumber(volumeDiscount);
|
||||
|
||||
@@ -244,8 +245,8 @@ export const TradingFees = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="pt-6 leading-none">
|
||||
<div className="pt-4">
|
||||
<div className="leading-none">
|
||||
<p className="block text-3xl leading-none" data-testid="adjusted-fees">
|
||||
{minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined
|
||||
? `${formatPercentage(minAdjustedTotal)}%-${formatPercentage(
|
||||
@@ -253,47 +254,43 @@ export const TradingFees = ({
|
||||
)}%`
|
||||
: `${formatPercentage(adjustedTotal)}%`}
|
||||
</p>
|
||||
<table className="w-full mt-0.5 text-xs text-muted">
|
||||
<tbody>
|
||||
<CardTable>
|
||||
<tr className="text-default">
|
||||
<CardTableTH>{t('Total fee before discount')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{minTotal !== undefined && maxTotal !== undefined
|
||||
? `${formatPercentage(minTotal.toNumber())}%-${formatPercentage(
|
||||
maxTotal.toNumber()
|
||||
)}%`
|
||||
: `${formatPercentage(total.toNumber())}%`}
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
<tr>
|
||||
<CardTableTH>{t('Infrastructure')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{formatPercentage(
|
||||
Number(params.market_fee_factors_infrastructureFee)
|
||||
)}
|
||||
%
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
<tr>
|
||||
<CardTableTH>{t('Maker')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{formatPercentage(Number(params.market_fee_factors_makerFee))}%
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
{minLiq && maxLiq && (
|
||||
<tr>
|
||||
<th className="font-normal text-left text-default">
|
||||
{t('Total fee before discount')}
|
||||
</th>
|
||||
<td className="text-right text-default">
|
||||
{minTotal !== undefined && maxTotal !== undefined
|
||||
? `${formatPercentage(
|
||||
minTotal.toNumber()
|
||||
)}%-${formatPercentage(maxTotal.toNumber())}%`
|
||||
: `${formatPercentage(total.toNumber())}%`}
|
||||
</td>
|
||||
<CardTableTH>{t('Liquidity')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{formatPercentage(Number(minLiq.fees.factors.liquidityFee))}%
|
||||
{'-'}
|
||||
{formatPercentage(Number(maxLiq.fees.factors.liquidityFee))}%
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="font-normal text-left">{t('Infrastructure')}</th>
|
||||
<td className="text-right">
|
||||
{formatPercentage(
|
||||
Number(params.market_fee_factors_infrastructureFee)
|
||||
)}
|
||||
%
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="font-normal text-left ">{t('Maker')}</th>
|
||||
<td className="text-right">
|
||||
{formatPercentage(Number(params.market_fee_factors_makerFee))}%
|
||||
</td>
|
||||
</tr>
|
||||
{minLiq && maxLiq && (
|
||||
<tr>
|
||||
<th className="font-normal text-left ">{t('Liquidity')}</th>
|
||||
<td className="text-right">
|
||||
{formatPercentage(Number(minLiq.fees.factors.liquidityFee))}%
|
||||
{'-'}
|
||||
{formatPercentage(Number(maxLiq.fees.factors.liquidityFee))}%
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</CardTable>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -310,19 +307,20 @@ export const CurrentVolume = ({
|
||||
windowLengthVolume: number;
|
||||
windowLength: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const nextTier = tiers[tierIndex + 1];
|
||||
const requiredForNextTier = nextTier
|
||||
? Number(nextTier.minimumRunningNotionalTakerVolume) - windowLengthVolume
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stat
|
||||
<div className="flex flex-col gap-3 pt-4">
|
||||
<CardStat
|
||||
value={formatNumberRounded(new BigNumber(windowLengthVolume))}
|
||||
text={t('Past %s epochs', windowLength.toString())}
|
||||
text={t('Past {{count}} epochs', { count: windowLength })}
|
||||
/>
|
||||
{requiredForNextTier > 0 && (
|
||||
<Stat
|
||||
<CardStat
|
||||
value={formatNumber(requiredForNextTier)}
|
||||
text={t('Required for next tier')}
|
||||
/>
|
||||
@@ -340,17 +338,17 @@ const ReferralBenefits = ({
|
||||
setRunningNotionalTakerVolume: number;
|
||||
epochs: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<div>
|
||||
<Stat
|
||||
<div className="flex flex-col gap-3 pt-4">
|
||||
<CardStat
|
||||
// all sets volume (not just current party)
|
||||
value={formatNumber(setRunningNotionalTakerVolume)}
|
||||
text={t(
|
||||
'Combined running notional over the %s epochs',
|
||||
epochs.toString()
|
||||
)}
|
||||
text={t('Combined running notional over the {{count}} epochs', {
|
||||
count: epochs,
|
||||
})}
|
||||
/>
|
||||
<Stat value={epochsInSet} text={t('epochs in referral set')} />
|
||||
<CardStat value={epochsInSet} text={t('epochs in referral set')} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -366,6 +364,7 @@ const TotalDiscount = ({
|
||||
isReferralProgramRunning: boolean;
|
||||
isVolumeDiscountProgramRunning: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const totalDiscount = 1 - (1 - volumeDiscount) * (1 - referralDiscount);
|
||||
const totalDiscountDescription = t(
|
||||
'The total discount is calculated according to the following formula: '
|
||||
@@ -377,8 +376,8 @@ const TotalDiscount = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stat
|
||||
<div className="pt-4">
|
||||
<CardStat
|
||||
description={
|
||||
<>
|
||||
{totalDiscountDescription}
|
||||
@@ -388,38 +387,36 @@ const TotalDiscount = ({
|
||||
value={formatPercentage(totalDiscount) + '%'}
|
||||
highlight={true}
|
||||
/>
|
||||
<table className="w-full mt-0.5 text-xs text-muted">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th className="font-normal text-left">{t('Volume discount')}</th>
|
||||
<td className="text-right">
|
||||
{formatPercentage(volumeDiscount)}%
|
||||
{!isVolumeDiscountProgramRunning && (
|
||||
<Tooltip description={t('No active volume discount programme')}>
|
||||
<span className="cursor-help">
|
||||
{' '}
|
||||
<VegaIcon name={VegaIconNames.INFO} size={12} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="font-normal text-left ">{t('Referral discount')}</th>
|
||||
<td className="text-right">
|
||||
{formatPercentage(referralDiscount)}%
|
||||
{!isReferralProgramRunning && (
|
||||
<Tooltip description={t('No active referral programme')}>
|
||||
<span className="cursor-help">
|
||||
{' '}
|
||||
<VegaIcon name={VegaIconNames.INFO} size={12} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<CardTable>
|
||||
<tr>
|
||||
<CardTableTH>{t('Volume discount')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{formatPercentage(volumeDiscount)}%
|
||||
{!isVolumeDiscountProgramRunning && (
|
||||
<Tooltip description={t('No active volume discount programme')}>
|
||||
<span className="cursor-help">
|
||||
{' '}
|
||||
<VegaIcon name={VegaIconNames.INFO} size={12} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
<tr>
|
||||
<CardTableTH>{t('Referral discount')}</CardTableTH>
|
||||
<CardTableTD>
|
||||
{formatPercentage(referralDiscount)}%
|
||||
{!isReferralProgramRunning && (
|
||||
<Tooltip description={t('No active referral programme')}>
|
||||
<span className="cursor-help">
|
||||
{' '}
|
||||
<VegaIcon name={VegaIconNames.INFO} size={12} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</CardTableTD>
|
||||
</tr>
|
||||
</CardTable>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -438,9 +435,10 @@ const VolumeTiers = ({
|
||||
lastEpochVolume: number;
|
||||
windowLength: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
if (!tiers.length) {
|
||||
return (
|
||||
<p className="text-sm text-muted">
|
||||
<p className="text-muted text-sm">
|
||||
{t('No volume discount program active')}
|
||||
</p>
|
||||
);
|
||||
@@ -454,7 +452,9 @@ const VolumeTiers = ({
|
||||
<Th>{t('Tier')}</Th>
|
||||
<Th>{t('Discount')}</Th>
|
||||
<Th>{t('Min. trading volume')}</Th>
|
||||
<Th>{t('My volume (last %s epochs)', windowLength.toString())}</Th>
|
||||
<Th>
|
||||
{t('My volume (last {{count}} epochs)', { count: windowLength })}
|
||||
</Th>
|
||||
<Th />
|
||||
</tr>
|
||||
</THead>
|
||||
@@ -499,9 +499,11 @@ const ReferralTiers = ({
|
||||
epochsInSet: number;
|
||||
referralVolumeInWindow: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
|
||||
if (!tiers.length) {
|
||||
return (
|
||||
<p className="text-sm text-muted">{t('No referral program active')}</p>
|
||||
<p className="text-muted text-sm">{t('No referral program active')}</p>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -556,37 +558,43 @@ const ReferralTiers = ({
|
||||
};
|
||||
|
||||
const YourTier = () => {
|
||||
const t = useT();
|
||||
|
||||
return (
|
||||
<span className="px-4 py-1.5 rounded-xl bg-rainbow whitespace-nowrap text-white">
|
||||
<span className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white">
|
||||
{t('Your tier')}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const ReferrerInfo = ({ code }: { code?: string }) => (
|
||||
<div className="pt-3 text-sm text-vega-clight-200 dark:vega-cdark-200">
|
||||
<p className="mb-1">
|
||||
{t('Connected key is owner of the referral set')}
|
||||
{code && (
|
||||
<>
|
||||
{' '}
|
||||
<span className="text-transparent bg-rainbow bg-clip-text">
|
||||
{truncateMiddle(code)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{'. '}
|
||||
{t('As owner, it is eligible for commission not fee discounts.')}
|
||||
</p>
|
||||
<p>
|
||||
{t('See')}{' '}
|
||||
<Link
|
||||
className="underline text-black dark:text-white"
|
||||
to={Links.REFERRALS()}
|
||||
>
|
||||
{t('Referrals')}
|
||||
</Link>{' '}
|
||||
{t('for more information.')}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
const ReferrerInfo = ({ code }: { code?: string }) => {
|
||||
const t = useT();
|
||||
|
||||
return (
|
||||
<div className="text-vega-clight-200 dark:vega-cdark-200 pt-3 text-sm">
|
||||
<p className="mb-1">
|
||||
{t('Connected key is owner of the referral set')}
|
||||
{code && (
|
||||
<>
|
||||
{' '}
|
||||
<span className="bg-rainbow bg-clip-text text-transparent">
|
||||
{truncateMiddle(code)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{'. '}
|
||||
{t('As owner, it is eligible for commission not fee discounts.')}
|
||||
</p>
|
||||
<p>
|
||||
{t('See')}{' '}
|
||||
<Link
|
||||
className="text-black underline dark:text-white"
|
||||
to={Links.REFERRALS()}
|
||||
>
|
||||
{t('Referrals')}
|
||||
</Link>{' '}
|
||||
{t('for more information.')}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
import compact from 'lodash/compact';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { formatPercentage, getAdjustedFee } from './utils';
|
||||
import { MarketCodeCell } from '../../client-pages/markets/market-code-cell';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useNavigateWithMeta } from '../../lib/hooks/use-market-click-handler';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const feesTableColumnDefs = [
|
||||
{ field: 'code', cellRenderer: 'MarketCodeCell' },
|
||||
{
|
||||
field: 'feeAfterDiscount',
|
||||
headerName: t('Total fee after discount'),
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'infraFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'makerFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'liquidityFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'totalFee',
|
||||
headerName: t('Total fee before discount'),
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
];
|
||||
const useFeesTableColumnDefs = () => {
|
||||
const t = useT();
|
||||
return useMemo(
|
||||
() => [
|
||||
{ field: 'code', cellRenderer: 'MarketCodeCell' },
|
||||
{
|
||||
field: 'feeAfterDiscount',
|
||||
headerName: t('Total fee after discount'),
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'infraFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'makerFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'liquidityFee',
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
{
|
||||
field: 'totalFee',
|
||||
headerName: t('Total fee before discount'),
|
||||
valueFormatter: ({ value }: { value: number }) => value + '%',
|
||||
},
|
||||
],
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
||||
const feesTableDefaultColDef = {
|
||||
flex: 1,
|
||||
@@ -83,7 +90,7 @@ export const MarketFees = ({
|
||||
return (
|
||||
<div className="border rounded-sm border-default">
|
||||
<AgGrid
|
||||
columnDefs={feesTableColumnDefs}
|
||||
columnDefs={useFeesTableColumnDefs()}
|
||||
rowData={rows}
|
||||
getRowId={({ data }) => data.id}
|
||||
defaultColDef={feesTableDefaultColDef}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export const Stat = ({
|
||||
value,
|
||||
text,
|
||||
highlight,
|
||||
description,
|
||||
}: {
|
||||
value: string | number;
|
||||
text?: string;
|
||||
highlight?: boolean;
|
||||
description?: ReactNode;
|
||||
}) => {
|
||||
const val = (
|
||||
<span
|
||||
className={classNames('inline-block text-3xl leading-none', {
|
||||
'text-transparent bg-rainbow bg-clip-text': highlight,
|
||||
'cursor-help': description,
|
||||
})}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<p className="pt-3 leading-none first:pt-6">
|
||||
{description ? <Tooltip description={description}>{val}</Tooltip> : val}
|
||||
{text && (
|
||||
<small className="block mt-0.5 text-xs text-muted">{text}</small>
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
@@ -3,13 +3,14 @@ import { FillsManager } from '@vegaprotocol/fills';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const FillsContainer = () => {
|
||||
const t = useT();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import 'pennant/dist/style.css';
|
||||
import { useFundingPeriodsQuery } from '@vegaprotocol/markets';
|
||||
import { LineChart } from 'pennant';
|
||||
import { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const calculateStartDate = (range: string): string | undefined => {
|
||||
const now = new Date();
|
||||
@@ -41,6 +41,7 @@ const DateRange = {
|
||||
};
|
||||
|
||||
export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
const t = useT();
|
||||
const { theme } = useThemeSwitcher();
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
@@ -73,7 +74,7 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
cols: ['Date', t('Funding rate')],
|
||||
rows: sortBy(rows, 'endTime').map((d) => [d.endTime, d.fundingRate]),
|
||||
};
|
||||
}, [data?.fundingPeriods.edges]);
|
||||
}, [data?.fundingPeriods.edges, t]);
|
||||
if (!data || !values?.rows.length) {
|
||||
return <Splash> {t('No funding history data')}</Splash>;
|
||||
}
|
||||
|
||||
@@ -3,17 +3,18 @@ import { FundingPaymentsManager } from '@vegaprotocol/funding-payments';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const FundingPaymentsContainer = ({
|
||||
marketId,
|
||||
}: {
|
||||
marketId?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { LedgerExportForm } from '@vegaprotocol/ledger';
|
||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { PartyAssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { usePartyAssetsQuery } from '@vegaprotocol/assets';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const LedgerContainer = () => {
|
||||
const t = useT();
|
||||
const VEGA_URL = useEnvironment((store) => store.VEGA_URL);
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data, loading } = usePartyAssetsQuery({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
lpAggregatedDataProvider,
|
||||
type Filter,
|
||||
@@ -17,6 +16,7 @@ import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { useEffect } from 'react';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const LiquidityContainer = ({
|
||||
marketId,
|
||||
@@ -25,6 +25,7 @@ export const LiquidityContainer = ({
|
||||
marketId: string | undefined;
|
||||
filter?: Filter;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const gridStore = useLiquidityStore((store) => store.gridStore);
|
||||
const updateGridStore = useLiquidityStore((store) => store.updateGridStore);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
CopyWithTooltip,
|
||||
ExternalLink,
|
||||
@@ -24,8 +23,10 @@ import {
|
||||
usePaidFeesQuery,
|
||||
} from '@vegaprotocol/liquidity';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const LiquidityHeader = () => {
|
||||
const t = useT();
|
||||
const { marketId } = useParams();
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId);
|
||||
@@ -60,10 +61,9 @@ export const LiquidityHeader = () => {
|
||||
marketId && (
|
||||
<HeaderTitle>
|
||||
{market.tradableInstrument.instrument.code &&
|
||||
t(
|
||||
'%s liquidity provision',
|
||||
market.tradableInstrument.instrument.code
|
||||
)}
|
||||
t('{{instrumentCode}} liquidity provision', {
|
||||
instrumentCode: market.tradableInstrument.instrument.code,
|
||||
})}
|
||||
</HeaderTitle>
|
||||
)
|
||||
}
|
||||
@@ -102,8 +102,8 @@ export const LiquidityHeader = () => {
|
||||
<HeaderStat
|
||||
heading={t('Fees paid')}
|
||||
description={t(
|
||||
'The amount of fees paid to liquidity providers across the whole market during the last epoch %s.',
|
||||
feesObject?.node.epoch.toString() || '-'
|
||||
'The amount of fees paid to liquidity providers across the whole market during the last epoch {{epoch}}.',
|
||||
{ epoch: feesObject?.node.epoch.toString() || '-' }
|
||||
)}
|
||||
testId="fees-paid"
|
||||
>
|
||||
|
||||
@@ -21,10 +21,10 @@ import {
|
||||
addDecimalsFormatNumberQuantum,
|
||||
formatNumberPercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
interface Props {
|
||||
marketId?: string;
|
||||
@@ -39,6 +39,7 @@ export const MarketLiquiditySupplied = ({
|
||||
noUpdate = false,
|
||||
quantum,
|
||||
}: Props) => {
|
||||
const t = useT();
|
||||
const [market, setMarket] = useState<MarketData>();
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
|
||||
@@ -132,7 +132,9 @@ describe('MarketSuccessorBanner', () => {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(
|
||||
screen.getByText('has a 24h trading volume of 101.367')
|
||||
screen.getByText('has a 24h trading volume of 101.367', {
|
||||
exact: false,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ import {
|
||||
getMarketExpiryDate,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
const getExpiryDate = (tags: string[], close?: string): Date | null => {
|
||||
const expiryDate = getMarketExpiryDate(tags);
|
||||
@@ -30,6 +31,7 @@ export const MarketSuccessorBanner = ({
|
||||
}: {
|
||||
market: Market | null;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { data: marketState } = useMarketState(market?.id);
|
||||
const isSettled = marketState === Types.MarketState.STATE_SETTLED;
|
||||
const { data: successorData, loading } = useSuccessorMarket(market?.id);
|
||||
@@ -81,8 +83,8 @@ export const MarketSuccessorBanner = ({
|
||||
<div className="mt-1">
|
||||
{duration && (
|
||||
<span>
|
||||
{t('This market expires in %s.', [
|
||||
formatDuration(duration, {
|
||||
{t('This market expires in {{duration}}.', {
|
||||
duration: formatDuration(duration, {
|
||||
format: [
|
||||
'years',
|
||||
'months',
|
||||
@@ -92,22 +94,46 @@ export const MarketSuccessorBanner = ({
|
||||
'minutes',
|
||||
],
|
||||
}),
|
||||
])}
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
{successorData && (
|
||||
<>
|
||||
{' '}
|
||||
{t('The successor market')}
|
||||
{!successorVolume ? ' is ' : ' '}
|
||||
<ExternalLink href={`/#/markets/${successorData?.id}`}>
|
||||
{successorData?.tradableInstrument.instrument.name}
|
||||
</ExternalLink>
|
||||
{successorVolume && (
|
||||
<span>
|
||||
{' '}
|
||||
{t('has a 24h trading volume of %s', [successorVolume])}
|
||||
</span>
|
||||
{successorVolume ? (
|
||||
<Trans
|
||||
defaults="The successor market <0>{{instrumentName}}</0> has a 24h trading volume of {{successorVolume}}"
|
||||
values={{
|
||||
successorVolume,
|
||||
instrumentName:
|
||||
successorData?.tradableInstrument.instrument.name,
|
||||
}}
|
||||
components={[
|
||||
<ExternalLink
|
||||
href={`/#/markets/${successorData?.id}`}
|
||||
key="link"
|
||||
>
|
||||
successor market name
|
||||
</ExternalLink>,
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
defaults="The successor market is <0>{{instrumentName}}</0>"
|
||||
values={{
|
||||
instrumentName:
|
||||
successorData?.tradableInstrument.instrument.name,
|
||||
}}
|
||||
components={[
|
||||
<ExternalLink
|
||||
href={`/#/markets/${successorData?.id}`}
|
||||
key="link"
|
||||
>
|
||||
successor market name
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -9,16 +9,17 @@ import {
|
||||
Intent,
|
||||
NotificationBanner,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketSuccessorProposalBanner = ({
|
||||
marketId,
|
||||
}: {
|
||||
marketId?: string;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { data: proposals } = useDataProvider({
|
||||
dataProvider: marketViewProposalsDataProvider,
|
||||
skip: !marketId,
|
||||
@@ -57,9 +58,13 @@ export const MarketSuccessorProposalBanner = ({
|
||||
: t('Successors to this market have been proposed')}
|
||||
</div>
|
||||
<div>
|
||||
{successors.length === 1
|
||||
? t('Check out the terms of the proposal and vote:')
|
||||
: t('Check out the terms of the proposals and vote:')}{' '}
|
||||
{t(
|
||||
'checkOutProposalsAndVote',
|
||||
'Check out the terms of the proposals and vote:',
|
||||
{
|
||||
count: successors.length,
|
||||
}
|
||||
)}{' '}
|
||||
{successors.map((item, i) => {
|
||||
const externalLink = tokenLink(
|
||||
TOKEN_PROPOSAL.replace(':id', item.id || '')
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { MarketViewProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { marketViewProposalsDataProvider } from '@vegaprotocol/proposals';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { getQuoteName } from '@vegaprotocol/markets';
|
||||
@@ -21,6 +20,7 @@ import {
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const filterProposals = (
|
||||
data: MarketViewProposalFieldsFragment[] | null,
|
||||
@@ -68,6 +68,7 @@ export const MarketTerminationBanner = ({
|
||||
}: {
|
||||
market: Market | null;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const [visible, setVisible] = useState(true);
|
||||
const skip = !market || !visible;
|
||||
const { data: passedProposalsData } = useDataProvider({
|
||||
@@ -113,19 +114,22 @@ export const MarketTerminationBanner = ({
|
||||
content = (
|
||||
<>
|
||||
<div className="uppercase mb-1">
|
||||
{t('Trading on Market %s will stop on %s', [name, date])}
|
||||
{t('Trading on Market {{name}} will stop on {{date}}', {
|
||||
name,
|
||||
date,
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'You will no longer be able to hold a position on this market when it closes in %s.',
|
||||
[duration]
|
||||
'You will no longer be able to hold a position on this market when it closes in {{duration}}.',
|
||||
{ duration }
|
||||
)}{' '}
|
||||
{price &&
|
||||
assetSymbol &&
|
||||
t('The final price will be %s %s.', [
|
||||
addDecimalsFormatNumber(price, market.decimalPlaces),
|
||||
t('The final price will be {{price}} {{assetSymbol}}.', {
|
||||
price: addDecimalsFormatNumber(price, market.decimalPlaces),
|
||||
assetSymbol,
|
||||
])}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
@@ -134,8 +138,8 @@ export const MarketTerminationBanner = ({
|
||||
<>
|
||||
<div className="uppercase mb-1">
|
||||
{t(
|
||||
'Trading on Market %s may stop. There are open proposals to close this market',
|
||||
[name]
|
||||
'Trading on Market {{name}} may stop. There are open proposals to close this market',
|
||||
{ name }
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
@@ -151,17 +155,17 @@ export const MarketTerminationBanner = ({
|
||||
<>
|
||||
<div className="uppercase mb-1">
|
||||
{t(
|
||||
'Trading on Market %s may stop on %s. There is open proposal to close this market.',
|
||||
[name, date]
|
||||
'Trading on Market {{name}} may stop on {{date}}. There is open proposal to close this market.',
|
||||
{ name, date }
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{price &&
|
||||
assetSymbol &&
|
||||
t('Proposed final price is %s %s.', [
|
||||
addDecimalsFormatNumber(price, market.decimalPlaces),
|
||||
t('Proposed final price is {{price}} {{assetSymbol}}.', {
|
||||
price: addDecimalsFormatNumber(price, market.decimalPlaces),
|
||||
assetSymbol,
|
||||
])}
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingDropdown,
|
||||
TradingDropdownCheckboxItem,
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
TradingDropdownTrigger,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketSelectorButton } from './market-selector-button';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
type Assets = Array<{ id: string; symbol: string }>;
|
||||
|
||||
@@ -19,6 +19,7 @@ export const AssetDropdown = ({
|
||||
checkedAssets: string[];
|
||||
onSelect: (id: string, checked: boolean) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
if (!assets?.length) {
|
||||
return null;
|
||||
}
|
||||
@@ -29,7 +30,7 @@ export const AssetDropdown = ({
|
||||
trigger={
|
||||
<TradingDropdownTrigger data-testid="asset-trigger">
|
||||
<MarketSelectorButton>
|
||||
{triggerText({ assets, checkedAssets })}
|
||||
{triggerText({ assets, checkedAssets }, t)}
|
||||
</MarketSelectorButton>
|
||||
</TradingDropdownTrigger>
|
||||
}
|
||||
@@ -58,13 +59,16 @@ export const AssetDropdown = ({
|
||||
);
|
||||
};
|
||||
|
||||
const triggerText = ({
|
||||
assets,
|
||||
checkedAssets,
|
||||
}: {
|
||||
assets: Assets;
|
||||
checkedAssets: string[];
|
||||
}) => {
|
||||
const triggerText = (
|
||||
{
|
||||
assets,
|
||||
checkedAssets,
|
||||
}: {
|
||||
assets: Assets;
|
||||
checkedAssets: string[];
|
||||
},
|
||||
t: ReturnType<typeof useT>
|
||||
) => {
|
||||
let text = t('Assets');
|
||||
|
||||
if (checkedAssets.length === 1) {
|
||||
@@ -72,7 +76,9 @@ const triggerText = ({
|
||||
const asset = assets.find((a) => a.id === assetId);
|
||||
text = asset ? asset.symbol : t('Asset (1)');
|
||||
} else if (checkedAssets.length > 1) {
|
||||
text = t(`${checkedAssets.length} Assets`);
|
||||
text = t('{{checkedAssets}} Assets', {
|
||||
checkedAssets: checkedAssets.length,
|
||||
});
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
MarketTradingMode,
|
||||
MarketTradingModeMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketProductPill } from '@vegaprotocol/datagrid';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketSelectorItem = ({
|
||||
market,
|
||||
@@ -52,6 +52,7 @@ const MarketData = ({
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { data } = useMarketDataUpdateSubscription({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import {
|
||||
getAsset,
|
||||
@@ -21,6 +20,7 @@ import type { SortType } from './sort-dropdown';
|
||||
import { Sort, SortDropdown } from './sort-dropdown';
|
||||
import { MarketSelectorItem } from './market-selector-item';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export type Filter = {
|
||||
searchTerm: string;
|
||||
@@ -40,6 +40,7 @@ export const MarketSelector = ({
|
||||
currentMarketId?: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const [filter, setFilter] = useState<Filter>({
|
||||
searchTerm: '',
|
||||
product: Product.All,
|
||||
@@ -158,6 +159,7 @@ const MarketList = ({
|
||||
noItems: string;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const itemSize = 45;
|
||||
const listRef = useRef<HTMLDivElement | null>(null);
|
||||
const rect = listRef.current?.getBoundingClientRect();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
// Make sure these match the available __typename properties on product
|
||||
export const Product = {
|
||||
@@ -14,15 +14,6 @@ export const Product = {
|
||||
|
||||
export type ProductType = keyof typeof Product;
|
||||
|
||||
const ProductTypeMapping: {
|
||||
[key in ProductType]: string;
|
||||
} = {
|
||||
[Product.All]: 'All',
|
||||
[Product.Future]: 'Futures',
|
||||
[Product.Spot]: 'Spot',
|
||||
[Product.Perpetual]: 'Perpetuals',
|
||||
};
|
||||
|
||||
export const ProductSelector = ({
|
||||
product,
|
||||
onSelect,
|
||||
@@ -30,6 +21,15 @@ export const ProductSelector = ({
|
||||
product: ProductType;
|
||||
onSelect: (product: ProductType) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const ProductTypeMapping: {
|
||||
[key in ProductType]: string;
|
||||
} = {
|
||||
[Product.All]: t('All'),
|
||||
[Product.Future]: t('Futures'),
|
||||
[Product.Spot]: t('Spot'),
|
||||
[Product.Perpetual]: t('Perpetuals'),
|
||||
};
|
||||
return (
|
||||
<div className="flex mb-2">
|
||||
{Object.keys(Product).map((t) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import throttle from 'lodash/throttle';
|
||||
import type { MarketData, Market } from '@vegaprotocol/markets';
|
||||
import { marketDataProvider } from '@vegaprotocol/markets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { HeaderStat } from '../header';
|
||||
@@ -9,8 +8,10 @@ import { useCallback, useRef, useState } from 'react';
|
||||
import * as constants from '../constants';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
const t = useT();
|
||||
const [marketState, setMarketState] = useState<Schema.MarketState | null>(
|
||||
null
|
||||
);
|
||||
@@ -41,7 +42,7 @@ export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
return (
|
||||
<HeaderStat
|
||||
heading={t('Status')}
|
||||
description={getMarketStateTooltip(marketState)}
|
||||
description={useGetMarketStateTooltip(marketState)}
|
||||
testId="market-state"
|
||||
>
|
||||
{marketState ? Schema.MarketStateMapping[marketState] : '-'}
|
||||
@@ -49,7 +50,8 @@ export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const getMarketStateTooltip = (state: Schema.MarketState | null) => {
|
||||
const useGetMarketStateTooltip = (state: Schema.MarketState | null) => {
|
||||
const t = useT();
|
||||
if (state === Schema.MarketState.STATE_ACTIVE) {
|
||||
return t('Enactment date reached and usual auction exit checks pass');
|
||||
}
|
||||
@@ -96,7 +98,7 @@ const getMarketStateTooltip = (state: Schema.MarketState | null) => {
|
||||
return (
|
||||
<p>
|
||||
{t(
|
||||
`This market has been suspended via a governance vote and can be resumed or terminated by further votes.`
|
||||
'This market has been suspended via a governance vote and can be resumed or terminated by further votes.'
|
||||
)}
|
||||
{DocsLinks && (
|
||||
<ExternalLink href={DocsLinks.MARKET_LIFECYCLE} className="ml-1">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingModeTooltip } from '@vegaprotocol/deal-ticket';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { HeaderStat } from '../header';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { useStaticMarketData } from '@vegaprotocol/markets';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const getTradingModeLabel = (
|
||||
marketTradingMode?: Schema.MarketTradingMode,
|
||||
@@ -36,6 +36,7 @@ export const HeaderStatMarketTradingMode = ({
|
||||
initialTradingMode,
|
||||
initialTrigger,
|
||||
}: HeaderStatMarketTradingModeProps) => {
|
||||
const t = useT();
|
||||
const { data } = useStaticMarketData(marketId);
|
||||
const marketTradingMode = data?.marketTradingMode ?? initialTradingMode;
|
||||
const trigger = data?.trigger ?? initialTrigger;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import type { MarketData } from '@vegaprotocol/markets';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/markets';
|
||||
import { HeaderStat } from '../header';
|
||||
import * as constants from '../constants';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const MarketVolume = ({ marketId }: { marketId: string }) => {
|
||||
const t = useT();
|
||||
const [marketVolume, setMarketVolume] = useState<string>('-');
|
||||
const variables = { marketId };
|
||||
const { data } = useDataProvider({
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketSelector } from '../market-selector';
|
||||
import { useMarket, useMarketList } from '@vegaprotocol/markets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||
import { useState } from 'react';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
/**
|
||||
* This is only rendered for the mobile navigation
|
||||
*/
|
||||
export const NavHeader = () => {
|
||||
const t = useT();
|
||||
const { marketId } = useParams();
|
||||
const { data } = useMarket(marketId);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
@@ -68,6 +68,7 @@ describe('Navbar', () => {
|
||||
['/portfolio', 'Portfolio'],
|
||||
['/referrals', 'Referrals'],
|
||||
['/fees', 'Fees'],
|
||||
['/rewards', 'Rewards'],
|
||||
[expect.stringContaining('governance'), 'Governance'],
|
||||
];
|
||||
|
||||
@@ -102,6 +103,7 @@ describe('Navbar', () => {
|
||||
['/portfolio', 'Portfolio'],
|
||||
['/referrals', 'Referrals'],
|
||||
['/fees', 'Fees'],
|
||||
['/rewards', 'Rewards'],
|
||||
[expect.stringContaining('governance'), 'Governance'],
|
||||
];
|
||||
const links = menu.getAllByRole('link');
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
DApp,
|
||||
useLinks,
|
||||
FLAGS,
|
||||
useEnvNameMapping,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||
import { VegaIconNames, VegaIcon, VLogo } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -22,6 +22,7 @@ import { VegaWalletMenu } from '../vega-wallet';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { WalletIcon } from '../icons/wallet';
|
||||
import { ProtocolUpgradeCountdown } from '@vegaprotocol/proposals';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
type MenuState = 'wallet' | 'nav' | null;
|
||||
type Theme = 'system' | 'yellow';
|
||||
@@ -33,6 +34,7 @@ export const Navbar = ({
|
||||
children?: ReactNode;
|
||||
theme?: Theme;
|
||||
}) => {
|
||||
const t = useT();
|
||||
// menu state for small screens
|
||||
const [menu, setMenu] = useState<MenuState>(null);
|
||||
|
||||
@@ -73,7 +75,7 @@ export const Navbar = ({
|
||||
</div>
|
||||
|
||||
{/* Right section */}
|
||||
<div className="flex items-center justify-end ml-auto gap-2">
|
||||
<div className="ml-auto flex items-center justify-end gap-2">
|
||||
<ProtocolUpgradeCountdown />
|
||||
<NavbarMobileButton
|
||||
onClick={() => {
|
||||
@@ -107,18 +109,18 @@ export const Navbar = ({
|
||||
onOpenChange={(open) => setMenu((x) => (open ? x : null))}
|
||||
>
|
||||
<D.Overlay
|
||||
className="fixed inset-0 z-20 lg:hidden dark:bg-black/80 bg-black/50"
|
||||
className="fixed inset-0 z-20 bg-black/50 dark:bg-black/80 lg:hidden"
|
||||
data-testid="navbar-menu-overlay"
|
||||
/>
|
||||
<D.Content
|
||||
className={classNames(
|
||||
'lg:hidden',
|
||||
'fixed top-0 right-0 z-20 w-3/4 h-screen border-l border-default bg-vega-clight-700 dark:bg-vega-cdark-700',
|
||||
'border-default bg-vega-clight-700 dark:bg-vega-cdark-700 fixed right-0 top-0 z-20 h-screen w-3/4 border-l',
|
||||
navTextClasses
|
||||
)}
|
||||
data-testid="navbar-menu-content"
|
||||
>
|
||||
<div className="flex items-center justify-end h-10 p-1">
|
||||
<div className="flex h-10 items-center justify-end p-1">
|
||||
<NavbarMobileButton onClick={() => setMenu(null)}>
|
||||
<span className="sr-only">{t('Close menu')}</span>
|
||||
<VegaIcon name={VegaIconNames.CROSS} size={24} />
|
||||
@@ -138,11 +140,13 @@ export const Navbar = ({
|
||||
* of the navigation
|
||||
*/
|
||||
const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
const t = useT();
|
||||
const envNameMapping = useEnvNameMapping();
|
||||
const { VEGA_ENV, VEGA_NETWORKS, GITHUB_FEEDBACK_URL } = useEnvironment();
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
|
||||
return (
|
||||
<div className="lg:flex lg:h-full gap-3">
|
||||
<div className="gap-3 lg:flex lg:h-full">
|
||||
<NavbarList>
|
||||
<NavbarItem>
|
||||
<NavbarTrigger data-testid="navbar-network-switcher-trigger">
|
||||
@@ -192,6 +196,11 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
{t('Fees')}
|
||||
</NavbarLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<NavbarLink to={Links.REWARDS()} onClick={onClick}>
|
||||
{t('Rewards')}
|
||||
</NavbarLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<NavbarLinkExternal to={useLinks(DApp.Governance)()}>
|
||||
{t('Governance')}
|
||||
@@ -241,8 +250,8 @@ const NavbarTrigger = ({
|
||||
onPointerMove={preventHover}
|
||||
onPointerLeave={preventHover}
|
||||
className={classNames(
|
||||
'w-full lg:w-auto lg:h-full',
|
||||
'flex items-center justify-between lg:justify-center gap-2 px-6 py-2 lg:p-0',
|
||||
'w-full lg:h-full lg:w-auto',
|
||||
'flex items-center justify-between gap-2 px-6 py-2 lg:justify-center lg:p-0',
|
||||
'text-lg lg:text-sm',
|
||||
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100'
|
||||
)}
|
||||
@@ -273,8 +282,8 @@ const NavbarLink = ({
|
||||
to={to}
|
||||
end={end}
|
||||
className={classNames(
|
||||
'block lg:flex lg:h-full flex-col justify-center',
|
||||
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
||||
'block flex-col justify-center lg:flex lg:h-full',
|
||||
'px-6 py-2 text-lg lg:p-0 lg:text-sm',
|
||||
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100'
|
||||
)}
|
||||
onClick={onClick}
|
||||
@@ -297,7 +306,7 @@ const NavbarLink = ({
|
||||
</span>
|
||||
<span
|
||||
className={classNames(
|
||||
'hidden lg:block absolute left-0 bottom-0 w-full h-0',
|
||||
'absolute bottom-0 left-0 hidden h-0 w-full lg:block',
|
||||
borderClasses
|
||||
)}
|
||||
/>
|
||||
@@ -318,7 +327,7 @@ const NavbarSubItem = (props: LiHTMLAttributes<HTMLElement>) => {
|
||||
};
|
||||
|
||||
const NavbarList = (props: N.NavigationMenuListProps) => {
|
||||
return <N.List {...props} className="lg:flex lg:h-full gap-6" />;
|
||||
return <N.List {...props} className="gap-6 lg:flex lg:h-full" />;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -329,10 +338,10 @@ const NavbarContent = (props: N.NavigationMenuContentProps) => {
|
||||
<N.Content
|
||||
{...props}
|
||||
className={classNames(
|
||||
'group navbar-content',
|
||||
'lg:absolute lg:mt-2 pl-2 lg:pl-0 z-20 lg:min-w-[290px]',
|
||||
'navbar-content group',
|
||||
'z-20 pl-2 lg:absolute lg:mt-2 lg:min-w-[290px] lg:pl-0',
|
||||
'lg:bg-vega-clight-700 lg:dark:bg-vega-cdark-700',
|
||||
'lg:border border-vega-clight-500 dark:border-vega-cdark-500 lg:rounded'
|
||||
'border-vega-clight-500 dark:border-vega-cdark-500 lg:rounded lg:border'
|
||||
)}
|
||||
onPointerEnter={preventHover}
|
||||
onPointerLeave={preventHover}
|
||||
@@ -357,8 +366,8 @@ const NavbarLinkExternal = ({
|
||||
<NavLink
|
||||
to={to}
|
||||
className={classNames(
|
||||
'flex gap-2 lg:h-full items-center',
|
||||
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
||||
'flex items-center gap-2 lg:h-full',
|
||||
'px-6 py-2 text-lg lg:p-0 lg:text-sm',
|
||||
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100'
|
||||
)}
|
||||
onClick={onClick}
|
||||
@@ -386,7 +395,7 @@ const BurgerIcon = () => (
|
||||
const NavbarListDivider = () => {
|
||||
return (
|
||||
<div className="px-6 py-2 lg:px-0" role="separator">
|
||||
<div className="w-full h-px lg:h-full lg:w-px bg-vega-clight-500 dark:bg-vega-cdark-500" />
|
||||
<div className="bg-vega-clight-500 dark:bg-vega-cdark-500 h-px w-full lg:h-full lg:w-px" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -399,7 +408,7 @@ const NavbarMobileButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
|
||||
<button
|
||||
{...props}
|
||||
className={classNames(
|
||||
'w-8 h-8 lg:hidden flex items-center p-1 rounded ',
|
||||
'flex h-8 w-8 items-center rounded p-1 lg:hidden ',
|
||||
'hover:bg-vega-clight-500 dark:hover:bg-vega-cdark-500',
|
||||
'hover:text-vega-clight-50 dark:hover:text-vega-cdark-50'
|
||||
)}
|
||||
@@ -407,16 +416,6 @@ const NavbarMobileButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
|
||||
);
|
||||
};
|
||||
|
||||
const envNameMapping: Record<Networks, string> = {
|
||||
[Networks.VALIDATOR_TESTNET]: t('VALIDATOR_TESTNET'),
|
||||
[Networks.CUSTOM]: t('Custom'),
|
||||
[Networks.DEVNET]: t('Devnet'),
|
||||
[Networks.STAGNET1]: t('Stagnet'),
|
||||
[Networks.TESTNET]: t('Fairground testnet'),
|
||||
[Networks.MAINNET_MIRROR]: t('Mirror'),
|
||||
[Networks.MAINNET]: t('Mainnet'),
|
||||
};
|
||||
|
||||
// https://github.com/radix-ui/primitives/issues/1630
|
||||
// eslint-disable-next-line
|
||||
const preventHover = (e: any) => {
|
||||
|
||||
@@ -3,11 +3,12 @@ import {
|
||||
useNodeHealth,
|
||||
useNodeSwitcherStore,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Indicator, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { Tooltip } from '../../components/tooltip';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const NodeHealthContainer = () => {
|
||||
const t = useT();
|
||||
const { VEGA_URL, VEGA_INCIDENT_URL } = useEnvironment();
|
||||
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
||||
const { text, intent, datanodeBlockHeight } = useNodeHealth();
|
||||
@@ -57,6 +58,7 @@ interface NodeUrlProps {
|
||||
}
|
||||
|
||||
export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
const t = useT();
|
||||
const urlObj = new URL(url);
|
||||
const nodeUrl = urlObj.hostname;
|
||||
return <span title={t('Connected node')}>{nodeUrl}</span>;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { Filter, OrderListManager } from '@vegaprotocol/orders';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useNavigateWithMeta } from '../../lib/hooks/use-market-click-handler';
|
||||
@@ -9,8 +8,12 @@ import { persist } from 'zustand/middleware';
|
||||
import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
||||
import { OrderStatus } from '@vegaprotocol/types';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
const resolveNoRowsMessage = (filter?: Filter) => {
|
||||
const resolveNoRowsMessage = (
|
||||
filter: Filter | undefined,
|
||||
t: ReturnType<typeof useT>
|
||||
) => {
|
||||
switch (filter) {
|
||||
case Filter.Open:
|
||||
return t('No open orders');
|
||||
@@ -42,6 +45,7 @@ export interface OrderContainerProps {
|
||||
const AUTO_SIZE_COLUMNS = ['instrument-code'];
|
||||
|
||||
export const OrdersContainer = ({ filter }: OrderContainerProps) => {
|
||||
const t = useT();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const navigate = useNavigateWithMeta();
|
||||
const { gridState, updateGridState } = useOrderListGridState(filter);
|
||||
@@ -56,7 +60,7 @@ export const OrdersContainer = ({ filter }: OrderContainerProps) => {
|
||||
if (!pubKey) {
|
||||
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||
}
|
||||
const noRowsMessage = resolveNoRowsMessage(filter);
|
||||
const noRowsMessage = resolveNoRowsMessage(filter, t);
|
||||
|
||||
return (
|
||||
<OrderListManager
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user