199 lines
5 KiB
TypeScript
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>
|
|
);
|
|
}
|