locale/browserTag

This commit is contained in:
jaredvu
2023-08-23 17:18:10 -07:00
parent 42f4142307
commit 591166e93d
8 changed files with 108 additions and 30 deletions
-19
View File
@@ -1,19 +0,0 @@
import { useEffect, useMemo, useState } from 'react';
import { getSeparator } from '@/lib/numbers';
export const useLocaleSeparators = () => {
const [locale, setLocale] = useState(navigator.language || 'en-US');
useEffect(() => {
const handler = () => setLocale(navigator.language || 'en-US');
globalThis.addEventListener('languagechange', handler);
return () => globalThis.removeEventListener('languagechange', handler);
}, []);
return useMemo(() => {
return {
group: getSeparator({ locale, separatorType: 'group' }),
decimal: getSeparator({ locale, separatorType: 'decimal' }),
};
}, [locale]);
};
+55
View File
@@ -0,0 +1,55 @@
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { SUPPORTED_BASE_TAGS_LOCALE_MAPPING } from '@/constants/localization';
import { getSelectedLocale } from '@/state/localizationSelectors';
import abacusStateManager from '@/lib/abacus';
import { getSeparator } from '@/lib/numbers';
type LocaleContextType = ReturnType<typeof useLocaleContext>;
const LocaleContext = createContext<LocaleContextType>({} as LocaleContextType);
LocaleContext.displayName = 'Locale';
export const LocaleProvider = ({ ...props }) => (
<LocaleContext.Provider value={useLocaleContext()} {...props} />
);
const useLocaleContext = () => {
const selectedLocale = useSelector(getSelectedLocale);
const [browserLanguage, setBrowserLanguage] = useState(navigator.language || 'en-US');
useEffect(() => {
const handler = () => setBrowserLanguage(navigator.language || 'en-US');
globalThis.addEventListener('languagechange', handler);
return () => globalThis.removeEventListener('languagechange', handler);
}, []);
useEffect(() => {
if (selectedLocale) {
const updatedBrowserLanguage = Object.entries(SUPPORTED_BASE_TAGS_LOCALE_MAPPING).find(
([, value]) => value === selectedLocale
);
if (updatedBrowserLanguage) {
setBrowserLanguage(selectedLocale);
}
}
}, [selectedLocale]);
const separators = useMemo(() => {
return {
group: getSeparator({ browserLanguage, separatorType: 'group' }),
decimal: getSeparator({ browserLanguage, separatorType: 'decimal' }),
};
}, [browserLanguage]);
useEffect(() => {
abacusStateManager.setLocaleSeparators(separators);
}, [separators]);
return separators;
};
export const useLocaleSeparators = () => useContext(LocaleContext);
+15 -2
View File
@@ -1,12 +1,25 @@
import type { AbacusFormatterProtocol } from '@/constants/abacus';
import { type LocaleSeparators, MustBigNumber, getFractionDigits } from '../numbers';
class AbacusFormatter implements AbacusFormatterProtocol {
localeSeparators: LocaleSeparators;
constructor() {
this.localeSeparators = { group: ',', decimal: '.' };
}
setLocaleSeparators({ group, decimal }: LocaleSeparators) {
this.localeSeparators = { group, decimal };
}
percent(value: number, digits: number): string {
return value.toString();
return MustBigNumber(value).toFixed(digits);
}
dollar(value: number, tickSize: string): string {
return value.toString();
const tickSizeDecimals = getFractionDigits(tickSize);
return MustBigNumber(value).toFixed(tickSizeDecimals);
}
}
+8 -1
View File
@@ -34,6 +34,7 @@ import AbacusStateNotifier from './stateNotification';
import AbacusLocalizer from './localizer';
import AbacusFormatter from './formatter';
import AbacusThreading from './threading';
import { LocaleSeparators } from '../numbers';
class AbacusStateManager {
private store: RootStore | undefined;
@@ -42,12 +43,14 @@ class AbacusStateManager {
stateManager: InstanceType<typeof AsyncAbacusStateManager>;
websocket: AbacusWebsocket;
stateNotifier: AbacusStateNotifier;
abacusFormatter: AbacusFormatter;
constructor() {
this.store = undefined;
this.currentMarket = undefined;
this.stateNotifier = new AbacusStateNotifier();
this.websocket = new AbacusWebsocket();
this.abacusFormatter = new AbacusFormatter();
const ioImplementations = new IOImplementations(
// @ts-ignore
@@ -63,7 +66,7 @@ class AbacusStateManager {
const uiImplementations = new UIImplementations(
// @ts-ignore
new AbacusLocalizer(),
new AbacusFormatter()
this.abacusFormatter
);
this.stateManager = new AsyncAbacusStateManager(
@@ -179,6 +182,10 @@ class AbacusStateManager {
this.stateManager.closePosition(value, field);
};
setLocaleSeparators = ({ group, decimal }: LocaleSeparators) => {
this.abacusFormatter.setLocaleSeparators({ group, decimal });
};
// ------ Utils ------ //
placeOrderPayload = (): Nullable<HumanReadablePlaceOrderPayload> =>
this.stateManager.placeOrderPayload();
+4 -3
View File
@@ -1,6 +1,7 @@
import { BigNumber } from 'bignumber.js';
export type BigNumberish = BigNumber | string | number;
export type LocaleSeparators = { group?: string; decimal?: string };
export const BIG_NUMBERS = {
ZERO: new BigNumber(0),
@@ -56,12 +57,12 @@ export const shorternNumberForDisplay = (num?: number) =>
* @returns separator for the given locale and separator type
*/
export const getSeparator = ({
locale = navigator.language || 'en-US',
browserLanguage = navigator.language || 'en-US',
separatorType,
}: {
locale?: string;
browserLanguage?: string;
separatorType: Intl.NumberFormatPartTypes;
}) =>
Intl.NumberFormat(locale)
Intl.NumberFormat(browserLanguage)
.formatToParts(1000.1)
.find?.((part) => part.type === separatorType)?.value;
+18 -3
View File
@@ -13,7 +13,7 @@ import {
} from '@/constants/abacus';
import { AlertType } from '@/constants/alerts';
import { PERCENT_DECIMALS } from '@/constants/numbers';
import { PERCENT_DECIMALS, USD_DECIMALS } from '@/constants/numbers';
import { TRADE_ROUTE } from '@/constants/routes';
import { PositionSide, TradeTypes } from '@/constants/trade';
@@ -65,9 +65,13 @@ export const hasPositionSideChanged = ({
const formatErrorParam = ({
value,
format,
stepSizeDecimals,
tickSizeDecimals,
}: {
value: Nullable<string>;
format?: Nullable<string>;
stepSizeDecimals: Nullable<number>;
tickSizeDecimals: Nullable<number>;
}) => {
switch (format) {
case 'percent': {
@@ -76,7 +80,11 @@ const formatErrorParam = ({
}
case 'size': {
const sizeBN = MustBigNumber(value);
return sizeBN.toFixed(0);
return sizeBN.toFixed(stepSizeDecimals ?? 0);
}
case 'price': {
const dollarBN = MustBigNumber(value);
return `$${dollarBN.toFixed(tickSizeDecimals ?? USD_DECIMALS)}`;
}
default: {
return value || '';
@@ -90,9 +98,13 @@ const formatErrorParam = ({
export const getTradeInputAlert = ({
abacusInputErrors,
stringGetter,
stepSizeDecimals,
tickSizeDecimals,
}: {
abacusInputErrors: ValidationError[];
stringGetter: StringGetterFunction;
stepSizeDecimals: Nullable<number>;
tickSizeDecimals: Nullable<number>;
}) => {
const inputAlerts = abacusInputErrors.map(({ action: errorAction, resources, type }) => {
const { action, text } = resources || {};
@@ -104,7 +116,10 @@ export const getTradeInputAlert = ({
Object.fromEntries(
stringParams
.toArray()
.map(({ key, value, format }) => [key, formatErrorParam({ value, format })])
.map(({ key, value, format }) => [
key,
formatErrorParam({ value, format, stepSizeDecimals, tickSizeDecimals }),
])
);
return {
+4 -1
View File
@@ -11,12 +11,15 @@ import { ErrorBoundary } from './components/ErrorBoundary';
import './index.css';
import App from './App';
import { LocaleProvider } from './hooks/useLocaleSeparators';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<ErrorBoundary>
<StrictMode>
<Provider store={store}>
<HashRouter children={<App />} />
<LocaleProvider>
<HashRouter children={<App />} />
</LocaleProvider>
</Provider>
</StrictMode>
</ErrorBoundary>
+4 -1
View File
@@ -99,7 +99,8 @@ export const TradeForm = ({
const { limitPrice, triggerPrice, trailingPercent } = price || {};
const hasUncommittedOrders = useSelector(calculateHasUncommittedOrders);
const currentInput = useSelector(getCurrentInput);
const { tickSizeDecimals } = useSelector(getCurrentMarketConfig, shallowEqual) || {};
const { tickSizeDecimals, stepSizeDecimals } =
useSelector(getCurrentMarketConfig, shallowEqual) || {};
const needsAdvancedOptions =
needsGoodUntil || timeInForceOptions || executionOptions || needsPostOnly || needsReduceOnly;
@@ -120,6 +121,8 @@ export const TradeForm = ({
const inputAlert = getTradeInputAlert({
abacusInputErrors: tradeErrors ?? [],
stringGetter,
stepSizeDecimals,
tickSizeDecimals,
});
if (placeOrderError) {