tweaks + autoreload QR with loader display
This commit is contained in:
parent
53a7b02393
commit
2ccebb34fc
5 changed files with 84 additions and 24 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<boolean>(false);
|
||||
const [errorDisconnectingMobileApp, setErrorDisconnectingMobileApp] = useState<string>(null);
|
||||
const [userTimeoutId, setUserTimeoutId] = useState<NodeJS.Timeout>(undefined);
|
||||
const [refreshTimeoutId, setRefreshTimeoutId] = useState<NodeJS.Timeout>(undefined);
|
||||
const [isQRBlurry, setIsQRBlurry] = useState<boolean>(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
|
||||
</Text>
|
||||
<Text type="primary">Open Grafana IRM mobile application and scan this code to sync it with your account.</Text>
|
||||
<div className="u-width-100 u-flex u-flex-center">
|
||||
<QRCode value={QRCodeValue} />
|
||||
<div className={cx('u-width-100', 'u-flex', 'u-flex-center', 'u-position-relative')}>
|
||||
<QRCode className={cx({ blurry: isQRBlurry })} value={QRCodeValue} />
|
||||
{isQRBlurry && (
|
||||
<div className={cx('blurry-loader')}>
|
||||
<LoadingPlaceholder text="Regenerating QR code..." />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Text type="primary" className="u-break-word">
|
||||
<strong>Note:</strong> 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.
|
||||
</Text>
|
||||
</VerticalGroup>
|
||||
);
|
||||
}
|
||||
|
|
@ -142,13 +157,26 @@ const MobileAppVerification = observer(({ userPk }: Props) => {
|
|||
return !!(user || userStore.currentUser).messaging_backends[BACKEND]?.connected;
|
||||
}
|
||||
|
||||
async function queueRefreshQR(): Promise<void> {
|
||||
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<void> {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ import Block from 'components/GBlock/Block';
|
|||
|
||||
type Props = {
|
||||
value: string;
|
||||
className: string;
|
||||
};
|
||||
|
||||
const QRCode: FC<Props> = ({ value }) => (
|
||||
<Block bordered>
|
||||
const QRCode: FC<Props> = ({ value, className }) => (
|
||||
<Block bordered className={className}>
|
||||
<QRCodeBase value={value} />
|
||||
</Block>
|
||||
);
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue