From 01cac0980cf5ea10b821014a7c4f28ba24a1f660 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 7 Jun 2024 12:30:52 +0800 Subject: [PATCH 1/6] feat: implement redirection to oauth login page [WIP] --- src/App.tsx | 21 +++++++++++++++++ src/components/AppHeader/AppHeader.tsx | 31 +++----------------------- src/constants/url.ts | 13 ++++++++++- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 557b074b..9020d926 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,14 @@ +/* eslint-disable no-console */ +import { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5'; import { AppFooter, AppHeader, DerivIframe } from '@/components'; +import { useAccountList, useAuthData } from '@deriv-com/api-hooks'; import { initializeI18n, TranslationProvider } from '@deriv-com/translations'; import { useDevice } from '@deriv-com/ui'; import AppContent from './routes/AppContent'; +import { getOauthUrl } from './constants'; const { VITE_CROWDIN_BRANCH_NAME, VITE_PROJECT_NAME, VITE_TRANSLATIONS_CDN_URL } = import.meta.env; const i18nInstance = initializeI18n({ @@ -13,6 +17,23 @@ const i18nInstance = initializeI18n({ const App = () => { const { isDesktop } = useDevice(); + const { data: accountList } = useAccountList(); + const { activeLoginid, isAuthorized } = useAuthData(); + + const oauthUrl = getOauthUrl(); + useEffect(() => { + const hasActiveLoginid = !!activeLoginid; + const hasAccounts = !!accountList?.length; + const shouldRedirectToLogin = !isAuthorized && !hasActiveLoginid && !hasAccounts; + console.log('isAuthorized', isAuthorized); + console.log('hasActiveLoginid', hasActiveLoginid); + console.log('hasAccounts', hasAccounts); + console.log('shouldRedirectToLogin', shouldRedirectToLogin); + console.log('===='); + // if (shouldRedirectToLogin) { + // window.open(oauthUrl, '_self'); + // } + }, [accountList, activeLoginid, isAuthorized, oauthUrl]); return ( diff --git a/src/components/AppHeader/AppHeader.tsx b/src/components/AppHeader/AppHeader.tsx index 8e643571..dc4feb5c 100644 --- a/src/components/AppHeader/AppHeader.tsx +++ b/src/components/AppHeader/AppHeader.tsx @@ -1,9 +1,8 @@ -import { useEffect } from 'react'; +import { getOauthUrl } from '@/constants'; import { StandaloneCircleUserRegularIcon } from '@deriv/quill-icons'; -import { useAccountList, useAuthData } from '@deriv-com/api-hooks'; +import { useAuthData } from '@deriv-com/api-hooks'; import { useTranslations } from '@deriv-com/translations'; import { Button, Header, Text, TooltipMenuIcon, useDevice, Wrapper } from '@deriv-com/ui'; -import { LocalStorageConstants, LocalStorageUtils, URLUtils } from '@deriv-com/utils'; import { AccountSwitcher } from './AccountSwitcher'; import { AppLogo } from './AppLogo'; import { MenuItems } from './MenuItems'; @@ -14,34 +13,10 @@ import './AppHeader.scss'; // TODO: handle local storage values not updating after changing local storage values const AppHeader = () => { - const { data: accounts } = useAccountList(); const { isDesktop } = useDevice(); const { activeLoginid, logout } = useAuthData(); const { localize } = useTranslations(); - const appId = LocalStorageUtils.getValue(LocalStorageConstants.configAppId); - const serverUrl = localStorage.getItem(LocalStorageConstants.configServerURL.toString()); - const oauthUrl = - appId && serverUrl - ? `https://${serverUrl}/oauth2/authorize?app_id=${appId}&l=EN&&brand=deriv` - : URLUtils.getOauthURL(); - - useEffect(() => { - const shouldRedirectToLogin = () => { - if (typeof accounts !== 'undefined') { - const userHasNoP2PAccount = !accounts.find( - account => account.broker === 'CR' && account.currency === 'USD' - ); - const activeAccount = accounts.find(account => account.loginid === activeLoginid); - const activeAccountCurrency = activeAccount?.currency || null; - - if (userHasNoP2PAccount || activeAccountCurrency !== 'USD') { - window.open(oauthUrl, '_self'); - } - } - }; - - shouldRedirectToLogin(); - }, [accounts, activeLoginid, oauthUrl]); + const oauthUrl = getOauthUrl(); return (
diff --git a/src/constants/url.ts b/src/constants/url.ts index e0f58557..f50ce1a2 100644 --- a/src/constants/url.ts +++ b/src/constants/url.ts @@ -1,4 +1,4 @@ -import { URLConstants } from '@deriv-com/utils'; +import { LocalStorageConstants, LocalStorageUtils, URLConstants, URLUtils } from '@deriv-com/utils'; export const BUY_SELL_URL = '/buy-sell'; export const ORDERS_URL = '/orders'; @@ -12,3 +12,14 @@ export const ACCOUNT_LIMITS = `${URLConstants.derivAppProduction}/account/accoun export const DERIV_COM = URLConstants.derivComProduction; export const HELP_CENTRE = `${URLConstants.derivComProduction}/help-centre/`; export const RESPONSIBLE = `${URLConstants.derivComProduction}/responsible/`; + +export const getOauthUrl = () => { + const appId = LocalStorageUtils.getValue(LocalStorageConstants.configAppId); + const serverUrl = localStorage.getItem(LocalStorageConstants.configServerURL.toString()); + const oauthUrl = + appId && serverUrl + ? `https://${serverUrl}/oauth2/authorize?app_id=${appId}&l=EN&&brand=deriv` + : URLUtils.getOauthURL(); + + return oauthUrl; +}; From bb72de2020233ce0871488ba85383ba524791cce Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Mon, 10 Jun 2024 16:42:38 +0800 Subject: [PATCH 2/6] feat: implement user redirection to oauth page --- package-lock.json | 27 +++++++++++---------------- package.json | 2 +- src/App.tsx | 27 ++++++++++----------------- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index e66f9f92..64c58cd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@babel/preset-env": "^7.24.5", - "@deriv-com/api-hooks": "^0.1.24", + "@deriv-com/api-hooks": "^1.0.10", "@deriv-com/translations": "^1.2.4", "@deriv-com/ui": "^1.27.9", "@deriv-com/utils": "latest", @@ -2604,26 +2604,21 @@ } }, "node_modules/@deriv-com/api-hooks": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/@deriv-com/api-hooks/-/api-hooks-0.1.24.tgz", - "integrity": "sha512-SiZsyZlnfXWlioa7MSiZgu8N4wTEpiKzYpKhuKvQS86Ek/dyjw43iviqJkXD3n/AZX2FZA40lCwE363tURMGVg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@deriv-com/api-hooks/-/api-hooks-1.0.10.tgz", + "integrity": "sha512-sCa/rzSToCPo0kuBtZz7AeL5Mzm69eONSoH5seJ1PE/d/A7XGBRNaJK/+Y4eoYKVZuW9I1bM5ZKmHSQsHY7+CQ==", "dependencies": { - "@deriv-com/utils": "^0.0.22", - "@deriv/api-types": "^1.0.560", + "@deriv-com/utils": "^0.0.24", + "@deriv/api-types": "^1.0.667", "@deriv/deriv-api": "^1.0.15", - "@tanstack/react-query": "^5.37.1", + "@tanstack/react-query": "^5.40.0", "@types/js-cookie": "^3.0.6", "js-cookie": "^3.0.5" }, "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "^4.17.2" + "@rollup/rollup-linux-x64-gnu": "^4.18.0" } }, - "node_modules/@deriv-com/api-hooks/node_modules/@deriv-com/utils": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/@deriv-com/utils/-/utils-0.0.22.tgz", - "integrity": "sha512-9eVZTPEwfNPXhHsq0qHAGxQW0/ZwzP7gca3CfjPgI9rNvFNVcduxi9wJ3HXl3FKrT8rSpO0X8rHjJKxdOjmjog==" - }, "node_modules/@deriv-com/eslint-config-deriv": { "version": "2.1.0-beta.3", "resolved": "https://registry.npmjs.org/@deriv-com/eslint-config-deriv/-/eslint-config-deriv-2.1.0-beta.3.tgz", @@ -2692,9 +2687,9 @@ "integrity": "sha512-dK9H6GfI/DB7eRTjZS3+K9cEg3gZlCJV+zmDL27OpRHSyddrw2Z//PuMq3WZxtXTGuHt3g7TLDUP7PdvXL8DdA==" }, "node_modules/@deriv/api-types": { - "version": "1.0.659", - "resolved": "https://registry.npmjs.org/@deriv/api-types/-/api-types-1.0.659.tgz", - "integrity": "sha512-8TsTvYftDXBmzWD6SVyEi8N3DudSlB2rewilUefMn8gErsVAahTkq8xgCU6iRtbLvmKOpEj2St5otIftZ3uczw==" + "version": "1.0.801", + "resolved": "https://registry.npmjs.org/@deriv/api-types/-/api-types-1.0.801.tgz", + "integrity": "sha512-w5oNwBRTpnz0j4jYUbqyu7QgrNcW0l8hi2uWda2rNX5fDgnhDU+eWJmsyhqDMNqlWG41FiH2Ed4VBereF7YuEw==" }, "node_modules/@deriv/deriv-api": { "version": "1.0.15", diff --git a/package.json b/package.json index f18cf7e6..33c266c3 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@babel/preset-env": "^7.24.5", - "@deriv-com/api-hooks": "^0.1.24", + "@deriv-com/api-hooks": "^1.0.10", "@deriv-com/translations": "^1.2.4", "@deriv-com/ui": "^1.27.9", "@deriv-com/utils": "latest", diff --git a/src/App.tsx b/src/App.tsx index 9020d926..8292b55b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,11 +4,12 @@ import { BrowserRouter } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5'; import { AppFooter, AppHeader, DerivIframe } from '@/components'; -import { useAccountList, useAuthData } from '@deriv-com/api-hooks'; +import { getOauthUrl } from '@/constants'; +import AppContent from '@/routes/AppContent'; +import { getCurrentRoute } from '@/utils'; +import { useAuthData } from '@deriv-com/api-hooks'; import { initializeI18n, TranslationProvider } from '@deriv-com/translations'; import { useDevice } from '@deriv-com/ui'; -import AppContent from './routes/AppContent'; -import { getOauthUrl } from './constants'; const { VITE_CROWDIN_BRANCH_NAME, VITE_PROJECT_NAME, VITE_TRANSLATIONS_CDN_URL } = import.meta.env; const i18nInstance = initializeI18n({ @@ -17,23 +18,15 @@ const i18nInstance = initializeI18n({ const App = () => { const { isDesktop } = useDevice(); - const { data: accountList } = useAccountList(); - const { activeLoginid, isAuthorized } = useAuthData(); + const { isAuthorized, isAuthorizing } = useAuthData(); + const isEndpointPage = getCurrentRoute() === 'endpoint'; const oauthUrl = getOauthUrl(); useEffect(() => { - const hasActiveLoginid = !!activeLoginid; - const hasAccounts = !!accountList?.length; - const shouldRedirectToLogin = !isAuthorized && !hasActiveLoginid && !hasAccounts; - console.log('isAuthorized', isAuthorized); - console.log('hasActiveLoginid', hasActiveLoginid); - console.log('hasAccounts', hasAccounts); - console.log('shouldRedirectToLogin', shouldRedirectToLogin); - console.log('===='); - // if (shouldRedirectToLogin) { - // window.open(oauthUrl, '_self'); - // } - }, [accountList, activeLoginid, isAuthorized, oauthUrl]); + if (!isEndpointPage && !isAuthorized && !isAuthorizing) { + window.open(oauthUrl, '_self'); + } + }, [isAuthorized, isAuthorizing, isEndpointPage, oauthUrl]); return ( From 500f2103e049299744bb609672d74084e415808f Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Mon, 10 Jun 2024 17:08:11 +0800 Subject: [PATCH 3/6] chore: moved the redirection logic to a hook --- src/App.tsx | 16 +++--------- src/components/AppHeader/HeaderConfig.tsx | 8 +++--- src/hooks/custom-hooks/index.ts | 1 + src/hooks/custom-hooks/useRedirectToOauth.ts | 27 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 src/hooks/custom-hooks/useRedirectToOauth.ts diff --git a/src/App.tsx b/src/App.tsx index 8292b55b..6672603f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,9 @@ -/* eslint-disable no-console */ -import { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5'; import { AppFooter, AppHeader, DerivIframe } from '@/components'; -import { getOauthUrl } from '@/constants'; +import { useRedirectToOauth } from '@/hooks'; import AppContent from '@/routes/AppContent'; -import { getCurrentRoute } from '@/utils'; -import { useAuthData } from '@deriv-com/api-hooks'; import { initializeI18n, TranslationProvider } from '@deriv-com/translations'; import { useDevice } from '@deriv-com/ui'; @@ -18,15 +14,9 @@ const i18nInstance = initializeI18n({ const App = () => { const { isDesktop } = useDevice(); - const { isAuthorized, isAuthorizing } = useAuthData(); - const isEndpointPage = getCurrentRoute() === 'endpoint'; + const { redirectToOauth } = useRedirectToOauth(); - const oauthUrl = getOauthUrl(); - useEffect(() => { - if (!isEndpointPage && !isAuthorized && !isAuthorizing) { - window.open(oauthUrl, '_self'); - } - }, [isAuthorized, isAuthorizing, isEndpointPage, oauthUrl]); + redirectToOauth(); return ( diff --git a/src/components/AppHeader/HeaderConfig.tsx b/src/components/AppHeader/HeaderConfig.tsx index 43dc9041..342d6428 100644 --- a/src/components/AppHeader/HeaderConfig.tsx +++ b/src/components/AppHeader/HeaderConfig.tsx @@ -81,14 +81,14 @@ export const MenuItems: MenuItemsConfig[] = [ label: "Trader's Hub", }, { - as: 'button', - href: 'https://app.deriv.com/appstore/traders-hub', + as: 'a', + href: 'https://app.deriv.com/appstore/reports', icon: , label: 'Reports', }, { - as: 'button', - href: 'https://app.deriv.com/appstore/traders-hub', + as: 'a', + href: 'https://app.deriv.com/appstore/cashier', icon: , label: 'Cashier', }, diff --git a/src/hooks/custom-hooks/index.ts b/src/hooks/custom-hooks/index.ts index ce72bec8..49adab7e 100644 --- a/src/hooks/custom-hooks/index.ts +++ b/src/hooks/custom-hooks/index.ts @@ -12,5 +12,6 @@ export { default as useNavigatorOnline } from './useNavigatorOnline'; export { default as useNetworkStatus } from './useNetworkStatus'; export { default as usePoiPoaStatus } from './usePoiPoaStatus'; export { default as useQueryString } from './useQueryString'; +export { default as useRedirectToOauth } from './useRedirectToOauth'; export { default as useSendbird } from './useSendbird'; export { default as useSyncedTime } from './useSyncedTime'; diff --git a/src/hooks/custom-hooks/useRedirectToOauth.ts b/src/hooks/custom-hooks/useRedirectToOauth.ts new file mode 100644 index 00000000..8584a5e9 --- /dev/null +++ b/src/hooks/custom-hooks/useRedirectToOauth.ts @@ -0,0 +1,27 @@ +import { useCallback, useEffect, useState } from 'react'; +import { getOauthUrl } from '@/constants'; +import { getCurrentRoute } from '@/utils'; +import { useAuthData } from '@deriv-com/api-hooks'; + +const useRedirectToOauth = () => { + const [shouldRedirect, setShouldRedirect] = useState(false); + const { isAuthorized, isAuthorizing } = useAuthData(); + const isEndpointPage = getCurrentRoute() === 'endpoint'; + + const oauthUrl = getOauthUrl(); + const redirectToOauth = useCallback(() => { + shouldRedirect && window.open(oauthUrl, '_self'); + }, [oauthUrl, shouldRedirect]); + + useEffect(() => { + if (!isEndpointPage && !isAuthorized && !isAuthorizing) { + setShouldRedirect(true); + } + }, [isAuthorized, isAuthorizing, isEndpointPage, oauthUrl]); + + return { + redirectToOauth, + }; +}; + +export default useRedirectToOauth; From fe7d7d08a6109980778403dc71d6f66ddac66001 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Tue, 11 Jun 2024 15:10:40 +0800 Subject: [PATCH 4/6] ci: updated api-hooks version --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64c58cd9..4d4c49e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@babel/preset-env": "^7.24.5", - "@deriv-com/api-hooks": "^1.0.10", + "@deriv-com/api-hooks": "^1.1.1", "@deriv-com/translations": "^1.2.4", "@deriv-com/ui": "^1.27.9", "@deriv-com/utils": "latest", @@ -2604,9 +2604,9 @@ } }, "node_modules/@deriv-com/api-hooks": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@deriv-com/api-hooks/-/api-hooks-1.0.10.tgz", - "integrity": "sha512-sCa/rzSToCPo0kuBtZz7AeL5Mzm69eONSoH5seJ1PE/d/A7XGBRNaJK/+Y4eoYKVZuW9I1bM5ZKmHSQsHY7+CQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@deriv-com/api-hooks/-/api-hooks-1.1.1.tgz", + "integrity": "sha512-lM/XrjCLXF6NMuzGz5Tza1OhfuvP5/NxZ8ofykVG0wySNF4klYvTiSOvk+kJv+MLT8FY48JhdH1HMbdPKREtvA==", "dependencies": { "@deriv-com/utils": "^0.0.24", "@deriv/api-types": "^1.0.667", diff --git a/package.json b/package.json index 33c266c3..5d8d0988 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@babel/preset-env": "^7.24.5", - "@deriv-com/api-hooks": "^1.0.10", + "@deriv-com/api-hooks": "^1.1.1", "@deriv-com/translations": "^1.2.4", "@deriv-com/ui": "^1.27.9", "@deriv-com/utils": "latest", From d14eee25852e07b6fa19ad1a0163ef805276d780 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Tue, 11 Jun 2024 15:28:03 +0800 Subject: [PATCH 5/6] ci: fixed build errors --- src/hooks/custom-hooks/useIsAdvertiser.ts | 2 +- src/pages/orders/screens/OrderDetails/OrderDetails.tsx | 2 +- .../AdvertiserInfoStateProvider.tsx | 3 +-- src/routes/AppContent/index.tsx | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hooks/custom-hooks/useIsAdvertiser.ts b/src/hooks/custom-hooks/useIsAdvertiser.ts index cfd49ef8..876d8238 100644 --- a/src/hooks/custom-hooks/useIsAdvertiser.ts +++ b/src/hooks/custom-hooks/useIsAdvertiser.ts @@ -12,7 +12,7 @@ const useIsAdvertiser = (): boolean => { const [isAdvertiser, setIsAdvertiser] = useState(!error && !isEmptyObject(data)); useEffect(() => { - if (error && error?.error.code === ERROR_CODES.ADVERTISER_NOT_FOUND) { + if (error && error?.code === ERROR_CODES.ADVERTISER_NOT_FOUND) { setIsAdvertiser(false); } else if (!error && !isEmptyObject(data)) { setIsAdvertiser(true); diff --git a/src/pages/orders/screens/OrderDetails/OrderDetails.tsx b/src/pages/orders/screens/OrderDetails/OrderDetails.tsx index ce2805fa..0d27edf2 100644 --- a/src/pages/orders/screens/OrderDetails/OrderDetails.tsx +++ b/src/pages/orders/screens/OrderDetails/OrderDetails.tsx @@ -80,7 +80,7 @@ const OrderDetails = () => { if (isLoading || (!orderInfo && !error)) return ; // TODO: replace with proper error screen once design is ready - if (error) return {error?.error?.message}; + if (error) return {error?.message}; if (isMobile) { return ( diff --git a/src/providers/AdvertiserInfoStateProvider/AdvertiserInfoStateProvider.tsx b/src/providers/AdvertiserInfoStateProvider/AdvertiserInfoStateProvider.tsx index d11efbc9..c26beb45 100644 --- a/src/providers/AdvertiserInfoStateProvider/AdvertiserInfoStateProvider.tsx +++ b/src/providers/AdvertiserInfoStateProvider/AdvertiserInfoStateProvider.tsx @@ -1,8 +1,7 @@ import { createContext, PropsWithChildren, useContext } from 'react'; -import { TSocketError } from 'types'; type TContextValue = { - error: TSocketError<'p2p_advertiser_info'> | undefined; + error: { code: string; message: string } | undefined; isIdle: boolean; isLoading: boolean; isSubscribed: boolean; diff --git a/src/routes/AppContent/index.tsx b/src/routes/AppContent/index.tsx index d98b4c34..ac0d1fb8 100644 --- a/src/routes/AppContent/index.tsx +++ b/src/routes/AppContent/index.tsx @@ -51,7 +51,6 @@ const AppContent = () => { useEffect(() => { if (hasCreatedAdvertiser) { // Need to pass params to subscribeAdvertiserInfo to trigger the subscription. - // @ts-expect-error - passthrough is not a valid parameter subscribeAdvertiserInfo({ passthrough: { createdNickname: 'nickname' } }); } }, [hasCreatedAdvertiser, subscribeAdvertiserInfo]); From 9cfa01f6959e568ec9a5fda7446aac010286eb28 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Tue, 11 Jun 2024 15:43:02 +0800 Subject: [PATCH 6/6] ci: fixed test failing issue --- .../orders/screens/OrderDetails/__tests__/OrderDetails.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/orders/screens/OrderDetails/__tests__/OrderDetails.spec.tsx b/src/pages/orders/screens/OrderDetails/__tests__/OrderDetails.spec.tsx index 3d7f398d..587752e4 100644 --- a/src/pages/orders/screens/OrderDetails/__tests__/OrderDetails.spec.tsx +++ b/src/pages/orders/screens/OrderDetails/__tests__/OrderDetails.spec.tsx @@ -225,7 +225,7 @@ describe('', () => { (mockUseGet as jest.Mock).mockReturnValue({ ...mockUseGet(), data: {}, - error: { error: { message: 'error message' } }, + error: { code: 'code', message: 'error message' }, isLoading: false, });