diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx
index 2a01d07d3d..216b00f580 100644
--- a/apps/mobile/src/App.tsx
+++ b/apps/mobile/src/App.tsx
@@ -22,12 +22,13 @@ import { MobileErrorReportingProvider } from '~/contexts/MobileErrorReportingPro
import { createRelayEnvironment } from '~/contexts/relay/RelayProvider';
import { env } from '~/env/runtime';
import { RootStackNavigator } from '~/navigation/RootStackNavigator';
+import MaintenanceStatusProvider from '~/shared/contexts/MaintenanceStatusContext';
import { ReportingErrorBoundary } from '~/shared/errors/ReportingErrorBoundary';
import { DevMenuItems } from './components/DevMenuItems';
import { LoadingView } from './components/LoadingView';
+import { CheckMaintenanceOnAppForeground, MaintenanceScreen } from './components/MaintenanceScreen';
import SearchProvider from './components/Search/SearchContext';
-import { Typography } from './components/Typography';
import BottomSheetModalProvider from './contexts/BottomSheetModalContext';
import ManageWalletProvider from './contexts/ManageWalletContext';
import SyncTokensProvider from './contexts/SyncTokensContext';
@@ -35,7 +36,6 @@ import ToastProvider from './contexts/ToastContext';
import { TokenStateManagerProvider } from './contexts/TokenStateManagerContext';
import { magic } from './magic';
import { useCacheIntroVideo } from './screens/Onboarding/useCacheIntroVideo';
-import { useSanityMaintenanceCheckMobile } from './utils/useSanityMaintenanceCheckMobile';
SplashScreen.preventAutoHideAsync();
@@ -115,82 +115,68 @@ export default function App() {
[colorScheme, colorSchemeLoaded]
);
- // NOTE: this is deprecated and should use shared/MaintenanceStatusContext instead
- const { maintenanceCheckLoadedOrError, maintenanceModeResponse } =
- useSanityMaintenanceCheckMobile();
-
useEffect(
function markTheAppAsReadyWhenTheFontsAndColorSchemeHaveLoaded() {
- if (fontsLoaded && colorSchemeLoaded && maintenanceCheckLoadedOrError) {
+ if (fontsLoaded && colorSchemeLoaded) {
SplashScreen.hideAsync();
}
},
- [colorSchemeLoaded, fontsLoaded, maintenanceCheckLoadedOrError]
+ [colorSchemeLoaded, fontsLoaded]
);
- if (!fontsLoaded || !colorSchemeLoaded || !maintenanceCheckLoadedOrError || !introVideoLoaded) {
+ if (!fontsLoaded || !colorSchemeLoaded || !introVideoLoaded) {
return null;
}
- if (maintenanceModeResponse?.isActive) {
- return (
-
-
- Maintenance in Progress
-
-
- {maintenanceModeResponse?.message}
-
-
- );
- }
-
return (
}>
-
-
- }>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Register the user's push token if one exists (does not prompt the user) */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ }
+ MaintenanceChecker={}
+ >
+
+
+ }>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Register the user's push token if one exists (does not prompt the user) */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/apps/mobile/src/components/MaintenanceScreen.tsx b/apps/mobile/src/components/MaintenanceScreen.tsx
new file mode 100644
index 0000000000..95de492770
--- /dev/null
+++ b/apps/mobile/src/components/MaintenanceScreen.tsx
@@ -0,0 +1,107 @@
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import { useCallback, useEffect, useState } from 'react';
+import { View } from 'react-native';
+import { contexts } from 'shared/analytics/constants';
+import {
+ MaintenanceContent,
+ useMaintenanceContext,
+} from 'shared/contexts/MaintenanceStatusContext';
+import { AlertIcon } from 'src/icons/AlertIcon';
+import { useEffectOnAppForeground } from 'src/utils/useEffectOnAppForeground';
+
+import { useBottomSheetModalActions } from '~/contexts/BottomSheetModalContext';
+
+import { Button } from './Button';
+import { BaseM, TitleL } from './Text';
+import { Typography } from './Typography';
+
+export function MaintenanceScreen() {
+ const { currentlyActiveMaintenanceNoticeContent } = useMaintenanceContext();
+
+ return (
+
+
+ Maintenance in Progress
+
+
+ {currentlyActiveMaintenanceNoticeContent?.message}
+
+
+ );
+}
+
+export function CheckMaintenanceOnAppForeground() {
+ const { fetchMaintenanceModeStatus } = useMaintenanceContext();
+
+ useEffectOnAppForeground(fetchMaintenanceModeStatus);
+
+ return <>>;
+}
+
+export function MaintenanceNoticeBottomSheet({ onClose }: { onClose: () => void }) {
+ const { upcomingMaintenanceNoticeContent } = useMaintenanceContext();
+
+ const handleContinuePress = useCallback(() => {
+ onClose();
+ }, [onClose]);
+
+ return (
+
+
+
+
+ Upcoming Maintenance
+
+ {upcomingMaintenanceNoticeContent?.message}
+
+
+
+ );
+}
+
+export function MaintenanceNoticeBottomSheetWrapper({
+ noticeContent,
+}: {
+ noticeContent: MaintenanceContent;
+}) {
+ const [hasSeenNotice, setHasSeenNotice] = useState('loading');
+
+ const { showBottomSheetModal, hideBottomSheetModal } = useBottomSheetModalActions();
+ const handleBottomSheetClose = useCallback(() => {
+ AsyncStorage.setItem(noticeContent.id, 'true');
+ }, [noticeContent.id]);
+
+ useEffect(() => {
+ const getNoticeStatus = async () => {
+ try {
+ const seen = await AsyncStorage.getItem(noticeContent.id);
+
+ setHasSeenNotice(seen === 'true' ? 'true' : 'false');
+ } catch (error) {}
+ };
+
+ getNoticeStatus();
+ });
+
+ useEffect(() => {
+ if (hasSeenNotice === 'false') {
+ showBottomSheetModal({
+ content: ,
+ onDismiss: handleBottomSheetClose,
+ });
+ }
+ }, [handleBottomSheetClose, hasSeenNotice, hideBottomSheetModal, showBottomSheetModal]);
+
+ return null;
+}
diff --git a/apps/mobile/src/components/Text.tsx b/apps/mobile/src/components/Text.tsx
index 83edb720af..aadbaa3319 100644
--- a/apps/mobile/src/components/Text.tsx
+++ b/apps/mobile/src/components/Text.tsx
@@ -13,16 +13,35 @@ export const TitleXS = ({ children }: { children: React.ReactNode }) => {
);
};
+export const TitleL = ({
+ children,
+ classNameOverride,
+}: {
+ children: React.ReactNode;
+ classNameOverride: string;
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
export const BaseM = ({
children,
weight = 'Regular',
+ classNameOverride,
}: {
children: React.ReactNode;
weight?: Weight;
+ classNameOverride?: string;
}) => {
return (
{children}
diff --git a/apps/mobile/src/contexts/BottomSheetModalContext.tsx b/apps/mobile/src/contexts/BottomSheetModalContext.tsx
index b025f3db9d..ffe410eb17 100644
--- a/apps/mobile/src/contexts/BottomSheetModalContext.tsx
+++ b/apps/mobile/src/contexts/BottomSheetModalContext.tsx
@@ -56,22 +56,30 @@ type BottomSheetModalProviderProps = {
type BottomSheetModal = {
content: React.ReactNode;
+ onDismiss?: () => void;
};
function BottomSheetModalProvider({ children }: BottomSheetModalProviderProps) {
- const [bottomSheetModalContent, setBottomSheetModalContent] = useState();
+ const [bottomSheetModal, setBottomSheetModal] = useState();
const bottomSheetModalRef = useRef(null);
const showBottomSheetModal = useCallback((modal: BottomSheetModal) => {
- setBottomSheetModalContent(modal);
+ setBottomSheetModal(modal);
}, []);
const hideBottomSheetModal = useCallback(() => {
bottomSheetModalRef.current?.dismiss();
// delay clearing the content to allow the modal to animate out
- setTimeout(() => setBottomSheetModalContent(undefined), 300);
+ setTimeout(() => setBottomSheetModal(undefined), 300);
}, []);
+ const handleDismissBottomSheetModal = useCallback(() => {
+ if (bottomSheetModal?.onDismiss) {
+ bottomSheetModal.onDismiss();
+ }
+ hideBottomSheetModal();
+ }, [bottomSheetModal, hideBottomSheetModal]);
+
const { bottom } = useSafeAreaPadding(); // Use this for handling safe area, if necessary
const { animatedHandleHeight, animatedSnapPoints, animatedContentHeight, handleContentLayout } =
@@ -88,18 +96,18 @@ function BottomSheetModalProvider({ children }: BottomSheetModalProviderProps) {
// immediately present the modal when content is set
useEffect(() => {
bottomSheetModalRef?.current?.present();
- }, [bottomSheetModalContent]);
+ }, [bottomSheetModal]);
return (
{children}
- {bottomSheetModalContent && (
+ {bottomSheetModal && (
@@ -108,7 +116,7 @@ function BottomSheetModalProvider({ children }: BottomSheetModalProviderProps) {
style={{ paddingBottom: bottom }}
className="p-4 flex flex-col space-y-6"
>
- {bottomSheetModalContent.content}
+ {bottomSheetModal.content}
)}
diff --git a/apps/mobile/src/icons/AlertIcon.tsx b/apps/mobile/src/icons/AlertIcon.tsx
index 382897be7e..5f5d39e1e6 100644
--- a/apps/mobile/src/icons/AlertIcon.tsx
+++ b/apps/mobile/src/icons/AlertIcon.tsx
@@ -1,8 +1,17 @@
import Svg, { Path, SvgProps } from 'react-native-svg';
export function AlertIcon(props: SvgProps) {
+ const color = props.color ?? '#F00000';
return (
-