From 2ccebb34fcac7c2014d2280eba76508ed9bcc541 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Tue, 6 Dec 2022 15:05:38 +0200 Subject: [PATCH] tweaks + autoreload QR with loader display --- .../MobileAppVerification.module.scss | 28 ++++++++ .../MobileAppVerification.tsx | 68 +++++++++++++------ .../parts/QRCode/QRCode.test.tsx | 2 +- .../parts/QRCode/{index.tsx => QRCode.tsx} | 5 +- .../containers/UserSettings/UserSettings.tsx | 5 +- 5 files changed, 84 insertions(+), 24 deletions(-) rename grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/{index.tsx => QRCode.tsx} (66%) diff --git a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss index a97a1e43..7c466508 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss +++ b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss @@ -33,3 +33,31 @@ filter: blur(6px); opacity: 0.6; } + +.blurry { + filter: blur(4px); + opacity: 0.2; +} + +.blurry-loader { + position: absolute; + z-index: 10; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + > div { + margin-bottom: 0; + font-size: 16px; + text-align: center; + } + + [data-testid='Spinner'] { // No other way to overwrite Grafana's LoadingPlaceholder unfortunately + width: 100%; + padding-top: 12px; + } + + [data-testid='Spinner'] i { // No other way to overwrite Grafana's LoadingPlaceholder unfortunately + font-size: 32px; + } +} diff --git a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx index 7b8d2afb..c489bd4c 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx @@ -13,7 +13,7 @@ import { useStore } from 'state/useStore'; import styles from './MobileAppVerification.module.scss'; import DisconnectButton from './parts/DisconnectButton/DisconnectButton'; import DownloadIcons from './parts/DownloadIcons'; -import QRCode from './parts/QRCode'; +import QRCode from './parts/QRCode/QRCode'; const cx = cn.bind(styles); @@ -21,7 +21,8 @@ type Props = { userPk: User['pk']; }; -const INTERVAL_MS = 5000; +const INTERVAL_QUEUE_QR = 50000; +const INTERVAL_POLLING = 5000; const BACKEND = 'MOBILE_APP'; const MobileAppVerification = observer(({ userPk }: Props) => { @@ -36,18 +37,29 @@ const MobileAppVerification = observer(({ userPk }: Props) => { const [disconnectingMobileApp, setDisconnectingMobileApp] = useState(false); const [errorDisconnectingMobileApp, setErrorDisconnectingMobileApp] = useState(null); const [userTimeoutId, setUserTimeoutId] = useState(undefined); + const [refreshTimeoutId, setRefreshTimeoutId] = useState(undefined); + const [isQRBlurry, setIsQRBlurry] = useState(false); - const fetchQRCode = useCallback(async () => { - setFetchingQRCode(true); - try { - // backend verification code that we receive is a JSON object that has been "stringified" - const qrCodeContent = await userStore.sendBackendConfirmationCode(userPk, BACKEND); - setQRCodeValue(qrCodeContent); - } catch (e) { - setErrorFetchingQRCode('There was an error fetching your QR code. Please try again.'); - } - setFetchingQRCode(false); - }, [userPk]); + const fetchQRCode = useCallback( + async (showLoader: boolean = true) => { + if (showLoader) { + setFetchingQRCode(true); + } + + try { + // backend verification code that we receive is a JSON object that has been "stringified" + const qrCodeContent = await userStore.sendBackendConfirmationCode(userPk, BACKEND); + setQRCodeValue(qrCodeContent); + } catch (e) { + setErrorFetchingQRCode('There was an error fetching your QR code. Please try again.'); + } + + if (showLoader) { + setFetchingQRCode(false); + } + }, + [userPk] + ); const resetState = useCallback(() => { setErrorDisconnectingMobileApp(null); @@ -66,11 +78,13 @@ const MobileAppVerification = observer(({ userPk }: Props) => { } setDisconnectingMobileApp(false); + queueRefreshQR(); pollUserProfile(); }, [userPk, resetState]); useEffect(() => { if (!isUserConnected()) { + queueRefreshQR(); pollUserProfile(); } @@ -116,13 +130,14 @@ const MobileAppVerification = observer(({ userPk }: Props) => { Sign In Open Grafana IRM mobile application and scan this code to sync it with your account. -
- +
+ + {isQRBlurry && ( +
+ +
+ )}
- - Note: the QR code is only valid for one minute. If you have issues connecting your mobile - app, try refreshing this page to generate a new code. - ); } @@ -142,13 +157,26 @@ const MobileAppVerification = observer(({ userPk }: Props) => { return !!(user || userStore.currentUser).messaging_backends[BACKEND]?.connected; } + async function queueRefreshQR(): Promise { + clearTimeout(refreshTimeoutId); + setRefreshTimeoutId(undefined); + + const user = await userStore.loadUser(userPk); + if (!isUserConnected(user)) { + setIsQRBlurry(true); + await fetchQRCode(false); + setIsQRBlurry(false); + setTimeout(() => queueRefreshQR(), INTERVAL_QUEUE_QR); + } + } + async function pollUserProfile(): Promise { clearTimeout(userTimeoutId); setUserTimeoutId(undefined); const user = await userStore.loadUser(userPk); if (!isUserConnected(user)) { - setUserTimeoutId(setTimeout(() => pollUserProfile(), INTERVAL_MS)); + setUserTimeoutId(setTimeout(() => pollUserProfile(), INTERVAL_POLLING)); } else { setMobileAppIsCurrentlyConnected(true); } diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.test.tsx b/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.test.tsx index 8c3e1554..76008c27 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.test.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import QRCode from './'; +import QRCode from './QRCode'; describe('QRCode', () => { test('it renders properly', () => { diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/index.tsx b/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.tsx similarity index 66% rename from grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/index.tsx rename to grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.tsx index 98ec3561..0e8e65c9 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/index.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/QRCode/QRCode.tsx @@ -6,10 +6,11 @@ import Block from 'components/GBlock/Block'; type Props = { value: string; + className: string; }; -const QRCode: FC = ({ value }) => ( - +const QRCode: FC = ({ value, className }) => ( + ); diff --git a/grafana-plugin/src/containers/UserSettings/UserSettings.tsx b/grafana-plugin/src/containers/UserSettings/UserSettings.tsx index 78fdad24..4c025479 100644 --- a/grafana-plugin/src/containers/UserSettings/UserSettings.tsx +++ b/grafana-plugin/src/containers/UserSettings/UserSettings.tsx @@ -49,7 +49,10 @@ const UserSettings = observer(({ id, onHide, tab = UserSettingsTab.UserInfo }: U }, []); const isModalWide = - !isDesktopOrLaptop || activeTab === UserSettingsTab.UserInfo || activeTab === UserSettingsTab.PhoneVerification; + !isDesktopOrLaptop || + activeTab === UserSettingsTab.UserInfo || + activeTab === UserSettingsTab.PhoneVerification || + activeTab === UserSettingsTab.MobileAppVerification; const [ showNotificationSettingsTab,