beerbuddy/react-native/app/index.tsx
2023-12-11 18:44:38 -08:00

139 lines
4.3 KiB
TypeScript

import { useState, useRef, useEffect } from "react";
import { useWindowDimensions, Alert, StyleSheet } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import WebView, { WebViewMessageEvent } from "react-native-webview";
import { useAssets } from "expo-asset";
import * as Location from "expo-location";
import { useNavigation, router } from "expo-router";
export default function () {
const [assets] = useAssets([require("../assets/index.html")]);
const [htmlString, setHtmlString] = useState<string>();
const dimensions = useWindowDimensions();
const webViewRef = useRef<WebView | null>();
const navigation = useNavigation();
const messageHandler = (event: WebViewMessageEvent) => {
if (typeof event.nativeEvent.data == "string") {
const message = event.nativeEvent.data;
if (message === "new pin start") {
Alert.alert(
"New Pin",
`Please select location for new pin then press "OK"`,
[
{
text: "OK",
onPress: () => {
// makes injectable javascript string
const str = `window.placePin(); true()`;
// passes string to webview - there it is handled by OpenLayers to change the current location
webViewRef.current?.injectJavaScript(str);
},
},
]
);
} else if (message.startsWith(`create@`)) {
const coords = message.slice(7).split(",");
router.push({
pathname: "./store/new/[coords]",
params: {
coords: `${coords[0]}+${coords[1]}`,
},
});
} else if (message.startsWith(`open@`)) {
const coords = message.slice(5).split(",");
router.push({
pathname: "./store/[coords]",
params: {
coords: `${coords[0]}+${coords[1]}`,
},
});
} else if (message.startsWith(`search@`)) {
const chunks = message.slice(7).split(":");
const coords = chunks[0].split(",");
router.push({
pathname: "./search/[slug]",
params: {
slug: `${coords[0]}+${coords[1]}+${chunks[1]}`,
},
});
}
}
};
const getLocation = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") return;
const location = await Location.getCurrentPositionAsync({
distanceInterval: 0, // for IOS
accuracy: Location.Accuracy.High,
timeInterval: 3000, // for Android
});
// makes injectable javascript string
const str = `window.passLocation(${location.coords.longitude}, ${location.coords.latitude}); true()`;
// passes string to webview - there it is handled by OpenLayers to change the current location
webViewRef.current?.injectJavaScript(str);
};
// refresh on navigating back to this page
useEffect(() => {
// remove header
navigation.setOptions({ headerShown: false });
const focusHandler = navigation.addListener("focus", () => {
webViewRef.current?.reload();
getLocation();
});
return focusHandler;
}, [navigation]);
// loads assets
useEffect(() => {
if (assets) {
fetch(assets[0].localUri || "")
.then((res) => res.text())
.then((html) => setHtmlString(html));
}
}, [assets]);
// exits if no map passed in
if (!htmlString) {
return <></>;
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
});
return (
<SafeAreaProvider>
<SafeAreaView style={styles.container}>
<WebView
ref={(currentRef) => (webViewRef.current = currentRef)}
injectedJavascript=""
source={{
html: htmlString,
}}
javaScriptEnabled
style={{
width: dimensions.width,
height: dimensions.height,
}}
scrollEnabled={false}
overScrollMode="never"
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
scalesPageToFit={false}
containerStyle={{
flex: 1,
}}
onMessage={messageHandler}
webviewDebuggingEnabled={true}
/>
</SafeAreaView>
</SafeAreaProvider>
);
}