From edd5c4d14ca643342e7872f831b5771c23557416 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Mon, 27 May 2024 19:39:20 +0400 Subject: [PATCH] Handle no internet connection --- frontend/components/Layout/Layout.tsx | 45 +++++++++++++++++++++-- frontend/context/BalanceProvider.tsx | 4 +- frontend/context/MasterSafeProvider.tsx | 6 ++- frontend/context/OnlineStatusProvider.tsx | 43 ++++++++++++++++++++++ frontend/context/RewardProvider.tsx | 4 +- frontend/context/ServicesProvider.tsx | 7 +++- frontend/context/WalletProvider.tsx | 8 +++- frontend/pages/_app.tsx | 45 ++++++++++++----------- 8 files changed, 131 insertions(+), 31 deletions(-) create mode 100644 frontend/context/OnlineStatusProvider.tsx diff --git a/frontend/components/Layout/Layout.tsx b/frontend/components/Layout/Layout.tsx index 194608543..62f88eea4 100644 --- a/frontend/components/Layout/Layout.tsx +++ b/frontend/components/Layout/Layout.tsx @@ -1,20 +1,57 @@ -import { PropsWithChildren } from 'react'; -import styled from 'styled-components'; +import { WifiOutlined } from '@ant-design/icons'; +import { message } from 'antd'; +import { PropsWithChildren, useContext, useEffect } from 'react'; +import styled, { css } from 'styled-components'; import { COLOR } from '@/constants'; +import { OnlineStatusContext } from '@/context/OnlineStatusProvider'; import { TopBar } from './TopBar'; -const Container = styled.div` +const Container = styled.div<{ blur: 'true' | 'false' }>` background-color: ${COLOR.WHITE}; border-radius: 8px; + + ${(props) => + props.blur === 'true' && + css` + filter: blur(2px); + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(27, 38, 50, 0.1); + z-index: 1; + } + `} `; export const Layout = ({ children, }: PropsWithChildren & { vertical?: boolean }) => { + const { isOnline } = useContext(OnlineStatusContext); + + useEffect(() => { + let messageKey; + if (!isOnline) { + messageKey = message.error({ + content: 'Network connection is unstable', + duration: 0, + icon: , + }); + } else { + message.destroy(messageKey); + } + }, [isOnline]); + return ( - + {children} diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 7aa9d0c6e..bc539cedb 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -28,6 +28,7 @@ import { } from '@/types'; import { ServicesContext } from '.'; +import { OnlineStatusContext } from './OnlineStatusProvider'; import { RewardContext } from './RewardProvider'; import { WalletContext } from './WalletProvider'; @@ -64,6 +65,7 @@ export const BalanceContext = createContext<{ }); export const BalanceProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); const { wallets, masterEoaAddress, masterSafeAddress } = useContext(WalletContext); const { services, serviceAddresses } = useContext(ServicesContext); @@ -197,7 +199,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { () => { updateBalances(); }, - isPaused ? null : 5000, + isPaused || !isOnline ? null : 5000, ); return ( diff --git a/frontend/context/MasterSafeProvider.tsx b/frontend/context/MasterSafeProvider.tsx index 9bd27e393..f4a3356db 100644 --- a/frontend/context/MasterSafeProvider.tsx +++ b/frontend/context/MasterSafeProvider.tsx @@ -14,6 +14,7 @@ import { useInterval } from 'usehooks-ts'; import { GnosisSafeService } from '@/service/GnosisSafe'; import { Address } from '@/types'; +import { OnlineStatusContext } from './OnlineStatusProvider'; import { WalletContext } from './WalletProvider'; export const MasterSafeContext = createContext<{ @@ -31,6 +32,7 @@ export const MasterSafeContext = createContext<{ }); export const MasterSafeProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); const { masterSafeAddress, masterEoaAddress } = useContext(WalletContext); const [masterSafeOwners, setMasterSafeOwners] = useState(); @@ -66,7 +68,9 @@ export const MasterSafeProvider = ({ children }: PropsWithChildren) => { useInterval( updateMasterSafeOwners, - masterSafeOwners && masterSafeOwners.length >= 2 ? null : 5000, + (masterSafeOwners && masterSafeOwners.length >= 2) || !isOnline + ? null + : 5000, ); return ( diff --git a/frontend/context/OnlineStatusProvider.tsx b/frontend/context/OnlineStatusProvider.tsx new file mode 100644 index 000000000..c1bcfc2f2 --- /dev/null +++ b/frontend/context/OnlineStatusProvider.tsx @@ -0,0 +1,43 @@ +import React, { + createContext, + PropsWithChildren, + useEffect, + useState, +} from 'react'; + +type OnlineStatusContextProps = { + isOnline: boolean; +}; + +const initialState = { + isOnline: true, +}; + +const OnlineStatusContext = + createContext(initialState); + +const OnlineStatusProvider = ({ children }: PropsWithChildren) => { + const [isOnline, setIsOnline] = useState(initialState.isOnline); + + useEffect(() => { + const updateOnlineStatus = () => { + setIsOnline(navigator.onLine); + }; + + window.addEventListener('online', updateOnlineStatus); + window.addEventListener('offline', updateOnlineStatus); + + return () => { + window.removeEventListener('online', updateOnlineStatus); + window.removeEventListener('offline', updateOnlineStatus); + }; + }, []); + + return ( + + {children} + + ); +}; + +export { OnlineStatusContext, OnlineStatusProvider }; diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 6bf4ebdb3..c5252a5a3 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -14,6 +14,7 @@ import { useElectronApi } from '@/hooks/useElectronApi'; import { useStore } from '@/hooks/useStore'; import { AutonolasService } from '@/service/Autonolas'; +import { OnlineStatusContext } from './OnlineStatusProvider'; import { ServicesContext } from './ServicesProvider'; export const RewardContext = createContext<{ @@ -33,6 +34,7 @@ export const RewardContext = createContext<{ }); export const RewardProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); const { services } = useContext(ServicesContext); const service = useMemo(() => services?.[0], [services]); const { storeState } = useStore(); @@ -93,7 +95,7 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { storeState?.firstStakingRewardAchieved, ]); - useInterval(async () => updateRewards(), 5000); + useInterval(async () => updateRewards(), isOnline ? 5000 : null); return ( ({ }); export const ServicesProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); + const [services, setServices] = useState(); const [serviceStatus, setServiceStatus] = useState< @@ -86,7 +91,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { updateServicesState() .then(() => updateServiceStatus()) .catch((e) => message.error(e.message)), - 5000, + isOnline ? 5000 : null, ); return ( diff --git a/frontend/context/WalletProvider.tsx b/frontend/context/WalletProvider.tsx index 533594308..f175394b0 100644 --- a/frontend/context/WalletProvider.tsx +++ b/frontend/context/WalletProvider.tsx @@ -1,10 +1,12 @@ -import { createContext, PropsWithChildren, useState } from 'react'; +import { createContext, PropsWithChildren, useContext, useState } from 'react'; import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { WalletService } from '@/service/Wallet'; import { Address } from '@/types'; +import { OnlineStatusContext } from './OnlineStatusProvider'; + export const WalletContext = createContext<{ masterEoaAddress?: Address; masterSafeAddress?: Address; @@ -18,6 +20,8 @@ export const WalletContext = createContext<{ }); export const WalletProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); + const [wallets, setWallets] = useState(); const masterEoaAddress: Address | undefined = wallets?.[0]?.address; @@ -29,7 +33,7 @@ export const WalletProvider = ({ children }: PropsWithChildren) => { setWallets(wallets); }; - useInterval(updateWallets, 5000); + useInterval(updateWallets, isOnline ? 5000 : null); return ( - - - - - - - - {isMounted ? ( - - - - - - ) : null} - - - - - - - + + + + + + + + + {isMounted ? ( + + + + + + ) : null} + + + + + + + +