From abf510eb8a4d3dda9ae3db4bd7ac979fbed216d1 Mon Sep 17 00:00:00 2001 From: simeng-li Date: Thu, 9 Jun 2022 10:27:53 +0800 Subject: [PATCH] refactor(ui): refactor ui loading (#1067) * refactor(ui): refactor ui loading refactor ui loading * refactor(ui): refactor use-social-landing refactor use-social-landing * fix(ui): remove useless style remove useless style * fix(ui): fix typo fix typo --- packages/phrases/src/locales/en.ts | 2 -- packages/phrases/src/locales/zh-cn.ts | 2 -- packages/ui/src/App.tsx | 30 +++++++++------- .../src/assets/icons/loading-icon-light.svg | 14 ++++++++ packages/ui/src/assets/icons/loading-icon.svg | 27 +++++++------- .../ui/src/components/AppContent/index.tsx | 6 +--- .../components/LoadingLayer/LoadingIcon.tsx | 16 +++++++++ .../LoadingLayer/LoadingIconLight.tsx | 16 +++++++++ .../components/LoadingLayer/index.module.scss | 2 +- .../ui/src/components/LoadingLayer/index.tsx | 8 +++-- .../containers/LoadingLayerProvider/index.tsx | 20 +++++++++++ .../SocialLanding/index.module.scss | 18 ++++------ .../ui/src/containers/SocialLanding/index.tsx | 10 +++--- .../src/hooks/use-social-callback-handler.ts | 7 ++-- .../src/hooks/use-social-landing-handler.ts | 35 +++++++++++-------- .../ui/src/pages/Callback/index.module.scss | 5 --- packages/ui/src/pages/Callback/index.tsx | 19 +++------- .../ui/src/pages/Consent/index.module.scss | 6 +--- packages/ui/src/pages/Consent/index.tsx | 16 +++++---- packages/ui/src/pages/SocialLanding/index.tsx | 15 +++++--- 20 files changed, 167 insertions(+), 107 deletions(-) create mode 100644 packages/ui/src/assets/icons/loading-icon-light.svg create mode 100644 packages/ui/src/components/LoadingLayer/LoadingIcon.tsx create mode 100644 packages/ui/src/components/LoadingLayer/LoadingIconLight.tsx create mode 100644 packages/ui/src/containers/LoadingLayerProvider/index.tsx diff --git a/packages/phrases/src/locales/en.ts b/packages/phrases/src/locales/en.ts index 61d910cc1..d9eb5f929 100644 --- a/packages/phrases/src/locales/en.ts +++ b/packages/phrases/src/locales/en.ts @@ -52,8 +52,6 @@ const translation = { phone_number: 'phone number', reminder: 'Reminder', not_found: '404 Not Found', - loading: 'Loading...', - redirecting: 'Redirecting...', agree_with_terms: 'I have read and agree to the ', agree_with_terms_modal: 'Please read the {{terms}} and then agree the box first.', terms_of_use: 'Terms of Use', diff --git a/packages/phrases/src/locales/zh-cn.ts b/packages/phrases/src/locales/zh-cn.ts index 96e9b019f..7733b917d 100644 --- a/packages/phrases/src/locales/zh-cn.ts +++ b/packages/phrases/src/locales/zh-cn.ts @@ -54,8 +54,6 @@ const translation = { phone_number: '手机', reminder: '提示', not_found: '404 页面不存在', - loading: '读取中...', - redirecting: '页面跳转中...', agree_with_terms: '我已阅读并同意 ', agree_with_terms_modal: 'Please read the {{terms}} and then agree the box first.', terms_of_use: '使用条款', diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 7814982f8..dd0c71a62 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -4,6 +4,7 @@ import { Route, Routes, BrowserRouter, Navigate } from 'react-router-dom'; import * as styles from './App.module.scss'; import AppContent from './components/AppContent'; +import LoadingLayerProvider from './containers/LoadingLayerProvider'; import usePageContext from './hooks/use-page-context'; import usePreview from './hooks/use-preview'; import initI18n from './i18n/init'; @@ -52,25 +53,28 @@ const App = () => { - {/* always keep route path with param as the last one */} } /> - } /> } /> - } /> - } /> - } /> - - {/* social sign-in pages */} - } /> - } /> - } /> - } /> - - } /> } /> + + }> + {/* always keep route path with param as the last one */} + } /> + } /> + } /> + } /> + + {/* social sign-in pages */} + } /> + } /> + } /> + } /> + } /> + + } /> diff --git a/packages/ui/src/assets/icons/loading-icon-light.svg b/packages/ui/src/assets/icons/loading-icon-light.svg new file mode 100644 index 000000000..ac7418abe --- /dev/null +++ b/packages/ui/src/assets/icons/loading-icon-light.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/packages/ui/src/assets/icons/loading-icon.svg b/packages/ui/src/assets/icons/loading-icon.svg index a3d47ef40..f9989c748 100644 --- a/packages/ui/src/assets/icons/loading-icon.svg +++ b/packages/ui/src/assets/icons/loading-icon.svg @@ -1,14 +1,15 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/packages/ui/src/components/AppContent/index.tsx b/packages/ui/src/components/AppContent/index.tsx index f60ef281a..e5784f99b 100644 --- a/packages/ui/src/components/AppContent/index.tsx +++ b/packages/ui/src/components/AppContent/index.tsx @@ -1,8 +1,6 @@ import { conditionalString } from '@silverhand/essentials'; import React, { ReactNode, useEffect, useCallback, useContext } from 'react'; -import { useDebouncedLoader } from 'use-debounced-loader'; -import LoadingLayer from '@/components/LoadingLayer'; import Toast from '@/components/Toast'; import useColorTheme from '@/hooks/use-color-theme'; import { PageContext } from '@/hooks/use-page-context'; @@ -16,8 +14,7 @@ export type Props = { const AppContent = ({ children }: Props) => { const theme = useTheme(); - const { toast, loading, platform, setToast, experienceSettings } = useContext(PageContext); - const debouncedLoading = useDebouncedLoader(loading); + const { toast, platform, setToast, experienceSettings } = useContext(PageContext); // Prevent internal eventListener rebind const hideToast = useCallback(() => { @@ -48,7 +45,6 @@ const AppContent = ({ children }: Props) => {
{children}
{platform === 'web' &&
} - {debouncedLoading && }
); }; diff --git a/packages/ui/src/components/LoadingLayer/LoadingIcon.tsx b/packages/ui/src/components/LoadingLayer/LoadingIcon.tsx new file mode 100644 index 000000000..49c1c7ddf --- /dev/null +++ b/packages/ui/src/components/LoadingLayer/LoadingIcon.tsx @@ -0,0 +1,16 @@ +import classNames from 'classnames'; +import React from 'react'; + +import LoadingSvg from '@/assets/icons/loading-icon.svg'; + +import * as styles from './index.module.scss'; + +type Props = { + className?: string; +}; + +const LoadingIcon = ({ className }: Props) => ( + +); + +export default LoadingIcon; diff --git a/packages/ui/src/components/LoadingLayer/LoadingIconLight.tsx b/packages/ui/src/components/LoadingLayer/LoadingIconLight.tsx new file mode 100644 index 000000000..c634a4279 --- /dev/null +++ b/packages/ui/src/components/LoadingLayer/LoadingIconLight.tsx @@ -0,0 +1,16 @@ +import classNames from 'classnames'; +import React from 'react'; + +import LoadingSvg from '@/assets/icons/loading-icon-light.svg'; + +import * as styles from './index.module.scss'; + +type Props = { + className?: string; +}; + +const LoadingIconLight = ({ className }: Props) => ( + +); + +export default LoadingIconLight; diff --git a/packages/ui/src/components/LoadingLayer/index.module.scss b/packages/ui/src/components/LoadingLayer/index.module.scss index fda3dcf2c..4ed907ca3 100644 --- a/packages/ui/src/components/LoadingLayer/index.module.scss +++ b/packages/ui/src/components/LoadingLayer/index.module.scss @@ -20,7 +20,7 @@ } .loadingIcon { - animation: rotating 1s linear infinite; + animation: rotating 1s steps(12, end) infinite; } @keyframes rotating { diff --git a/packages/ui/src/components/LoadingLayer/index.tsx b/packages/ui/src/components/LoadingLayer/index.tsx index e2071e039..c4ec77502 100644 --- a/packages/ui/src/components/LoadingLayer/index.tsx +++ b/packages/ui/src/components/LoadingLayer/index.tsx @@ -1,13 +1,15 @@ import React from 'react'; -import LoadingIcon from '@/assets/icons/loading-icon.svg'; - +import LoadingIcon from './LoadingIcon'; import * as styles from './index.module.scss'; +export { default as LoadingIcon } from './LoadingIcon'; +export { default as LoadingIconLight } from './LoadingIconLight'; + const LoadingLayer = () => (
- +
); diff --git a/packages/ui/src/containers/LoadingLayerProvider/index.tsx b/packages/ui/src/containers/LoadingLayerProvider/index.tsx new file mode 100644 index 000000000..a5f21a86a --- /dev/null +++ b/packages/ui/src/containers/LoadingLayerProvider/index.tsx @@ -0,0 +1,20 @@ +import React, { useContext } from 'react'; +import { Outlet } from 'react-router-dom'; +import { useDebouncedLoader } from 'use-debounced-loader'; + +import LoadingLayer from '@/components/LoadingLayer'; +import { PageContext } from '@/hooks/use-page-context'; + +const LoadingLayerProvider = () => { + const { loading } = useContext(PageContext); + const debouncedLoading = useDebouncedLoader(loading); + + return ( + <> + + {debouncedLoading && } + + ); +}; + +export default LoadingLayerProvider; diff --git a/packages/ui/src/containers/SocialLanding/index.module.scss b/packages/ui/src/containers/SocialLanding/index.module.scss index 08b9e6215..38813f41e 100644 --- a/packages/ui/src/containers/SocialLanding/index.module.scss +++ b/packages/ui/src/containers/SocialLanding/index.module.scss @@ -1,22 +1,16 @@ @use '@/scss/underscore' as _; -.connector > img { - width: 96px; - height: 96px; - @include _.image-align-center; -} - -.message { - margin-top: _.unit(2); -} .container { @include _.flex-column; } +.connector { + margin-bottom: _.unit(4); -:global(body.desktop) { - .message { - margin-top: _.unit(1); + > img { + width: 96px; + height: 96px; + @include _.image-align-center; } } diff --git a/packages/ui/src/containers/SocialLanding/index.tsx b/packages/ui/src/containers/SocialLanding/index.tsx index b4b8ef6a4..c20fd47f4 100644 --- a/packages/ui/src/containers/SocialLanding/index.tsx +++ b/packages/ui/src/containers/SocialLanding/index.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import React, { useContext } from 'react'; +import { LoadingIcon, LoadingIconLight } from '@/components/LoadingLayer'; import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; @@ -8,19 +9,20 @@ import * as styles from './index.module.scss'; type Props = { className?: string; connectorId: string; - message?: string; + isLoading?: boolean; }; -const SocialLanding = ({ className, connectorId, message }: Props) => { - const { experienceSettings } = useContext(PageContext); +const SocialLanding = ({ className, connectorId, isLoading = false }: Props) => { + const { experienceSettings, theme } = useContext(PageContext); const connector = experienceSettings?.socialConnectors.find(({ id }) => id === connectorId); + const Loading = theme === 'light' ? LoadingIconLight : LoadingIcon; return (
{connector?.logo ? : connectorId}
-
{message}
+ {isLoading && }
); }; diff --git a/packages/ui/src/hooks/use-social-callback-handler.ts b/packages/ui/src/hooks/use-social-callback-handler.ts index f916cccdc..9bf2bc81b 100644 --- a/packages/ui/src/hooks/use-social-callback-handler.ts +++ b/packages/ui/src/hooks/use-social-callback-handler.ts @@ -1,4 +1,4 @@ -import { useCallback, useContext } from 'react'; +import { useCallback, useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -8,6 +8,7 @@ import { getCallbackLinkFromStorage } from '@/utils/social-connectors'; import { PageContext } from './use-page-context'; const useSocialCallbackHandler = () => { + const [loading, setLoading] = useState(true); const { setToast } = useContext(PageContext); const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); const navigate = useNavigate(); @@ -20,6 +21,7 @@ const useSocialCallbackHandler = () => { // Connector auth error if (error) { + setLoading(false); setToast(`${error}${error_description ? `: ${error_description}` : ''}`); return; @@ -27,6 +29,7 @@ const useSocialCallbackHandler = () => { // Connector auth missing state if (!state || !connectorId) { + setLoading(false); setToast(t('error.invalid_connector_auth')); return; @@ -55,7 +58,7 @@ const useSocialCallbackHandler = () => { [navigate, setToast, t] ); - return socialCallbackHandler; + return { socialCallbackHandler, loading }; }; export default useSocialCallbackHandler; diff --git a/packages/ui/src/hooks/use-social-landing-handler.ts b/packages/ui/src/hooks/use-social-landing-handler.ts index f7f35a764..46066b1d9 100644 --- a/packages/ui/src/hooks/use-social-landing-handler.ts +++ b/packages/ui/src/hooks/use-social-landing-handler.ts @@ -1,4 +1,4 @@ -import { useEffect, useContext } from 'react'; +import { useContext, useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { SearchParameters } from '@/types'; @@ -7,28 +7,35 @@ import { storeCallbackLink } from '@/utils/social-connectors'; import { PageContext } from './use-page-context'; -const useSocialLandingHandler = (connectorId?: string) => { +const useSocialLandingHandler = () => { + const [loading, setLoading] = useState(true); const { setToast } = useContext(PageContext); const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); const { search } = window.location; - useEffect(() => { - const redirectUri = getSearchParameters(search, SearchParameters.redirectTo); + const socialLandingHandler = useCallback( + (connectorId: string) => { + const redirectUri = getSearchParameters(search, SearchParameters.redirectTo); - if (!redirectUri || !connectorId) { - setToast(t('error.invalid_connector_request')); + if (!redirectUri) { + setLoading(false); + setToast(t('error.invalid_connector_request')); - return; - } + return; + } - const nativeCallbackLink = getSearchParameters(search, SearchParameters.nativeCallbackLink); + const nativeCallbackLink = getSearchParameters(search, SearchParameters.nativeCallbackLink); - if (nativeCallbackLink) { - storeCallbackLink(connectorId, nativeCallbackLink); - } + if (nativeCallbackLink) { + storeCallbackLink(connectorId, nativeCallbackLink); + } - window.location.replace(redirectUri); - }, [connectorId, search, setToast, t]); + window.location.replace(redirectUri); + }, + [search, setToast, t] + ); + + return { loading, socialLandingHandler }; }; export default useSocialLandingHandler; diff --git a/packages/ui/src/pages/Callback/index.module.scss b/packages/ui/src/pages/Callback/index.module.scss index efb487d4d..05aacdf36 100644 --- a/packages/ui/src/pages/Callback/index.module.scss +++ b/packages/ui/src/pages/Callback/index.module.scss @@ -10,8 +10,3 @@ .connectorContainer { flex: 1; } - -.button { - @include _.full-width; - margin-bottom: _.unit(4); -} diff --git a/packages/ui/src/pages/Callback/index.tsx b/packages/ui/src/pages/Callback/index.tsx index 13c3b2abc..1ce8eb5b3 100644 --- a/packages/ui/src/pages/Callback/index.tsx +++ b/packages/ui/src/pages/Callback/index.tsx @@ -1,22 +1,19 @@ import React, { useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; -import Button from '@/components/Button'; import SocialLanding from '@/containers/SocialLanding'; import useSocialCallbackHandler from '@/hooks/use-social-callback-handler'; import * as styles from './index.module.scss'; -type Props = { +type Parameters = { connector: string; }; const Callback = () => { - const { connector: connectorId } = useParams(); - const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); + const { connector: connectorId } = useParams(); - const socialCallbackHandler = useSocialCallbackHandler(); + const { socialCallbackHandler, loading } = useSocialCallbackHandler(); // SocialSignIn Callback Handler useEffect(() => { @@ -35,16 +32,8 @@ const Callback = () => { - ); }; diff --git a/packages/ui/src/pages/Consent/index.module.scss b/packages/ui/src/pages/Consent/index.module.scss index 8d6ce4d59..ef463ed6c 100644 --- a/packages/ui/src/pages/Consent/index.module.scss +++ b/packages/ui/src/pages/Consent/index.module.scss @@ -8,10 +8,6 @@ width: 96px; height: 96px; @include _.image-align-center; - } - - .content { - margin-top: _.unit(2); - @include _.text-hint; + margin-bottom: _.unit(4); } } diff --git a/packages/ui/src/pages/Consent/index.tsx b/packages/ui/src/pages/Consent/index.tsx index 67bd7fb7c..198666c4a 100644 --- a/packages/ui/src/pages/Consent/index.tsx +++ b/packages/ui/src/pages/Consent/index.tsx @@ -1,18 +1,22 @@ import React, { useEffect, useContext } from 'react'; -import { useTranslation } from 'react-i18next'; import { consent } from '@/apis/consent'; +import { LoadingIcon, LoadingIconLight } from '@/components/LoadingLayer'; import useApi from '@/hooks/use-api'; import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; const Consent = () => { - const { experienceSettings } = useContext(PageContext); - const logoUrl = experienceSettings?.branding.logoUrl; - const { result, run: asyncConsent } = useApi(consent); + const { experienceSettings, theme } = useContext(PageContext); + const { error, result, run: asyncConsent } = useApi(consent); - const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); + const logoUrl = + theme === 'light' + ? experienceSettings?.branding.logoUrl + : experienceSettings?.branding.darkLogoUrl; + + const Loading = theme === 'light' ? LoadingIconLight : LoadingIcon; useEffect(() => { void asyncConsent(); @@ -27,7 +31,7 @@ const Consent = () => { return (
-
{t('description.loading')}
+ {!error && }
); }; diff --git a/packages/ui/src/pages/SocialLanding/index.tsx b/packages/ui/src/pages/SocialLanding/index.tsx index a4565c42c..553efb57e 100644 --- a/packages/ui/src/pages/SocialLanding/index.tsx +++ b/packages/ui/src/pages/SocialLanding/index.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { useTranslation } from 'react-i18next'; +import React, { useEffect } from 'react'; import { useParams } from 'react-router-dom'; import SocialLandingContainer from '@/containers/SocialLanding'; @@ -13,9 +12,15 @@ type Parameters = { const SocialLanding = () => { const { connector: connectorId } = useParams(); - const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); + const { loading, socialLandingHandler } = useSocialLandingHandler(); - useSocialLandingHandler(connectorId); + // SocialSignIn Callback Handler + useEffect(() => { + if (!connectorId) { + return; + } + socialLandingHandler(connectorId); + }, [connectorId, socialLandingHandler]); if (!connectorId) { return null; @@ -26,7 +31,7 @@ const SocialLanding = () => { );