feat(utils): use i18next (#5269)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
5827b87f89
commit
bb47747501
@ -8,7 +8,7 @@ import {
|
|||||||
doesValueEquateToParam,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/proposals';
|
} from '@vegaprotocol/proposals';
|
||||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { validateJson } from '@vegaprotocol/utils';
|
import { useValidateJson } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
@ -41,6 +41,7 @@ export interface NewAssetProposalFormFields {
|
|||||||
const DOCS_LINK = '/new-asset-proposal';
|
const DOCS_LINK = '/new-asset-proposal';
|
||||||
|
|
||||||
export const ProposeNewAsset = () => {
|
export const ProposeNewAsset = () => {
|
||||||
|
const validateJson = useValidateJson();
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: networkParamsLoading,
|
loading: networkParamsLoading,
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
doesValueEquateToParam,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/proposals';
|
} from '@vegaprotocol/proposals';
|
||||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { validateJson } from '@vegaprotocol/utils';
|
import { useValidateJson } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
@ -39,6 +39,7 @@ export interface NewMarketProposalFormFields {
|
|||||||
const DOCS_LINK = '/new-market-proposal';
|
const DOCS_LINK = '/new-market-proposal';
|
||||||
|
|
||||||
export const ProposeNewMarket = () => {
|
export const ProposeNewMarket = () => {
|
||||||
|
const validateJson = useValidateJson();
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: networkParamsLoading,
|
loading: networkParamsLoading,
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
RoundedWrapper,
|
RoundedWrapper,
|
||||||
TextArea,
|
TextArea,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { validateJson } from '@vegaprotocol/utils';
|
import { useValidateJson } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
@ -31,6 +31,7 @@ export interface RawProposalFormFields {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ProposeRaw = () => {
|
export const ProposeRaw = () => {
|
||||||
|
const validateJson = useValidateJson();
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: networkParamsLoading,
|
loading: networkParamsLoading,
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
doesValueEquateToParam,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/proposals';
|
} from '@vegaprotocol/proposals';
|
||||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { validateJson } from '@vegaprotocol/utils';
|
import { useValidateJson } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
@ -39,6 +39,7 @@ export interface UpdateAssetProposalFormFields {
|
|||||||
const DOCS_LINK = '/update-asset-proposal';
|
const DOCS_LINK = '/update-asset-proposal';
|
||||||
|
|
||||||
export const ProposeUpdateAsset = () => {
|
export const ProposeUpdateAsset = () => {
|
||||||
|
const validateJson = useValidateJson();
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: networkParamsLoading,
|
loading: networkParamsLoading,
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
} from '@vegaprotocol/proposals';
|
} from '@vegaprotocol/proposals';
|
||||||
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
|
||||||
import { validateJson } from '@vegaprotocol/utils';
|
import { useValidateJson } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
@ -53,6 +53,7 @@ export interface UpdateMarketProposalFormFields {
|
|||||||
const DOCS_LINK = '/update-market-proposal';
|
const DOCS_LINK = '/update-market-proposal';
|
||||||
|
|
||||||
export const ProposeUpdateMarket = () => {
|
export const ProposeUpdateMarket = () => {
|
||||||
|
const validateJson = useValidateJson();
|
||||||
const {
|
const {
|
||||||
params,
|
params,
|
||||||
loading: networkParamsLoading,
|
loading: networkParamsLoading,
|
||||||
@ -260,7 +261,7 @@ export const ProposeUpdateMarket = () => {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
{selectedMarket && (
|
{selectedMarket && (
|
||||||
<div className="mt-[-20px] mb-6">
|
<div className="mb-6 mt-[-20px]">
|
||||||
<KeyValueTable data-testid="update-market-details">
|
<KeyValueTable data-testid="update-market-details">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('MarketName')}
|
{t('MarketName')}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
import {
|
import {
|
||||||
maxSafe,
|
useMaxSafe,
|
||||||
required,
|
useRequired,
|
||||||
vegaPublicKey,
|
useVegaPublicKey,
|
||||||
addDecimal,
|
addDecimal,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@ -67,6 +67,9 @@ export const TransferForm = ({
|
|||||||
minQuantumMultiple,
|
minQuantumMultiple,
|
||||||
}: TransferFormProps) => {
|
}: TransferFormProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const maxSafe = useMaxSafe();
|
||||||
|
const required = useRequired();
|
||||||
|
const vegaPublicKey = useVegaPublicKey();
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
register,
|
register,
|
||||||
@ -415,7 +418,7 @@ export const TransferForm = ({
|
|||||||
{accountBalance && (
|
{accountBalance && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="absolute top-0 right-0 ml-auto text-xs underline"
|
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setValue('amount', parseFloat(accountBalance).toString(), {
|
setValue('amount', parseFloat(accountBalance).toString(), {
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
@ -491,7 +494,7 @@ export const TransferFee = ({
|
|||||||
const totalValue = new BigNumber(transferAmount).plus(fee).toString();
|
const totalValue = new BigNumber(transferAmount).plus(fee).toString();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col mb-4 text-xs gap-2">
|
<div className="mb-4 flex flex-col gap-2 text-xs">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-1">
|
<div className="flex flex-wrap items-center justify-between gap-1">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
description={t(
|
description={t(
|
||||||
@ -560,7 +563,7 @@ export const AddressField = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onChange}
|
onClick={onChange}
|
||||||
className="absolute top-0 right-0 ml-auto text-xs underline"
|
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||||
>
|
>
|
||||||
{isInput ? t('Select from wallet') : t('Enter manually')}
|
{isInput ? t('Select from wallet') : t('Enter manually')}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Controller, type Control } from 'react-hook-form';
|
import { Controller, type Control } from 'react-hook-form';
|
||||||
import type { Market } from '@vegaprotocol/markets';
|
import type { Market } from '@vegaprotocol/markets';
|
||||||
import type { OrderFormValues } from '../../hooks/use-form-values';
|
import type { OrderFormValues } from '../../hooks/use-form-values';
|
||||||
import { toDecimal, validateAmount } from '@vegaprotocol/utils';
|
import { toDecimal, useValidateAmount } from '@vegaprotocol/utils';
|
||||||
import {
|
import {
|
||||||
TradingFormGroup,
|
TradingFormGroup,
|
||||||
TradingInput,
|
TradingInput,
|
||||||
@ -28,6 +28,7 @@ export const DealTicketSizeIceberg = ({
|
|||||||
peakSize,
|
peakSize,
|
||||||
}: DealTicketSizeIcebergProps) => {
|
}: DealTicketSizeIcebergProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||||
|
|
||||||
const renderPeakSizeError = () => {
|
const renderPeakSizeError = () => {
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
formatValue,
|
formatValue,
|
||||||
removeDecimal,
|
removeDecimal,
|
||||||
toDecimal,
|
toDecimal,
|
||||||
validateAmount,
|
useValidateAmount,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { type Control, type UseFormWatch } from 'react-hook-form';
|
import { type Control, type UseFormWatch } from 'react-hook-form';
|
||||||
import { useForm, Controller, useController } from 'react-hook-form';
|
import { useForm, Controller, useController } from 'react-hook-form';
|
||||||
@ -109,6 +109,7 @@ const Trigger = ({
|
|||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
const triggerType = watch(oco ? 'ocoTriggerType' : 'triggerType');
|
const triggerType = watch(oco ? 'ocoTriggerType' : 'triggerType');
|
||||||
const triggerDirection = watch('triggerDirection');
|
const triggerDirection = watch('triggerDirection');
|
||||||
const isPriceTrigger = triggerType === 'price';
|
const isPriceTrigger = triggerType === 'price';
|
||||||
@ -341,6 +342,7 @@ const Size = ({
|
|||||||
assetUnit?: string;
|
assetUnit?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
return (
|
return (
|
||||||
<Controller
|
<Controller
|
||||||
name={oco ? 'ocoSize' : 'size'}
|
name={oco ? 'ocoSize' : 'size'}
|
||||||
@ -401,6 +403,7 @@ const Price = ({
|
|||||||
oco?: boolean;
|
oco?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
if (watch(oco ? 'ocoType' : 'type') === Schema.OrderType.TYPE_MARKET) {
|
if (watch(oco ? 'ocoType' : 'type') === Schema.OrderType.TYPE_MARKET) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import { useOpenVolume } from '@vegaprotocol/positions';
|
|||||||
import {
|
import {
|
||||||
toBigNum,
|
toBigNum,
|
||||||
removeDecimal,
|
removeDecimal,
|
||||||
validateAmount,
|
useValidateAmount,
|
||||||
toDecimal,
|
toDecimal,
|
||||||
formatForInput,
|
formatForInput,
|
||||||
formatValue,
|
formatValue,
|
||||||
@ -140,6 +140,7 @@ export const DealTicket = ({
|
|||||||
onDeposit,
|
onDeposit,
|
||||||
}: DealTicketProps) => {
|
}: DealTicketProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
const setType = useDealTicketFormValues((state) => state.setType);
|
const setType = useDealTicketFormValues((state) => state.setType);
|
||||||
const storedFormValues = useDealTicketFormValues(
|
const storedFormValues = useDealTicketFormValues(
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import type { Asset, AssetFieldsFragment } from '@vegaprotocol/assets';
|
import type { Asset, AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
import { AssetOption } from '@vegaprotocol/assets';
|
import { AssetOption } from '@vegaprotocol/assets';
|
||||||
import {
|
import {
|
||||||
ethereumAddress,
|
useEthereumAddress,
|
||||||
required,
|
useRequired,
|
||||||
vegaPublicKey,
|
useVegaPublicKey,
|
||||||
minSafe,
|
useMinSafe,
|
||||||
maxSafe,
|
useMaxSafe,
|
||||||
addDecimal,
|
addDecimal,
|
||||||
isAssetTypeERC20,
|
isAssetTypeERC20,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
@ -85,6 +85,11 @@ export const DepositForm = ({
|
|||||||
isFaucetable,
|
isFaucetable,
|
||||||
}: DepositFormProps) => {
|
}: DepositFormProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const ethereumAddress = useEthereumAddress();
|
||||||
|
const required = useRequired();
|
||||||
|
const vegaPublicKey = useVegaPublicKey();
|
||||||
|
const minSafe = useMinSafe();
|
||||||
|
const maxSafe = useMaxSafe();
|
||||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
const openDialog = useWeb3ConnectStore((store) => store.open);
|
const openDialog = useWeb3ConnectStore((store) => store.open);
|
||||||
const { isActive, account } = useWeb3React();
|
const { isActive, account } = useWeb3React();
|
||||||
@ -459,7 +464,7 @@ const UseButton = (props: UseButtonProps) => {
|
|||||||
<button
|
<button
|
||||||
{...props}
|
{...props}
|
||||||
type="button"
|
type="button"
|
||||||
className="absolute top-0 right-0 ml-auto text-sm underline"
|
className="absolute right-0 top-0 ml-auto text-sm underline"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -519,7 +524,7 @@ export const AddressField = ({
|
|||||||
setIsInput((curr) => !curr);
|
setIsInput((curr) => !curr);
|
||||||
onChange();
|
onChange();
|
||||||
}}
|
}}
|
||||||
className="absolute top-0 right-0 ml-auto text-sm underline"
|
className="absolute right-0 top-0 ml-auto text-sm underline"
|
||||||
data-testid="enter-pubkey-manually"
|
data-testid="enter-pubkey-manually"
|
||||||
>
|
>
|
||||||
{isInput ? t('Select from wallet') : t('Enter manually')}
|
{isInput ? t('Select from wallet') : t('Enter manually')}
|
||||||
|
15
libs/i18n/src/locales/en/utils.json
Normal file
15
libs/i18n/src/locales/en/utils.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"Expired on {{date}}": "Expired on {{date}}",
|
||||||
|
"Not time-based": "Not time-based",
|
||||||
|
"Expired": "Expired",
|
||||||
|
"Mark": "Mark",
|
||||||
|
"Required": "Required",
|
||||||
|
"Invalid Ethereum address": "Invalid Ethereum address",
|
||||||
|
"Invalid Vega key": "Invalid Vega key",
|
||||||
|
"Value is below minimum": "Value is below minimum",
|
||||||
|
"Value is above maximum": "Value is above maximum",
|
||||||
|
"Must be valid JSON": "Must be valid JSON",
|
||||||
|
"{{field}} must be a multiple of {{step}} for this market": "{{field}} must be a multiple of {{step}} for this market",
|
||||||
|
"{{field}} must be whole numbers for this market": "{{field}} must be whole numbers for this market",
|
||||||
|
"{{field}} accepts up to {{decimals}} decimal places": "{{field}} accepts up to {{decimals}} decimal places"
|
||||||
|
}
|
@ -3,7 +3,7 @@ import {
|
|||||||
getDateTimeFormat,
|
getDateTimeFormat,
|
||||||
addDecimal,
|
addDecimal,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
validateAmount,
|
useValidateAmount,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { Size } from '@vegaprotocol/datagrid';
|
import { Size } from '@vegaprotocol/datagrid';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
@ -39,6 +39,7 @@ export const OrderEditDialog = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}: OrderEditDialogProps) => {
|
}: OrderEditDialogProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
const headerClassName = 'text-xs font-bold text-black dark:text-white';
|
const headerClassName = 'text-xs font-bold text-black dark:text-white';
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
getDateTimeFormat,
|
getDateTimeFormat,
|
||||||
isNumeric,
|
isNumeric,
|
||||||
toBigNum,
|
toBigNum,
|
||||||
formatTrigger,
|
useFormatTrigger,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import {
|
import {
|
||||||
@ -52,6 +52,7 @@ export type StopOrdersTableProps = TypedDataAgGrid<StopOrder> & {
|
|||||||
export const StopOrdersTable = memo(
|
export const StopOrdersTable = memo(
|
||||||
({ onCancel, onMarketClick, onView, ...props }: StopOrdersTableProps) => {
|
({ onCancel, onMarketClick, onView, ...props }: StopOrdersTableProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const formatTrigger = useFormatTrigger();
|
||||||
const showAllActions = !props.isReadOnly;
|
const showAllActions = !props.isReadOnly;
|
||||||
const columnDefs: ColDef[] = useMemo(
|
const columnDefs: ColDef[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -282,7 +283,15 @@ export const StopOrdersTable = memo(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[onCancel, onMarketClick, onView, props.isReadOnly, showAllActions, t]
|
[
|
||||||
|
onCancel,
|
||||||
|
onMarketClick,
|
||||||
|
onView,
|
||||||
|
props.isReadOnly,
|
||||||
|
showAllActions,
|
||||||
|
t,
|
||||||
|
formatTrigger,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
14
libs/utils/__mocks__/react-i18next.ts
Normal file
14
libs/utils/__mocks__/react-i18next.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export const useTranslation = () => ({
|
||||||
|
t: (label: string, replacements?: Record<string, string>) => {
|
||||||
|
let translatedLabel = label;
|
||||||
|
if (typeof replacements === 'object' && replacements !== null) {
|
||||||
|
Object.keys(replacements).forEach((key) => {
|
||||||
|
translatedLabel = translatedLabel.replace(
|
||||||
|
`{{${key}}}`,
|
||||||
|
replacements[key]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return translatedLabel;
|
||||||
|
},
|
||||||
|
});
|
@ -1,27 +1,37 @@
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { addDecimalsFormatNumber } from './number';
|
import { addDecimalsFormatNumber } from './number';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useT } from '../use-t';
|
||||||
|
|
||||||
export const formatTrigger = (
|
export const useFormatTrigger = () => {
|
||||||
data: Pick<Schema.StopOrder, 'trigger' | 'triggerDirection'> | undefined,
|
const t = useT();
|
||||||
marketDecimalPlaces: number,
|
return useCallback(
|
||||||
defaultValue = '-'
|
(
|
||||||
) => {
|
data: Pick<Schema.StopOrder, 'trigger' | 'triggerDirection'> | undefined,
|
||||||
if (data && data?.trigger?.__typename === 'StopOrderPrice') {
|
marketDecimalPlaces: number,
|
||||||
return `${t('Mark')} ${
|
defaultValue = '-'
|
||||||
data?.triggerDirection ===
|
) => {
|
||||||
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
|
if (data && data?.trigger?.__typename === 'StopOrderPrice') {
|
||||||
? '<'
|
return `${t('Mark')} ${
|
||||||
: '>'
|
data?.triggerDirection ===
|
||||||
} ${addDecimalsFormatNumber(data.trigger.price, marketDecimalPlaces)}`;
|
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
|
||||||
}
|
? '<'
|
||||||
if (data && data?.trigger?.__typename === 'StopOrderTrailingPercentOffset') {
|
: '>'
|
||||||
return `${t('Mark')} ${
|
} ${addDecimalsFormatNumber(data.trigger.price, marketDecimalPlaces)}`;
|
||||||
data?.triggerDirection ===
|
}
|
||||||
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
|
if (
|
||||||
? '+'
|
data &&
|
||||||
: '-'
|
data?.trigger?.__typename === 'StopOrderTrailingPercentOffset'
|
||||||
}${(Number(data?.trigger.trailingPercentOffset) * 100).toFixed(1)}%`;
|
) {
|
||||||
}
|
return `${t('Mark')} ${
|
||||||
return defaultValue;
|
data?.triggerDirection ===
|
||||||
|
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
|
||||||
|
? '+'
|
||||||
|
: '-'
|
||||||
|
}${(Number(data?.trigger.trailingPercentOffset) * 100).toFixed(1)}%`;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MarketState } from '@vegaprotocol/types';
|
import { MarketState } from '@vegaprotocol/types';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { isValid, parseISO } from 'date-fns';
|
import { isValid, parseISO } from 'date-fns';
|
||||||
import { getDateTimeFormat } from './format';
|
import { getDateTimeFormat } from './format';
|
||||||
|
import { useT } from './use-t';
|
||||||
|
|
||||||
export const getMarketExpiryDate = (
|
export const getMarketExpiryDate = (
|
||||||
tags?: ReadonlyArray<string> | null
|
tags?: ReadonlyArray<string> | null
|
||||||
@ -40,12 +40,15 @@ export const getExpiryDate = (
|
|||||||
close: string | null,
|
close: string | null,
|
||||||
state: MarketState
|
state: MarketState
|
||||||
): string => {
|
): string => {
|
||||||
|
const t = useT();
|
||||||
const metadataExpiryDate = getMarketExpiryDate(tags);
|
const metadataExpiryDate = getMarketExpiryDate(tags);
|
||||||
const marketTimestampCloseDate = close && new Date(close);
|
const marketTimestampCloseDate = close && new Date(close);
|
||||||
let content = null;
|
let content = null;
|
||||||
if (!metadataExpiryDate) {
|
if (!metadataExpiryDate) {
|
||||||
content = marketTimestampCloseDate
|
content = marketTimestampCloseDate
|
||||||
? `Expired on ${getDateTimeFormat().format(marketTimestampCloseDate)}`
|
? t('Expired on {{date}}', {
|
||||||
|
date: getDateTimeFormat().format(marketTimestampCloseDate),
|
||||||
|
})
|
||||||
: t('Not time-based');
|
: t('Not time-based');
|
||||||
} else {
|
} else {
|
||||||
const isExpired =
|
const isExpired =
|
||||||
@ -54,7 +57,9 @@ export const getExpiryDate = (
|
|||||||
state === MarketState.STATE_SETTLED);
|
state === MarketState.STATE_SETTLED);
|
||||||
if (isExpired) {
|
if (isExpired) {
|
||||||
content = marketTimestampCloseDate
|
content = marketTimestampCloseDate
|
||||||
? `Expired on ${getDateTimeFormat().format(marketTimestampCloseDate)}`
|
? t('Expired on {{date}}', {
|
||||||
|
date: getDateTimeFormat().format(marketTimestampCloseDate),
|
||||||
|
})
|
||||||
: t('Expired');
|
: t('Expired');
|
||||||
} else {
|
} else {
|
||||||
content = getDateTimeFormat().format(metadataExpiryDate);
|
content = getDateTimeFormat().format(metadataExpiryDate);
|
||||||
|
3
libs/utils/src/lib/use-t.ts
Normal file
3
libs/utils/src/lib/use-t.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
export const ns = 'utils';
|
||||||
|
export const useT = () => useTranslation(ns).t;
|
@ -1,6 +1,10 @@
|
|||||||
import { ethereumAddress, vegaPublicKey } from './common';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { useEthereumAddress, useVegaPublicKey } from './common';
|
||||||
|
|
||||||
it('ethereumAddress', () => {
|
it('ethereumAddress', () => {
|
||||||
|
const result = renderHook(useEthereumAddress);
|
||||||
|
const ethereumAddress = result.result.current;
|
||||||
|
|
||||||
const errorMessage = 'Invalid Ethereum address';
|
const errorMessage = 'Invalid Ethereum address';
|
||||||
|
|
||||||
const validAddress = '0x72c22822A19D20DE7e426fB84aa047399Ddd8853';
|
const validAddress = '0x72c22822A19D20DE7e426fB84aa047399Ddd8853';
|
||||||
@ -17,6 +21,9 @@ it('ethereumAddress', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('vegaPublicKey', () => {
|
it('vegaPublicKey', () => {
|
||||||
|
const result = renderHook(useVegaPublicKey);
|
||||||
|
const vegaPublicKey = result.result.current;
|
||||||
|
|
||||||
const errorMessage = 'Invalid Vega key';
|
const errorMessage = 'Invalid Vega key';
|
||||||
|
|
||||||
const validKey =
|
const validKey =
|
||||||
|
@ -1,40 +1,71 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { useT } from '../use-t';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
export const required = (value: string) => {
|
export const useRequired = () => {
|
||||||
if (value === null || value === undefined || value === '') {
|
const t = useT();
|
||||||
return t('Required');
|
return useCallback(
|
||||||
}
|
(value: string) => {
|
||||||
return true;
|
if (value === null || value === undefined || value === '') {
|
||||||
|
return t('Required');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ethereumAddress = (value: string) => {
|
export const useEthereumAddress = () => {
|
||||||
if (!/^0x[0-9a-fA-F]{40}$/i.test(value)) {
|
const t = useT();
|
||||||
return t('Invalid Ethereum address');
|
return useCallback(
|
||||||
}
|
(value: string) => {
|
||||||
return true;
|
if (!/^0x[0-9a-fA-F]{40}$/i.test(value)) {
|
||||||
|
return t('Invalid Ethereum address');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VEGA_ID_REGEX = /^[A-Fa-f0-9]{64}$/i;
|
export const VEGA_ID_REGEX = /^[A-Fa-f0-9]{64}$/i;
|
||||||
export const vegaPublicKey = (value: string) => {
|
export const useVegaPublicKey = () => {
|
||||||
if (!VEGA_ID_REGEX.test(value)) {
|
const t = useT();
|
||||||
return t('Invalid Vega key');
|
return useCallback(
|
||||||
}
|
(value: string) => {
|
||||||
return true;
|
if (!VEGA_ID_REGEX.test(value)) {
|
||||||
|
return t('Invalid Vega key');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const minSafe = (min: BigNumber) => (value: string) => {
|
export const useMinSafe = () => {
|
||||||
if (new BigNumber(value).isLessThan(min)) {
|
const t = useT();
|
||||||
return t('Value is below minimum');
|
return useCallback(
|
||||||
}
|
(min: BigNumber) => (value: string) => {
|
||||||
return true;
|
if (new BigNumber(value).isLessThan(min)) {
|
||||||
|
return t('Value is below minimum');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const maxSafe = (max: BigNumber) => (value: string) => {
|
export const useMaxSafe = () => {
|
||||||
if (new BigNumber(value).isGreaterThan(max)) {
|
const t = useT();
|
||||||
return t('Value is above maximum');
|
return useCallback(
|
||||||
}
|
(max: BigNumber) => (value: string) => {
|
||||||
return true;
|
if (new BigNumber(value).isGreaterThan(max)) {
|
||||||
|
return t('Value is above maximum');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const suitableForSyntaxHighlighter = (str: string) => {
|
export const suitableForSyntaxHighlighter = (str: string) => {
|
||||||
@ -46,11 +77,17 @@ export const suitableForSyntaxHighlighter = (str: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateJson = (value: string) => {
|
export const useValidateJson = () => {
|
||||||
try {
|
const t = useT();
|
||||||
JSON.parse(value);
|
return useCallback(
|
||||||
return true;
|
(value: string) => {
|
||||||
} catch (e) {
|
try {
|
||||||
return t('Must be valid JSON');
|
JSON.parse(value);
|
||||||
}
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return t('Must be valid JSON');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,40 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { useCallback } from 'react';
|
||||||
|
import { useT } from '../use-t';
|
||||||
|
|
||||||
export const validateAmount = (step: number | string, field: string) => {
|
export const useValidateAmount = () => {
|
||||||
const [, stepDecimals = ''] = String(step).split('.');
|
const t = useT();
|
||||||
|
return useCallback(
|
||||||
|
(step: number | string, field: string) => {
|
||||||
|
const [, stepDecimals = ''] = String(step).split('.');
|
||||||
|
|
||||||
return (value?: string) => {
|
return (value?: string) => {
|
||||||
if (Number(step) > 1) {
|
if (Number(step) > 1) {
|
||||||
if (Number(value) % Number(step) > 0) {
|
if (Number(value) % Number(step) > 0) {
|
||||||
return t(`${field} must be a multiple of ${step} for this market`);
|
return t(
|
||||||
}
|
'{{field}} must be a multiple of {{step}} for this market',
|
||||||
return true;
|
{
|
||||||
}
|
field,
|
||||||
const [, valueDecimals = ''] = (value || '').split('.');
|
step,
|
||||||
if (stepDecimals.length < valueDecimals.length) {
|
}
|
||||||
if (stepDecimals === '') {
|
);
|
||||||
return t(`${field} must be whole numbers for this market`);
|
}
|
||||||
}
|
return true;
|
||||||
return t(`${field} accepts up to ${stepDecimals.length} decimal places`);
|
}
|
||||||
}
|
const [, valueDecimals = ''] = (value || '').split('.');
|
||||||
return true;
|
if (stepDecimals.length < valueDecimals.length) {
|
||||||
};
|
if (stepDecimals === '') {
|
||||||
|
return t('{{field}} must be whole numbers for this market', {
|
||||||
|
field,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return t('{{field}} accepts up to {{decimals}} decimal places', {
|
||||||
|
field,
|
||||||
|
decimals: stepDecimals.length,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ import {
|
|||||||
formatNumber,
|
formatNumber,
|
||||||
toBigNum,
|
toBigNum,
|
||||||
truncateByChars,
|
truncateByChars,
|
||||||
formatTrigger,
|
useFormatTrigger,
|
||||||
MAXGOINT64,
|
MAXGOINT64,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { useAssetsMapProvider } from '@vegaprotocol/assets';
|
import { useAssetsMapProvider } from '@vegaprotocol/assets';
|
||||||
@ -260,6 +260,7 @@ const SubmitStopOrderSetup = ({
|
|||||||
triggerDirection: Schema.StopOrderTriggerDirection;
|
triggerDirection: Schema.StopOrderTriggerDirection;
|
||||||
market: Market;
|
market: Market;
|
||||||
}) => {
|
}) => {
|
||||||
|
const formatTrigger = useFormatTrigger();
|
||||||
if (!market || !stopOrderSetup) return null;
|
if (!market || !stopOrderSetup) return null;
|
||||||
|
|
||||||
const { price, size, side } = stopOrderSetup.orderSubmission;
|
const { price, size, side } = stopOrderSetup.orderSubmission;
|
||||||
@ -446,6 +447,7 @@ const CancelOrderDetails = ({
|
|||||||
|
|
||||||
const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
|
const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const formatTrigger = useFormatTrigger();
|
||||||
const { data: orderById } = useStopOrderByIdQuery({
|
const { data: orderById } = useStopOrderByIdQuery({
|
||||||
variables: { stopOrderId },
|
variables: { stopOrderId },
|
||||||
});
|
});
|
||||||
@ -732,7 +734,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
|||||||
<p>{t('Your funds have been unlocked for withdrawal.')}</p>
|
<p>{t('Your funds have been unlocked for withdrawal.')}</p>
|
||||||
{tx.txHash && (
|
{tx.txHash && (
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
className="block mb-[5px] break-all"
|
className="mb-[5px] block break-all"
|
||||||
href={explorerLink(EXPLORER_TX.replace(':hash', tx.txHash))}
|
href={explorerLink(EXPLORER_TX.replace(':hash', tx.txHash))}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import type { Asset } from '@vegaprotocol/assets';
|
import type { Asset } from '@vegaprotocol/assets';
|
||||||
import { AssetOption } from '@vegaprotocol/assets';
|
import { AssetOption } from '@vegaprotocol/assets';
|
||||||
import {
|
import {
|
||||||
ethereumAddress,
|
useEthereumAddress,
|
||||||
minSafe,
|
useRequired,
|
||||||
|
useMinSafe,
|
||||||
removeDecimal,
|
removeDecimal,
|
||||||
required,
|
|
||||||
isAssetTypeERC20,
|
isAssetTypeERC20,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
@ -23,7 +23,6 @@ import {
|
|||||||
import { useWeb3React } from '@web3-react/core';
|
import { useWeb3React } from '@web3-react/core';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { useEffect, type ButtonHTMLAttributes } from 'react';
|
import { useEffect, type ButtonHTMLAttributes } from 'react';
|
||||||
import type { ControllerRenderProps } from 'react-hook-form';
|
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { useForm, Controller, useWatch } from 'react-hook-form';
|
import { useForm, Controller, useWatch } from 'react-hook-form';
|
||||||
import { WithdrawLimits } from './withdraw-limits';
|
import { WithdrawLimits } from './withdraw-limits';
|
||||||
@ -112,6 +111,10 @@ export const WithdrawForm = ({
|
|||||||
onSelectAsset,
|
onSelectAsset,
|
||||||
submitWithdraw,
|
submitWithdraw,
|
||||||
}: WithdrawFormProps) => {
|
}: WithdrawFormProps) => {
|
||||||
|
const ethereumAddress = useEthereumAddress();
|
||||||
|
const required = useRequired();
|
||||||
|
const minSafe = useMinSafe();
|
||||||
|
|
||||||
const { account: address } = useWeb3React();
|
const { account: address } = useWeb3React();
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@ -150,36 +153,6 @@ export const WithdrawForm = ({
|
|||||||
trigger('to');
|
trigger('to');
|
||||||
}, [address, setValue, trigger]);
|
}, [address, setValue, trigger]);
|
||||||
|
|
||||||
const renderAssetsSelector = ({
|
|
||||||
field,
|
|
||||||
}: {
|
|
||||||
field: ControllerRenderProps<FormFields, 'asset'>;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<TradingRichSelect
|
|
||||||
data-testid="select-asset"
|
|
||||||
id="asset"
|
|
||||||
name="asset"
|
|
||||||
required
|
|
||||||
onValueChange={(value) => {
|
|
||||||
onSelectAsset(value);
|
|
||||||
field.onChange(value);
|
|
||||||
}}
|
|
||||||
placeholder={t('Please select an asset')}
|
|
||||||
value={selectedAsset?.id}
|
|
||||||
hasError={Boolean(errors.asset?.message)}
|
|
||||||
>
|
|
||||||
{assets.filter(isAssetTypeERC20).map((a) => (
|
|
||||||
<AssetOption
|
|
||||||
key={a.id}
|
|
||||||
asset={a}
|
|
||||||
balance={<AssetBalance asset={a} />}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</TradingRichSelect>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const showWithdrawDelayNotification =
|
const showWithdrawDelayNotification =
|
||||||
Boolean(delay) &&
|
Boolean(delay) &&
|
||||||
Boolean(selectedAsset) &&
|
Boolean(selectedAsset) &&
|
||||||
@ -189,7 +162,7 @@ export const WithdrawForm = ({
|
|||||||
<>
|
<>
|
||||||
<div className="mb-4 text-sm">
|
<div className="mb-4 text-sm">
|
||||||
<p>{t('There are two steps required to make a withdrawal')}</p>
|
<p>{t('There are two steps required to make a withdrawal')}</p>
|
||||||
<ol className="pl-4 list-disc">
|
<ol className="list-disc pl-4">
|
||||||
<li>{t('Step 1 - Release funds from Vega')}</li>
|
<li>{t('Step 1 - Release funds from Vega')}</li>
|
||||||
<li>{t('Step 2 - Transfer funds to your Ethereum wallet')}</li>
|
<li>{t('Step 2 - Transfer funds to your Ethereum wallet')}</li>
|
||||||
</ol>
|
</ol>
|
||||||
@ -208,7 +181,29 @@ export const WithdrawForm = ({
|
|||||||
required: (value) => !!selectedAsset || required(value),
|
required: (value) => !!selectedAsset || required(value),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
render={renderAssetsSelector}
|
render={({ field }) => (
|
||||||
|
<TradingRichSelect
|
||||||
|
data-testid="select-asset"
|
||||||
|
id="asset"
|
||||||
|
name="asset"
|
||||||
|
required
|
||||||
|
onValueChange={(value) => {
|
||||||
|
onSelectAsset(value);
|
||||||
|
field.onChange(value);
|
||||||
|
}}
|
||||||
|
placeholder={t('Please select an asset')}
|
||||||
|
value={selectedAsset?.id}
|
||||||
|
hasError={Boolean(errors.asset?.message)}
|
||||||
|
>
|
||||||
|
{assets.filter(isAssetTypeERC20).map((a) => (
|
||||||
|
<AssetOption
|
||||||
|
key={a.id}
|
||||||
|
asset={a}
|
||||||
|
balance={<AssetBalance asset={a} />}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TradingRichSelect>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
{errors.asset?.message && (
|
{errors.asset?.message && (
|
||||||
<TradingInputError intent="danger">
|
<TradingInputError intent="danger">
|
||||||
@ -314,7 +309,7 @@ const UseButton = (props: UseButtonProps) => {
|
|||||||
<button
|
<button
|
||||||
{...props}
|
{...props}
|
||||||
type="button"
|
type="button"
|
||||||
className="absolute top-0 right-0 ml-auto text-sm underline"
|
className="absolute right-0 top-0 ml-auto text-sm underline"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user