diff --git a/src/components/Loading/Loading.js b/src/components/Loading/Loading.js index 24110f9..c0d2992 100644 --- a/src/components/Loading/Loading.js +++ b/src/components/Loading/Loading.js @@ -6,10 +6,10 @@ import {isMobile} from 'react-device-detect'; const Loading = ({type}) => { const {t} = useTranslation(); - const isDark = useSelector((state) => state.global.isDark) + const theme = useSelector((state) => state.global.theme) return (
- loading... + loading... {type !== "linear" && {t('loading')}}
); diff --git a/src/components/SideMenu/SideMenu.js b/src/components/SideMenu/SideMenu.js index 6ce5df9..8d1df89 100644 --- a/src/components/SideMenu/SideMenu.js +++ b/src/components/SideMenu/SideMenu.js @@ -2,33 +2,46 @@ import React, {useEffect} from 'react'; import classes from './SideMenu.module.css' import Icon from "../Icon/Icon"; import {useDispatch, useSelector} from "react-redux"; -import {setThemeInitiate, showSideMenu} from "../../store/actions/global"; +import { showSideMenu} from "../../store/actions/global"; import {Link, useLocation} from "react-router-dom"; import {useTranslation} from "react-i18next"; import ReactTooltip from "react-tooltip"; import {setLogoutInitiate} from "../../store/actions"; import {toast} from "react-hot-toast"; -import {logout} from "js-api-client"; +import {logout, setUserConfig} from "js-api-client"; import {images} from "../../assets/images"; import i18n from "i18next"; import ToggleSwitch from "../ToggleSwitch/ToggleSwitch"; import * as Routes from "../../main/Mobile/Routes/routes"; import {toAbsoluteUrl} from "../../utils/utils"; import packageJson from "../../../package.json" +import {setThemeInitiate} from "../../store/actions"; const SideMenu = () => { const {t} = useTranslation(); - const isDark = useSelector((state) => state.global.isDark) - const dispatch = useDispatch(); + let location = useLocation(); + const open = useSelector((state) => state.global.showSideMenu) - const isLogin = useSelector((state) => state.auth.isLogin) + const firstName = useSelector((state) => state.auth.firstName) const lastName = useSelector((state) => state.auth.lastName) - let location = useLocation(); - const languages = window.env.REACT_APP_LANGS_SUPPORT.split(",") + const theme = useSelector((state) => state.global.theme) + const isLogin = useSelector((state) => state.auth.isLogin) + const dispatch = useDispatch() + const languages = useSelector((state) => state.exchange.supportedLanguages) + const changeLanguage = (lang) => { + i18n.changeLanguage(lang) + if (isLogin) { + setUserConfig({ + language: lang + }) + } + } + + useEffect(() => { ReactTooltip.rebuild(); @@ -44,7 +57,7 @@ const SideMenu = () => { } const changeLanguageHandler = (lang) => { - i18n.changeLanguage(lang) + changeLanguage(lang) dispatch(showSideMenu(false)) } @@ -143,7 +156,10 @@ const SideMenu = () => { }
{t("Footer.darkMode")}: - dispatch(setThemeInitiate(e.target.checked))} checked={isDark}/> + dispatch(setThemeInitiate(e.target.checked ? "DARK" : "LIGHT", isLogin))} + checked={theme === "DARK"}/> +
{t("title")} {packageJson.version} diff --git a/src/components/TextInput/TextInput.js b/src/components/TextInput/TextInput.js index 8b84a22..a25bfd5 100644 --- a/src/components/TextInput/TextInput.js +++ b/src/components/TextInput/TextInput.js @@ -6,13 +6,13 @@ import DatePicker from "react-multi-date-picker"; import persian_fa from "react-date-object/locales/persian_fa"; import persian from "react-date-object/calendars/persian"; import {useSelector} from "react-redux"; -import i18n from "../../i18n/i18n"; +import i18n from "i18next"; import "react-multi-date-picker/styles/backgrounds/bg-dark.css" const TextInput = (props) => { const {customRef,readOnly,onchange,customClass,options, lead, ltr, after ,select ,alerts ,max, datePicker, ...other} = props - const isDark = useSelector((state) => state.global.isDark) + const theme = useSelector((state) => state.global.theme) const optionClassHandler = (state) => { let className = classes.selectOptions @@ -62,7 +62,7 @@ const TextInput = (props) => { if ( datePicker ){ inputSection = { - const dispatch = useDispatch(); const query = useQuery(); + const dispatch = useDispatch(); - const isDark = useSelector((state) => state.global.isDark) + const theme = useSelector((state) => state.global.theme) const isLoading = useSelector((state) => state.global.isLoading) const hasError = useSelector((state) => state.global.hasError) - const isLogin = useSelector((state) => state.auth.isLogin) + const title = useSelector((state) => state.exchange.title) + const description = useSelector((state) => state.exchange.description) - isDark ? document.body.classList.add('dark') : document.body.classList.remove('dark'); + theme === "DARK" ? document.body.classList.add('dark') : document.body.classList.remove('dark'); useEffect(() => { const impersonate = query.get("impersonate"); @@ -57,13 +58,19 @@ const Mobile = () => { }, []); - useInterval(() => { + /*useInterval(() => { dispatch(setUserAccountInfoInitiate()); }, isLogin ? 3000 : null) useInterval(() => { dispatch(setLastPriceInitiate()); - }, 3000) + }, 3000)*/ + + useEffect(() => { + const meta = document.getElementsByTagName('meta') + document.title = title ? title : " "; + meta.description.content = description ? description : " " + }, [title, description]) const Toast = () => { }, }} containerStyle={{}}/> - if (isLoading) { - return - } - if (hasError) { - return - } + if (isLoading) return + + if (hasError) return return (
}/> }/> - {/*}/>*/} - {/*}/>*/} - {/*}/>*/} }/> - - }> }/> }/> @@ -122,14 +121,10 @@ const Mobile = () => { }/> }/> - - - -
); }; diff --git a/src/main/Mobile/Pages/AllMarket/components/MarketStats/components/MostIncreasedPrice/MostIncreasedPrice.js b/src/main/Mobile/Pages/AllMarket/components/MarketStats/components/MostIncreasedPrice/MostIncreasedPrice.js index 1b7df0b..84783f2 100644 --- a/src/main/Mobile/Pages/AllMarket/components/MarketStats/components/MostIncreasedPrice/MostIncreasedPrice.js +++ b/src/main/Mobile/Pages/AllMarket/components/MarketStats/components/MostIncreasedPrice/MostIncreasedPrice.js @@ -6,8 +6,6 @@ import {useTranslation} from "react-i18next"; const MostIncreasedPrice = ({mostIncreasedPrice}) => { - console.log("mostIncreasedPrice" , mostIncreasedPrice) - const {t} = useTranslation(); return ( diff --git a/src/main/Mobile/Pages/Login/components/LoginForm/LoginForm.js b/src/main/Mobile/Pages/Login/components/LoginForm/LoginForm.js index 44808ce..e7d34e3 100644 --- a/src/main/Mobile/Pages/Login/components/LoginForm/LoginForm.js +++ b/src/main/Mobile/Pages/Login/components/LoginForm/LoginForm.js @@ -3,7 +3,12 @@ import React, {useEffect, useState} from "react"; import classes from "../../Login.module.css"; import TextInput from "../../../../../../components/TextInput/TextInput"; import LoginFormLoading from "../LoginLoading/LoginFormLoading"; -import {setUserAccountInfoInitiate, setUserInfo, setUserTokensInitiate} from "../../../../../../store/actions"; +import { + getUserConfigsInitiate, + setUserAccountInfoInitiate, + setUserInfo, + setUserTokensInitiate +} from "../../../../../../store/actions"; import {useLocation, useNavigate} from "react-router-dom"; import {useTranslation} from "react-i18next"; import Button from "../../../../../../components/Button/Button"; @@ -77,9 +82,12 @@ const LoginForm = () => { .then(async (res) => { const userToken = parseToken(res.data); const jwt = jwtDecode(userToken.accessToken) - await dispatch(setUserInfo(jwt)); - await dispatch(setUserTokensInitiate(userToken)); - await dispatch(setUserAccountInfoInitiate()) + /*dispatch(setUserAccountInfoInitiate())*/ + + dispatch(setUserInfo(jwt)); + dispatch(setUserTokensInitiate(userToken)); + dispatch(getUserConfigsInitiate()); + await getKycStatus() return navigate(from, {replace: true}); }) diff --git a/src/main/Mobile/Pages/Login/components/LoginLoading/LoginFormLoading.js b/src/main/Mobile/Pages/Login/components/LoginLoading/LoginFormLoading.js index 24e7569..6f851d6 100644 --- a/src/main/Mobile/Pages/Login/components/LoginLoading/LoginFormLoading.js +++ b/src/main/Mobile/Pages/Login/components/LoginLoading/LoginFormLoading.js @@ -4,10 +4,10 @@ import {useSelector} from "react-redux"; const LoginFormLoading = () => { - const isDark = useSelector((state) => state.global.isDark) + const theme = useSelector((state) => state.global.theme) return
- Loading + Loading
} diff --git a/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Market/components/TradingView/components/MarketChart/MarketChart.js b/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Market/components/TradingView/components/MarketChart/MarketChart.js index 42ebc0b..63ee7fe 100644 --- a/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Market/components/TradingView/components/MarketChart/MarketChart.js +++ b/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Market/components/TradingView/components/MarketChart/MarketChart.js @@ -16,7 +16,7 @@ const MarketChart = ({type}) => { let chartProperties, candleSeries, volumeSeries; const chart = useRef(); - const isDark = useSelector((state) => state.global.isDark) + const theme = useSelector((state) => state.global.theme) const activePairSymbol = useSelector((state) => state.exchange.activePair.symbol) const {data, error} = useGetChartCandlesticks(activePairSymbol, type) @@ -54,7 +54,7 @@ const MarketChart = ({type}) => { priceScale: lightTheme.priceScale, timeScale: {...lightTheme.timeScale, ...timeScale} }; - if (isDark) { + if (theme === "DARK") { chartProperties = { ...chartProperties, layout: { @@ -77,7 +77,7 @@ const MarketChart = ({type}) => { chartProperties, ); - candleSeries = chart.current.addCandlestickSeries(isDark ? darkTheme : candleColors); + candleSeries = chart.current.addCandlestickSeries(theme === "DARK" ? darkTheme : candleColors); volumeSeries = chart.current.addHistogramSeries({ priceFormat: { type: 'volume', @@ -134,7 +134,7 @@ const MarketChart = ({type}) => { }, []) useEffect(() => { - if (isDark) { + if (theme === "DARK") { chart.current.applyOptions({ ...chartProperties, layout: { @@ -155,7 +155,7 @@ const MarketChart = ({type}) => { timeScale: lightTheme.timeScale, }); } - }, [isDark]); + }, [theme]); return (
diff --git a/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Wallet/components/withdrawal/withdrawal.js b/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Wallet/components/withdrawal/withdrawal.js index 4d01cab..675815d 100644 --- a/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Wallet/components/withdrawal/withdrawal.js +++ b/src/main/Mobile/Pages/UserPanel/Secttions/Content/components/Wallet/components/withdrawal/withdrawal.js @@ -67,7 +67,6 @@ const Withdrawal = () => { if (navigator.clipboard !== undefined) { navigator.clipboard.readText() .then(text => { - //console.log('Pasted content: ', text); setAddress({...address, value: text}) toast.success(t('DepositWithdraw.paste')); }) diff --git a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/MarketSubMenu.js b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/MarketSubMenu.js index cbcdcae..25b7173 100644 --- a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/MarketSubMenu.js +++ b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/MarketSubMenu.js @@ -4,23 +4,28 @@ import {useTranslation} from "react-i18next"; import AccordionBox from "../../../../../../../../components/AccordionBox/AccordionBox"; import Icon from "../../../../../../../../components/Icon/Icon"; import MarketCard from "./components/MarketCard/MarketCard"; +import {useDispatch, useSelector} from "react-redux"; +import {setFavPairInitiate} from "../../../../../../../../store/actions"; const MarketSubMenu = () => { const {t} = useTranslation(); const [activeTab] = useState(JSON.parse(localStorage.getItem("activeMarketTab")) || 1); - const [fav, setFav] = useState(JSON.parse(localStorage.getItem("favPair")) || []); + const symbols = useSelector((state) => state.exchange.symbols) + const fav = useSelector((state) => state.auth.favoritePairs) + const dispatch = useDispatch(); - useEffect(() => { + + /*useEffect(() => { localStorage.setItem("favPair", JSON.stringify(fav)) - }, [fav]) + }, [fav])*/ const addToFav = (selected) => { if (fav.includes(selected)) { const newFav = fav.filter((item) => item !== selected); - setFav(newFav); + dispatch(setFavPairInitiate(newFav)) } else { - setFav((prev) => [...prev, selected]); + dispatch(setFavPairInitiate([...fav, selected])) } }; @@ -31,6 +36,7 @@ const MarketSubMenu = () => { fav.includes(p.symbol))} favPair={fav} addFav={(selected) => addToFav(selected)} /> @@ -42,6 +48,7 @@ const MarketSubMenu = () => { addToFav(selected)} /> @@ -55,6 +62,7 @@ const MarketSubMenu = () => { id="2" type="BTC" favPair={fav} + pairs={symbols.filter(p => (p.baseAsset === "BTC" || p.quoteAsset === "BTC"))} addFav={(selected) => addToFav(selected)} /> ), @@ -67,6 +75,7 @@ const MarketSubMenu = () => { id="4" type="USDT" favPair={fav} + pairs={symbols.filter(p => (p.baseAsset === "USDT" || p.quoteAsset === "USDT"))} addFav={(selected) => addToFav(selected)} /> ), diff --git a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js index 5ae06b8..672adca 100644 --- a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js +++ b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketCard/MarketCard.js @@ -4,20 +4,11 @@ import ScrollBar from "../../../../../../../../../../components/ScrollBar"; import MarketPairCard from "../MarketPairCard/MarketPairCard"; const MarketCard = ({type, ...props}) => { - let all = useSelector((state) => state.exchange.symbols) - - if (type === "fav") { - all = all.filter(p => props.favPair.includes(p.symbol)) - } - - if (type !== "all" && type !== "fav") { - all = all.filter(p => (p.baseAsset === type || p.quoteAsset === type)) - } return (
- {all.map((pair) => )} + {props.pairs.map((pair) => )}
); diff --git a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js index 3d62110..f6ffeed 100644 --- a/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js +++ b/src/main/Mobile/Pages/UserPanel/Secttions/SubMenu/components/MarketSubMenu/components/MarketPairCard/MarketPairCard.js @@ -6,24 +6,25 @@ import Icon from "../../../../../../../../../../components/Icon/Icon"; import {BN} from "../../../../../../../../../../utils/utils"; import {setActivePairInitiate} from "../../../../../../../../../../store/actions"; import {activeActionSheet} from "../../../../../../../../../../store/actions/global"; +import {useGetLastPrices} from "../../../../../../../../../../queries/hooks/useGetLastPrices"; const MarketPairCard = ({id, pair,favPair,addFav}) => { const activePair = useSelector((state) => state.exchange.activePair.symbol) - const price = useSelector((state) => state.exchange.lastPrice[pair.symbol]) + const {data: prices} = useGetLastPrices() const dispatch = useDispatch(); - - const onClickHandler = () => { - - dispatch(setActivePairInitiate(pair, id)) - dispatch(activeActionSheet({ - menu: false, - subMenu: false, - })) + const changeActivePair = () =>{ + if (activePair !== pair.symbol) { + dispatch(setActivePairInitiate(pair, id)) + dispatch(activeActionSheet({ + menu: false, + subMenu: false, + })) + } } - return (
{
- { new BN(price).toFormat()} + {new BN(prices[pair.symbol] || 0).toFormat()}
diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 6cc1275..69b605d 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -24,10 +24,8 @@ export const SET_BEST_BUY_PRICE = "SET_BEST_BUY_PRICE"; export const SET_BEST_SELL_PRICE = "SET_BEST_SELL_PRICE"; export const SET_LAST_TRADE_PRICE = "SET_LAST_TRADE_PRICE"; -export const SET_PANEL_TOKENS = "SET_PANEL_TOKENS"; -export const SET_PANEL_TOKENS_INITIATE = "SET_PANEL_TOKENS_INITIATE"; - export const SET_EXCHANGE = "SET_EXCHANGE"; +export const SET_EXCHANGE_CONFIG = "SET_EXCHANGE_CONFIG"; export const SET_LAST_PRICE = "SET_LAST_PRICE"; export const SET_LAST_PRICE_INITIATE = "SET_LAST_PRICE_INITIATE"; @@ -45,14 +43,22 @@ export const SET_KYC_STATUS = "SET_KYC_STATUS"; export const SET_KYC_STATUS_INITIATE = "SET_KYC_STATUS_INITIATE"; export const SET_LAST_TRANSACTION = "SET_LAST_TRANSACTION"; -export const LOGIN_INITIATE = "LOGIN_INITIATE"; export const LOGOUT = "LOGOUT"; export const LOGOUT_INITIATE = "LOGOUT_INITIATE"; +export const SET_MARKET_INTERVAL = "SET_MARKET_INTERVAL"; + +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" + export const SET_SHOW_SIDE_MENU = "SET_SHOW_SIDE_MENU"; export const ACTIVE_ORDER_LAYOUT = "ACTIVE_ORDER_LAYOUT"; export const ACTIVE_ACTION_SHEET = "ACTIVE_ACTION_SHEET"; -export const Set_MARKET_INTERVAL = "Set_MARKET_INTERVAL"; + diff --git a/src/store/actions/auth.js b/src/store/actions/auth.js index fc69fcc..3b22c48 100644 --- a/src/store/actions/auth.js +++ b/src/store/actions/auth.js @@ -79,3 +79,30 @@ export const setLogoutInitiate = () => { type: actionTypes.LOGOUT_INITIATE, }; }; + +export const setFavPairInitiate = (favoritePairs) => { + return { + type: actionTypes.SET_FAV_PAIR_INITIATE, + favoritePairs + }; +}; +export const setFavPair = (favoritePairs) => { + return { + type: actionTypes.SET_FAV_PAIR, + favoritePairs + }; +}; +export const setUserConfig = (configs) => { + return { + type: actionTypes.SET_USER_CONFIG, + configs + }; +}; + +export const getUserConfigsInitiate = (configs) => { + return { + type: actionTypes.GET_USER_CONFIGS_INITIATE, + configs + }; +}; + diff --git a/src/store/actions/exchange.js b/src/store/actions/exchange.js index 09eeeed..04e0f64 100644 --- a/src/store/actions/exchange.js +++ b/src/store/actions/exchange.js @@ -96,4 +96,11 @@ export const setLastPriceInitiate = () => { return { type: actionTypes.SET_LAST_PRICE_INITIATE, }; +}; + +export const setExchangeConfigs = configs => { + return { + type: actionTypes.SET_EXCHANGE_CONFIG, + configs: configs + }; }; \ No newline at end of file diff --git a/src/store/actions/global.js b/src/store/actions/global.js index 84f06b1..fee74ee 100644 --- a/src/store/actions/global.js +++ b/src/store/actions/global.js @@ -1,16 +1,17 @@ import * as actionTypes from "./actionTypes"; -export const setThemeInitiate = (isDark) => { +export const setThemeInitiate = (theme, isLogin) => { return { type: actionTypes.SET_THEME_INITIATE, - isDark, + isLogin, + theme, }; }; -export const setTheme = (isDark) => { +export const setTheme = (theme) => { return { type: actionTypes.SET_THEME, - isDark, + theme: theme.toUpperCase(), }; }; @@ -45,7 +46,7 @@ export const setInfoMessage = (messageType, message) => { export const setMarketInterval = (interval) => { return { - type: actionTypes.Set_MARKET_INTERVAL, + type: actionTypes.SET_MARKET_INTERVAL, interval, }; }; diff --git a/src/store/actions/index.js b/src/store/actions/index.js index a15a7b9..0acfe70 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -21,7 +21,8 @@ export { setIPG, setIPGInitiate, setVerifyEmailLock, - setVerifyEmailLockInitiate + setVerifyEmailLockInitiate, + setExchangeConfigs } from "./exchange"; @@ -35,7 +36,9 @@ export { setUserAccountInfo, setUserAccountInfoInitiate, setKYCStatus, - setKYCStatusInitiate -} from "./auth"; - - + setKYCStatusInitiate, + setUserConfig, + getUserConfigsInitiate, + setFavPair, + setFavPairInitiate +} from "./auth"; \ No newline at end of file diff --git a/src/store/reducers/authReducer.js b/src/store/reducers/authReducer.js index 25bc671..c867b35 100644 --- a/src/store/reducers/authReducer.js +++ b/src/store/reducers/authReducer.js @@ -17,6 +17,7 @@ const initialState = { lastTransaction: null, tradeFee: {}, isLogin: false, + favoritePairs: [] }; const reducer = (state = initialState, action) => { @@ -73,6 +74,16 @@ const reducer = (state = initialState, action) => { ...state, lastTransaction: action.time } + case actionTypes.SET_USER_CONFIG: + return { + ...state, + ...action.configs + } + case actionTypes.SET_FAV_PAIR: + return { + ...state, + favoritePairs: action.favoritePairs + } default: return state; } diff --git a/src/store/reducers/exchangeReducer.js b/src/store/reducers/exchangeReducer.js index de98e60..8a5923c 100644 --- a/src/store/reducers/exchangeReducer.js +++ b/src/store/reducers/exchangeReducer.js @@ -21,6 +21,15 @@ const initialState = { }, ipgLock: null, verifyEmailLock: null, + logoUrl: "", + title: "", + description: "", + defaultLanguage: "en", + supportedLanguages: [], + defaultTheme: "", + supportEmail: "", + baseCurrency: "", + dateType: "" }; const exchangeReducer = (state = initialState, action) => { @@ -93,6 +102,11 @@ const exchangeReducer = (state = initialState, action) => { ...state, ...action.exchangeInfo }; + case actionTypes.SET_EXCHANGE_CONFIG: + return { + ...state, + ...action.configs + }; default: return state; } diff --git a/src/store/reducers/globalReducer.js b/src/store/reducers/globalReducer.js index 10c38ea..94ff32d 100644 --- a/src/store/reducers/globalReducer.js +++ b/src/store/reducers/globalReducer.js @@ -1,7 +1,7 @@ import * as actionTypes from "../actions/actionTypes"; const initialState = { - isDark: window.env.REACT_APP_DEFAULT_THEME === 'DARK', + theme: "DARK", isLoading: true, hasError: false, marketInterval: "24h", @@ -22,7 +22,7 @@ const globalReducer = (state = initialState, action) => { case actionTypes.SET_THEME: return { ...state, - isDark: action.isDark, + theme: action.theme, }; case actionTypes.SET_INFO_MESSAGE: return { @@ -42,7 +42,7 @@ const globalReducer = (state = initialState, action) => { ...state, hasError: action.error, }; - case actionTypes.Set_MARKET_INTERVAL: + case actionTypes.SET_MARKET_INTERVAL: return { ...state, marketInterval: action.interval diff --git a/src/store/sagas/auth.js b/src/store/sagas/auth.js index 58a0e4b..a53925d 100644 --- a/src/store/sagas/auth.js +++ b/src/store/sagas/auth.js @@ -1,6 +1,7 @@ import {call, put} from "redux-saga/effects"; import * as actions from "../actions/index"; import axios from "axios"; +import i18n from "i18next"; export function* logout() { yield call([localStorage, 'removeItem'], "refreshToken") @@ -19,4 +20,32 @@ export function* getUserKYCStatus() { } catch (e) { console.log(e) } +} + +export function* getUserConfigs() { + try { + const { + data: { + theme: userTheme, + language, + ...userConfigs + } + } = yield call(axios.get, '/config/user/v1') + i18n.changeLanguage(language) + yield put(actions.setUserConfig(userConfigs)); + if (userTheme) yield put(actions.setTheme(userTheme)); + } catch (e) { + console.log(e) + } +} + +export function* setFavPair(action) { + try { + yield put(actions.setFavPair(action.favoritePairs)); + yield call(axios.post, '/config/user/v1', { + favoritePairs: action.favoritePairs + }) + } catch (e) { + console.log(e) + } } \ No newline at end of file diff --git a/src/store/sagas/global.js b/src/store/sagas/global.js index 12c967b..d798644 100644 --- a/src/store/sagas/global.js +++ b/src/store/sagas/global.js @@ -1,11 +1,21 @@ -import {call, put} from "redux-saga/effects"; +import {call, delay, put} from "redux-saga/effects"; import * as actions from "../actions/index"; import jwtDecode from "jwt-decode"; import axios from "axios"; +import i18n from "i18next"; export function* setThemeSaga(action) { - yield call([localStorage, 'setItem'], "isDark", action.isDark) - yield put(actions.setTheme(action.isDark)); + try { + yield put(actions.setTheme(action.theme)); + yield call([localStorage, 'setItem'], "theme", action.theme) + if (action.isLogin) { + yield call(axios.post, '/config/user/v1', { + theme: action.theme + }) + } + } catch (e) { + console.log(e) + } } export function* setActivePair(action) { @@ -37,11 +47,30 @@ export function* getExchangeLastPrice() { } } +function* getExchangeInfo() { + + for (let i = 0; i < 10; i++) { + try { + const {data: {symbols}} = yield call(axios.get, '/api/v3/exchangeInfo') + return symbols + } catch (err) { + if (i < 2) { + yield delay(1000) + continue + } + } + + throw new Error('getExchangeInfo failed!') + } +} + export function* loadConfig(action) { yield put(actions.setLoading(true)) yield put(actions.setError(false)) + let appTheme; + const pairs = []; const assets = []; const wallets = {}; @@ -49,7 +78,21 @@ export function* loadConfig(action) { const lastPrice = {}; try { - const {data: {symbols}} = yield call(axios.get, '/api/v3/exchangeInfo') + const { + data: { + defaultTheme, + ...configs + } + } = yield call(axios.get, '/config/web/v1') + + yield put(actions.setExchangeConfigs(configs)); + + appTheme = defaultTheme; + + const localTheme = yield call([localStorage, 'getItem'], 'theme') + if (localTheme) appTheme = localTheme; + + const symbols = yield call(getExchangeInfo) for (const symbol of symbols) { if (symbol.symbol.toUpperCase().includes("NLN")) continue if (!assets.includes(symbol.baseAsset)) { @@ -65,7 +108,7 @@ export function* loadConfig(action) { if (!pairs.includes(symbol.symbol)) pairs.push(symbol.symbol) symbol.baseRange = {min: 0.000001, max: 100000, step: 0.00001} symbol.quoteRange = {min: 0.000001, max: 100000, step: 0.00001} - symbol.name = symbol.baseAsset+"/"+symbol.quoteAsset + symbol.name = symbol.baseAsset + "/" + symbol.quoteAsset lastPrice[symbol.symbol] = 0 } yield put(actions.setExchange({pairs, assets, symbols, lastPrice})); @@ -80,11 +123,8 @@ export function* loadConfig(action) { return yield put(actions.setLoading(false)); } - const isDark = yield call([localStorage, 'getItem'], 'isDark') - if (isDark) yield put(actions.setTheme(JSON.parse(isDark))); - if (action.token) { - yield put(actions.setUserTokens({refreshToken : null, accessToken: action.token})); + yield put(actions.setUserTokens({refreshToken: null, accessToken: action.token})); yield call([localStorage, 'removeItem'], "refreshToken") const jwt = jwtDecode(action.token) yield put(actions.setUserInfo(jwt)); @@ -99,16 +139,24 @@ export function* loadConfig(action) { if (verifyEmailLockTime) yield put(actions.setVerifyEmailLock(verifyEmailLockTime)); const refreshToken = localStorage.getItem("refreshToken") - if (refreshToken) { const params = new URLSearchParams(); params.append('client_id', window.env.REACT_APP_CLIENT_ID); params.append('client_secret', window.env.REACT_APP_CLIENT_SECRET); params.append('grant_type', 'refresh_token'); params.append('refresh_token', refreshToken); - try { const {data: {access_token}} = yield call(axios.post, '/auth/realms/opex/protocol/openid-connect/token', params) + const { + data: { + theme: userTheme, + language, + ...userConfigs + } + } = yield call(axios.get, '/config/user/v1', {headers: {Authorization: `Bearer ${access_token}`}}) + i18n.changeLanguage(language) + yield put(actions.setUserConfig(userConfigs)); + if (userTheme) appTheme = userTheme const jwt = jwtDecode(access_token) yield call([localStorage, 'setItem'], "refreshToken", refreshToken) yield put(actions.setUserTokens({refreshToken, accessToken: access_token})); @@ -117,7 +165,8 @@ export function* loadConfig(action) { } catch (e) { yield put(actions.setLogoutInitiate()); } - } + } + yield put(actions.setTheme(appTheme)); yield put(actions.setLoading(false)); } diff --git a/src/store/sagas/index.js b/src/store/sagas/index.js index 193a678..8f8e702 100644 --- a/src/store/sagas/index.js +++ b/src/store/sagas/index.js @@ -3,7 +3,7 @@ import * as actionTypes from "../actions/actionTypes"; import {getExchangeLastPrice, loadConfig, setActivePair, setIPGLock, setThemeSaga, setVerifyEmailLock} from "./global"; -import {getUserKYCStatus, logout, setUserTokens} from "./auth"; +import {getUserConfigs, getUserKYCStatus, logout, setFavPair, setUserTokens} from "./auth"; export function* watchGlobal() { yield takeEvery(actionTypes.LOGOUT_INITIATE, logout); @@ -15,4 +15,6 @@ export function* watchGlobal() { yield takeEvery(actionTypes.SET_VERIFY_EMAIL_LOCK_INITIATE, setVerifyEmailLock); yield takeEvery(actionTypes.SET_KYC_STATUS_INITIATE, getUserKYCStatus); yield takeEvery(actionTypes.SET_LAST_PRICE_INITIATE, getExchangeLastPrice); + yield takeEvery(actionTypes.SET_FAV_PAIR_INITIATE, setFavPair); + yield takeEvery(actionTypes.GET_USER_CONFIGS_INITIATE, getUserConfigs); }