beerbuddy/react-native/app/store/[coords].tsx
2023-12-11 18:44:38 -08:00

199 lines
5 KiB
TypeScript

import { useEffect, useState } from "react";
import {
TouchableOpacity,
Image,
Text,
View,
ScrollView,
Alert,
} from "react-native";
import {
useNavigation,
Stack,
useLocalSearchParams,
router,
} from "expo-router";
import * as ImagePicker from "expo-image-picker";
import * as FileSystem from "expo-file-system";
import { styled } from "nativewind";
import utmObj from "utm-latlng";
import mime from "mime";
import StoreItem from "../../components/StoreItem";
declare function isNaN(x: string | number): boolean;
interface storeItemInterface {
key: String;
lastUpdated: String;
name: String;
perFloz: Number;
price: Number;
store: String;
volumeFloz: Number;
}
export default function () {
const [storeKey, setStoreKey] = useState("");
const [storeName, setStoreName] = useState("");
const [storeItems, setStoreItems] = useState([]);
const [image, setImage] = useState(null);
const navigation = useNavigation();
const utm = new utmObj();
const StyledText = styled(Text);
const coords = useLocalSearchParams().coords.toString().split("%2B");
const lon = coords[0];
const lat = coords[1];
const utmCoords = utm.convertLatLngToUtm(lat, lon, 5);
// get store information
const getStore = async () => {
const res = await fetch(
`${process.env.EXPO_PUBLIC_BACKEND_URL}/?` +
new URLSearchParams({
easting: utmCoords.Easting,
northing: utmCoords.Northing,
zone: utmCoords.ZoneNumber,
})
);
if (!res.ok)
return Alert.alert(
"Error!",
"Server error. Please report to ak95@riseup.net"
);
const json = await res.json();
setStoreName(json.name);
setStoreKey(json.key.toString());
const items = json.items.map((item: storeItemInterface, index: number) => {
const date = new Date(item.lastUpdated.replace(" ", "T") + "Z");
return (
<View className="flex flex-row w-[100vw]" key={index}>
<StoreItem
name={item.name.toString()}
volume={item.volumeFloz.toString()}
price={item.price.toString()}
date={date}
storeKey={item.store.toString()}
/>
</View>
);
});
setStoreItems(items);
const imageURL = `${process.env.EXPO_PUBLIC_BACKEND_URL}/img?imageKey=${storeKey}`;
await FileSystem.downloadAsync(
imageURL,
FileSystem.documentDirectory + storeKey
)
.then(({ uri }) => {
setImage(uri);
})
.catch(() => {});
};
useEffect(() => {
getStore();
}, []);
const uploadImage = async () => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
setImage(result.assets[0]);
const formData = new FormData();
formData.append("file", {
uri: image.uri,
type: mime.getType(image.uri),
name: "file",
} as unknown as File);
const res = await fetch(
`${process.env.EXPO_PUBLIC_BACKEND_URL}/?` +
new URLSearchParams({
storeKey: storeKey,
}),
{
method: "PUT",
body: formData,
mode: "cors",
redirect: "follow",
}
);
if (!res.ok) {
Alert.alert("Error!", "Server error! Please report to ak95@riseup.net");
}
}
};
const handleAddItem = () => {
router.push({
pathname: "/item/new/[storeKey]",
params: {
storeKey: storeKey,
},
});
};
useEffect(() => {
// remove header
const focusHandler = navigation.addListener("focus", () => {
getStore();
});
return focusHandler;
}, [navigation]);
return (
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
<View
style={{
flex: 1,
alignItems: "center",
height: "100%",
}}
>
<Stack.Screen
options={{
title: storeName,
}}
/>
<TouchableOpacity onPress={uploadImage}>
{image ? (
<Image source={{ uri: image }} className="h-[33vh] w-[100vw]" />
) : (
<Image
source={require("../../assets/images/photo_placeholder.png")}
className="h-[33vh] w-[100vw]"
/>
)}
</TouchableOpacity>
<View className="flex w-[100vw] py-6 justify-center items-center border-b dark:border-white">
<StyledText className="text-2xl dark:text-white">
{storeName}
</StyledText>
</View>
<ScrollView style={{ flex: 1 }}>{storeItems}</ScrollView>
<TouchableOpacity
className="px-8 py-4 my-4 bg-green-700 rounded"
onPress={handleAddItem}
>
<StyledText className="text-white text-center text-2xl">
Add
</StyledText>
</TouchableOpacity>
</View>
</ScrollView>
);
}