diff --git a/.eslintrc.js b/.eslintrc.js
index 6e6ad9d984b..90104cdbbe3 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -317,6 +317,7 @@ module.exports = {
['types', './src/types'],
['ui', './src/ui'],
['web', './src/web'],
+ ['store', './src/store'],
],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.mjs'],
},
diff --git a/src/App.tsx b/src/App.tsx
index f863ed0ddb2..1d4171a340d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,10 +1,12 @@
import React, { FunctionComponent, useEffect } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
-import 'react-native-gesture-handler' // @react-navigation
-import 'react-native-get-random-values' // required for `uuid` module to work
import { LogBox, Platform, StatusBar } from 'react-native'
import CodePush from 'react-native-code-push'
+import SplashScreen from 'react-native-lottie-splash-screen'
+import { onlineManager } from 'react-query'
+import 'react-native-get-random-values' // required for `uuid` module to work
+import 'react-native-gesture-handler' // @react-navigation
// if __DEV__ import if you want to debug
// import './why-did-you-render'
if (process.env.NODE_ENV === 'development') {
@@ -41,8 +43,8 @@ import { BatchMessaging, BatchPush } from 'libs/react-native-batch'
import { configureGoogleSignin } from 'libs/react-native-google-sso/configureGoogleSignin'
import { SafeAreaProvider } from 'libs/react-native-save-area-provider'
import { ReactQueryClientProvider } from 'libs/react-query/ReactQueryClientProvider'
-import { SplashScreenProvider } from 'libs/splashscreen'
import { ThemeProvider } from 'libs/styled'
+import { clearNotification, setAppReady, setNotification, useAppStore } from 'store/useAppStore'
import { theme } from 'theme'
import { SnackBarProvider } from 'ui/components/snackBar/SnackBarContext'
@@ -81,13 +83,13 @@ const App: FunctionComponent = function () {
}, [])
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -96,23 +98,21 @@ const App: FunctionComponent = function () {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -121,13 +121,13 @@ const App: FunctionComponent = function () {
-
-
-
-
-
-
-
+
+
+
+
+
+
+
)
}
@@ -139,6 +139,33 @@ const AppWithMonitoring = eventMonitoring.wrap(AppWithoutMonitoring) as React.Co
}>
const AppWithCodepush = __DEV__ ? AppWithMonitoring : CodePush(config)(AppWithMonitoring)
+// SIDE EFFECTS
+useAppStore.subscribe(
+ (state) => state.isNetworkAvailable,
+ (isNetworkAvailable) => {
+ if (isNetworkAvailable === true) {
+ onlineManager.setOnline(true)
+ clearNotification()
+ } else if (isNetworkAvailable === false) {
+ onlineManager.setOnline(false)
+ setAppReady(true)
+ setNotification({
+ type: 'info',
+ message: 'Aucune connexion internet. RĂ©essaie plus tard',
+ })
+ }
+ }
+)
+
+useAppStore.subscribe(
+ (state) => state.isAppReady,
+ (isAppReady) => {
+ if (isAppReady) {
+ SplashScreen.hide()
+ }
+ }
+)
+
/**
* We have an import bug in the test file App.native.test.tsx with the new eventMonitoring wrapper : WEIRD !!! :
* Element type is invalid: expected a string (for built-in components) or a class/function (for composite components)
diff --git a/src/features/auth/context/AuthContext.native.test.tsx b/src/features/auth/context/AuthContext.native.test.tsx
index f46bd2c3070..478bcfec0f3 100644
--- a/src/features/auth/context/AuthContext.native.test.tsx
+++ b/src/features/auth/context/AuthContext.native.test.tsx
@@ -3,7 +3,7 @@ import React from 'react'
import { BatchProfile } from '__mocks__/@batch.com/react-native-plugin'
import * as jwt from '__mocks__/jwt-decode'
-import { UserProfileResponse } from 'api/gen'
+import { RefreshResponse, UserProfileResponse } from 'api/gen'
import { CURRENT_DATE } from 'features/auth/fixtures/fixtures'
import * as NavigationRef from 'features/navigation/navigationRef'
import { beneficiaryUser, nonBeneficiaryUser } from 'fixtures/user'
@@ -12,8 +12,7 @@ import { amplitude } from 'libs/amplitude'
import { decodedTokenWithRemainingLifetime, tokenRemainingLifetimeInMs } from 'libs/jwt/fixtures'
import { clearRefreshToken, getRefreshToken, saveRefreshToken } from 'libs/keychain/keychain'
import { eventMonitoring } from 'libs/monitoring'
-import { NetInfoWrapper } from 'libs/network/NetInfoWrapper'
-import { useNetInfo } from 'libs/network/useNetInfo'
+import { useNetInfoContext as useNetInfoContextDefault } from 'libs/network/NetInfoWrapper'
import * as PackageJson from 'libs/packageJson'
import { QueryKeys } from 'libs/queryKeys'
import { StorageKey, storage } from 'libs/storage'
@@ -24,7 +23,8 @@ import { act, renderHook } from 'tests/utils'
import { useAuthContext } from './AuthContext'
import { AuthWrapper } from './AuthWrapper'
-const mockedUseNetInfo = useNetInfo as jest.Mock
+jest.mock('libs/network/NetInfoWrapper')
+const mockUseNetInfoContext = useNetInfoContextDefault as jest.Mock
jest.mock('libs/amplitude/amplitude')
@@ -54,17 +54,25 @@ describe('AuthContext', () => {
describe('useAuthContext', () => {
beforeEach(() => {
mockServer.getApi('/v1/me', nonBeneficiaryUser)
+ mockServer.postApi('/v1/refresh_access_token', {})
+ mockUseNetInfoContext.mockReturnValue({
+ isConnected: true,
+ isInternetReachable: true,
+ })
})
it('should not return user when logged in but no internet connection', async () => {
- mockedUseNetInfo.mockReturnValueOnce({ isConnected: false, isInternetReachable: false })
+ mockUseNetInfoContext.mockReturnValueOnce({
+ isConnected: false,
+ isInternetReachable: false,
+ })
await saveRefreshToken('token')
const result = renderUseAuthContext()
await act(async () => {})
- expect(result.current).toBeNull()
+ expect(result.current.user).toEqual({})
})
it('should return the user when logged in with internet connection', async () => {
@@ -278,12 +286,7 @@ describe('AuthContext', () => {
const renderUseAuthContext = () => {
const { result } = renderHook(useAuthContext, {
- wrapper: ({ children }) =>
- reactQueryProviderHOC(
-
- {children}
-
- ),
+ wrapper: ({ children }) => reactQueryProviderHOC({children}),
})
return result
diff --git a/src/features/location/helpers/useLocationWidgetTooltip.ts b/src/features/location/helpers/useLocationWidgetTooltip.ts
index 0a0d6420e03..b54bf65da89 100644
--- a/src/features/location/helpers/useLocationWidgetTooltip.ts
+++ b/src/features/location/helpers/useLocationWidgetTooltip.ts
@@ -3,7 +3,6 @@ import { LayoutChangeEvent, Platform } from 'react-native'
import { ScreenOrigin } from 'features/location/enums'
import { useLocation } from 'libs/location'
-import { useSplashScreenContext } from 'libs/splashscreen'
import { storage } from 'libs/storage'
const START_OFFSET = 1000
@@ -12,9 +11,6 @@ const TOOLTIP_DISPLAY_DURATION = 8000
export const useLocationWidgetTooltip = (screenOrigin: ScreenOrigin) => {
const touchableRef = React.useRef()
- const { isSplashScreenHidden } = useSplashScreenContext()
- const isNativeSplashScreenHidden = isSplashScreenHidden || Platform.OS === 'web'
-
const [widgetWidth, setWidgetWidth] = React.useState()
const [isTooltipVisible, setIsTooltipVisible] = React.useState(false)
const hideTooltip = useCallback(() => setIsTooltipVisible(false), [setIsTooltipVisible])
@@ -52,8 +48,6 @@ export const useLocationWidgetTooltip = (screenOrigin: ScreenOrigin) => {
return
}
- if (!isNativeSplashScreenHidden || !enableTooltip) return
-
const displayTooltipIfNeeded = async () => {
const timesLocationTooltipHasBeenDisplayed = Number(
await storage.readString('times_location_tooltip_has_been_displayed')
@@ -73,7 +67,7 @@ export const useLocationWidgetTooltip = (screenOrigin: ScreenOrigin) => {
clearTimeout(timeoutOff)
}
// eslint-disable-next-line react-hooks/exhaustive-deps -- should only be called on startup
- }, [isNativeSplashScreenHidden, geolocPosition])
+ }, [geolocPosition])
return {
isTooltipVisible,
diff --git a/src/features/navigation/NavigationContainer/NavigationContainer.tsx b/src/features/navigation/NavigationContainer/NavigationContainer.tsx
index 43f708faaf9..8d0d936f9bf 100644
--- a/src/features/navigation/NavigationContainer/NavigationContainer.tsx
+++ b/src/features/navigation/NavigationContainer/NavigationContainer.tsx
@@ -10,8 +10,9 @@ import { DefaultTheme, useTheme } from 'styled-components/native'
import { RootNavigator } from 'features/navigation/RootNavigator'
import { linking } from 'features/navigation/RootNavigator/linking'
-import { useSplashScreenContext } from 'libs/splashscreen'
+import { useInitialScreen } from 'features/navigation/RootNavigator/useInitialScreenConfig'
import { storage } from 'libs/storage'
+import { setAppReady } from 'store/useAppStore'
import { LoadingPage } from 'ui/components/LoadingPage'
import { author } from '../../../../package.json'
@@ -33,12 +34,13 @@ const DOCUMENT_TITLE_OPTIONS: DocumentTitleOptions = {
}
export const AppNavigationContainer = () => {
- const { hideSplashScreen } = useSplashScreenContext()
const theme = useTheme()
-
const [isNavReady, setIsNavReady] = useState(false)
+ const [navigationStateLoaded, setNavigationStateLoaded] = useState(false)
const [initialNavigationState, setInitialNavigationState] = useState()
+ const initialScreen = useInitialScreen()
+
useEffect(() => {
async function restoreNavStateOnReload() {
try {
@@ -50,34 +52,29 @@ export const AppNavigationContainer = () => {
setInitialNavigationState(savedState)
} finally {
- setIsNavReady(true)
+ setNavigationStateLoaded(true)
}
}
restoreNavStateOnReload()
}, [])
- useEffect(() => {
- if (isNavReady) {
- hideSplashScreen?.()
- }
- }, [isNavReady, hideSplashScreen])
-
- if (!isNavReady) {
- return
+ if (isNavReady && navigationStateLoaded && initialScreen) {
+ setAppReady(true)
}
- return (
+ return initialScreen ? (
setIsNavReady(true)}
fallback={}
ref={navigationRef}
documentTitle={DOCUMENT_TITLE_OPTIONS}
theme={getNavThemeConfig(theme)}>
-
+
- )
+ ) : null
}
export default AppNavigationContainer
diff --git a/src/features/navigation/RootNavigator/RootNavigator.tsx b/src/features/navigation/RootNavigator/RootNavigator.tsx
index f2b35cd786e..54d7e7fa0ae 100644
--- a/src/features/navigation/RootNavigator/RootNavigator.tsx
+++ b/src/features/navigation/RootNavigator/RootNavigator.tsx
@@ -9,13 +9,11 @@ import { PrivacyPolicy } from 'features/cookies/pages/PrivacyPolicy'
import { useCurrentRoute } from 'features/navigation/helpers/useCurrentRoute'
import { AccessibleTabBar } from 'features/navigation/RootNavigator/Header/AccessibleTabBar'
import { RootScreenNames } from 'features/navigation/RootNavigator/types'
-import { useInitialScreen } from 'features/navigation/RootNavigator/useInitialScreenConfig'
import { withWebWrapper } from 'features/navigation/RootNavigator/withWebWrapper'
import { TabNavigationStateProvider } from 'features/navigation/TabBar/TabNavigationStateContext'
import { VenueMapFiltersStackNavigator } from 'features/navigation/VenueMapFiltersStackNavigator/VenueMapFiltersStackNavigator'
import { AccessibilityRole } from 'libs/accessibilityRole/accessibilityRole'
import { env } from 'libs/environment'
-import { useSplashScreenContext } from 'libs/splashscreen'
import { storage } from 'libs/storage'
import { IconFactoryProvider } from 'ui/components/icons/IconFactoryProvider'
import { LoadingPage } from 'ui/components/LoadingPage'
@@ -38,7 +36,7 @@ const CheatcodesStackNavigator = lazy(async () => {
})
const RootStackNavigator = withWebWrapper(
- ({ initialRouteName }: { initialRouteName: RootScreenNames }) => {
+ ({ initialRouteName }: { initialRouteName?: RootScreenNames }) => {
const { top } = useSafeAreaInsets()
return (
@@ -76,14 +74,11 @@ const RootStackNavigator = withWebWrapper(
}
)
-export const RootNavigator: React.ComponentType = () => {
+export const RootNavigator = ({ initialScreen }: { initialScreen?: RootScreenNames }) => {
const mainId = uuidv4()
const tabBarId = uuidv4()
const { showTabBar } = useTheme()
const { isLoggedIn } = useAuthContext()
- const { isSplashScreenHidden } = useSplashScreenContext()
-
- const initialScreen = useInitialScreen()
const currentRoute = useCurrentRoute()
const showHeaderQuickAccess = currentRoute && currentRoute.name === 'TabNavigator'
@@ -103,10 +98,6 @@ export const RootNavigator: React.ComponentType = () => {
}
}, [isLoggedIn])
- if (!initialScreen) {
- return
- }
-
const mainAccessibilityRole: AccessibilityRole | undefined =
determineAccessibilityRole(currentRoute)
@@ -121,8 +112,9 @@ export const RootNavigator: React.ComponentType = () => {
) : null}
- {/* The components below are those for which we do not want their rendering to happen while the splash is displayed. */}
- {isSplashScreenHidden ? : null}
+ {/* The components below are those for which we do not want
+ their rendering to happen while the splash is displayed. */}
+
)
}
diff --git a/src/libs/network/NetInfoWrapper.native.test.tsx b/src/libs/network/NetInfoWrapper.native.test.tsx
index 0ad982e3ddf..2d6608e3f84 100644
--- a/src/libs/network/NetInfoWrapper.native.test.tsx
+++ b/src/libs/network/NetInfoWrapper.native.test.tsx
@@ -6,19 +6,18 @@ import { View } from 'react-native'
import { analytics } from 'libs/analytics'
import { NetInfoWrapper, useNetInfoContext } from 'libs/network/NetInfoWrapper'
import { useNetInfo } from 'libs/network/useNetInfo'
-import { useSplashScreenContext } from 'libs/splashscreen'
+import { setNetworkAvailable } from 'store/useAppStore'
import { render, screen } from 'tests/utils'
const mockedUseNetInfo = useNetInfo as unknown as jest.Mock<{
- isConnected: boolean
- isInternetReachable: boolean
+ isConnected: boolean | null
+ isInternetReachable: boolean | null
type: NetInfoStateType
details?: Record
}>
-jest.mock('libs/splashscreen')
-const mockUseSplashScreenContext = useSplashScreenContext as jest.Mock
-mockUseSplashScreenContext.mockReturnValue({ isSplashScreenHidden: true })
+jest.mock('store/useAppStore')
+const mockSetNetworkAvailable = setNetworkAvailable as jest.Mock
describe('NetInfoWrapper', () => {
describe('useNetInfoContext', () => {
@@ -39,23 +38,6 @@ describe('NetInfoWrapper', () => {
expect(onConnectionLost).not.toHaveBeenCalled()
})
- it('should call onConnectionLost', () => {
- mockedUseNetInfo.mockReturnValueOnce({
- isConnected: false,
- isInternetReachable: true,
- type: NetInfoStateType.wifi,
- })
- renderNetInfoWrapper({
- onInternetConnection,
- onInternetConnectionLost,
- onConnection,
- onConnectionLost,
- })
-
- expect(onConnection).not.toHaveBeenCalled()
- expect(onConnectionLost).toHaveBeenCalledTimes(1)
- })
-
it('should call onInternetConnection', () => {
mockedUseNetInfo.mockReturnValueOnce({
isConnected: true,
@@ -69,14 +51,15 @@ describe('NetInfoWrapper', () => {
onConnectionLost,
})
+ expect(mockSetNetworkAvailable).toHaveBeenCalledWith(true)
expect(onInternetConnection).toHaveBeenCalledTimes(1)
expect(onInternetConnectionLost).not.toHaveBeenCalled()
})
- it('should call onInternetConnectionLost', () => {
+ it('should log network information when wifi is used', async () => {
mockedUseNetInfo.mockReturnValueOnce({
- isConnected: true,
- isInternetReachable: false,
+ isConnected: false,
+ isInternetReachable: true,
type: NetInfoStateType.wifi,
})
renderNetInfoWrapper({
@@ -86,14 +69,14 @@ describe('NetInfoWrapper', () => {
onConnectionLost,
})
- expect(onInternetConnection).not.toHaveBeenCalled()
- expect(onInternetConnectionLost).toHaveBeenCalledTimes(1)
+ expect(mockSetNetworkAvailable).toHaveBeenCalledWith(false)
+ expect(analytics.logConnectionInfo).toHaveBeenCalledWith({ type: 'wifi' })
})
- it('should log network information when wifi is used', async () => {
+ it('should update global store if network info is null', () => {
mockedUseNetInfo.mockReturnValueOnce({
- isConnected: false,
- isInternetReachable: true,
+ isConnected: null,
+ isInternetReachable: null,
type: NetInfoStateType.wifi,
})
renderNetInfoWrapper({
@@ -103,7 +86,7 @@ describe('NetInfoWrapper', () => {
onConnectionLost,
})
- expect(analytics.logConnectionInfo).toHaveBeenCalledWith({ type: 'wifi' })
+ expect(mockSetNetworkAvailable).toHaveBeenCalledWith(null)
})
it('should log network information when cellular is used', async () => {
@@ -144,24 +127,7 @@ describe('NetInfoWrapper', () => {
expect(analytics.logConnectionInfo).not.toHaveBeenCalled()
})
- it('should display children if splashscreen is not visible and there is no network', () => {
- mockedUseNetInfo.mockReturnValueOnce({
- isConnected: false,
- isInternetReachable: false,
- type: NetInfoStateType.unknown,
- })
- renderNetInfoWrapper({
- onInternetConnection,
- onInternetConnectionLost,
- onConnection,
- onConnectionLost,
- })
-
- expect(screen.getByTestId('dumbComponent')).toBeOnTheScreen()
- })
-
- it('should not display children if splashscreen is visible and there is no network', () => {
- mockUseSplashScreenContext.mockReturnValueOnce({ isSplashScreenHidden: false })
+ it('should not display children if there is no network', () => {
mockedUseNetInfo.mockReturnValueOnce({
isConnected: false,
isInternetReachable: false,
diff --git a/src/libs/network/NetInfoWrapper.tsx b/src/libs/network/NetInfoWrapper.tsx
index ace14976ef1..024e075f748 100644
--- a/src/libs/network/NetInfoWrapper.tsx
+++ b/src/libs/network/NetInfoWrapper.tsx
@@ -2,12 +2,11 @@
import { NetInfoState, NetInfoStateType } from '@react-native-community/netinfo'
import React, { createContext, memo, useContext, useEffect } from 'react'
import { Platform } from 'react-native'
-import { onlineManager } from 'react-query'
import { analytics } from 'libs/analytics'
+import { OfflinePage } from 'libs/network/OfflinePage'
import { useNetInfo } from 'libs/network/useNetInfo'
-import { useSplashScreenContext } from 'libs/splashscreen'
-import { SNACK_BAR_TIME_OUT, useSnackBarContext } from 'ui/components/snackBar/SnackBarContext'
+import { setNetworkAvailable } from 'store/useAppStore'
export const NetInfoWrapper = memo(function NetInfoWrapper({
children,
@@ -15,20 +14,13 @@ export const NetInfoWrapper = memo(function NetInfoWrapper({
children: React.JSX.Element
}) {
const networkInfo = useNetInfo()
- const { showInfoSnackBar } = useSnackBarContext()
- const isConnected = !!networkInfo.isConnected && !!networkInfo.isInternetReachable
- const { isSplashScreenHidden } = useSplashScreenContext()
+ const isConnected = networkInfo.isConnected && networkInfo.isInternetReachable
useEffect(() => {
- onlineManager.setOnline(isConnected)
- if (isConnected === false) {
- showInfoSnackBar({
- message: 'Aucune connexion internet. RĂ©essaie plus tard',
- timeout: SNACK_BAR_TIME_OUT,
- })
- }
+ setNetworkAvailable(isConnected)
+ // setNetworkAvailable is not necessary in dependency array
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [networkInfo.isConnected, networkInfo.isInternetReachable])
+ }, [isConnected])
useEffect(() => {
const connectionType = networkInfo.type
@@ -47,7 +39,7 @@ export const NetInfoWrapper = memo(function NetInfoWrapper({
return (
- {!isSplashScreenHidden && !isConnected ? null : children}
+ {isConnected ? children : }
)
})
diff --git a/src/libs/splashscreen/__mocks__/index.ts b/src/libs/splashscreen/__mocks__/index.ts
deleted file mode 100644
index 695c7e8dfea..00000000000
--- a/src/libs/splashscreen/__mocks__/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-
-export const useSplashScreenContext = jest
- .fn()
- .mockReturnValue({ isSplashScreenHidden: true, hideSplashScreen: jest.fn() })
-
-export const SplashScreenProvider: React.FC<{ children: React.ReactElement }> = (props) =>
- props.children
diff --git a/src/libs/splashscreen/index.ts b/src/libs/splashscreen/index.ts
deleted file mode 100644
index 99d8aeda076..00000000000
--- a/src/libs/splashscreen/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { useSplashScreenContext, SplashScreenProvider } from './splashscreen'
diff --git a/src/libs/splashscreen/splashscreen.native.test.tsx b/src/libs/splashscreen/splashscreen.native.test.tsx
deleted file mode 100644
index 1ef1ec04619..00000000000
--- a/src/libs/splashscreen/splashscreen.native.test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import mockdate from 'mockdate'
-
-import { SplashScreenProvider, useSplashScreenContext } from 'libs/splashscreen/splashscreen'
-import { renderHook, act } from 'tests/utils'
-
-const MIN_SPLASHSCREEN_DURATION_IN_MS = 2000
-
-const TODAY = new Date('2022-10-14')
-
-jest.useFakeTimers()
-
-describe('useSplashScreenContext()', () => {
- beforeEach(() => {
- mockdate.set(TODAY)
- jest.clearAllTimers()
- })
-
- it('should hide splashscreen without waiting when it has been shown for long enough', () => {
- const { result } = renderSplashScreenHook()
- mockdate.set(TODAY.getTime() + MIN_SPLASHSCREEN_DURATION_IN_MS)
-
- act(() => {
- result.current.hideSplashScreen?.()
- })
-
- expect(result.current.isSplashScreenHidden).toBe(true)
- })
-
- it('should not hide splashscreen when it has not been shown for long enough', () => {
- const { result } = renderSplashScreenHook()
-
- act(() => {
- result.current.hideSplashScreen?.()
- jest.advanceTimersByTime(MIN_SPLASHSCREEN_DURATION_IN_MS - 1)
- })
-
- expect(result.current.isSplashScreenHidden).toBe(false)
- })
-
- it('should hide splashscreen when it has been shown for long enough', () => {
- const { result } = renderSplashScreenHook()
-
- act(() => {
- result.current.hideSplashScreen?.()
- jest.advanceTimersByTime(MIN_SPLASHSCREEN_DURATION_IN_MS)
- })
-
- expect(result.current.isSplashScreenHidden).toBe(true)
- })
-})
-
-function renderSplashScreenHook() {
- return renderHook(useSplashScreenContext, {
- wrapper: SplashScreenProvider,
- })
-}
diff --git a/src/libs/splashscreen/splashscreen.tsx b/src/libs/splashscreen/splashscreen.tsx
deleted file mode 100644
index 08e60fe053b..00000000000
--- a/src/libs/splashscreen/splashscreen.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, { createContext, useCallback, useContext, memo, useState, useMemo } from 'react'
-import SplashScreen from 'react-native-lottie-splash-screen'
-
-import { SplashScreenContextInterface } from './types'
-
-const MIN_SPLASHSCREEN_DURATION_IN_MS = 2000
-
-const SplashScreenContext = createContext({
- isSplashScreenHidden: false,
-})
-
-export function useSplashScreenContext() {
- return useContext(SplashScreenContext)
-}
-
-export const SplashScreenProvider = memo(function SplashScreenProvider(props: {
- children: React.ReactNode
-}) {
- const splashScreenBeginningTime = new Date().getTime()
- const [isSplashScreenHidden, setIsSplashScreenHidden] = useState(false)
-
- const hideSplashscreenCallback = useCallback(() => {
- SplashScreen.hide()
- setIsSplashScreenHidden(true)
- }, [])
-
- const hideSplashScreen = useCallback(() => {
- const splashScreenDisplayDuration = new Date().getTime() - splashScreenBeginningTime
- if (splashScreenDisplayDuration < MIN_SPLASHSCREEN_DURATION_IN_MS) {
- setTimeout(
- hideSplashscreenCallback,
- MIN_SPLASHSCREEN_DURATION_IN_MS - splashScreenDisplayDuration
- )
- } else {
- hideSplashscreenCallback()
- }
- }, [splashScreenBeginningTime, hideSplashscreenCallback])
-
- const value = useMemo(
- () => ({ isSplashScreenHidden, hideSplashScreen }),
- [hideSplashScreen, isSplashScreenHidden]
- )
- return {props.children}
-})
diff --git a/src/libs/splashscreen/splashscreen.web.test.tsx b/src/libs/splashscreen/splashscreen.web.test.tsx
deleted file mode 100644
index d1dd7a4fb19..00000000000
--- a/src/libs/splashscreen/splashscreen.web.test.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { SplashScreenProvider, useSplashScreenContext } from 'libs/splashscreen/splashscreen'
-import { renderHook } from 'tests/utils/web'
-
-describe('useSplashScreenContext()', () => {
- it('should always have a hidden splashscreen', () => {
- const { result } = renderHook(useSplashScreenContext, {
- wrapper: SplashScreenProvider,
- })
-
- expect(result.current).toEqual({
- isSplashScreenHidden: true,
- hideSplashScreen: undefined,
- })
- })
-})
diff --git a/src/libs/splashscreen/splashscreen.web.tsx b/src/libs/splashscreen/splashscreen.web.tsx
deleted file mode 100644
index 85d31f13029..00000000000
--- a/src/libs/splashscreen/splashscreen.web.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react'
-
-import { SplashScreenContextInterface } from './types'
-
-/**
- * There is no splash screen in web, but for compatibility with other platforms,
- * we provide a function and a provider mocking the splashscreen context.
- */
-
-export function useSplashScreenContext(): SplashScreenContextInterface {
- return { isSplashScreenHidden: true, hideSplashScreen: undefined }
-}
-
-export const SplashScreenProvider: React.FC<{ children: React.ReactElement }> = (props) =>
- props.children
diff --git a/src/libs/splashscreen/types.ts b/src/libs/splashscreen/types.ts
deleted file mode 100644
index ccce7de888b..00000000000
--- a/src/libs/splashscreen/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface SplashScreenContextInterface {
- isSplashScreenHidden: boolean
- hideSplashScreen?: () => void
-}
diff --git a/src/store/useAppStore.ts b/src/store/useAppStore.ts
new file mode 100644
index 00000000000..d016db37076
--- /dev/null
+++ b/src/store/useAppStore.ts
@@ -0,0 +1,30 @@
+// eslint-disable-next-line no-restricted-imports
+import { create } from 'zustand'
+import { subscribeWithSelector } from 'zustand/middleware'
+
+export type NotificationData = {
+ type: 'info' | 'success' | 'error'
+ message: string
+}
+
+type State = {
+ isNetworkAvailable: boolean | null
+ isAppReady: boolean
+ notificationData?: NotificationData
+}
+
+export const useAppStore = create()(
+ subscribeWithSelector(() => ({
+ isNetworkAvailable: false,
+ isAppReady: false,
+ notificationData: undefined,
+ }))
+)
+
+export const setNetworkAvailable = (value: boolean | null) =>
+ useAppStore.setState({ isNetworkAvailable: value })
+
+export const setAppReady = (value: boolean) => useAppStore.setState({ isAppReady: value })
+export const setNotification = (value: NotificationData) =>
+ useAppStore.setState({ notificationData: value })
+export const clearNotification = () => useAppStore.setState({ notificationData: undefined })
diff --git a/src/ui/components/snackBar/SnackBarContext.tsx b/src/ui/components/snackBar/SnackBarContext.tsx
index 02f89a28e97..d181a27f5fe 100644
--- a/src/ui/components/snackBar/SnackBarContext.tsx
+++ b/src/ui/components/snackBar/SnackBarContext.tsx
@@ -1,6 +1,8 @@
-import React, { createContext, memo, useContext, useRef, useState } from 'react'
+import React, { createContext, memo, useContext, useEffect, useRef, useState } from 'react'
import { useTheme } from 'styled-components/native'
+import { NotificationData, useAppStore } from 'store/useAppStore'
+
import { mapSnackBarTypeToStyle } from './mapSnackBarTypeToStyle'
import { SnackBar, SnackBarProps } from './SnackBar'
import { SnackBarHelperSettings, SnackBarSettings, SnackBarType } from './types'
@@ -29,6 +31,7 @@ export const SnackBarProvider = memo(function SnackBarProviderComponent({
children: React.ReactNode
}) {
const theme = useTheme()
+ const notificationData = useAppStore((state) => state.notificationData)
const [snackBarProps, setSnackBarProps] = useState({
visible: false,
message: '',
@@ -66,6 +69,25 @@ export const SnackBarProvider = memo(function SnackBarProviderComponent({
}),
})
+ const handleShowSnackBarEvent = ({ message, type }: NotificationData) => {
+ const { showErrorSnackBar, showInfoSnackBar, showSuccessSnackBar } = snackBarToolsRef.current
+ const showMessageFnMap = {
+ error: showErrorSnackBar,
+ info: showInfoSnackBar,
+ success: showSuccessSnackBar,
+ }
+
+ showMessageFnMap[type]?.({ message, timeout: SNACK_BAR_TIME_OUT })
+ }
+
+ useEffect(() => {
+ if (notificationData) {
+ handleShowSnackBarEvent(notificationData)
+ } else {
+ hideSnackBar()
+ }
+ }, [notificationData])
+
return (
{
extensions: allExtensions,
alias: [
{
- find: /^((api|cheatcodes|features|fixtures|libs|shared|theme|ui|web).*)/,
+ find: /^((api|cheatcodes|features|fixtures|libs|shared|theme|ui|web|store).*)/,
replacement: '/src/$1',
},
{ find: 'react-native', replacement: 'react-native-web' },