From 113337e9c39d39534f8e9adf66ca094ba69a1252 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sat, 4 Jan 2025 11:38:30 +0330 Subject: [PATCH 01/29] #246 feat: fetch and store currencies as a Map in Redux state --- src/main/Browser/Browser.js | 12 ++++++++++++ src/store/actions/actionTypes.js | 5 ++++- src/store/actions/exchange.js | 7 +++++++ src/store/actions/index.js | 3 ++- src/store/reducers/exchangeReducer.js | 10 +++++++++- src/store/sagas/global.js | 23 +++++++++++++++++++++++ 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index 289d9b94..55a1e376 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -23,6 +23,7 @@ import Guide from "./Pages/Info/Guide/Guide"; import Rules from "./Pages/Info/Rules/Rules"; import ContactUs from "./Pages/Info/ContactUs/ContactUs"; import EasyTrading from "./Pages/EasyTrading/EasyTrading"; +import axios from "axios"; const Browser = () => { const query = useQuery(); @@ -34,6 +35,10 @@ const Browser = () => { const title = useSelector((state) => state.exchange.title) const description = useSelector((state) => state.exchange.description) + const currencies = useSelector((state) => state.exchange.currencies) + + console.log("currencies from redux", currencies) + theme === "DARK" ? document.body.classList.add('dark') : document.body.classList.remove('dark'); @@ -59,6 +64,13 @@ const Browser = () => { meta.description.content = description ? description : " " }, [title, description]) + + /*const getCurrencies = (currency = "") => { + return axios.get(`/wallet/currency/${currency}`) + } + + console.log("getCurrencies", getCurrencies())*/ + if (isLoading) return if (hasError) return diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 1c897a99..45c924da 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -53,4 +53,7 @@ export const SET_USER_CONFIG = "SET_USER_CONFIG" export const SET_FAV_PAIR = "SET_FAV_PAIR" export const SET_FAV_PAIR_INITIATE = "SET_FAV_PAIR_INITIATE" -export const GET_USER_CONFIGS_INITIATE = "GET_USER_CONFIGS_INITIATE" \ No newline at end of file +export const GET_USER_CONFIGS_INITIATE = "GET_USER_CONFIGS_INITIATE" + + +export const GET_CURRENCIES = "GET_CURRENCIES"; \ No newline at end of file diff --git a/src/store/actions/exchange.js b/src/store/actions/exchange.js index 79c0d27a..ab1ed15a 100644 --- a/src/store/actions/exchange.js +++ b/src/store/actions/exchange.js @@ -97,4 +97,11 @@ export const setExchangeConfigs = configs => { type: actionTypes.SET_EXCHANGE_CONFIG, configs: configs }; +}; + +export const getCurrencies = currencies => { + return { + type: actionTypes.GET_CURRENCIES, + currencies, + }; }; \ No newline at end of file diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 0acfe700..8292561d 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -22,7 +22,8 @@ export { setIPGInitiate, setVerifyEmailLock, setVerifyEmailLockInitiate, - setExchangeConfigs + setExchangeConfigs, + getCurrencies } from "./exchange"; diff --git a/src/store/reducers/exchangeReducer.js b/src/store/reducers/exchangeReducer.js index a34e2f46..f6df2ac9 100644 --- a/src/store/reducers/exchangeReducer.js +++ b/src/store/reducers/exchangeReducer.js @@ -27,7 +27,8 @@ const initialState = { defaultTheme: "", supportEmail: "", baseCurrency: "", - dateType: "" + dateType: "", + currencies: [] }; const exchangeReducer = (state = initialState, action) => { @@ -105,6 +106,13 @@ const exchangeReducer = (state = initialState, action) => { ...state, ...action.configs }; + + case actionTypes.GET_CURRENCIES: + return { + ...state, + currencies: action.currencies, + }; + default: return state; } diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index 3bf4294c..e050b142 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -65,6 +65,21 @@ function* getExchangeInfo() { throw new Error('getExchangeInfo failed!') } } +function* fetchCurrencies() { + for (let i = 0; i < 10; i++) { + try { + const response = yield call(axios.get, '/wallet/currency'); + const { currencies } = response.data; + return currencies; + } catch (err) { + if (i < 9) { + yield delay(1000); + } else { + throw new Error('Failed to fetch currencies after 10 attempts.'); + } + } + } +} export function* loadConfig(action) { @@ -100,6 +115,13 @@ export function* loadConfig(action) { try { + const currencies = yield call(fetchCurrencies); + const currenciesMap = currencies.reduce((acc, currency) => { + acc[currency.symbol] = currency; + return acc; + }, {}); + yield put(actions.getCurrencies(currenciesMap)); + const localTheme = yield call([localStorage, 'getItem'], 'theme') if (localTheme) appTheme = localTheme; @@ -125,6 +147,7 @@ export function* loadConfig(action) { lastPrice[symbol.symbol] = 0 } yield put(actions.setExchange({pairs, assets, symbols, lastPrice})); + /*yield put(actions.getCurrencies({currencies}));*/ yield put(actions.setUserAccountInfo({wallets, tradeFee})); const activePair = yield call([localStorage, 'getItem'], 'activePair') From 24752b770297e9ebad7af9ab81df64c30b624428 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sat, 4 Jan 2025 13:27:16 +0330 Subject: [PATCH 02/29] #246 refactor: optimize pairs data storage in Redux state --- src/main/Browser/Browser.js | 10 ++-------- src/store/actions/actionTypes.js | 3 ++- src/store/actions/exchange.js | 6 ++++++ src/store/actions/index.js | 3 ++- src/store/reducers/exchangeReducer.js | 8 +++++++- src/store/sagas/global.js | 20 ++++++++++++++++++++ 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index 55a1e376..a689de67 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -36,8 +36,9 @@ const Browser = () => { const description = useSelector((state) => state.exchange.description) const currencies = useSelector((state) => state.exchange.currencies) + const pairsList = useSelector((state) => state.exchange.pairsList) - console.log("currencies from redux", currencies) + console.log("pairsList from redux", pairsList) theme === "DARK" ? document.body.classList.add('dark') : document.body.classList.remove('dark'); @@ -64,13 +65,6 @@ const Browser = () => { meta.description.content = description ? description : " " }, [title, description]) - - /*const getCurrencies = (currency = "") => { - return axios.get(`/wallet/currency/${currency}`) - } - - console.log("getCurrencies", getCurrencies())*/ - if (isLoading) return if (hasError) return diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 45c924da..fa362f32 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -56,4 +56,5 @@ export const SET_FAV_PAIR_INITIATE = "SET_FAV_PAIR_INITIATE" export const GET_USER_CONFIGS_INITIATE = "GET_USER_CONFIGS_INITIATE" -export const GET_CURRENCIES = "GET_CURRENCIES"; \ No newline at end of file +export const GET_CURRENCIES = "GET_CURRENCIES"; +export const GET_PAIRS = "GET_PAIRS"; \ No newline at end of file diff --git a/src/store/actions/exchange.js b/src/store/actions/exchange.js index ab1ed15a..03549a15 100644 --- a/src/store/actions/exchange.js +++ b/src/store/actions/exchange.js @@ -104,4 +104,10 @@ export const getCurrencies = currencies => { type: actionTypes.GET_CURRENCIES, currencies, }; +}; +export const getPairs = pairs => { + return { + type: actionTypes.GET_PAIRS, + pairs, + }; }; \ No newline at end of file diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 8292561d..746533a0 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -23,7 +23,8 @@ export { setVerifyEmailLock, setVerifyEmailLockInitiate, setExchangeConfigs, - getCurrencies + getCurrencies, + getPairs } from "./exchange"; diff --git a/src/store/reducers/exchangeReducer.js b/src/store/reducers/exchangeReducer.js index f6df2ac9..9a107dc8 100644 --- a/src/store/reducers/exchangeReducer.js +++ b/src/store/reducers/exchangeReducer.js @@ -28,7 +28,8 @@ const initialState = { supportEmail: "", baseCurrency: "", dateType: "", - currencies: [] + currencies: [], + pairsList: [] }; const exchangeReducer = (state = initialState, action) => { @@ -112,6 +113,11 @@ const exchangeReducer = (state = initialState, action) => { ...state, currencies: action.currencies, }; + case actionTypes.GET_PAIRS: + return { + ...state, + pairsList: action.pairs, + }; default: return state; diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index e050b142..cc09726f 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -54,6 +54,8 @@ function* getExchangeInfo() { for (let i = 0; i < 10; i++) { try { const {data: {symbols}} = yield call(axios.get, '/api/v3/exchangeInfo') + + console.log("symbols", symbols) return symbols } catch (err) { if (i < 2) { @@ -122,6 +124,24 @@ export function* loadConfig(action) { }, {}); yield put(actions.getCurrencies(currenciesMap)); + const pairsList = yield call(getExchangeInfo); + const pairsListMap = pairsList.reduce((acc, pair) => { + /*acc[pair.symbol] = pair;*/ + acc[pair.symbol] = { + symbol: pair.symbol, + baseAsset: pair.baseAsset, + quoteAsset: pair.quoteAsset, + orderTypes: pair.orderTypes, + }; + return acc; + }, {}); + yield put(actions.getPairs(pairsListMap)); + + + + console.log("pairsListMap", pairsListMap) + + const localTheme = yield call([localStorage, 'getItem'], 'theme') if (localTheme) appTheme = localTheme; From c0cc409269718aceaa48d73dbc8783d62ac8d768 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sat, 4 Jan 2025 14:06:36 +0330 Subject: [PATCH 03/29] #246 feat: fetch and store fees as a Map in Redux state --- src/main/Browser/Browser.js | 2 ++ src/store/actions/actionTypes.js | 3 ++- src/store/actions/exchange.js | 7 +++++++ src/store/actions/index.js | 4 ++-- src/store/reducers/exchangeReducer.js | 8 +++++++- src/store/sagas/global.js | 27 +++++++++++++++++++++------ 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index a689de67..56a45beb 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -37,7 +37,9 @@ const Browser = () => { const currencies = useSelector((state) => state.exchange.currencies) const pairsList = useSelector((state) => state.exchange.pairsList) + const fees = useSelector((state) => state.exchange.fees) + console.log("fees from redux", fees) console.log("pairsList from redux", pairsList) diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index fa362f32..699da1ab 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -57,4 +57,5 @@ export const GET_USER_CONFIGS_INITIATE = "GET_USER_CONFIGS_INITIATE" export const GET_CURRENCIES = "GET_CURRENCIES"; -export const GET_PAIRS = "GET_PAIRS"; \ No newline at end of file +export const GET_PAIRS = "GET_PAIRS"; +export const GET_FEES = "GET_FEES"; \ No newline at end of file diff --git a/src/store/actions/exchange.js b/src/store/actions/exchange.js index 03549a15..2261c7af 100644 --- a/src/store/actions/exchange.js +++ b/src/store/actions/exchange.js @@ -1,4 +1,5 @@ import * as actionTypes from "./actionTypes"; +import {GET_FEES} from "./actionTypes"; export const setActivePairInitiate = (pair, activeTab) => { return { @@ -110,4 +111,10 @@ export const getPairs = pairs => { type: actionTypes.GET_PAIRS, pairs, }; +}; +export const getFees = fees => { + return { + type: actionTypes.GET_FEES, + fees, + }; }; \ No newline at end of file diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 746533a0..36947b0a 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -24,8 +24,8 @@ export { setVerifyEmailLockInitiate, setExchangeConfigs, getCurrencies, - getPairs - + getPairs, + getFees } from "./exchange"; export { diff --git a/src/store/reducers/exchangeReducer.js b/src/store/reducers/exchangeReducer.js index 9a107dc8..370c5a70 100644 --- a/src/store/reducers/exchangeReducer.js +++ b/src/store/reducers/exchangeReducer.js @@ -29,7 +29,8 @@ const initialState = { baseCurrency: "", dateType: "", currencies: [], - pairsList: [] + pairsList: [], + fees: [], }; const exchangeReducer = (state = initialState, action) => { @@ -118,6 +119,11 @@ const exchangeReducer = (state = initialState, action) => { ...state, pairsList: action.pairs, }; + case actionTypes.GET_FEES: + return { + ...state, + fees: action.fees, + }; default: return state; diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index cc09726f..e20d1e28 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -53,10 +53,9 @@ function* getExchangeInfo() { for (let i = 0; i < 10; i++) { try { - const {data: {symbols}} = yield call(axios.get, '/api/v3/exchangeInfo') + const {data} = yield call(axios.get, '/api/v3/exchangeInfo') - console.log("symbols", symbols) - return symbols + return data } catch (err) { if (i < 2) { yield delay(1000) @@ -117,6 +116,8 @@ export function* loadConfig(action) { try { + const exchangeInfo = yield call(getExchangeInfo); + const currencies = yield call(fetchCurrencies); const currenciesMap = currencies.reduce((acc, currency) => { acc[currency.symbol] = currency; @@ -124,10 +125,11 @@ export function* loadConfig(action) { }, {}); yield put(actions.getCurrencies(currenciesMap)); - const pairsList = yield call(getExchangeInfo); + const pairsList = exchangeInfo.symbols; const pairsListMap = pairsList.reduce((acc, pair) => { /*acc[pair.symbol] = pair;*/ - acc[pair.symbol] = { + const key = `${pair.baseAsset}_${pair.quoteAsset}`; + acc[key] = { symbol: pair.symbol, baseAsset: pair.baseAsset, quoteAsset: pair.quoteAsset, @@ -137,6 +139,19 @@ export function* loadConfig(action) { }, {}); yield put(actions.getPairs(pairsListMap)); + const fees = exchangeInfo.fees; + const feesMap = fees.reduce((acc, fee) => { + acc[fee.pair] = fee; + /* acc[pair.symbol] = { + symbol: pair.symbol, + baseAsset: pair.baseAsset, + quoteAsset: pair.quoteAsset, + orderTypes: pair.orderTypes, + };*/ + return acc; + }, {}); + yield put(actions.getFees(feesMap)); + console.log("pairsListMap", pairsListMap) @@ -145,7 +160,7 @@ export function* loadConfig(action) { const localTheme = yield call([localStorage, 'getItem'], 'theme') if (localTheme) appTheme = localTheme; - const symbols = yield call(getExchangeInfo) + const symbols = exchangeInfo.symbols for (const symbol of symbols) { if (symbol.symbol.toUpperCase().includes("NLN")) continue if (!assets.includes(symbol.baseAsset)) { From 692b183074dca8c7ee4e55e1688e17277f838e9a Mon Sep 17 00:00:00 2001 From: Hossein Date: Sun, 5 Jan 2025 14:01:02 +0330 Subject: [PATCH 04/29] #246 Feat: Add utility function to retrieve currency name or alias based on language --- src/main/Browser/Browser.js | 1 + .../components/MarketInfo/MarketInfo.js | 14 +++++++++++--- src/utils/utils.js | 18 +++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index 56a45beb..6d17e7dd 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -39,6 +39,7 @@ const Browser = () => { const pairsList = useSelector((state) => state.exchange.pairsList) const fees = useSelector((state) => state.exchange.fees) + console.log("currencies from redux", currencies) console.log("fees from redux", fees) console.log("pairsList from redux", pairsList) diff --git a/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js b/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js index c88dee96..94493d14 100644 --- a/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js +++ b/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js @@ -10,6 +10,7 @@ import Loading from "../../../../../../components/Loading/Loading"; import Error from "../../../../../../components/Error/Error"; import {useTranslation} from "react-i18next"; import i18n from "i18next"; +import {useSelector} from "react-redux"; const MarketInfo = () => { @@ -21,8 +22,12 @@ const MarketInfo = () => { const interval = "24h" const quote = activeCurrency === "" ? null : activeCurrency + const currencies = useSelector((state) => state.exchange.currencies) + const {data: overview, isLoading, error} = useOverview(null, interval, quote) - const {data: currencies} = useGetQuoteCurrencies() + const {data: quoteCurrencies} = useGetQuoteCurrencies() + + console.log("overview", overview) const content = () => { @@ -50,8 +55,11 @@ const MarketInfo = () => { ( {t("marketInterval." + interval)} )
- {currencies?.map((currency) => - setActiveCurrency(currency)} key={currency}>{t("currency." + currency)} + {quoteCurrencies?.map((currency) => + setActiveCurrency(currency)} key={currency}> + {currencies[currency]?.name} + {/*{t("currency." + currency)}*/} + )}
diff --git a/src/utils/utils.js b/src/utils/utils.js index 07535afa..05a328bc 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -72,4 +72,20 @@ export const timeValidator = str => { return /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/.test(str); } -export const toAbsoluteUrl = (path) => process.env.PUBLIC_URL + path \ No newline at end of file +export const toAbsoluteUrl = (path) => process.env.PUBLIC_URL + path + + +export function getCurrencyNameOrAlias(currency, lang) { + + const languagesConfig = { fa: "alias", en: "name", ar: "alias" }; + const langOption = languagesConfig[lang] || 'name'; + + if (!currency || typeof currency !== 'object') { + return '-'; + } + + const name = currency.name || '-'; + const alias = currency.alias || '-'; + + return langOption === 'alias' ? alias : name; +} From 675dcafa6320ea0d15b793a141545c1041b70b3a Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 7 Jan 2025 11:31:45 +0330 Subject: [PATCH 05/29] #246 feat: Integrated currency data from service into MarketDisplay component --- .../components/AllMarketInfo/AllMarketInfo.js | 11 +++-- .../AllMarketInfoCard/AllMarketInfoCard.js | 25 ++++++---- .../AllMarketInfoTable/AllMarketInfoTable.js | 46 ++++++++++++------- .../components/MarketInfo/MarketInfo.js | 5 +- .../MarketInfoCard/MarketInfoCard.js | 23 ++++++---- .../MarketInfoTable/MarketInfoTable.js | 29 ++++++++---- .../Login/components/LoginForm/LoginForm.js | 3 ++ src/store/sagas/global.js | 22 ++++++++- 8 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js index 049e5d9f..96c412f1 100644 --- a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js +++ b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js @@ -9,6 +9,8 @@ import Loading from "../../../../../../components/Loading/Loading"; import Error from "../../../../../../components/Error/Error"; import {setMarketInterval} from "../../../../../../store/actions"; import {useTranslation} from "react-i18next"; +import i18n from "i18next"; +import {getCurrencyNameOrAlias} from "../../../../../../utils/utils"; const AllMarketInfo = () => { @@ -21,8 +23,11 @@ const AllMarketInfo = () => { const interval = useSelector((state) => state.global.marketInterval) const quote = activeCurrency === "" ? null : activeCurrency + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const {data: overview, isLoading, error} = useOverview(null, interval, quote) - const {data: currencies} = useGetQuoteCurrencies() + const {data: quoteCurrencies} = useGetQuoteCurrencies() const content = () => { @@ -44,8 +49,8 @@ const AllMarketInfo = () => { setCard(prevState => !prevState)}/>

