Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions components/NetworkDetector/NetworkDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ import {Text, View} from "react-native";
*/
export default function NetworkDetector() {
const [connection, setConnection] = useState<'online' | 'offline' | null>(null);

//for animation we need to avoid safeArea
const [isShowSafeArea, setIsShowSafeArea] = React.useState(false);
const handleSafeAreaVisibility = React.useCallback((visible: boolean) => {
setIsShowSafeArea(visible);
}, []);
useEffect(() => {
return NetInfo.addEventListener(state => {

const unsubscribe = NetInfo.addEventListener((state) => {
state.isConnected ? setConnection('online') : setConnection('offline')
});
return () => {
unsubscribe();
};
}, []);

if (connection === null) {
Expand All @@ -30,7 +38,9 @@ export default function NetworkDetector() {
// extra logic for this. Shouldn't be too hard though we would just add
// hasBeenOnline which gets set to true once we have the first isConnected
// event. After that we mount online and display it for the first time.

if (connection === "online" && !isShowSafeArea) {
return <Online handleSafeAreaVisibility={handleSafeAreaVisibility} />;
}
return (
<SafeAreaContainer>
<>
Expand All @@ -39,10 +49,11 @@ export default function NetworkDetector() {
<Text>Detecting network state .... </Text>
</View>
)}
{connection === 'online' && <Online/>}
{connection === 'offline' && <Offline/>}
{connection === "online" && (
<Online handleSafeAreaVisibility={handleSafeAreaVisibility} />
)}
{connection === "offline" && <Offline />}
</>
</SafeAreaContainer>
)

);
}
11 changes: 6 additions & 5 deletions components/Online/Online.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from "react";
import Webapp from "@/components/Webapp/Webapp";

export default function Online() {

type OnlineProps = {
handleSafeAreaVisibility: (showSafeArea: boolean) => void;
};
export default function Online({ handleSafeAreaVisibility }: OnlineProps) {
// true if we are in the auth stage... at which we unmount the webview and
// re-mount the main view.

return (
<>
<Webapp/>
<Webapp handleSafeAreaVisibility={handleSafeAreaVisibility} />
</>
)
);
}
48 changes: 41 additions & 7 deletions components/Webapp/Webapp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {useURL} from "expo-linking";
import {useRouter} from "expo-router";
import {NotificationsListener} from "@/components/Webapp/NotificationsListener";
import * as Notifications from "expo-notifications";

import AsyncStorage from "@react-native-async-storage/async-storage";
/**
* Enable a fake URL bar to debug the URL we're visiting.
*/
Expand Down Expand Up @@ -41,8 +41,10 @@ type TouchStartGesture = {
start: number;
startY: 0;
}

export default function Webapp() {
type WebAppProps = {
handleSafeAreaVisibility: (showSafeArea: boolean) => void;
};
export default function Webapp({handleSafeAreaVisibility}:WebAppProps) {

const [userInfo, setUserInfo] = useState<UserInfo | undefined>(undefined)
const expoURL = useURL()
Expand All @@ -54,7 +56,7 @@ export default function Webapp() {
const [error, setError] = useState<string | undefined>(undefined);
const webViewRef = useRef<WebView | null>(null);
const [notificationStatus, setNotificationStatus] = useState<Notifications.PermissionStatus | undefined>(undefined);

const [isFirstLaunch, setIsFirstLaunch] = useState<boolean | null>(null);
const notificationsListener = useMemo(() => {

const postMessage = (msg: string) => {
Expand Down Expand Up @@ -107,6 +109,25 @@ export default function Webapp() {
return () => backHandler.remove();
}, []);

useEffect(() => {
const checkFirstLaunch = async () => {
try {
const firstTime = await AsyncStorage.getItem("isFirstTime");
if (firstTime === null) {
setIsFirstLaunch(true);
const newUrl = `${url}/onboarding`;
setUrl(newUrl);
await AsyncStorage.setItem("isFirstTime", "false");
} else {
setIsFirstLaunch(false);
}
} catch (error) {
console.error("Error checking first launch:", error);
}
};

checkFirstLaunch();
}, []);
const changeURL = useCallback((url: string) => {
setUrl(url)
}, []);
Expand Down Expand Up @@ -177,7 +198,17 @@ export default function Webapp() {
}
return true; // Allow the WebView to load the URL
}, []);

const handleNavigationStateChange = (newNavState: any) => {
const { url } = newNavState;
// Hide WebView for onboarding route
if (url.includes("/onboarding")) {
handleSafeAreaVisibility(false);
}
// Show WebView for dashboard route
else if (!url.includes("/onboarding")) {
handleSafeAreaVisibility(true);
}
};
if (error) {
return <Error error={error} onRetry={retryWebview}/>;
}
Expand Down Expand Up @@ -220,7 +251,10 @@ export default function Webapp() {
onError={(event) => setError(event.nativeEvent.description)}
allowsBackForwardNavigationGestures={true}
javaScriptCanOpenWindowsAutomatically={true}
style={{ flex: 1 }} />
style={{ flex: 1 }}
onNavigationStateChange={handleNavigationStateChange}

/>
)}

{notificationStatus === 'granted' && userInfo && userInfo.userId !== 0 && (
Expand Down Expand Up @@ -255,4 +289,4 @@ const Styles = {
textContainer: {
backgroundColor: 'red', color: 'white'
}
} as const
} as const
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@expo/vector-icons": "^14.0.2",
"@knocklabs/expo": "^0.2.2",
"@magic-sdk/react-native-expo": "^29.21.0",
"@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/bottom-tabs": "^7.0.0",
"@react-navigation/native": "^7.0.0",
Expand Down