setActiveCurrency("")}>{t("market.title")}

- {currencies?.map((currency) => - setActiveCurrency(currency)} key={currency}>{t("currency." + currency)} + {quoteCurrencies?.map((currency) => + setActiveCurrency(currency)} key={currency}>{getCurrencyNameOrAlias(currencies[currency], language)} )}
diff --git a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoCard/AllMarketInfoCard.js b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoCard/AllMarketInfoCard.js index a3741bbd..ac5d2983 100644 --- a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoCard/AllMarketInfoCard.js +++ b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoCard/AllMarketInfoCard.js @@ -3,7 +3,7 @@ import classes from './AllMarketInfoCard.module.css' import {useTranslation} from "react-i18next"; import {images} from "../../../../../../../../assets/images"; import Button from "../../../../../../../../components/Button/Button"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {setActivePairInitiate} from "../../../../../../../../store/actions"; import {Panel} from "../../../../../../Routes/routes"; import {useNavigate} from "react-router-dom"; @@ -16,6 +16,8 @@ const AllMarketInfoCard = ({data, activeCurrency}) => { const {t} = useTranslation(); const navigate = useNavigate(); const dispatch = useDispatch(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) const allExchangeSymbols = useSelector((state) => state.exchange.symbols) const [showButton, setShowButton] = useState(null) @@ -53,33 +55,38 @@ const AllMarketInfoCard = ({data, activeCurrency}) => {
MouseEnterEventHandler(index)} onMouseLeave={MouseLeaveEventHandler}>
-
+
- {tr?.base} - {activeCurrency ? t("currency." + tr?.base) : tr?.base + " / " + tr?.quote} + {activeCurrency ? + <> + {getCurrencyNameOrAlias(currencies[tr?.base], language)} + {tr?.base} + + : tr?.base + " / " + tr?.quote}
- 0 ? "text-green" : "text-red"} direction-ltr mr-05`}>{new BN(tr.priceChangePercent).toFormat(2)} % + 0 ? "text-green" : tr.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{tr.priceChangePercent === 0 ? "0 %" : `${new BN(tr.priceChangePercent).toFormat(2)} %`}
{t("MarketInfo.lastPrice")}: - 0 ? "text-green" : "text-red"} fs-01`}>{new BN(tr.lastPrice).toFormat()} {t("currency." + tr?.quote)} + 0 ? "text-green" : "text-red"} fs-01`}>{new BN(tr.lastPrice).toFormat()} {tr?.quote}
{t("MarketInfo.lowPrice")}: - {new BN(tr.lowPrice).toFormat()} + {new BN(tr.lowPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote}
{t("MarketInfo.highPrice")}: - {new BN(tr.highPrice).toFormat()} + {new BN(tr.highPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote}
{t("MarketInfo.volume")}: - {new BN(tr.volume).toFormat()} + {new BN(tr.volume).decimalPlaces(currencies[tr?.base]?.precision ?? 0).toFormat()} {tr?.base}
diff --git a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoTable/AllMarketInfoTable.js b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoTable/AllMarketInfoTable.js index ca325345..10369eb9 100644 --- a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoTable/AllMarketInfoTable.js +++ b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/components/AllMarketInfoTable/AllMarketInfoTable.js @@ -3,7 +3,7 @@ import classes from './AllMarketInfoTable.module.css' import {useTranslation} from "react-i18next"; import {images} from "../../../../../../../../assets/images"; import Button from "../../../../../../../../components/Button/Button"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import i18n from "i18next"; import {setActivePairInitiate} from "../../../../../../../../store/actions"; import {Panel} from "../../../../../../Routes/routes"; @@ -17,6 +17,9 @@ const AllMarketInfTable = ({data, activeCurrency}) => { const dispatch = useDispatch(); const allExchangeSymbols = useSelector((state) => state.exchange.symbols) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const navigateToPanel = (symbol) => { const selectedPair = allExchangeSymbols.find( s => s.symbol === symbol) dispatch(setActivePairInitiate(selectedPair, 0)) @@ -25,17 +28,17 @@ const AllMarketInfTable = ({data, activeCurrency}) => { let head = (
- {t("MarketInfo.name")} + {t("MarketInfo.name")} {t("MarketInfo.lastPrice")} - {t("MarketInfo.priceChange")} + {t("MarketInfo.priceChange")} {t("MarketInfo.lowPrice")} {t("MarketInfo.highPrice")} - {t("MarketInfo.volume")} + {t("MarketInfo.volume")} {/*{t("MarketInfo.lowPrice")} {t("MarketInfo.highPrice")}*/} - {t("MarketInfo.chart")}{/* - {t("MarketInfo.details")} - {t("MarketInfo.trade")}*/} + {t("MarketInfo.chart")} + +
); @@ -44,25 +47,36 @@ const AllMarketInfTable = ({data, activeCurrency}) => { {data.map((tr, index) => { return (
- - {tr?.base} + {tr?.base} - {activeCurrency ? t("currency." + tr?.base) : tr?.base + " / " + tr?.quote} + {activeCurrency ? + <> + {getCurrencyNameOrAlias(currencies[tr?.base], language)} + {tr?.base} + + + : tr?.base + " / " + tr?.quote} - 0 ? "text-green" : "text-red"}`}>{new BN(tr.lastPrice).toFormat()} {t("currency." + tr?.quote)} + 0 ? "text-green" : "text-red"}`}>{new BN(tr.lastPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote} + + + + + 0 ? "text-green" : tr.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{tr.priceChangePercent === 0 ? "0 %" : `${new BN(tr.priceChangePercent).toFormat(2)} %`} + - 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(tr?.priceChangePercent).toFormat(2)} % - {new BN(tr?.lowPrice).toFormat()} + {new BN(tr?.lowPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote} - {new BN(tr?.highPrice).toFormat()} + {new BN(tr?.highPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote} - {new BN(tr?.volume).toFormat()} + {new BN(tr?.volume).decimalPlaces(currencies[tr?.base]?.precision ?? 0).toFormat()} {tr?.base} {/*{tr.lowPrice} {tr.highPrice}*/} - + { @@ -23,11 +24,13 @@ const MarketInfo = () => { const quote = activeCurrency === "" ? null : activeCurrency const currencies = useSelector((state) => state.exchange.currencies) + const language = i18n.language const {data: overview, isLoading, error} = useOverview(null, interval, quote) const {data: quoteCurrencies} = useGetQuoteCurrencies() console.log("overview", overview) + console.log("i18n.language", i18n.language) const content = () => { @@ -57,7 +60,7 @@ const MarketInfo = () => {
{quoteCurrencies?.map((currency) => setActiveCurrency(currency)} key={currency}> - {currencies[currency]?.name} + {getCurrencyNameOrAlias(currencies[currency], language)} {/*{t("currency." + currency)}*/} )} diff --git a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoCard/MarketInfoCard.js b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoCard/MarketInfoCard.js index 91e2f346..7f786523 100644 --- a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoCard/MarketInfoCard.js +++ b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoCard/MarketInfoCard.js @@ -2,17 +2,20 @@ import React from 'react'; import classes from './MarketInfoCard.module.css' import {images} from "../../../../../../../../assets/images"; import {useTranslation} from "react-i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {setActivePairInitiate} from "../../../../../../../../store/actions"; import {Panel} from "../../../../../../Routes/routes"; import {useNavigate} from "react-router-dom"; import {useDispatch, useSelector} from "react-redux"; +import i18n from "i18next"; const MarketInfoCard = ({data, activeCurrency}) => { const {t} = useTranslation(); const navigate = useNavigate(); const dispatch = useDispatch(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) const allExchangeSymbols = useSelector((state) => state.exchange.symbols) const backgroundBar = (percent) => { @@ -38,19 +41,23 @@ const MarketInfoCard = ({data, activeCurrency}) => { return (
navigateToPanel(tr.symbol)}>
- {tr?.base}
- {activeCurrency ? t("currency." + tr?.base) : tr?.base + " / " + tr?.quote} - 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(tr.priceChangePercent).toFormat(2)} % + {activeCurrency ? + <> + {getCurrencyNameOrAlias(currencies[tr?.base], language)} + {tr?.base} + + : tr?.base + " / " + tr?.quote} + 0 ? "text-green" : tr.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{tr.priceChangePercent === 0 ? "0 %" : `${new BN(tr.priceChangePercent).toFormat(2)} %`} +
- 0 ? "text-green" : "text-red"} fs-02`}>{new BN(tr.lastPrice).toFormat()} {t("currency." + tr?.quote)} + 0 ? "text-green" : "text-red"} fs-02`}>{new BN(tr.lastPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote}
{t("MarketInfo.volume")}: - {new BN(tr.volume).toFormat()} + {new BN(tr.volume).decimalPlaces(currencies[tr?.base]?.precision ?? 0).toFormat()} {tr?.base}
{ const {t} = useTranslation(); const navigate = useNavigate(); const dispatch = useDispatch(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) const allExchangeSymbols = useSelector((state) => state.exchange.symbols) const navigateToPanel = (symbol) => { @@ -24,8 +26,8 @@ const MarketInfoTable = ({data, activeCurrency}) => { let head = (
- {t("MarketInfo.name")} - {t("MarketInfo.lastPrice")} + {t("MarketInfo.name")} + {t("MarketInfo.lastPrice")} {t("MarketInfo.priceChange")} {t("MarketInfo.volume")} {t("MarketInfo.chart")} @@ -37,14 +39,23 @@ const MarketInfoTable = ({data, activeCurrency}) => { {data.map((tr, index) => { return (
navigateToPanel(tr.symbol)}> - - {tr?.base} + {tr?.base} - {activeCurrency ? t("currency." + tr?.base) : tr?.base + " / " + tr?.quote} + {activeCurrency ? + <> + {getCurrencyNameOrAlias(currencies[tr?.base], language)} + {tr?.base} + + : tr?.base + " / " + tr?.quote} - 0 ? "text-green" : "text-red"}`}>{new BN(tr.lastPrice).toFormat()} {t("currency." + tr?.quote)} - 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(tr.priceChangePercent).toFormat(2)} % - {new BN(tr.volume).toFormat()} + + 0 ? "text-green" : "text-red"}`}>{new BN(tr.lastPrice).decimalPlaces(currencies[tr?.quote]?.precision ?? 0).toFormat()} {tr?.quote} + + 0 ? "text-green" : tr.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{tr.priceChangePercent === 0 ? "0 %" : `${new BN(tr.priceChangePercent).toFormat(2)} %`} + + {new BN(tr.volume).decimalPlaces(currencies[tr?.base]?.precision ?? 0).toFormat()} {tr?.base} + { }) .catch((err) => { if (err?.response?.status === 401) { + setShowVerifyEmail(false) return setLoginError(t("login.wrongPassword")); } if (err?.response?.status === 403) { + setShowVerifyEmail(false) setLoginError(t("login.wrongOTP")); return setNeedOTP(true) } @@ -100,6 +102,7 @@ const LoginForm = () => { setShowVerifyEmail(true) return setLoginError(t("login.accountNotActive")); } + setShowVerifyEmail(false) setLoginError(t("login.loginError")); }) .finally(() => { diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index e20d1e28..a83630e9 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -119,10 +119,30 @@ export function* loadConfig(action) { const exchangeInfo = yield call(getExchangeInfo); const currencies = yield call(fetchCurrencies); - const currenciesMap = currencies.reduce((acc, currency) => { + + console.log("currencies", currencies) + + /*const currenciesMap = currencies.reduce((acc, currency) => { acc[currency.symbol] = currency; return acc; + }, {});*/ + + const currenciesMap = currencies.reduce((acc, currency) => { + const precisionValue = currency.precision.toString(); + const decimalPlaces = precisionValue.includes('.') + ? precisionValue.split('.')[1].length + : 0; + acc[currency.symbol] = { + ...currency, + precision: decimalPlaces, + }; + return acc; }, {}); + + console.log("currenciesMap", currenciesMap) + + + yield put(actions.getCurrencies(currenciesMap)); const pairsList = exchangeInfo.symbols; From a8e755c31a3968ad130715878fbd086baedb5d73 Mon Sep 17 00:00:00 2001 From: Hossein Date: Wed, 8 Jan 2025 17:50:37 +0330 Subject: [PATCH 06/29] #246 feat: Updated MarketStats to fetch currency details from service for stats display --- .../MostDecreasedPrice/MostDecreasedPrice.js | 16 ++++++++-------- .../MostIncreasedPrice/MostIncreasedPrice.js | 13 ++++++++----- .../components/MostTrades/MostTrades.js | 10 ++++++---- .../components/MostVolume/MostVolume.js | 12 +++++++----- .../MostDecreasedPrice/MostDecreasedPrice.js | 15 +++++++++------ .../MostIncreasedPrice/MostIncreasedPrice.js | 13 ++++++++----- .../components/MostVolume/MostVolume.js | 18 ++++++++++-------- src/store/sagas/global.js | 10 ---------- 8 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostDecreasedPrice/MostDecreasedPrice.js b/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostDecreasedPrice/MostDecreasedPrice.js index 26fb0843..dbec9afd 100644 --- a/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostDecreasedPrice/MostDecreasedPrice.js +++ b/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostDecreasedPrice/MostDecreasedPrice.js @@ -1,26 +1,26 @@ import React from 'react'; -import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; -import {useTranslation} from "react-i18next"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; +import {useSelector} from "react-redux"; const MostDecreasedPrice = ({mostDecreasedPrice}) => { - const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return ( <> - {mostDecreasedPrice?.pairInfo?.baseAsset} - {t("currency." + mostDecreasedPrice?.pairInfo?.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostDecreasedPrice?.pairInfo?.baseAsset], language)}
{mostDecreasedPrice?.pairInfo?.quoteAsset} - {new BN(mostDecreasedPrice?.lastPrice).toFormat()} + {new BN(mostDecreasedPrice?.lastPrice).decimalPlaces(currencies[mostDecreasedPrice.pairInfo.quoteAsset]?.precision ?? 0).toFormat()}
- 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(mostDecreasedPrice?.priceChangePercent).toFormat(2)} % + 0 ? "text-green" : mostDecreasedPrice?.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{mostDecreasedPrice?.priceChangePercent === 0 ? "0 %" : `${new BN(mostDecreasedPrice?.priceChangePercent).toFormat(2)} %`}
); diff --git a/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostIncreasedPrice/MostIncreasedPrice.js b/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostIncreasedPrice/MostIncreasedPrice.js index 1e4b60a8..213a4ebe 100644 --- a/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostIncreasedPrice/MostIncreasedPrice.js +++ b/src/main/Browser/Pages/AllMarket/components/PriceInfo/components/MostIncreasedPrice/MostIncreasedPrice.js @@ -1,26 +1,29 @@ import React from 'react'; import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostIncreasedPrice = ({mostIncreasedPrice}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return ( <> - {mostIncreasedPrice?.pairInfo?.baseAsset} - {t("currency." + mostIncreasedPrice?.pairInfo?.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostIncreasedPrice?.pairInfo?.baseAsset], language)}
{mostIncreasedPrice?.pairInfo?.quoteAsset} - {new BN(mostIncreasedPrice?.lastPrice).toFormat()} + {new BN(mostIncreasedPrice?.lastPrice).decimalPlaces(currencies[mostIncreasedPrice.pairInfo.quoteAsset]?.precision ?? 0).toFormat()}
- 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(mostIncreasedPrice?.priceChangePercent).toFormat(2)} % + 0 ? "text-green" : mostIncreasedPrice?.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{mostIncreasedPrice?.priceChangePercent === 0 ? "0 %" : `${new BN(mostIncreasedPrice?.priceChangePercent).toFormat(2)} %`}
); diff --git a/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostTrades/MostTrades.js b/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostTrades/MostTrades.js index 6eda6b87..54697300 100644 --- a/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostTrades/MostTrades.js +++ b/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostTrades/MostTrades.js @@ -1,20 +1,22 @@ import React from 'react'; import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostTrades = ({mostTrades}) => { - const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return ( <> - {mostTrades?.pairInfo?.baseAsset} - {t("currency." + mostTrades?.pairInfo?.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostTrades?.pairInfo?.baseAsset], language)}
{new BN(mostTrades?.tradeCount).toFormat()}
diff --git a/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostVolume/MostVolume.js b/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostVolume/MostVolume.js index 8ca16917..3555cafc 100644 --- a/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostVolume/MostVolume.js +++ b/src/main/Browser/Pages/AllMarket/components/VolumeInfo/components/MostVolume/MostVolume.js @@ -1,23 +1,25 @@ import React from 'react'; import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostVolume = ({mostVolume}) => { - const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return ( <> - {mostVolume?.pairInfo?.baseAsset} - {t("currency." + mostVolume?.pairInfo?.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostVolume?.pairInfo?.baseAsset], language)}
{mostVolume?.pairInfo?.baseAsset} - {new BN(mostVolume?.volume).toFormat()} + {new BN(mostVolume?.volume).decimalPlaces(currencies[mostVolume?.pairInfo?.baseAsset]?.precision ?? 0).toFormat()}
{/*++ to do ++*/} diff --git a/src/main/Browser/Pages/Landing/components/MarketView/components/MostDecreasedPrice/MostDecreasedPrice.js b/src/main/Browser/Pages/Landing/components/MarketView/components/MostDecreasedPrice/MostDecreasedPrice.js index 0f4ca3d7..19d40377 100644 --- a/src/main/Browser/Pages/Landing/components/MarketView/components/MostDecreasedPrice/MostDecreasedPrice.js +++ b/src/main/Browser/Pages/Landing/components/MarketView/components/MostDecreasedPrice/MostDecreasedPrice.js @@ -1,13 +1,15 @@ import React from 'react'; import classes from "../../MarketView.module.css"; -import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostDecreasedPrice = ({mostDecreasedPrice}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return (
@@ -16,21 +18,22 @@ const MostDecreasedPrice = ({mostDecreasedPrice}) => {
{mostDecreasedPrice.pairInfo.baseAsset} - {t("currency." + mostDecreasedPrice.pairInfo.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostDecreasedPrice.pairInfo.baseAsset], language)}
{mostDecreasedPrice.pairInfo.quoteAsset} - {new BN(mostDecreasedPrice?.lastPrice).toFormat()} + {new BN(mostDecreasedPrice?.lastPrice).decimalPlaces(currencies[mostDecreasedPrice.pairInfo.quoteAsset]?.precision ?? 0).toFormat()}
- 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(mostDecreasedPrice?.priceChangePercent).toFormat(2)} % + 0 ? "text-green" : mostDecreasedPrice?.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{mostDecreasedPrice?.priceChangePercent === 0 ? "0 %" : `${new BN(mostDecreasedPrice?.priceChangePercent).toFormat(2)} %`}
+ ); }; diff --git a/src/main/Browser/Pages/Landing/components/MarketView/components/MostIncreasedPrice/MostIncreasedPrice.js b/src/main/Browser/Pages/Landing/components/MarketView/components/MostIncreasedPrice/MostIncreasedPrice.js index 9e75edf6..52c44b5a 100644 --- a/src/main/Browser/Pages/Landing/components/MarketView/components/MostIncreasedPrice/MostIncreasedPrice.js +++ b/src/main/Browser/Pages/Landing/components/MarketView/components/MostIncreasedPrice/MostIncreasedPrice.js @@ -2,12 +2,15 @@ import React from 'react'; import classes from "../../MarketView.module.css"; import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostIncreasedPrice = ({mostIncreasedPrice}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return (
@@ -16,18 +19,18 @@ const MostIncreasedPrice = ({mostIncreasedPrice}) => {
{mostIncreasedPrice.pairInfo.baseAsset} - {t("currency." + mostIncreasedPrice.pairInfo.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostIncreasedPrice.pairInfo.baseAsset], language)}
{mostIncreasedPrice.pairInfo.quoteAsset} - {new BN(mostIncreasedPrice?.lastPrice).toFormat()} + {new BN(mostIncreasedPrice?.lastPrice).decimalPlaces(currencies[mostIncreasedPrice.pairInfo.quoteAsset]?.precision ?? 0).toFormat()}
- 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(mostIncreasedPrice?.priceChangePercent).toFormat(2)} % + 0 ? "text-green" : mostIncreasedPrice?.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{mostIncreasedPrice?.priceChangePercent === 0 ? "0 %" : `${new BN(mostIncreasedPrice?.priceChangePercent).toFormat(2)} %`}
diff --git a/src/main/Browser/Pages/Landing/components/MarketView/components/MostVolume/MostVolume.js b/src/main/Browser/Pages/Landing/components/MarketView/components/MostVolume/MostVolume.js index 591a1538..4524f627 100644 --- a/src/main/Browser/Pages/Landing/components/MarketView/components/MostVolume/MostVolume.js +++ b/src/main/Browser/Pages/Landing/components/MarketView/components/MostVolume/MostVolume.js @@ -2,12 +2,15 @@ import React from 'react'; import classes from "../../MarketView.module.css"; import {images} from "../../../../../../../../assets/images"; import i18n from "i18next"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const MostVolume = ({mostVolume}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) return (
@@ -16,18 +19,17 @@ const MostVolume = ({mostVolume}) => {
{mostVolume.pairInfo.baseAsset} - {t("currency." + mostVolume.pairInfo.baseAsset)} + {getCurrencyNameOrAlias(currencies[mostVolume?.pairInfo?.baseAsset], language)}
- {mostVolume.pairInfo.baseAsset} - {new BN(mostVolume?.volume).toFormat()} + {mostVolume?.pairInfo?.baseAsset} + {new BN(mostVolume?.volume).decimalPlaces(currencies[mostVolume?.pairInfo?.baseAsset]?.precision ?? 0).toFormat()}
- {/*++ to do ++*/} {/* 0 ? "text-green" : "text-red"} direction-ltr`}>{new BN(mostVolume?.change).toFormat(2)} %*/}
diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index a83630e9..d3267aa4 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -120,7 +120,6 @@ export function* loadConfig(action) { const currencies = yield call(fetchCurrencies); - console.log("currencies", currencies) /*const currenciesMap = currencies.reduce((acc, currency) => { acc[currency.symbol] = currency; @@ -139,10 +138,6 @@ export function* loadConfig(action) { return acc; }, {}); - console.log("currenciesMap", currenciesMap) - - - yield put(actions.getCurrencies(currenciesMap)); const pairsList = exchangeInfo.symbols; @@ -172,11 +167,6 @@ export function* loadConfig(action) { }, {}); yield put(actions.getFees(feesMap)); - - - console.log("pairsListMap", pairsListMap) - - const localTheme = yield call([localStorage, 'getItem'], 'theme') if (localTheme) appTheme = localTheme; From 09fcd36e5c09bb5bb98242b59f95eb8e667ab2c3 Mon Sep 17 00:00:00 2001 From: Hossein Date: Thu, 9 Jan 2025 18:08:20 +0330 Subject: [PATCH 07/29] #246 fix: initialize activeCurrency after quoteCurrencies load --- .../components/AllMarketInfo/AllMarketInfo.js | 14 ++++++++---- .../components/MarketInfo/MarketInfo.js | 22 +++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js index 96c412f1..e4797e16 100644 --- a/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js +++ b/src/main/Browser/Pages/AllMarket/components/AllMarketInfo/AllMarketInfo.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import classes from './AllMarketInfo.module.css' import Icon from "../../../../../../components/Icon/Icon"; import AllMarketInfoCard from "./components/AllMarketInfoCard/AllMarketInfoCard"; @@ -27,12 +27,18 @@ const AllMarketInfo = () => { const currencies = useSelector((state) => state.exchange.currencies) const {data: overview, isLoading, error} = useOverview(null, interval, quote) - const {data: quoteCurrencies} = useGetQuoteCurrencies() + const {data: quoteCurrencies, isLoading:quoteCurrenciesIsLoading, error:quoteCurrenciesError} = useGetQuoteCurrencies() + + useEffect(() => { + if (quoteCurrencies?.length > 0) { + setActiveCurrency(quoteCurrencies[0]); + } + }, [quoteCurrencies]); const content = () => { - if (isLoading) return
- if (error) return
+ if (isLoading || quoteCurrenciesIsLoading) return
+ if (error || quoteCurrenciesError) return
else return <> {card ? diff --git a/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js b/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js index 260c1236..e89d2f38 100644 --- a/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js +++ b/src/main/Browser/Pages/Landing/components/MarketInfo/MarketInfo.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import classes from './MarketInfo.module.css' import Icon from "../../../../../../components/Icon/Icon"; import MarketInfoTable from "./components/MarketInfoTable/MarketInfoTable"; @@ -18,24 +18,32 @@ const MarketInfo = () => { const {t} = useTranslation(); const [card, setCard] = useState(false) - const [activeCurrency, setActiveCurrency] = useState("") + + const [activeCurrency, setActiveCurrency] = useState(""); const interval = "24h" + + + const quote = activeCurrency === "" ? null : activeCurrency const currencies = useSelector((state) => state.exchange.currencies) const language = i18n.language const {data: overview, isLoading, error} = useOverview(null, interval, quote) - const {data: quoteCurrencies} = useGetQuoteCurrencies() + const {data: quoteCurrencies, isLoading:quoteCurrenciesIsLoading, error:quoteCurrenciesError} = useGetQuoteCurrencies() + - console.log("overview", overview) - console.log("i18n.language", i18n.language) + useEffect(() => { + if (quoteCurrencies?.length > 0) { + setActiveCurrency(quoteCurrencies[0]); + } + }, [quoteCurrencies]); const content = () => { - if (isLoading) return
- if (error) return
+ if (isLoading || quoteCurrenciesIsLoading) return
+ if (error || quoteCurrenciesError) return
else return <> {card ? From 4d97e9e00d4c05b2c6e2104739fa3aa4754b5338 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sun, 12 Jan 2025 15:42:36 +0330 Subject: [PATCH 08/29] #246 feat: Updated pair display in professional trading to fetch currency details from service --- src/main/Browser/Browser.js | 4 +-- .../components/MarketSubMenu/MarketSubMenu.js | 16 ++++++--- .../components/MarketCard/MarketCard.js | 8 ++++- .../MarketPairCard/MarketCard.module.css | 2 +- .../MarketPairCard/MarketPairCard.js | 36 ++++++++++--------- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index 6d17e7dd..0be6f3e6 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -36,12 +36,10 @@ const Browser = () => { const description = useSelector((state) => state.exchange.description) const currencies = useSelector((state) => state.exchange.currencies) - const pairsList = useSelector((state) => state.exchange.pairsList) const fees = useSelector((state) => state.exchange.fees) - console.log("currencies from redux", currencies) + console.log("fees from redux", fees) - console.log("pairsList from redux", pairsList) theme === "DARK" ? document.body.classList.add('dark') : document.body.classList.remove('dark'); diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js index f7aa2128..12aed721 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js @@ -12,8 +12,15 @@ const MarketSubMenu = () => { const {t} = useTranslation(); const [activeTab] = useState(JSON.parse(localStorage.getItem("activeMarketTab")) || 1); const symbols = useSelector((state) => state.exchange.symbols) + + console.log("symbols", symbols) + + const pairsList = useSelector((state) => state.exchange.pairsList) + console.log("pairsList from redux", pairsList) + const fav = useSelector((state) => state.auth.favoritePairs) const dispatch = useDispatch(); + console.log("fav", fav) const addToFav = (selected) => { if (fav.includes(selected)) { @@ -31,10 +38,11 @@ const MarketSubMenu = () => { fav.includes(p.symbol))} + pairs={Object.values(pairsList).filter(pair => fav.includes(pair.symbol))} favPair={fav} addFav={(selected) => addToFav(selected)} /> + ), }, { @@ -43,7 +51,7 @@ const MarketSubMenu = () => { addToFav(selected)} /> @@ -57,7 +65,7 @@ const MarketSubMenu = () => { id="2" type="BTC" favPair={fav} - pairs={symbols.filter(p => (p.baseAsset === "BTC" || p.quoteAsset === "BTC"))} + pairs={Object.values(pairsList).filter(pair => pair.baseAsset === "BTC" || pair.quoteAsset === "BTC")} addFav={(selected) => addToFav(selected)} /> ), @@ -70,7 +78,7 @@ const MarketSubMenu = () => { id="3" type="USDT" favPair={fav} - pairs={symbols.filter(p => (p.baseAsset === "USDT" || p.quoteAsset === "USDT"))} + pairs={Object.values(pairsList).filter(pair => pair.baseAsset === "USDT" || pair.quoteAsset === "USDT")} addFav={(selected) => addToFav(selected)} /> ), diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js index 8db19022..9b945e5b 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js @@ -7,7 +7,13 @@ const MarketCard = ({type, ...props}) => { return (
- {props.pairs.map((pair) => )} + + { + Object.keys(props?.pairs) + + .map((pair) => ) + } +
); diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketCard.module.css b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketCard.module.css index cf953119..7783ea07 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketCard.module.css +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketCard.module.css @@ -6,7 +6,7 @@ width: 14%; } .marketCardContent { - width: 86%; + width: 84%; } .selected { background-color: var(--mainContent); diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js index 53881382..9cd9547f 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js @@ -3,42 +3,44 @@ import classes from "./MarketCard.module.css"; import {useDispatch, useSelector} from "react-redux"; import {images} from "../../../../../../../../../../assets/images"; import Icon from "../../../../../../../../../../components/Icon/Icon"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; import {setActivePairInitiate} from "../../../../../../../../../../store/actions"; import {useGetLastPrices} from "../../../../../../../../../../queries/hooks/useGetLastPrices"; +import i18n from "i18next"; const MarketPairCard = ({id, pair, favPair, addFav}) => { const activePair = useSelector((state) => state.exchange.activePair.symbol) const {data: prices} = useGetLastPrices() + + console.log("prices", prices) + console.log("pair", pair) + + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const dispatch = useDispatch(); const changeActivePair = () =>{ if (activePair !== pair.symbol) dispatch(setActivePairInitiate(pair, id)) } return (
+ className={`width-100 row jc-between ai-center px-1 py-05 cursor-pointer double-striped border-bottom ${classes.container} ${activePair === pair.symbol ? classes.selected : ""} `}>
{pair.symbol}
-
-
{ - e.stopPropagation(); - addFav(pair.symbol); - }} - data-name={pair.symbol}> - -
- {pair.baseAsset + " / " + pair.quoteAsset} +
+ {e.stopPropagation();addFav(pair?.symbol);}}/> + {pair?.baseAsset + " / " + pair?.quoteAsset }
-
- {new BN(prices[pair.symbol] || 0).toFormat()} +
+ {new BN(prices[pair?.symbol] || 0).decimalPlaces(currencies[pair?.quoteAsset]?.precision ?? 0).toFormat()}
From 73f5398c389a4178ecf42440d4c389eec41fd298 Mon Sep 17 00:00:00 2001 From: Hossein Date: Mon, 13 Jan 2025 15:22:14 +0330 Subject: [PATCH 09/29] #246 feat: Updated professional trading header with service-based currency details --- .../MarketInfoTable/MarketInfoTable.js | 16 +++++++--------- .../MarketInfoTable/MarketInfoTable.module.css | 3 ++- .../components/MarketHeader/MarketHeader.js | 18 +++++++++++------- .../MarketPairCard/MarketPairCard.js | 4 ---- src/utils/utils.js | 1 - 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.js b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.js index 4a566cf3..eb93c071 100644 --- a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.js +++ b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.js @@ -1,7 +1,6 @@ import React from 'react'; import classes from './MarketInfoTable.module.css' import {useTranslation} from "react-i18next"; -import {images} from "../../../../../../../../assets/images"; import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import i18n from "i18next"; import {setActivePairInitiate} from "../../../../../../../../store/actions"; @@ -9,6 +8,7 @@ import {useDispatch, useSelector} from "react-redux"; import {Panel} from "../../../../../../Routes/routes"; import {useNavigate} from "react-router-dom"; + const MarketInfoTable = ({data, activeCurrency}) => { const {t} = useTranslation(); @@ -34,6 +34,10 @@ const MarketInfoTable = ({data, activeCurrency}) => {
); + const base64Data = "PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbG5zOnhsaW5rPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJyB4bWxuczpqZnJlZXN2Zz0naHR0cDovL3d3dy5qZnJlZS5vcmcvamZyZWVzdmcvc3ZnJyB3aWR0aD0nMTAwJyBoZWlnaHQ9JzM1JyB0ZXh0LXJlbmRlcmluZz0nYXV0bycgc2hhcGUtcmVuZGVyaW5nPSdhdXRvJz48ZGVmcz48Y2xpcFBhdGggaWQ9J18xMTIzOTc0MzA1MTMzY2xpcC0wJz48cGF0aCBkPSdNMTIsOEwxMiwyN0w4OCwyN0w4OCw4WicvPjwvY2xpcFBhdGg+PC9kZWZzPjxsaW5lIHgxPScxNS40NScgeTE9JzI0LjIzJyB4Mj0nMTcuMScgeTI9JzIyLjAyJyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzE3LjEnIHkxPScyMi4wMicgeDI9JzE4Ljc0JyB5Mj0nMjMuMjcnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nMTguNzQnIHkxPScyMy4yNycgeDI9JzIwLjM5JyB5Mj0nMjAuNTcnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nMjAuMzknIHkxPScyMC41NycgeDI9JzIyLjAzJyB5Mj0nMjYuMTYnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nMjIuMDMnIHkxPScyNi4xNicgeDI9JzIzLjY4JyB5Mj0nMTkuNDUnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nMjMuNjgnIHkxPScxOS40NScgeDI9JzI1LjMyJyB5Mj0nMjIuOCcgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPScyNS4zMicgeTE9JzIyLjgnIHgyPScyNi45NycgeTI9JzIzLjYzJyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzI2Ljk3JyB5MT0nMjMuNjMnIHgyPScyOC42MScgeTI9JzI0LjY4JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzI4LjYxJyB5MT0nMjQuNjgnIHgyPSczMC4yNicgeTI9JzE5LjY3JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzMwLjI2JyB5MT0nMTkuNjcnIHgyPSczMS45JyB5Mj0nMjMuMzQnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nMzEuOScgeTE9JzIzLjM0JyB4Mj0nMzMuNTUnIHkyPScyMi42Mycgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSczMy41NScgeTE9JzIyLjYzJyB4Mj0nMzUuMTknIHkyPScxOC4yOScgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSczNS4xOScgeTE9JzE4LjI5JyB4Mj0nMzYuODQnIHkyPScxNy42Micgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSczNi44NCcgeTE9JzE3LjYyJyB4Mj0nMzguNDgnIHkyPScxNi4xNicgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSczOC40OCcgeTE9JzE2LjE2JyB4Mj0nNDAuMTMnIHkyPScyMS44NCcgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0MC4xMycgeTE9JzIxLjg0JyB4Mj0nNDEuNzcnIHkyPScxOS40Nycgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0MS43NycgeTE9JzE5LjQ3JyB4Mj0nNDMuNDInIHkyPScyMi4zOScgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0My40MicgeTE9JzIyLjM5JyB4Mj0nNDUuMDYnIHkyPScxNS45Micgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0NS4wNicgeTE9JzE1LjkyJyB4Mj0nNDYuNzEnIHkyPScxNS42OScgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0Ni43MScgeTE9JzE1LjY5JyB4Mj0nNDguMzUnIHkyPScyMC4wNCcgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc0OC4zNScgeTE9JzIwLjA0JyB4Mj0nNTAnIHkyPScxNS4zNCcgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc1MCcgeTE9JzE1LjM0JyB4Mj0nNTEuNjUnIHkyPScyMS4xNycgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc1MS42NScgeTE9JzIxLjE3JyB4Mj0nNTMuMjknIHkyPScyMC42JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzUzLjI5JyB5MT0nMjAuNicgeDI9JzU0Ljk0JyB5Mj0nMTUuNzQnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNTQuOTQnIHkxPScxNS43NCcgeDI9JzU2LjU4JyB5Mj0nMTYuNzknIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNTYuNTgnIHkxPScxNi43OScgeDI9JzU4LjIzJyB5Mj0nMTkuOCcgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc1OC4yMycgeTE9JzE5LjgnIHgyPSc1OS44NycgeTI9JzEzLjk2JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzU5Ljg3JyB5MT0nMTMuOTYnIHgyPSc2MS41MicgeTI9JzE4LjEnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNjEuNTInIHkxPScxOC4xJyB4Mj0nNjMuMTYnIHkyPScxMScgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc2My4xNicgeTE9JzExJyB4Mj0nNjQuODEnIHkyPScxMS4xMicgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc2NC44MScgeTE9JzExLjEyJyB4Mj0nNjYuNDUnIHkyPScxNC43Nicgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc2Ni40NScgeTE9JzE0Ljc2JyB4Mj0nNjguMScgeTI9JzExLjg3JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9JzY4LjEnIHkxPScxMS44NycgeDI9JzY5Ljc0JyB5Mj0nMTYuMTcnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNjkuNzQnIHkxPScxNi4xNycgeDI9JzcxLjM5JyB5Mj0nMTQuMzgnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNzEuMzknIHkxPScxNC4zOCcgeDI9JzczLjAzJyB5Mj0nMTYuMScgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjxsaW5lIHgxPSc3My4wMycgeTE9JzE2LjEnIHgyPSc3NC42OCcgeTI9JzEwLjY2JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9Jzc0LjY4JyB5MT0nMTAuNjYnIHgyPSc3Ni4zMicgeTI9JzEyLjUxJyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9Jzc2LjMyJyB5MT0nMTIuNTEnIHgyPSc3Ny45NycgeTI9JzE1LjE2JyBzdHlsZT0nc3Ryb2tlLXdpZHRoOjEuMDtzdHJva2U6cmdiKDI1NSwyNTUsMjU1KTtzdHJva2Utb3BhY2l0eToxLjA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uJyBjbGlwLXBhdGg9J3VybCgjXzExMjM5NzQzMDUxMzNjbGlwLTApJy8+PGxpbmUgeDE9Jzc3Ljk3JyB5MT0nMTUuMTYnIHgyPSc3OS42MScgeTI9JzgnIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nNzkuNjEnIHkxPSc4JyB4Mj0nODEuMjYnIHkyPSc5LjknIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nODEuMjYnIHkxPSc5LjknIHgyPSc4Mi45JyB5Mj0nMTAuNzknIHN0eWxlPSdzdHJva2Utd2lkdGg6MS4wO3N0cm9rZTpyZ2IoMjU1LDI1NSwyNTUpO3N0cm9rZS1vcGFjaXR5OjEuMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24nIGNsaXAtcGF0aD0ndXJsKCNfMTEyMzk3NDMwNTEzM2NsaXAtMCknLz48bGluZSB4MT0nODIuOScgeTE9JzEwLjc5JyB4Mj0nODQuNTUnIHkyPScxMS4wNycgc3R5bGU9J3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlOnJnYigyNTUsMjU1LDI1NSk7c3Ryb2tlLW9wYWNpdHk6MS4wO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbicgY2xpcC1wYXRoPSd1cmwoI18xMTIzOTc0MzA1MTMzY2xpcC0wKScvPjwvc3ZnPg==" + const svgBase64 = `data:image/svg+xml;base64,${base64Data}`; + + let body = ( <> {data.map((tr, index) => { @@ -57,14 +61,8 @@ const MarketInfoTable = ({data, activeCurrency}) => { {new BN(tr.volume).decimalPlaces(currencies[tr?.base]?.precision ?? 0).toFormat()} {tr?.base} - {""} - {t("comingSoon")} - + {svgBase64 && SVG Example} +
) })} diff --git a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.module.css b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.module.css index cf0d2b65..8e700398 100644 --- a/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.module.css +++ b/src/main/Browser/Pages/Landing/components/MarketInfo/components/MarketInfoTable/MarketInfoTable.module.css @@ -11,5 +11,6 @@ } .filter { - filter: blur(4px); + /*filter: invert(51%) sepia(94%) saturate(370%) hue-rotate(109deg) brightness(87%) contrast(92%);*/ + filter: invert(38%) sepia(77%) saturate(5872%) hue-rotate(347deg) brightness(93%) contrast(79%); } \ No newline at end of file diff --git a/src/main/Browser/Pages/UserPanel/Sections/Header/components/MarketHeader/MarketHeader.js b/src/main/Browser/Pages/UserPanel/Sections/Header/components/MarketHeader/MarketHeader.js index 79443266..81b7c3bd 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Header/components/MarketHeader/MarketHeader.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Header/components/MarketHeader/MarketHeader.js @@ -2,11 +2,12 @@ import React, {useEffect, useState} from "react"; import classes from "./MarketHeader.module.css"; import {useTranslation} from "react-i18next"; import {useSelector} from "react-redux"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import Icon from "../../../../../../../../components/Icon/Icon"; import Popup from "../../../../../../../../components/Popup/Popup"; import {useGetUserAccount} from "../../../../../../../../queries/hooks/useGetUserAccount"; import {useGetLastPrices} from "../../../../../../../../queries/hooks/useGetLastPrices"; +import i18n from "i18next"; const MarketHeader = () => { @@ -19,6 +20,9 @@ const MarketHeader = () => { const base = userAccount?.wallets[activePair.baseAsset]?.free || 0 const quote = userAccount?.wallets[activePair.quoteAsset]?.free || 0 + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const [showPopUp, setShowPopUp] = useState(false); const [showPopUpAsset, setShowPopUpAsset] = useState(null); @@ -42,8 +46,8 @@ const MarketHeader = () => { return ( <>
-

{t("currency." + activePair.baseAsset)}/{t("currency." + activePair.quoteAsset)}

-

{t("header.lastPrice")}:{" "}{" "}{new BN(lastPrices[activePair.symbol] || 0).toFormat()+" "+t("currency." + activePair.quoteAsset)}

+

{getCurrencyNameOrAlias(currencies[activePair?.baseAsset], language)}/{getCurrencyNameOrAlias(currencies[activePair?.quoteAsset], language)}

+

{t("header.lastPrice")}:{" "}{" "}{new BN(lastPrices[activePair.symbol] || 0).decimalPlaces(currencies[activePair?.quoteAsset]?.precision ?? 0).toFormat() +" "+ getCurrencyNameOrAlias(currencies[activePair?.quoteAsset], language)}

{t("header.availableBalance")}

@@ -51,12 +55,12 @@ const MarketHeader = () => {
ClickHandler(activePair.baseAsset)}/> {/*{ new BN (base).decimalPlaces(activePair.baseAssetPrecision).toFormat()}*/} - { new BN (base).toFormat()} - {t("currency." + activePair.baseAsset)} + { new BN (base).decimalPlaces(currencies[activePair?.baseAsset]?.precision ?? 0).toFormat()} + {getCurrencyNameOrAlias(currencies[activePair?.baseAsset], language)}
- { new BN(quote).toFormat()} - {t("currency." + activePair.quoteAsset)} + { new BN(quote).decimalPlaces(currencies[activePair?.quoteAsset]?.precision ?? 0).toFormat()} + {getCurrencyNameOrAlias(currencies[activePair?.quoteAsset], language)} ClickHandler(activePair.quoteAsset)}/>
diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js index 9cd9547f..7b86e252 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js @@ -12,13 +12,9 @@ const MarketPairCard = ({id, pair, favPair, addFav}) => { const activePair = useSelector((state) => state.exchange.activePair.symbol) const {data: prices} = useGetLastPrices() - console.log("prices", prices) - console.log("pair", pair) - const language = i18n.language const currencies = useSelector((state) => state.exchange.currencies) - const dispatch = useDispatch(); const changeActivePair = () =>{ if (activePair !== pair.symbol) dispatch(setActivePairInitiate(pair, id)) diff --git a/src/utils/utils.js b/src/utils/utils.js index 05a328bc..2fc5469d 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -74,7 +74,6 @@ export const timeValidator = str => { export const toAbsoluteUrl = (path) => process.env.PUBLIC_URL + path - export function getCurrencyNameOrAlias(currency, lang) { const languagesConfig = { fa: "alias", en: "name", ar: "alias" }; From 0627174b77b6894b5634e641a103fa950ed727de Mon Sep 17 00:00:00 2001 From: Hossein Date: Mon, 13 Jan 2025 16:32:58 +0330 Subject: [PATCH 10/29] #246 feat: Updated currency names in overview to use service-based details --- .../InformationBlock/InformationBlock.js | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Overview/components/InformationBlock/InformationBlock.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Overview/components/InformationBlock/InformationBlock.js index 15e11c8d..f83dee71 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Overview/components/InformationBlock/InformationBlock.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Overview/components/InformationBlock/InformationBlock.js @@ -5,38 +5,43 @@ import {useSelector} from "react-redux"; import Loading from "../../../../../../../../../../../../components/Loading/Loading"; import Error from "../../../../../../../../../../../../components/Error/Error"; import {useOverview} from "../../../../../../../../../../../../queries"; +import i18n from "i18next"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../../../utils/utils"; const InformationBlock = ({period}) => { const {t} = useTranslation(); const activePair = useSelector((state) => state.exchange.activePair) + + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const {data, isLoading, error} = useOverview(activePair.symbol, period) if (isLoading) return if (error) return return (
-

- {t("overview.change")}:{" "} - 0 ? "text-green" : "text-red"}> - %{data.priceChangePercent.toFixed(2)} - -

-

- {t("min")}:{" "} - {data.lowPrice.toLocaleString()}{" "} - {t(`currency.${activePair.quoteAsset}`)} -

-

- {t("max")}:{" "} - {data.highPrice.toLocaleString()}{" "} - {t(`currency.${activePair.quoteAsset}`)} -

-

- {t("overview.volume")}: {data.volume.toLocaleString()} - {t(`currency.${activePair.baseAsset}`)} -

+
+

{t("overview.change")}

+ 0 ? "text-green" : data?.priceChangePercent < 0 ? "text-red" : ""} direction-ltr`}>{data?.priceChangePercent === 0 ? "0 %" : `${new BN(data?.priceChangePercent).toFormat(2)} %`} +
+
+

{t("min")}:

+ {new BN(data?.lowPrice).decimalPlaces(currencies[data?.quote]?.precision ?? 0).toFormat()} + {getCurrencyNameOrAlias(currencies[data?.quote], language)} +
+
+

{t("max")}:

+ {new BN(data?.highPrice).decimalPlaces(currencies[data?.quote]?.precision ?? 0).toFormat()} + {getCurrencyNameOrAlias(currencies[data?.quote], language)} +
+
+

{t("volume")}:

+ {new BN(data?.volume).decimalPlaces(currencies[data?.base]?.precision ?? 0).toFormat()} + {getCurrencyNameOrAlias(currencies[data?.base], language)} +
) } From 0033640ab35f78a6a508ffa32cda08e9c84a285c Mon Sep 17 00:00:00 2001 From: Hossein Date: Mon, 20 Jan 2025 19:56:44 +0330 Subject: [PATCH 11/29] #246 feat: Integrated currency service for buy order details --- .../Content/components/Market/Market.js | 6 +- .../Order/components/BuyOrder/BuyOrder.js | 105 +++++++++++------- .../components/MarketCard/MarketCard.js | 5 +- .../MarketPairCard/MarketPairCard.js | 19 +++- src/store/actions/exchange.js | 7 ++ src/store/reducers/exchangeReducer.js | 28 ++++- src/store/sagas/global.js | 16 ++- 7 files changed, 135 insertions(+), 51 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js index b4b3ebbb..3779329e 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js @@ -16,15 +16,15 @@ const Market = () => {
- + {/**/}
- + {/**/}
- + {/**/}
diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js index 47312f06..2cfbfb3f 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js @@ -3,13 +3,14 @@ import {toast} from "react-hot-toast"; import classes from "../../Order.module.css"; import React, {useEffect, useState} from "react"; import {Trans, useTranslation} from "react-i18next"; -import {BN, parsePriceString} from "../../../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias, parsePriceString} from "../../../../../../../../../../../../utils/utils"; import NumberInput from "../../../../../../../../../../../../components/NumberInput/NumberInput"; import Button from "../../../../../../../../../../../../components/Button/Button"; import {setLastTransaction} from "../../../../../../../../../../../../store/actions/auth"; import {images} from "../../../../../../../../../../../../assets/images"; import {useGetUserAccount} from "../../../../../../../../../../../../queries/hooks/useGetUserAccount"; import {createOrder} from "js-api-client"; +import i18n from "i18next"; const BuyOrder = () => { @@ -23,6 +24,15 @@ const BuyOrder = () => { const bestBuyPrice = useSelector((state) => state.exchange.activePairOrders.bestBuyPrice) const selectedBuyOrder = useSelector((state) => state.exchange.activePairOrders.selectedBuyOrder) + + console.log("activePair", activePair) + console.log("bestBuyPrice", bestBuyPrice) + console.log("selectedBuyOrder", selectedBuyOrder) + console.log("activePair", typeof activePair) + + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const tradeFee = useSelector((state) => state.auth.tradeFee) const isLogin = useSelector((state) => state.auth.isLogin) @@ -71,26 +81,34 @@ const BuyOrder = () => { const currencyValidator = (key, val, rule) => { - if (!val.isZero() && val.isLessThan(rule.min)) { + + console.log("activePair.baseRange", activePair.baseRange) + + console.log("rule", rule) + + console.log("currencies?.[rule].step", currencies?.[rule]?.step) + + + if (!val.isZero() && val.isLessThan(currencies[rule].minOrder)) { return setAlert({ ...alert, [key]: ( ), }); } - if (!val.mod(rule.step).isZero()) { + if (!val.mod(currencies?.[rule]?.step).isZero()) { return setAlert({ ...alert, [key]: () }) } @@ -102,12 +120,14 @@ const BuyOrder = () => { switch (key) { case "reqAmount": const reqAmount = new BN(value); - currencyValidator("reqAmount", reqAmount, activePair.baseRange); + currencyValidator("reqAmount", reqAmount, activePair.baseAsset); setOrder({ ...order, reqAmount, - totalPrice: reqAmount.multipliedBy(order.pricePerUnit).decimalPlaces(activePair.quoteAssetPrecision), - tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision), + /*totalPrice: reqAmount.multipliedBy(order.pricePerUnit).decimalPlaces(activePair.quoteAssetPrecision),*/ + totalPrice: reqAmount.multipliedBy(order.pricePerUnit).decimalPlaces(currencies[activePair.quoteAsset].precision), + /*tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision),*/ + tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision), }); break; case "pricePerUnit": @@ -115,20 +135,24 @@ const BuyOrder = () => { setOrder({ ...order, pricePerUnit: pricePerUnit, - totalPrice: pricePerUnit.multipliedBy(order.reqAmount).decimalPlaces(activePair.quoteAssetPrecision), - tradeFee: order.reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision), + /*totalPrice: pricePerUnit.multipliedBy(order.reqAmount).decimalPlaces(activePair.quoteAssetPrecision),*/ + totalPrice: pricePerUnit.multipliedBy(order.reqAmount).decimalPlaces(currencies[activePair.quoteAsset].precision), + /*tradeFee: order.reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision),*/ + tradeFee: order.reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision), }); break; case "totalPrice": const totalPrice = new BN(value); - const req = totalPrice.dividedBy(order.pricePerUnit).decimalPlaces(activePair.baseAssetPrecision); + /*const req = totalPrice.dividedBy(order.pricePerUnit).decimalPlaces(activePair.baseAssetPrecision);*/ + const req = totalPrice.dividedBy(order.pricePerUnit).decimalPlaces(currencies[activePair.baseAsset].precision); setOrder({ ...order, reqAmount: req.isFinite() ? req : new BN(0), totalPrice, - tradeFee: req.isFinite() ? req.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision) : new BN(0), + /*tradeFee: req.isFinite() ? req.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision) : new BN(0),*/ + tradeFee: req.isFinite() ? req.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision) : new BN(0), }); - currencyValidator("reqAmount", req, activePair.baseRange); + currencyValidator("reqAmount", req, activePair.baseAsset); break; default: } @@ -151,7 +175,7 @@ const BuyOrder = () => { useEffect(() => { setOrder((prevState) => ({ ...order, - tradeFee: prevState.totalPrice.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision), + tradeFee: prevState.totalPrice.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision), })); }, [tradeFee]); @@ -169,10 +193,10 @@ const BuyOrder = () => { ...order, reqAmount, pricePerUnit: pricePerUnit, - totalPrice: reqAmount.multipliedBy(pricePerUnit).decimalPlaces(activePair.quoteAssetPrecision), - tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision), + totalPrice: reqAmount.multipliedBy(pricePerUnit).decimalPlaces(currencies[activePair.quoteAsset].precision), + tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision), }); - currencyValidator("reqAmount", reqAmount, activePair.baseRange); + currencyValidator("reqAmount", reqAmount, activePair.baseAsset); }, [selectedBuyOrder]); @@ -181,9 +205,9 @@ const BuyOrder = () => { if (order.pricePerUnit.isEqualTo(0)) { const pricePerUnit = new BN(bestBuyPrice) let totalPrice = new BN(quote); - let reqAmount = totalPrice.dividedBy(pricePerUnit).decimalPlaces(activePair.baseAssetPrecision) - if (!reqAmount.mod(activePair.baseRange.step).isZero()) { - reqAmount = reqAmount.minus(reqAmount.mod(activePair.baseRange.step)); + let reqAmount = totalPrice.dividedBy(pricePerUnit).decimalPlaces(currencies[activePair.baseAsset].precision) + if (!reqAmount.mod(currencies[activePair.baseAsset].step).isZero()) { + reqAmount = reqAmount.minus(reqAmount.mod(currencies[activePair.baseAsset].step)); totalPrice = reqAmount.multipliedBy(pricePerUnit); } setOrder({ @@ -191,13 +215,13 @@ const BuyOrder = () => { reqAmount, pricePerUnit, totalPrice, - tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(activePair.baseAssetPrecision), + tradeFee: reqAmount.multipliedBy(tradeFee[activePair.quoteAsset]).decimalPlaces(currencies[activePair.baseAsset].precision), }); } else { let totalPrice = new BN(quote); - let reqAmount = totalPrice.dividedBy(order.pricePerUnit).decimalPlaces(activePair.baseAssetPrecision) - if (!reqAmount.mod(activePair.baseRange.step).isZero()) { - reqAmount = reqAmount.minus(reqAmount.mod(activePair.baseRange.step)); + let reqAmount = totalPrice.dividedBy(order.pricePerUnit).decimalPlaces(currencies[activePair.baseAsset].precision) + if (!reqAmount.mod(currencies[activePair.baseAsset].step).isZero()) { + reqAmount = reqAmount.minus(reqAmount.mod(currencies[activePair.baseAsset].step)); } buyPriceHandler( reqAmount.toFormat(), @@ -236,8 +260,8 @@ const BuyOrder = () => { toast.success( { }}> {t("orders.availableAmount")}:{" "} - {new BN(quote).toFormat()}{" "} - {t("currency." + activePair.quoteAsset)} + {new BN(quote).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[activePair.quoteAsset], language)}

{ @@ -283,7 +306,7 @@ const BuyOrder = () => { }}> {t("orders.bestOffer")}:{" "} - {new BN(bestBuyPrice).toFormat()}{" "}{t("currency." + activePair.quoteAsset)} + {new BN(bestBuyPrice).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[activePair.quoteAsset], language)}

@@ -313,9 +336,9 @@ const BuyOrder = () => { buyPriceHandler(e.target.value, "reqAmount")} alert={alert.reqAmount} isAllowed={isAllowed} @@ -326,18 +349,18 @@ const BuyOrder = () => { customClass={classes.stopMarket} lead={t("orders.pricePerUnit")} prefix="~" - after={t("currency." + activePair.quoteAsset)} + after={getCurrencyNameOrAlias(currencies[activePair.quoteAsset], language)} value={order.pricePerUnit.toFormat()} - maxDecimal={activePair.quoteAssetPrecision} + maxDecimal={currencies[activePair.quoteAsset].precision} onchange={(e) => buyPriceHandler(e.target.value, "pricePerUnit")} isAllowed={isAllowed} /> ) : ( buyPriceHandler(e.target.value, "pricePerUnit")} isAllowed={isAllowed} /> @@ -356,8 +379,8 @@ const BuyOrder = () => { buyPriceHandler(e.target.value, "totalPrice")} alert={alert.totalPrice} isAllowed={isAllowed} @@ -367,12 +390,12 @@ const BuyOrder = () => {

{t("orders.tradeFee")}:{" "} {order.tradeFee.toFormat()}{" "} - {t("currency." + activePair.baseAsset)} + {getCurrencyNameOrAlias(currencies[activePair.baseAsset], language)}

{t("orders.getAmount")}:{" "} - {order.reqAmount.minus(order.tradeFee).decimalPlaces(activePair.baseAssetPrecision).toFormat()}{" "} - {t("currency." + activePair.baseAsset)} + {order.reqAmount.minus(order.tradeFee).decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()}{" "} + {getCurrencyNameOrAlias(currencies[activePair.baseAsset], language)}

- {/**/} +
diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/OrderBook.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/OrderBook.js index 406dfbda..2c738c43 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/OrderBook.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/OrderBook.js @@ -6,6 +6,8 @@ import {useSelector} from "react-redux"; import Error from "../../../../../../../../../../components/Error/Error"; import Loading from "../../../../../../../../../../components/Loading/Loading"; import {useOrderBook} from "../../../../../../../../../../queries"; +import i18n from "i18next"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const OrderBook = () => { @@ -14,6 +16,9 @@ const OrderBook = () => { const {data, isLoading, error, refetch} = useOrderBook(activePair.symbol) const lastTransaction = useSelector((state) => state.auth.lastTransaction) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + useEffect(() => { refetch() }, lastTransaction) @@ -32,8 +37,8 @@ const OrderBook = () => {

- {t("orderBook.title")} ({t("currency." + activePair.baseAsset)}/ - {t("currency." + activePair.quoteAsset)}) + {t("orderBook.title")} ({getCurrencyNameOrAlias(currencies[activePair.baseAsset], language)}/ + {getCurrencyNameOrAlias(currencies[activePair.quoteAsset], language)})

diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/components/OrderBookTable/OrderBookTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/components/OrderBookTable/OrderBookTable.js index 62840935..064ceee4 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/components/OrderBookTable/OrderBookTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/OrderBook/components/OrderBookTable/OrderBookTable.js @@ -18,6 +18,9 @@ const OrderBookTable = ({data, type}) => { const activePair = useSelector((state) => state.exchange.activePair) const dispatch = useDispatch(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + let header; let totalAmount = data.reduce((total, asks) => parseFloat(asks[1]) + total, 0); @@ -71,15 +74,15 @@ const OrderBookTable = ({data, type}) => { return `
${t("averagePrice")}: - ${average.pricePerUnit.dividedBy(index + 1).decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + ${average.pricePerUnit.dividedBy(index + 1).decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()}
${t("totalVolume",)}: - ${average.amount.decimalPlaces(activePair.baseAssetPrecision).toFormat()} + ${average.amount.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()}
${t("totalPrice")}: - ${average.total.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + ${average.total.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()}
` } @@ -114,15 +117,15 @@ const OrderBookTable = ({data, type}) => { data-tooltip-html={toolTipHandler(avg, index)} data-amount={avg.amount.toString()} onClick={(e) => dispatch(setSellOrder({ - pricePerUnit: pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toString(), + pricePerUnit: pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toString(), amount: parseFloat(e.currentTarget.getAttribute("data-amount")), }))}> {pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + className="width-30">{pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} {amount.decimalPlaces(activePair.baseAssetPrecision).toFormat()} + className="width-30">{amount.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} {totalPrice.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + className="width-40">{totalPrice.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()}
) : (
{ data-amount={avg.amount.toString()} onClick={(e) => dispatch(setBuyOrder({ - pricePerUnit: parseFloat(pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toString()), + pricePerUnit: parseFloat(pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toString()), amount: parseFloat(e.currentTarget.getAttribute("data-amount")), })) }> {totalPrice.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + className="width-40">{totalPrice.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} {amount.decimalPlaces(activePair.baseAssetPrecision).toFormat()} + className="width-30">{amount.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} {pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + className="width-30">{pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()}
); })} From d87837e7793f494a63d8b272f5d2cd99ea0fe8a2 Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 21 Jan 2025 12:00:37 +0330 Subject: [PATCH 14/29] #246 feat: Updated recent trades to utilize currency service for data --- .../Sections/Content/components/Market/Market.js | 2 +- .../Market/components/LastTrades/LastTrades.js | 2 ++ .../components/LastTradesTable/LastTradesTable.js | 13 +++++++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js index 3f784115..c3eef5e1 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js @@ -24,7 +24,7 @@ const Market = () => { {/**/}
- {/**/} +
diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/LastTrades.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/LastTrades.js index 93f04e00..74622aac 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/LastTrades.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/LastTrades.js @@ -27,6 +27,8 @@ const LastTrades = () => {
} + + return (
diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/components/LastTradesTable/LastTradesTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/components/LastTradesTable/LastTradesTable.js index 779f523b..73078cd3 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/components/LastTradesTable/LastTradesTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/LastTrades/components/LastTradesTable/LastTradesTable.js @@ -2,15 +2,20 @@ import React from "react"; import classes from "./LastTradesTable.module.css"; import {useTranslation} from "react-i18next"; import moment from "moment-jalaali"; -import {connect} from "react-redux"; +import {connect, useSelector} from "react-redux"; import ScrollBar from "../../../../../../../../../../../../components/ScrollBar"; import {BN} from "../../../../../../../../../../../../utils/utils"; import Date from "../../../../../../../../../../../../components/Date/Date"; +import i18n from "i18next"; const LastTradesTable = (props) => { const {t} = useTranslation(); const {activePair, data} = props + + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + return (
@@ -38,9 +43,9 @@ const LastTradesTable = (props) => { {moment(tr.time).format("HH:mm:ss")} - {amount.decimalPlaces(activePair.baseAssetPrecision).toFormat()} - {pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} - {totalPrice.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + {amount.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} + {pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + {totalPrice.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} ); })} From 5bb72c8bcb1dc3d7d64aa2f2c9bc4e78064221c7 Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 21 Jan 2025 12:06:26 +0330 Subject: [PATCH 15/29] #246 feat: Refactored current orders to fetch currency details from service --- .../Sections/Content/components/Market/Market.js | 2 +- .../MyOrders/components/OpenOrders/OpenOrders.js | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js index c3eef5e1..b4b3ebbb 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/Market.js @@ -21,7 +21,7 @@ const Market = () => {
- {/**/} +
diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OpenOrders/OpenOrders.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OpenOrders/OpenOrders.js index db2602c2..a0891f7b 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OpenOrders/OpenOrders.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OpenOrders/OpenOrders.js @@ -12,6 +12,7 @@ import Error from "../../../../../../../../../../../../components/Error/Error"; import {useMyOpenOrders} from "../../../../../../../../../../../../queries"; import {cancelOrderByOrderID} from "js-api-client"; import Date from "../../../../../../../../../../../../components/Date/Date"; +import i18n from "i18next"; const OpenOrders = () => { @@ -19,9 +20,13 @@ const OpenOrders = () => { const {t} = useTranslation(); const [openOrder, setOpenOrder] = useState(null) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) const activePair = useSelector((state) => state.exchange.activePair) const lastTransaction = useSelector((state) => state.auth.lastTransaction); + + const {data, isLoading, error, refetch} = useMyOpenOrders(activePair.symbol) useEffect(() => { @@ -71,9 +76,9 @@ const OpenOrders = () => { {moment(tr.time).format("HH:mm:ss")} - {origQty.decimalPlaces(activePair.baseAssetPrecision).toFormat()} - {pricePerUnit.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} - {totalPrice.decimalPlaces(activePair.quoteAssetPrecision).toFormat()} + {origQty.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} + {pricePerUnit.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + {totalPrice.decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} {executedQty.dividedBy(origQty).multipliedBy(100).toFormat(0)} {

{t("myOrders.tradedAmount")} :{" "} - {executedQty.decimalPlaces(activePair.baseAssetPrecision).toFormat()} + {executedQty.decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()}

{

{t("myOrders.tradedPrice")} :{" "} - {executedQty.multipliedBy(pricePerUnit).decimalPlaces(activePair.baseAssetPrecision).toFormat()} + {executedQty.multipliedBy(pricePerUnit).decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()}

From f22bdf5e963cc2d175a67d851c9bbb8b8c692d0d Mon Sep 17 00:00:00 2001 From: Hossein Date: Wed, 22 Jan 2025 16:08:21 +0330 Subject: [PATCH 16/29] #246 feat: Updated order history to use service-based currency details --- src/index.js | 1 + .../components/OrdersHistory/OrdersHistory.js | 20 ++++++++++++++++--- src/utils/utils.js | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 2758ac78..e2b29805 100644 --- a/src/index.js +++ b/src/index.js @@ -76,6 +76,7 @@ i18n }); + const Toast = () => { return { const {t} = useTranslation(); @@ -17,6 +19,9 @@ const OrdersHistory = () => { const activePair = useSelector((state) => state.exchange.activePair) const lastTransaction = useSelector((state) => state.auth.lastTransaction); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const {data, isLoading, error, refetch} = useMyOrderHistory(activePair.symbol) useEffect(() => { @@ -49,14 +54,23 @@ const OrdersHistory = () => { {data.map((tr, index) => ( + + console.log("tr.origQty", tr.origQty), + console.log("typeof tr.origQty", typeof tr.origQty), {moment(tr.time).format("HH:mm:ss")} - {tr.origQty} - {tr.price.toLocaleString()} - {(tr.origQty * tr.price).toLocaleString()} + + + {new BN(tr.origQty).decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} + + {new BN(tr.price).decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + + {new BN(tr.origQty).multipliedBy(tr.price).decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + {t("orderStatus." + tr.status)} + {openOrder === index ? ( setOpenOrder(null)}> { } export const BN = BigNumber.clone({ + + DECIMAL_PLACES: 8, + ROUNDING_MODE: BigNumber.ROUND_DOWN, + FORMAT: { groupSize: 3, groupSeparator: ',', From 90c900c685fcd2d2d6799066ef12e5c1812767aa Mon Sep 17 00:00:00 2001 From: Hossein Date: Wed, 22 Jan 2025 18:41:27 +0330 Subject: [PATCH 17/29] #246 feat: Integrated currency service for trade history display --- .../components/OrdersHistory/OrdersHistory.js | 3 --- .../MyOrders/components/Trades/Trades.js | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OrdersHistory/OrdersHistory.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OrdersHistory/OrdersHistory.js index 036f9501..946b4749 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OrdersHistory/OrdersHistory.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/OrdersHistory/OrdersHistory.js @@ -54,9 +54,6 @@ const OrdersHistory = () => { {data.map((tr, index) => ( - - console.log("tr.origQty", tr.origQty), - console.log("typeof tr.origQty", typeof tr.origQty), diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/Trades/Trades.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/Trades/Trades.js index 14f5ceed..1033f6b8 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/Trades/Trades.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/MyOrders/components/Trades/Trades.js @@ -9,7 +9,8 @@ import Icon from "../../../../../../../../../../../../components/Icon/Icon"; import Error from "../../../../../../../../../../../../components/Error/Error"; import {useMyTrades} from "../../../../../../../../../../../../queries"; import Date from "../../../../../../../../../../../../components/Date/Date"; -import {BN} from "../../../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../../../utils/utils"; +import i18n from "i18next"; const Trades = () => { @@ -20,6 +21,9 @@ const Trades = () => { const activePair = useSelector((state) => state.exchange.activePair) const lastTransaction = useSelector((state) => state.auth.lastTransaction); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const {data, isLoading, error, refetch} = useMyTrades(activePair.symbol) useEffect(() => { @@ -58,9 +62,10 @@ const Trades = () => { {moment(tr.time).format("HH:mm:ss")} - {tr.qty} - {tr.price.toLocaleString()} - {(tr.qty * tr.price).toLocaleString()} + {new BN(tr.qty).decimalPlaces(currencies[activePair.baseAsset].precision).toFormat()} + {new BN(tr.price).decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + {new BN(tr.qty).multipliedBy(tr.price).decimalPlaces(currencies[activePair.quoteAsset].precision).toFormat()} + {openOrder === index ? ( setOpenOrder(null)}> { style={{display: openOrder === index ? "revert" : "none"}}>

{t("myOrders.orderId")} : {tr.orderId}

- {t("commission")} : {new BN(tr.commission).toFormat()} {t("currency." + tr.commissionAsset.toUpperCase())} + {t("commission")} : {new BN(tr.commission).decimalPlaces(currencies[tr.commissionAsset.toUpperCase()].precision).toFormat()} + {getCurrencyNameOrAlias(currencies[tr.commissionAsset.toUpperCase()], language)}

From bc30dafb671e34f6285811df86a643cfc95a4092 Mon Sep 17 00:00:00 2001 From: Hossein Date: Wed, 22 Jan 2025 19:30:16 +0330 Subject: [PATCH 18/29] #246 feat: Refactored quick deposit in professional trading to fetch currency details from service --- src/components/Popup/Popup.js | 6 +++++- .../Market/components/Order/components/BuyOrder/BuyOrder.js | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/Popup/Popup.js b/src/components/Popup/Popup.js index 16038f1b..b844d591 100644 --- a/src/components/Popup/Popup.js +++ b/src/components/Popup/Popup.js @@ -11,6 +11,8 @@ import {useGetCurrencyInfo} from "../../queries"; import Loading from "../Loading/Loading"; import Error from "../Error/Error"; import PopupAddress from "./PopupAddress/PopupAddress"; +import i18n from "i18next"; +import {getCurrencyNameOrAlias} from "../../utils/utils"; const Popup = ({currency, closePopup}) => { @@ -18,6 +20,8 @@ const Popup = ({currency, closePopup}) => { const isLogin = useSelector((state) => state.auth.isLogin) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) const [networkName, setNetworkName] = useState({value: 0, error: []}); @@ -75,7 +79,7 @@ const Popup = ({currency, closePopup}) => { return (
-

{t("deposit")} {t("currency." + currency)}

+

{t("deposit")} {getCurrencyNameOrAlias(currencies[currency], language)}

{content()} diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js index 2cfbfb3f..008f6682 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js @@ -24,12 +24,6 @@ const BuyOrder = () => { const bestBuyPrice = useSelector((state) => state.exchange.activePairOrders.bestBuyPrice) const selectedBuyOrder = useSelector((state) => state.exchange.activePairOrders.selectedBuyOrder) - - console.log("activePair", activePair) - console.log("bestBuyPrice", bestBuyPrice) - console.log("selectedBuyOrder", selectedBuyOrder) - console.log("activePair", typeof activePair) - const language = i18n.language const currencies = useSelector((state) => state.exchange.currencies) From 576ac3d26395894a96f0982cb959184074d90881 Mon Sep 17 00:00:00 2001 From: Hossein Date: Thu, 23 Jan 2025 17:30:31 +0330 Subject: [PATCH 19/29] #246 feat: Update transaction history to use currency details from service --- .../History/components/Transactions/Transactions.js | 10 +++++++--- .../components/TransactionsTable/TransactionsTable.js | 11 +++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/Transactions/Transactions.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/Transactions/Transactions.js index 933d0064..9dca0f66 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/Transactions/Transactions.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/Transactions/Transactions.js @@ -13,12 +13,16 @@ import ToggleSwitch from "../../../../../../../../../../components/ToggleSwitch/ import Button from "../../../../../../../../../../components/Button/Button"; import TransactionsTable from "../TransactionsTable/TransactionsTable"; import {useGetTransactionsHistory} from "../../../../../../../../../../queries"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const Transactions = () => { const {t} = useTranslation(); const coins = useSelector((state) => state.exchange.assets) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const [query, setQuery] = useState({ "currency": null, // optional "category": null, // optional [DEPOSIT, FEE, TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED] @@ -52,8 +56,8 @@ const Transactions = () => { categoryOptions.push({value: o, label: t('TransactionCategory.' + o)}) }) - coins.forEach((o) => { - currenciesOptions.push({value: o, label: t('currency.' + o)}) + Object.keys(currencies).forEach((o) => { + currenciesOptions.push({value: o, label: getCurrencyNameOrAlias(currencies[o], language)}) }) const scrollRef = useRef(null); @@ -131,7 +135,7 @@ const Transactions = () => { type="select" value={{ value: query?.currency, - label: query?.currency ? t('currency.'+ query?.currency) : t('all'), + label: query?.currency ? getCurrencyNameOrAlias(currencies[query?.currency], language) : t('all'), }} onchange={(e) => setQuery({...query, currency: e.value, offset:0})} customClass={`width-20 ${classes.thisInput}`} diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/TransactionsTable/TransactionsTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/TransactionsTable/TransactionsTable.js index d434f2c9..f82de9d5 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/TransactionsTable/TransactionsTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/TransactionsTable/TransactionsTable.js @@ -3,11 +3,16 @@ import classes from './TransactionsTable.module.css'; import {useTranslation} from "react-i18next"; import Date from "../../../../../../../../../../components/Date/Date"; import moment from "moment-jalaali"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; +import i18n from "i18next"; +import {useSelector} from "react-redux"; const TransactionsTable = ({txs}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + let head = (
{t("date")} @@ -35,13 +40,15 @@ const TransactionsTable = ({txs}) => { {t("TransactionCategory." + tr.category )} - {t("currency." + tr.currency )} + {getCurrencyNameOrAlias(currencies[tr.currency], language)} {new BN(tr?.balanceChange).toFormat()} + {new BN(tr?.balanceChange).decimalPlaces(currencies[tr.currency].precision).toFormat()} {new BN(tr?.balance).toFormat()} + {new BN(tr?.balance).decimalPlaces(currencies[tr.currency].precision).toFormat()}
From 378636043367be70aa7a49ba9ecada468cb5a245 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sun, 26 Jan 2025 17:45:29 +0330 Subject: [PATCH 20/29] #246 feat: Update deposit history to fetch and display currency details from service --- .../components/DepositHistory/DepositHistory.js | 13 ++++++++++--- .../DepositHistoryTable/DepositHistoryTable.js | 11 ++++++++--- .../components/MarketPairCard/MarketPairCard.js | 4 ---- src/store/sagas/global.js | 14 +++++++++++--- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistory/DepositHistory.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistory/DepositHistory.js index 465d475f..b71b40e4 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistory/DepositHistory.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistory/DepositHistory.js @@ -13,6 +13,7 @@ import i18n from "i18next"; import ToggleSwitch from "../../../../../../../../../../components/ToggleSwitch/ToggleSwitch"; import Button from "../../../../../../../../../../components/Button/Button"; import DepositHistoryTable from "../DepositHistoryTable/DepositHistoryTable"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const DepositHistory = () => { @@ -20,6 +21,10 @@ const DepositHistory = () => { const {t} = useTranslation(); const coins = useSelector((state) => state.exchange.assets) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const [query, setQuery] = useState({ "currency": null, // optional "category": null, // optional [DEPOSIT, FEE, TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED] @@ -54,8 +59,10 @@ const DepositHistory = () => { categoryOptions.push({value: o, label: t('TransactionCategory.' + o)}) }) - coins.forEach((o) => { - currenciesOptions.push({value: o, label: t('currency.' + o)}) + + + Object.keys(currencies).forEach((o) => { + currenciesOptions.push({value: o, label: getCurrencyNameOrAlias(currencies[o], language)}) }) @@ -137,7 +144,7 @@ const DepositHistory = () => { type="select" value={{ value: query?.currency, - label: query?.currency ? t('currency.'+ query?.currency) : t('all'), + label: query?.currency ? getCurrencyNameOrAlias(currencies[query?.currency], language) : t('all'), }} onchange={(e) => setQuery({...query, currency: e.value, offset:0})} customClass={`width-20 ${classes.thisInput}`} diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistoryTable/DepositHistoryTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistoryTable/DepositHistoryTable.js index 1e070d7a..9d58a785 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistoryTable/DepositHistoryTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/DepositHistoryTable/DepositHistoryTable.js @@ -4,12 +4,17 @@ import {useTranslation} from "react-i18next"; import {useSelector} from "react-redux"; import Date from "../../../../../../../../../../components/Date/Date"; import moment from "moment-jalaali"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; +import i18n from "i18next"; const DepositHistoryTable = ({txs, offset}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + let head = (
{t("date")} @@ -37,7 +42,7 @@ const DepositHistoryTable = ({txs, offset}) => { - {t("currency." + tr.currency )} + {getCurrencyNameOrAlias(currencies[tr.currency], language)} @@ -45,7 +50,7 @@ const DepositHistoryTable = ({txs, offset}) => { - {new BN(tr?.amount).toFormat()} + {new BN(tr?.amount).decimalPlaces(currencies[tr.currency].precision).toFormat()} diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js index 0abb98c1..e5d4cba4 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js @@ -24,12 +24,8 @@ const MarketPairCard = ({id, pair, favPair, addFav}) => { }*/ const changeActivePair = () => { - // ساختن رشته با فرمت BASE_QUOTE const pairSymbolFormatted = `${pair.baseAsset}_${pair.quoteAsset}`; - - // مقایسه activePair با رشته ساخته‌شده if (activePair !== pairSymbolFormatted) { - // به‌روزرسانی activePair dispatch(setActivePairInitiate(`${pair.baseAsset}_${pair.quoteAsset}`, id)); } }; diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index 46843cee..d5b6d851 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -21,7 +21,9 @@ export function* setThemeSaga(action) { } export function* setActivePair(action) { - yield call([localStorage, 'setItem'], "activePair", action.pair.symbol) + + console.log("action.pair.symbol ------------------------------------>", action.pair) + yield call([localStorage, 'setItem'], "activePair", action.pair) yield call([localStorage, 'setItem'], "activeMarketTab", action.activeTab) yield put(actions.setActivePair(action.pair)); } @@ -201,11 +203,17 @@ export function* loadConfig(action) { yield put(actions.setUserAccountInfo({wallets, tradeFee})); const activePair = yield call([localStorage, 'getItem'], 'activePair') - const lastActivePair = symbols.find(symbol => symbol.symbol === activePair) + const lastActivePair = Object.keys(pairsListMap).includes(activePair) ? activePair : null; + + /*const lastActivePair = lastActivePairKey ? pairsListMap[lastActivePairKey] : null;*/ + + + + /*const lastActivePair = symbols.find(symbol => symbol.symbol === activePair)*/ console.log("symbols[0]", symbols[0]) console.log("activePair localStorage", activePair) - console.log("lastActivePair", lastActivePair) + console.log("lastActivePair -------------------------------------------------------- >>>>>>>>>>", lastActivePair) console.log("exchangeInfo.symbols", exchangeInfo.symbols) console.log("pairsListMap", pairsListMap) console.log("pairsListMap 0", Object.keys(pairsListMap)[0]) From 37d6dba16f2fb54698c585c0b3cbf58823d7f32d Mon Sep 17 00:00:00 2001 From: Hossein Date: Wed, 29 Jan 2025 18:13:50 +0330 Subject: [PATCH 21/29] #246 feat: Update withdrawal history to utilize currency details from service --- .../WithdrawHistory/WithdrawHistory.js | 12 +++++++++--- .../WithdrawHistoryTable.js | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistory/WithdrawHistory.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistory/WithdrawHistory.js index 0a5333e4..85872412 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistory/WithdrawHistory.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistory/WithdrawHistory.js @@ -13,12 +13,16 @@ import i18n from "i18next"; import ToggleSwitch from "../../../../../../../../../../components/ToggleSwitch/ToggleSwitch"; import Button from "../../../../../../../../../../components/Button/Button"; import WithdrawHistoryTable from "../WithdrawHistoryTable/WithdrawHistoryTable"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const WithdrawHistory = () => { const {t} = useTranslation(); const coins = useSelector((state) => state.exchange.assets) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const [query, setQuery] = useState({ "currency": null, // optional "category": null, // optional [DEPOSIT, FEE, TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED] @@ -53,11 +57,13 @@ const WithdrawHistory = () => { categoryOptions.push({value: o, label: t('TransactionCategory.' + o)}) }) - coins.forEach((o) => { - currenciesOptions.push({value: o, label: t('currency.' + o)}) + + Object.keys(currencies).forEach((o) => { + currenciesOptions.push({value: o, label: getCurrencyNameOrAlias(currencies[o], language)}) }) + const scrollRef = useRef(null); @@ -137,7 +143,7 @@ const WithdrawHistory = () => { type="select" value={{ value: query?.currency, - label: query?.currency ? t('currency.'+ query?.currency) : t('all'), + label: query?.currency ? getCurrencyNameOrAlias(currencies[query?.currency], language) : t('all'), }} onchange={(e) => setQuery({...query, currency: e.value, offset:0})} customClass={`width-20 ${classes.thisInput}`} diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistoryTable/WithdrawHistoryTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistoryTable/WithdrawHistoryTable.js index e80af9c9..96b8fb76 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistoryTable/WithdrawHistoryTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/History/components/WithdrawHistoryTable/WithdrawHistoryTable.js @@ -3,14 +3,21 @@ import classes from './WithdrawHistoryTable.module.css' import {useTranslation} from "react-i18next"; import Date from "../../../../../../../../../../components/Date/Date"; import moment from "moment-jalaali"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; import Icon from "../../../../../../../../../../components/Icon/Icon"; +import i18n from "i18next"; +import {useSelector} from "react-redux"; const WithdrawHistoryTable = ({txs, offset}) => { + const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const [isOpen, setIsOpen] = useState(false); - const {t} = useTranslation(); + let head = (
@@ -41,7 +48,7 @@ const WithdrawHistoryTable = ({txs, offset}) => { - {t("currency." + tr.currency )} + {getCurrencyNameOrAlias(currencies[tr.currency], language)} @@ -49,11 +56,11 @@ const WithdrawHistoryTable = ({txs, offset}) => { - {new BN(tr?.amount).toFormat()} + {new BN(tr?.amount).decimalPlaces(currencies[tr.currency].precision).toFormat()} - {new BN(tr?.appliedFee).toFormat()} + {new BN(tr?.appliedFee).decimalPlaces(currencies[tr.currency].precision).toFormat()} From 8e604529346e3db2d6eb28231aa18e6501be9d50 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sat, 1 Feb 2025 13:01:42 +0330 Subject: [PATCH 22/29] #246 feat: Use new currency data in recent deposits section --- .../components/Wallet/components/DepositTx/DepositTx.js | 7 ++++++- .../Wallet/components/DepositTxTable/DepositTxTable.js | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTx/DepositTx.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTx/DepositTx.js index ffed24e3..3839d6b4 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTx/DepositTx.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTx/DepositTx.js @@ -9,12 +9,17 @@ import DepositTxTable from "../DepositTxTable/DepositTxTable"; import * as Routes from "../../../../../../../../Routes/routes"; import Icon from "../../../../../../../../../../components/Icon/Icon"; import i18n from "i18next"; +import {useSelector} from "react-redux"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const DepositTx = () => { const {id} = useParams(); const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const query = { "currency": id, // optional "category": null, // optional [DEPOSIT, FEE, TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED] @@ -44,7 +49,7 @@ const DepositTx = () => { diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTxTable/DepositTxTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTxTable/DepositTxTable.js index 4b604b4d..47f90d83 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTxTable/DepositTxTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/DepositTxTable/DepositTxTable.js @@ -5,11 +5,16 @@ import Date from "../../../../../../../../../../components/Date/Date"; import moment from "moment-jalaali"; import {BN} from "../../../../../../../../../../utils/utils"; import Icon from "../../../../../../../../../../components/Icon/Icon"; +import {useSelector} from "react-redux"; +import i18n from "i18next"; const DepositTxTable = ({txs}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const [isOpen, setIsOpen] = useState(false); let head = ( @@ -42,7 +47,7 @@ const DepositTxTable = ({txs}) => { - {new BN(tr?.amount).toFormat()} + {new BN(tr?.amount).decimalPlaces(currencies[tr.currency].precision).toFormat()} From fe1b5315ff4715a6bf9571f46c32734c6a430c45 Mon Sep 17 00:00:00 2001 From: Hossein Date: Sat, 1 Feb 2025 13:22:19 +0330 Subject: [PATCH 23/29] #246 feat: Update recent withdrawals to use latest currency data --- .../Wallet/components/WithdrawTx/WithdrawTx.js | 8 +++++++- .../components/WithdrawTxTable/WithdrawTxTable.js | 12 ++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTx/WithdrawTx.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTx/WithdrawTx.js index 1fac782a..50b8007c 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTx/WithdrawTx.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTx/WithdrawTx.js @@ -10,12 +10,18 @@ import WithdrawTxTable from "../WithdrawTxTable/WithdrawTxTable"; import * as Routes from "../../../../../../../../Routes/routes"; import Icon from "../../../../../../../../../../components/Icon/Icon"; import i18n from "i18next"; +import {useSelector} from "react-redux"; +import {getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; const WithdrawTx = () => { const {id} = useParams(); const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const query = { "currency": id, // optional "category": null, // optional [DEPOSIT, FEE, TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED] @@ -44,7 +50,7 @@ const WithdrawTx = () => { diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTxTable/WithdrawTxTable.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTxTable/WithdrawTxTable.js index 5429ec10..b8296d17 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTxTable/WithdrawTxTable.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Wallet/components/WithdrawTxTable/WithdrawTxTable.js @@ -11,11 +11,17 @@ import {cancelWithdrawReq} from "js-api-client/client/withdraw"; import toast from "react-hot-toast"; import {useGetWithdrawHistory} from "../../../../../../../../../../queries"; import {useParams} from "react-router-dom"; +import i18n from "i18next"; +import {useSelector} from "react-redux"; const WithdrawTxTable = ({txs}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false) @@ -88,10 +94,8 @@ const WithdrawTxTable = ({txs}) => { {tr.destNetwork ?? "- - -"} - - - {new BN(tr?.amount).toFormat()} + {new BN(tr?.amount).decimalPlaces(currencies[tr.currency].precision).toFormat()} @@ -107,7 +111,7 @@ const WithdrawTxTable = ({txs}) => {
{t("history.fee")} - {new BN(tr?.appliedFee).toFormat()} + {new BN(tr?.appliedFee).decimalPlaces(currencies[tr.currency].precision).toFormat()}
From a3d79d88f42d94bfe4d51e56190eeb1ed1be6426 Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 11 Feb 2025 16:31:32 +0330 Subject: [PATCH 24/29] #246 feat: Fetch updated currency details in wallet overview --- .../components/WalletSubMenu/WalletSubMenu.js | 42 +++++++++++++++++-- .../WalletSubMenu/WalletSubMenu.module.css | 6 +++ .../WalletListItem/WalletListItem.js | 27 +++++++----- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.js index 918710ed..ec68212d 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.js @@ -8,15 +8,35 @@ import WalletBalance from "./components/WalletBalance/WalletBalance"; import ScrollBar from "../../../../../../../../components/ScrollBar"; import {useGetUserAccount} from "../../../../../../../../queries/hooks/useGetUserAccount"; import Loading from "../../../../../../../../components/Loading/Loading"; +import i18n from "i18next"; const WalletSubMenu = () => { const {t} = useTranslation(); const [showZero, setShowZero] = useState(false); const assets = useSelector((state) => state.exchange.assets) - console.log("assets", assets) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const {data: data, isLoading} = useGetUserAccount() - console.log("data", data) + + + const wallets = Object.keys(currencies) + .map(symbol => ({ + symbol, + name: currencies[symbol].name, + alias: currencies[symbol].alias, + icon: currencies[symbol].icon, + order: currencies[symbol].order, + isActive: currencies[symbol].isActive, + free: data?.wallets?.[symbol]?.free || 0, + })) + .filter(wallet => wallet.isActive || wallet.free > 0); + + wallets.sort((a, b) => { + if (b.free !== a.free) return b.free - a.free; + return a.order - b.order; + }); return (
@@ -35,9 +55,23 @@ const WalletSubMenu = () => {
- {assets?.filter(asset => data?.wallets?.[asset]?.free > 0) + + { + wallets.map((wallet) => ( + + )) + } + + {/*{assets?.filter(asset => data?.wallets?.[asset]?.free > 0) .concat(assets.filter(asset => data?.wallets?.[asset]?.free === 0)) - .map((name) => )} + .map((name) => )}*/}
diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.module.css b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.module.css index 0b0b25fe..845a3031 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.module.css +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/WalletSubMenu.module.css @@ -106,3 +106,9 @@ .selected:last-child:before{ width: 0; } + +.iconDisabled { + filter: grayscale(0.75); + opacity: 0.9;/* + background-color: var(--lightGray)*/ +} \ No newline at end of file diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js index 2a871ce3..af55d8a2 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js @@ -4,43 +4,50 @@ import {NavLink} from "react-router-dom"; import {useTranslation} from "react-i18next"; import {images} from "../../../../../../../../../../assets/images"; import * as Routes from "../../../../../../../../Routes/routes"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; import {useGetUserAccount} from "../../../../../../../../../../queries/hooks/useGetUserAccount"; import {useGetUserAssets} from "../../../../../../../../../../queries"; import {useSelector} from "react-redux"; +import i18n from "i18next"; + +const WalletListItem = ({symbol, data, assetName, freeWallet, showZero}) => { -const WalletListItem = ({assetName, showZero}) => { const {t} = useTranslation(); + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + const refCurrency = useSelector((state) => state.exchange.baseCurrency) const {data: userAccount} = useGetUserAccount() const free = userAccount?.wallets[assetName]?.free || 0 const {data: estimateValue , isLoading, error} = useGetUserAssets(refCurrency) - const freeEstimateValue = (isLoading || error) ? 0 : (estimateValue?.find( q => q.asset === assetName )?.free || 0) + const freeEstimateValue = (isLoading || error) ? 0 : (estimateValue?.find( q => q.asset === symbol )?.free || 0) + + const active = currencies[symbol]?.isActive if (showZero && free === 0) return <> return ( - isActive ? "width-100 row ai-center cursor-pointer position-relative px-1 py-105 " + classes.selected : "width-100 row ai-center cursor-pointer position-relative px-1 py-105" + isActive ? `width-100 row ai-center cursor-pointer position-relative px-1 py-105 ${!active && 'text-gray'} ${classes.selected}` : `width-100 row ai-center cursor-pointer position-relative px-1 py-105 ${!active && 'text-gray'}` } - to={Routes.Wallet + "/" + assetName}> + to={Routes.Wallet + "/" + symbol}>
{assetName}
- {assetName} - {t("currency." + assetName)} + {symbol} + {getCurrencyNameOrAlias(currencies[symbol], language)}
- {new BN(free).toFormat() + " "} {t("currency." + assetName)} + {new BN(freeWallet).decimalPlaces(currencies[symbol]?.precision ?? 0).toFormat() + " "} {getCurrencyNameOrAlias(currencies[symbol], language)} ~ {refCurrency === assetName ? new BN(free).toFormat() : new BN(freeEstimateValue).toFormat()} {t("currency."+refCurrency)} From 55e9c40648352817d5e79d3ab7f8d4d65af37d9f Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 11 Feb 2025 16:41:39 +0330 Subject: [PATCH 25/29] #246 feat: Update baseCurrency in walletBalance --- .../components/WalletBalance/WalletBalance.js | 9 +++++++-- src/setup/configs/configs.js | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js index abfaa719..dc6577a1 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js @@ -2,9 +2,10 @@ import React from 'react'; import classes from '../../WalletSubMenu.module.css' import {useTranslation} from "react-i18next"; import {images} from "../../../../../../../../../../assets/images"; -import {BN} from "../../../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../../../utils/utils"; import {useGetUserAssetsEstimatedValue} from "../../../../../../../../../../queries"; import {useSelector} from "react-redux"; +import i18n from "i18next"; const WalletBalance = () => { @@ -13,6 +14,10 @@ const WalletBalance = () => { const {data , isLoading, error} = useGetUserAssetsEstimatedValue(refCurrency) const totalValue = (isLoading || error) ? 0 : data.value + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + return (
{ {t("WalletSubMenu.approximate")}
- {new BN(totalValue).toFormat()}{" "}{t("currency."+refCurrency)} + {new BN(totalValue).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[refCurrency], language)}
diff --git a/src/setup/configs/configs.js b/src/setup/configs/configs.js index 2feded4f..8fcf72ac 100644 --- a/src/setup/configs/configs.js +++ b/src/setup/configs/configs.js @@ -8,6 +8,6 @@ export const defaultConfigs = { ], "defaultTheme": "DARK", "supportEmail": "supportEmail@gmail.com", - "baseCurrency": "TUSDT", + "baseCurrency": "USDT", "dateType": "Hijri" } \ No newline at end of file From a4caf247cb5012f80cb27824b8f9c57f9533f0d4 Mon Sep 17 00:00:00 2001 From: Hossein Date: Tue, 11 Feb 2025 19:31:59 +0330 Subject: [PATCH 26/29] =?UTF-8?q?#246=20feat:=20Integrate=20new=20currency?= =?UTF-8?q?=20source=20in=20user=E2=80=99s=20available,=20locked,=20and=20?= =?UTF-8?q?pending=20settlement=20balances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/WalletHeader/WalletHeader.js | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/Header/components/WalletHeader/WalletHeader.js b/src/main/Browser/Pages/UserPanel/Sections/Header/components/WalletHeader/WalletHeader.js index 23f75804..8a0cd742 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Header/components/WalletHeader/WalletHeader.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Header/components/WalletHeader/WalletHeader.js @@ -2,10 +2,11 @@ import React from "react"; import classes from "./WalletHeader.module.css"; import {useTranslation} from "react-i18next"; import {useParams} from "react-router-dom"; -import {BN} from "../../../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias} from "../../../../../../../../utils/utils"; import {useGetUserAccount} from "../../../../../../../../queries/hooks/useGetUserAccount"; import {useGetUserAssets} from "../../../../../../../../queries"; import {useSelector} from "react-redux"; +import i18n from "i18next"; const WalletHeader = () => { const {id} = useParams() @@ -17,28 +18,34 @@ const WalletHeader = () => { const {data: estimateValue , isLoading, error} = useGetUserAssets(refCurrency) const allEstimateValue = (isLoading || error) ? 0 : (estimateValue?.find( q => q.asset === id )) + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + return ( <>
-

{t("currency." + id)}

+

{getCurrencyNameOrAlias(currencies[id], language)}

{id}
{t("header.free")} - {new BN(userAccount?.wallets[id]?.free || 0).toFormat()} - ( {refCurrency === id ? new BN(userAccount?.wallets[id]?.free || 0).toFormat() : new BN(allEstimateValue?.free || 0).toFormat()} {t("currency."+refCurrency)} ) + + {new BN(userAccount?.wallets[id]?.free || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat()} + ({ refCurrency === id ? new BN(userAccount?.wallets[id]?.free || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat() : new BN(allEstimateValue?.free || 0).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat()} {refCurrency} )
{t("header.locked")} - {new BN(userAccount?.wallets[id]?.locked || 0).toFormat()} - ( {refCurrency === id ? new BN(userAccount?.wallets[id]?.locked || 0).toFormat() : new BN(allEstimateValue?.locked || 0).toFormat()} {t("currency."+refCurrency)} ) + + {new BN(userAccount?.wallets[id]?.locked || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat()} + ({ refCurrency === id ? new BN(userAccount?.wallets[id]?.locked || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat() : new BN(allEstimateValue?.locked || 0).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat()} {refCurrency} )
{t("header.inWithdrawalProcess")} - {new BN(userAccount?.wallets[id]?.withdraw || 0).toFormat()} - ( {refCurrency === id ? new BN(userAccount?.wallets[id]?.withdraw || 0).toFormat() : new BN(allEstimateValue?.withdrawing || 0).toFormat()} {t("currency."+refCurrency)} ) + + {new BN(userAccount?.wallets[id]?.withdraw || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat()} + ({ refCurrency === id ? new BN(userAccount?.wallets[id]?.withdraw || 0).decimalPlaces(currencies[id]?.precision ?? 0).toFormat() : new BN(allEstimateValue?.withdrawing || 0).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat()} {refCurrency} )
From abc91e53cd6e9bb36efdef0352a32b9f1185e0ae Mon Sep 17 00:00:00 2001 From: Hossein-ab99 Date: Fri, 14 Feb 2025 00:08:43 +0330 Subject: [PATCH 27/29] #246 feat: Integrate currency service in Easy Trade component --- src/main/Browser/Browser.js | 4 - .../components/EasyOrder/EasyOrder.js | 225 ++++++++++++------ .../Order/components/BuyOrder/BuyOrder.js | 7 - .../components/MarketSubMenu/MarketSubMenu.js | 4 - .../components/MarketCard/MarketCard.js | 3 - .../MarketPairCard/MarketPairCard.js | 3 - src/store/actions/exchange.js | 7 - src/store/sagas/global.js | 6 - 8 files changed, 148 insertions(+), 111 deletions(-) diff --git a/src/main/Browser/Browser.js b/src/main/Browser/Browser.js index 0be6f3e6..045da396 100644 --- a/src/main/Browser/Browser.js +++ b/src/main/Browser/Browser.js @@ -37,10 +37,6 @@ const Browser = () => { const currencies = useSelector((state) => state.exchange.currencies) const fees = useSelector((state) => state.exchange.fees) - console.log("currencies from redux", currencies) - - console.log("fees from redux", fees) - theme === "DARK" ? document.body.classList.add('dark') : document.body.classList.remove('dark'); diff --git a/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js b/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js index 8ae33257..754136c1 100644 --- a/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js +++ b/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js @@ -3,7 +3,7 @@ import classes from './EasyOrder.module.css' import {Trans, useTranslation} from "react-i18next"; import {useDispatch, useSelector} from "react-redux"; import {useGetUserAccount} from "../../../../../../queries/hooks/useGetUserAccount"; -import {BN, parsePriceString} from "../../../../../../utils/utils"; +import {BN, getCurrencyNameOrAlias, parsePriceString} from "../../../../../../utils/utils"; import {useOrderBook} from "../../../../../../queries"; import {toast} from "react-hot-toast"; import {createOrder} from "js-api-client"; @@ -13,6 +13,7 @@ import TextInput from "../../../../../../components/TextInput/TextInput"; import Icon from "../../../../../../components/Icon/Icon"; import NumberInput from "../../../../../../components/NumberInput/NumberInput"; import Button from "../../../../../../components/Button/Button"; +import i18n from "i18next"; const EasyOrder = () => { @@ -22,6 +23,12 @@ const EasyOrder = () => { const [isLoading, setIsLoading] = useState(false) const isLogin = useSelector((state) => state.auth.isLogin) + + const language = i18n.language + const currencies = useSelector((state) => state.exchange.currencies) + + const pairsList = useSelector((state) => state.exchange.pairsList) + const symbols = useSelector((state) => state.exchange.symbols) const [alert, setAlert] = useState({ @@ -42,32 +49,57 @@ const EasyOrder = () => { totalPrice: new BN(0), }); + /* const handleAvailableAssets = () => { + const availableAssets = []; + for (const symbol of symbols) { + if (!availableAssets.includes(symbol.baseAsset)) availableAssets.push(symbol.baseAsset) + if (!availableAssets.includes(symbol.quoteAsset)) availableAssets.push(symbol.quoteAsset) + } + return availableAssets; + } + + const handleAvailableDest = (buy) => { + const dest = [] + for (const symbol of symbols) { + if (symbol.baseAsset === buy) dest.push(symbol.quoteAsset) + if (symbol.quoteAsset === buy) dest.push(symbol.baseAsset) + } + return dest + }*/ + const handleAvailableAssets = () => { - const availableAssets = []; - for (const symbol of symbols) { - if (!availableAssets.includes(symbol.baseAsset)) availableAssets.push(symbol.baseAsset) - if (!availableAssets.includes(symbol.quoteAsset)) availableAssets.push(symbol.quoteAsset) - } - return availableAssets; - } + const availableAssets = new Set(); // استفاده از Set برای جلوگیری از مقادیر تکراری + Object.values(pairsList).forEach(pair => { + availableAssets.add(pair.baseAsset); + availableAssets.add(pair.quoteAsset); + }); + return Array.from(availableAssets); // تبدیل Set به آرایه + }; const handleAvailableDest = (buy) => { - const dest = [] - for (const symbol of symbols) { - if (symbol.baseAsset === buy) dest.push(symbol.quoteAsset) - if (symbol.quoteAsset === buy) dest.push(symbol.baseAsset) - } - return dest - } + const dest = new Set(); + Object.values(pairsList).forEach(pair => { + if (pair.baseAsset === buy) dest.add(pair.quoteAsset); + if (pair.quoteAsset === buy) dest.add(pair.baseAsset); + }); + return Array.from(dest); // تبدیل Set به آرایه + }; + - const findPair = (buy, sell) => symbols?.find(s => ((s?.baseAsset === buy) && (s?.quoteAsset === sell)) || ((s?.baseAsset === sell) && (s?.quoteAsset === buy))) + const findPair = (buy, sell) => + Object.values(pairsList)?.find(pair => + (pair.baseAsset === buy && pair.quoteAsset === sell) || + (pair.baseAsset === sell && pair.quoteAsset === buy) + ); + + const pairsArray = Object.values(pairsList); // تبدیل آبجکت به آرایه const [selected, setSelected] = useState({ - buy: symbols[0].baseAsset, - sell: symbols[0].quoteAsset, - pair: findPair(symbols[0].baseAsset, symbols[0].quoteAsset), + buy: pairsArray[0]?.baseAsset, // مقدار اولیه بر اساس اولین جفت موجود در لیست + sell: pairsArray[0]?.quoteAsset, + pair: findPair(pairsArray[0]?.baseAsset, pairsArray[0]?.quoteAsset), type: "ask" - }) + }); const reversePair = () => { @@ -117,10 +149,23 @@ const EasyOrder = () => { let newAlert = null value = parsePriceString(value); const reqAmount = new BN(value); - let range = "baseRange" - if (selected.type === "bid") range = "quoteRange" + /*let range = "baseRange" + if (selected.type === "bid") range = "quoteRange"*/ + + let selectedCurrency = "baseAsset" + if (selected.type === "bid") selectedCurrency = "quoteAsset" - if (reqAmount.isZero() && reqAmount.isLessThan(selected.pair[range].min)) { + if (reqAmount.isZero() && reqAmount.isLessThan(currencies[selected.pair[selectedCurrency]].minOrder)) { + newAlert = + } + + /*if (reqAmount.isZero() && reqAmount.isLessThan(selected.pair[range].min)) { newAlert = { currency: t("currency." + selected.buy), }} /> - } + }*/ - if (!reqAmount.mod(selected.pair[range].step).isZero()) { + if (!reqAmount.mod(currencies[selected.pair[selectedCurrency]].step).isZero()) { newAlert = } setAlert({...alert, reqAmount: newAlert}); @@ -146,14 +191,29 @@ const EasyOrder = () => { }); }; + const totalPriceHandler = (value) => { let newAlert = null value = parsePriceString(value); const totalPrice = new BN(value); - let range = "quoteRange" - if (selected.type === "bid") range = "baseRange" + /* let range = "quoteRange" + if (selected.type === "bid") range = "baseRange"*/ - if (totalPrice.isZero() && totalPrice.isLessThan(selected.pair[range].min)) { + let selectedCurrency = "quoteAsset" + if (selected.type === "bid") selectedCurrency = "baseAsset" + + if (totalPrice.isZero() && totalPrice.isLessThan(currencies[selected.pair[selectedCurrency]].minOrder)) { + newAlert = + + } + + /* if (totalPrice.isZero() && totalPrice.isLessThan(selected.pair[range].min)) { newAlert = { }} /> - } + }*/ - if (!totalPrice.mod(selected.pair[range].step).isZero()) { + if (!totalPrice.mod(currencies[selected.pair[selectedCurrency]].step).isZero()) { newAlert = } setAlert({...alert, totalPrice: newAlert}); @@ -184,8 +244,8 @@ const EasyOrder = () => { if (order.pricePerUnit.isEqualTo(0)) return toast.error(t("orders.hasNoOffer")); let totalPrice = new BN(userAccount?.wallets[selected?.sell]?.free); let reqAmount = totalPrice.dividedBy(order.pricePerUnit) - if (!reqAmount.mod(selected.pair?.[selected.type === "ask" ? "baseRange" : "quoteRange"].step).isZero()) { - reqAmount = reqAmount.minus(reqAmount.mod(selected.pair?.[selected.type === "ask" ? "baseRange" : "quoteRange"].step)); + if (!reqAmount.mod(currencies[selected.pair?.[selected.type === "ask" ? "baseAsset" : "quoteAsset"]].step).isZero()) { + reqAmount = reqAmount.minus(reqAmount.mod(currencies[selected.pair?.[selected.type === "ask" ? "baseAsset" : "quoteAsset"]].step)); } buyPriceHandler( reqAmount.toFormat(), @@ -194,6 +254,8 @@ const EasyOrder = () => { }; + + const submit = () => { if (!isLogin) return if (isLoading) return @@ -201,7 +263,7 @@ const EasyOrder = () => { setIsLoading(true) const newOrder = {...order} if (selected.type === "bid") { - newOrder.reqAmount = order.totalPrice.decimalPlaces(selected.pair?.baseAssetPrecision) + newOrder.reqAmount = order.totalPrice.decimalPlaces(currencies[selected?.pair?.baseAsset].precision) } createOrder(selected.pair?.symbol, selected.type === "ask" ? "BUY" : "SELL", newOrder) .then((res) => { @@ -217,8 +279,8 @@ const EasyOrder = () => { toast.success( { const buyOnChangeHandler = (e) => { const newBuy = e.value; - const sellOptions = handleAvailableDest(newBuy) + const sellOptions = handleAvailableDest(newBuy); + + setOptions(prevOptions => ({ + ...prevOptions, + sell: sellOptions, + })); - setOptions({ - ...options, - "sell": sellOptions, - }) const sell = sellOptions.includes(selected.sell) ? selected.sell : sellOptions[0]; - const pair = findPair(newBuy, sell) + const pair = findPair(newBuy, sell) || {}; // اطمینان از مقداردهی پیش‌فرض + setSelected({ buy: newBuy, sell, pair, - type: newBuy === pair.baseAsset ? "ask" : "bid" - }) + type: pair.baseAsset === newBuy ? "ask" : "bid" + }); + setOrder({ tradeFee: new BN(0), stopLimit: false, @@ -270,22 +335,26 @@ const EasyOrder = () => { reqAmount: new BN(0), pricePerUnit: new BN(0), totalPrice: new BN(0), - }) + }); + setAlert({ submit: false, reqAmount: null, totalPrice: null, - }) - } + }); + }; + const sellOnChangeHandler = (e) => { const newSell = e.value; - const pair = findPair(selected.buy, newSell) - setSelected({ - ...selected, + const pair = findPair(selected.buy, newSell) || {}; // مقدار پیش‌فرض برای جلوگیری از خطا + + setSelected(prevSelected => ({ + ...prevSelected, sell: newSell, pair, type: selected.buy === pair.baseAsset ? "ask" : "bid" - }) + })); + setOrder({ tradeFee: new BN(0), stopLimit: false, @@ -294,27 +363,28 @@ const EasyOrder = () => { reqAmount: new BN(0), pricePerUnit: new BN(0), totalPrice: new BN(0), - }) + }); + setAlert({ submit: false, reqAmount: null, totalPrice: null, - }) - } + }); + }; const showBestPrice = () => { if (order.pricePerUnit.isZero()) return 0 if (selected.type === "ask") return order.pricePerUnit.toFormat() - return new BN(1).dividedBy(order.pricePerUnit).decimalPlaces(selected.pair?.baseAssetPrecision).toFormat() + return new BN(1).dividedBy(order.pricePerUnit).decimalPlaces(currencies[selected?.pair?.baseAsset].precision).toFormat() } -/* useEffect(() => { - if (order.totalPrice.isGreaterThan(userAccount?.wallets[selected?.sell]?.free)) { - return setAlert({ - ...alert, - totalPrice: t('orders.notEnoughBalance') - }) - } - }, [order.totalPrice])*/ + /* useEffect(() => { + if (order.totalPrice.isGreaterThan(userAccount?.wallets[selected?.sell]?.free)) { + return setAlert({ + ...alert, + totalPrice: t('orders.notEnoughBalance') + }) + } + }, [order.totalPrice])*/ return ( @@ -334,9 +404,10 @@ const EasyOrder = () => { value: o, label:
- {t('currency.' + o)} + {getCurrencyNameOrAlias(currencies[o], language)}
} } @@ -345,15 +416,15 @@ const EasyOrder = () => { type="select" value={{ value: selected?.buy, - label: t('currency.' + selected?.buy), + label: getCurrencyNameOrAlias(currencies[selected?.buy], language), }} onchange={buyOnChangeHandler} customClass={`width-90 ${classes.thisInput} mb-1`} />
-

{t("MarketInfo.lastPrice")}{" "} {t("currency." + selected?.buy)}:

- {showBestPrice()}{" "}{t("currency." + selected?.sell)} +

{t("MarketInfo.lastPrice")}{" "} {getCurrencyNameOrAlias(currencies[selected?.buy], language)}:

+ {showBestPrice()}{" "}{ getCurrencyNameOrAlias(currencies[selected?.sell], language)}
@@ -373,9 +444,9 @@ const EasyOrder = () => { label:
- {t('currency.' + o)} + {getCurrencyNameOrAlias(currencies[o], language)}
} } @@ -384,7 +455,7 @@ const EasyOrder = () => { type="select" value={{ value: selected?.sell, - label: selected?.sell ? t('currency.' + selected?.sell) : t("PersonalizationForm.placeholder"), + label: selected?.sell ? getCurrencyNameOrAlias(currencies[selected?.sell], language) : t("PersonalizationForm.placeholder"), }} onchange={sellOnChangeHandler} customClass={`width-90 ${classes.thisInput} my-1`} @@ -393,14 +464,14 @@ const EasyOrder = () => {

{t("orders.availableAmount")}:{" "}

{new BN(userAccount?.wallets[selected?.sell]?.free || 0).toFormat()}{" "}{t("currency." + selected?.sell)} + onClick={fillBuyByWallet}>{new BN(userAccount?.wallets[selected?.sell]?.free || 0).decimalPlaces(currencies[selected?.sell]?.precision ?? 0).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[selected?.sell], language)}
buyPriceHandler(e.target.value)} alert={alert.reqAmount} customClass={`width-90 mb-1 mt-5`} @@ -409,8 +480,8 @@ const EasyOrder = () => { totalPriceHandler(e.target.value)} alert={alert.totalPrice} customClass={`width-90 my-1`} diff --git a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js index 008f6682..0954ee66 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js +++ b/src/main/Browser/Pages/UserPanel/Sections/Content/components/Market/components/Order/components/BuyOrder/BuyOrder.js @@ -76,13 +76,6 @@ const BuyOrder = () => { const currencyValidator = (key, val, rule) => { - console.log("activePair.baseRange", activePair.baseRange) - - console.log("rule", rule) - - console.log("currencies?.[rule].step", currencies?.[rule]?.step) - - if (!val.isZero() && val.isLessThan(currencies[rule].minOrder)) { return setAlert({ ...alert, diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js index 12aed721..c30f6e10 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/MarketSubMenu.js @@ -13,14 +13,10 @@ const MarketSubMenu = () => { const [activeTab] = useState(JSON.parse(localStorage.getItem("activeMarketTab")) || 1); const symbols = useSelector((state) => state.exchange.symbols) - console.log("symbols", symbols) - const pairsList = useSelector((state) => state.exchange.pairsList) - console.log("pairsList from redux", pairsList) const fav = useSelector((state) => state.auth.favoritePairs) const dispatch = useDispatch(); - console.log("fav", fav) const addToFav = (selected) => { if (fav.includes(selected)) { diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js index 9bb99a01..a26f4941 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js @@ -4,9 +4,6 @@ import MarketPairCard from "../MarketPairCard/MarketPairCard"; const MarketCard = ({type, ...props}) => { - - console.log("props?.pairs", props?.pairs) - return (
diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js index e5d4cba4..4fd9fe49 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js @@ -15,9 +15,6 @@ const MarketPairCard = ({id, pair, favPair, addFav}) => { const language = i18n.language const currencies = useSelector((state) => state.exchange.currencies) - console.log("pair", pair) - console.log("activePair in submenu", activePair) - const dispatch = useDispatch(); /*const changeActivePair = () =>{ if (activePair !== pair.symbol) dispatch(setActivePairInitiate(pair, id)) diff --git a/src/store/actions/exchange.js b/src/store/actions/exchange.js index 0af598fe..2261c7af 100644 --- a/src/store/actions/exchange.js +++ b/src/store/actions/exchange.js @@ -2,9 +2,6 @@ import * as actionTypes from "./actionTypes"; import {GET_FEES} from "./actionTypes"; export const setActivePairInitiate = (pair, activeTab) => { - - console.log("pair in excange", pair) - console.log("activeTab in excange", activeTab) return { type: actionTypes.SET_ACTIVE_PAIR_INITIATE, activeTab: activeTab, @@ -13,10 +10,6 @@ export const setActivePairInitiate = (pair, activeTab) => { }; export const setActivePair = pair => { - - console.log("pair---------->", pair) - console.log("pair---------->", typeof pair) - return { type: actionTypes.SET_ACTIVE_PAIR, pair: pair, diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index d5b6d851..c1b8fa7d 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -211,12 +211,6 @@ export function* loadConfig(action) { /*const lastActivePair = symbols.find(symbol => symbol.symbol === activePair)*/ - console.log("symbols[0]", symbols[0]) - console.log("activePair localStorage", activePair) - console.log("lastActivePair -------------------------------------------------------- >>>>>>>>>>", lastActivePair) - console.log("exchangeInfo.symbols", exchangeInfo.symbols) - console.log("pairsListMap", pairsListMap) - console.log("pairsListMap 0", Object.keys(pairsListMap)[0]) yield put(actions.setActivePair(lastActivePair || Object.keys(pairsListMap)[0])); From 0b4a7264d29628ebe4f33800f2ab459a90f60c8f Mon Sep 17 00:00:00 2001 From: Hossein-ab99 Date: Fri, 14 Feb 2025 00:16:13 +0330 Subject: [PATCH 28/29] =?UTF-8?q?#246=20feat:=20display=20user's=20equival?= =?UTF-8?q?ent=20balance=20based=20on=20reference=20currency=20with=20prec?= =?UTF-8?q?ision=C3=98=C3=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WalletSubMenu/components/WalletBalance/WalletBalance.js | 2 +- .../WalletSubMenu/components/WalletListItem/WalletListItem.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js index dc6577a1..78f59625 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletBalance/WalletBalance.js @@ -33,7 +33,7 @@ const WalletBalance = () => { {t("WalletSubMenu.approximate")}
- {new BN(totalValue).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[refCurrency], language)} + {new BN(totalValue).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat()}{" "}{getCurrencyNameOrAlias(currencies[refCurrency], language)}
diff --git a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js index af55d8a2..039f7294 100644 --- a/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js +++ b/src/main/Browser/Pages/UserPanel/Sections/SubMenu/components/WalletSubMenu/components/WalletListItem/WalletListItem.js @@ -49,7 +49,7 @@ const WalletListItem = ({symbol, data, assetName, freeWallet, showZero}) => {
{new BN(freeWallet).decimalPlaces(currencies[symbol]?.precision ?? 0).toFormat() + " "} {getCurrencyNameOrAlias(currencies[symbol], language)} - ~ {refCurrency === assetName ? new BN(free).toFormat() : new BN(freeEstimateValue).toFormat()} {t("currency."+refCurrency)} + ~ {refCurrency === assetName ? new BN(free).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat() : new BN(freeEstimateValue).decimalPlaces(currencies[refCurrency]?.precision ?? 0).toFormat()} {t("currency."+refCurrency)}
From c3d7f851b90c77673479e9af20fa713a7e822543 Mon Sep 17 00:00:00 2001 From: Hossein-ab99 Date: Fri, 14 Feb 2025 00:30:56 +0330 Subject: [PATCH 29/29] #246 refactor: cleaned up and streamlined extra sections in Easy Trade --- .../components/EasyOrder/EasyOrder.js | 78 ++----------------- 1 file changed, 8 insertions(+), 70 deletions(-) diff --git a/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js b/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js index 754136c1..c65ab7ee 100644 --- a/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js +++ b/src/main/Browser/Pages/EasyTrading/components/EasyOrder/EasyOrder.js @@ -23,22 +23,16 @@ const EasyOrder = () => { const [isLoading, setIsLoading] = useState(false) const isLogin = useSelector((state) => state.auth.isLogin) - const language = i18n.language const currencies = useSelector((state) => state.exchange.currencies) - const pairsList = useSelector((state) => state.exchange.pairsList) - const symbols = useSelector((state) => state.exchange.symbols) - const [alert, setAlert] = useState({ submit: false, reqAmount: null, totalPrice: null, }); - - const [order, setOrder] = useState({ tradeFee: new BN(0), stopLimit: false, @@ -49,31 +43,13 @@ const EasyOrder = () => { totalPrice: new BN(0), }); - /* const handleAvailableAssets = () => { - const availableAssets = []; - for (const symbol of symbols) { - if (!availableAssets.includes(symbol.baseAsset)) availableAssets.push(symbol.baseAsset) - if (!availableAssets.includes(symbol.quoteAsset)) availableAssets.push(symbol.quoteAsset) - } - return availableAssets; - } - - const handleAvailableDest = (buy) => { - const dest = [] - for (const symbol of symbols) { - if (symbol.baseAsset === buy) dest.push(symbol.quoteAsset) - if (symbol.quoteAsset === buy) dest.push(symbol.baseAsset) - } - return dest - }*/ - const handleAvailableAssets = () => { - const availableAssets = new Set(); // استفاده از Set برای جلوگیری از مقادیر تکراری + const availableAssets = new Set(); Object.values(pairsList).forEach(pair => { availableAssets.add(pair.baseAsset); availableAssets.add(pair.quoteAsset); }); - return Array.from(availableAssets); // تبدیل Set به آرایه + return Array.from(availableAssets); }; const handleAvailableDest = (buy) => { @@ -82,7 +58,7 @@ const EasyOrder = () => { if (pair.baseAsset === buy) dest.add(pair.quoteAsset); if (pair.quoteAsset === buy) dest.add(pair.baseAsset); }); - return Array.from(dest); // تبدیل Set به آرایه + return Array.from(dest); }; @@ -92,10 +68,10 @@ const EasyOrder = () => { (pair.baseAsset === sell && pair.quoteAsset === buy) ); - const pairsArray = Object.values(pairsList); // تبدیل آبجکت به آرایه + const pairsArray = Object.values(pairsList); const [selected, setSelected] = useState({ - buy: pairsArray[0]?.baseAsset, // مقدار اولیه بر اساس اولین جفت موجود در لیست + buy: pairsArray[0]?.baseAsset, sell: pairsArray[0]?.quoteAsset, pair: findPair(pairsArray[0]?.baseAsset, pairsArray[0]?.quoteAsset), type: "ask" @@ -149,8 +125,6 @@ const EasyOrder = () => { let newAlert = null value = parsePriceString(value); const reqAmount = new BN(value); - /*let range = "baseRange" - if (selected.type === "bid") range = "quoteRange"*/ let selectedCurrency = "baseAsset" if (selected.type === "bid") selectedCurrency = "quoteAsset" @@ -165,16 +139,6 @@ const EasyOrder = () => { /> } - /*if (reqAmount.isZero() && reqAmount.isLessThan(selected.pair[range].min)) { - newAlert = - }*/ - if (!reqAmount.mod(currencies[selected.pair[selectedCurrency]].step).isZero()) { newAlert = { let newAlert = null value = parsePriceString(value); const totalPrice = new BN(value); - /* let range = "quoteRange" - if (selected.type === "bid") range = "baseRange"*/ let selectedCurrency = "quoteAsset" if (selected.type === "bid") selectedCurrency = "baseAsset" @@ -213,17 +175,6 @@ const EasyOrder = () => { } - /* if (totalPrice.isZero() && totalPrice.isLessThan(selected.pair[range].min)) { - newAlert = - - }*/ - if (!totalPrice.mod(currencies[selected.pair[selectedCurrency]].step).isZero()) { newAlert = { }; - - const submit = () => { if (!isLogin) return if (isLoading) return @@ -318,8 +267,7 @@ const EasyOrder = () => { })); const sell = sellOptions.includes(selected.sell) ? selected.sell : sellOptions[0]; - const pair = findPair(newBuy, sell) || {}; // اطمینان از مقداردهی پیش‌فرض - + const pair = findPair(newBuy, sell) || {}; setSelected({ buy: newBuy, sell, @@ -346,7 +294,7 @@ const EasyOrder = () => { const sellOnChangeHandler = (e) => { const newSell = e.value; - const pair = findPair(selected.buy, newSell) || {}; // مقدار پیش‌فرض برای جلوگیری از خطا + const pair = findPair(selected.buy, newSell) || {}; setSelected(prevSelected => ({ ...prevSelected, @@ -377,22 +325,11 @@ const EasyOrder = () => { return new BN(1).dividedBy(order.pricePerUnit).decimalPlaces(currencies[selected?.pair?.baseAsset].precision).toFormat() } - /* useEffect(() => { - if (order.totalPrice.isGreaterThan(userAccount?.wallets[selected?.sell]?.free)) { - return setAlert({ - ...alert, - totalPrice: t('orders.notEnoughBalance') - }) - } - }, [order.totalPrice])*/ - - return (
{t("MarketTitle.easyTrading")} -
@@ -477,6 +414,7 @@ const EasyOrder = () => { customClass={`width-90 mb-1 mt-5`} isAllowed={isAllowed} /> +