diff --git a/api/locations.jsx b/api/locations.jsx index 228a605..5c03e50 100644 --- a/api/locations.jsx +++ b/api/locations.jsx @@ -6,15 +6,43 @@ export async function listLocations() { try { const response = await axios.get(`${API_URL}/locations/all`); if (!response) { - throw new Error("No locations found"); + return "No locations found"; } - return response.data; + + // Нормализуем изображения в полученных данных + return response.data.map(location => ({ + ...location, + imageSource: normalizeImageSource(location.image) + })); } catch (error) { console.error("Error fetching locations:", error); throw error; } } +const normalizeImageSource = (image) => { + if (!image) return null; + + // Проверка, является ли изображение URL + if (typeof image === 'string') { + // Если строка начинается с http или https, это URL + if (image.startsWith('http://') || image.startsWith('https://')) { + return { uri: image }; + } + + // Проверка на base64 + if (image.startsWith('data:image')) { + return { uri: image }; + } else if (image.length > 100) { + // Предполагаем, что это base64 без префикса + return { uri: `data:image/jpeg;base64,${image}` }; + } + } + + // Возвращаем null для неправильного формата + return null; +} + export async function getLocation(id) { try { const location = await axios.get(`${API_URL}/locations/${id}`); @@ -22,7 +50,7 @@ export async function getLocation(id) { throw new Error("Location not found"); } - return location.data; + return [...location.data, {image: normalizeImageSource(location.image)}]; } catch (error) { console.error("Error fetching location:", error); throw error; diff --git a/app/(tabs)/add.jsx b/app/(tabs)/add.jsx index 99c0cf2..1c76fe9 100644 --- a/app/(tabs)/add.jsx +++ b/app/(tabs)/add.jsx @@ -1,172 +1,239 @@ -import { useState } from "react"; +import {useState} from "react"; import { - StyleSheet, - Platform, - KeyboardAvoidingView, - ScrollView, - Image, + StyleSheet, + Platform, + KeyboardAvoidingView, + ScrollView, + Image, + View, } from "react-native"; -import { TextInput, Button, Snackbar } from "react-native-paper"; -import { requestCameraPermissionsAsync, launchCameraAsync } from 'expo-image-picker'; +import {TextInput, Button, Snackbar, Text} from "react-native-paper"; +import {requestCameraPermissionsAsync, launchCameraAsync} from 'expo-image-picker'; import useLocationStore from "@/locationStore"; export default function FormScreen() { - const [formData, setFormData] = useState({ - name: "", - description: "", - image: "", - area: 0, - population: 0, - }); - const [message, setMessage] = useState(""); - const [visible, setVisible] = useState(false); - const [picture, setPicture] = useState(null); - - const addLocation = useLocationStore((state) => state.addLocation); - - const handleAddLocation = async () => { - if ( - formData.name && - formData.description && - formData.image && - formData.area && - formData.population - ) { - const newLocation = { - id: Date.now(), - name: formData.name, - description: formData.description, - image: formData.image, - area: parseFloat(formData.area), - population: parseInt(formData.population), - }; - - const added = await addLocation(newLocation); - setFormData({ + const [formData, setFormData] = useState({ name: "", description: "", image: "", area: 0, population: 0, - }); - if (added != null) { - setMessage("Lokalizacja została dodana!"); - setVisible(true); - } else { - setMessage("Wystąpił błąd podczas dodawania lokalizacji!"); - setVisible(true); - } - } else { - setMessage("Wypełnij wszystkie pola!"); - setVisible(true); - } - }; - - const takePicture = async () => { - const {status} = await requestCameraPermissionsAsync(); - if (status !== 'granted') { - return; - } - const result = await launchCameraAsync({ - allowsEditing: false, }); + const [message, setMessage] = useState(""); + const [visible, setVisible] = useState(false); + const [picture, setPicture] = useState(null); + const [imageMethod, setImageMethod] = useState(null); // null, 'link' или 'camera' - if (!result.canceled && result.assets && result.assets.length > 0) { - setPicture(result.assets[0].uri); + const addLocation = useLocationStore((state) => state.addLocation); + + const handleAddLocation = async () => { + if ( + formData.name && + formData.description && + formData.image && + formData.area && + formData.population + ) { + const newLocation = { + id: Date.now(), + name: formData.name, + description: formData.description, + image: formData.image, + area: parseFloat(formData.area), + population: parseInt(formData.population), + }; + + const added = await addLocation(newLocation); + setFormData({ + name: "", + description: "", + image: "", + area: 0, + population: 0, + }); + setPicture(null); + setImageMethod(null); + + if (added != null) { + setMessage("Lokalizacja została dodana!"); + setVisible(true); + } else { + setMessage("Wystąpił błąd podczas dodawania lokalizacji!"); + setVisible(true); + } + } else { + setMessage("Wypełnij wszystkie pola!"); + console.log(formData); + setVisible(true); + } + }; + + const takePicture = async () => { + const {status} = await requestCameraPermissionsAsync(); + if (status !== 'granted') { + setMessage("Brak uprawnień do kamery!"); + setVisible(true); + return; + } + const result = await launchCameraAsync({ + allowsEditing: false, + base64: true, + }); + + if (!result.canceled && result.assets && result.assets.length > 0) { + const image = result.assets[0]; + setPicture(image.uri); + console.log(image.base64); + setFormData({...formData, image: image.base64}); + } } - } - return ( - - - setVisible(false)} - duration={3000} + const selectImageMethod = (method) => { + setImageMethod(method); + if (method === 'camera') { + takePicture() + } else { + setFormData({...formData, image: ""}); + setPicture(null); + } + } + + return ( + - {message} - - setFormData({ ...formData, name: e })} - /> - setFormData({ ...formData, description: e })} - /> - setFormData({ ...formData, image: e })} - /> - setFormData({ ...formData, area: e })} - /> - setFormData({ ...formData, population: e })} - /> - - - {picture && ( - - )} - - - ); + + setVisible(false)} + duration={3000} + > + {message} + + Jak chcesz dodać zdjęcie? + + + + + + {imageMethod === 'link' && ( + setFormData({...formData, image: e})} + /> + )} + + + {picture && ( + + + + )} + setFormData({...formData, name: e})} + /> + setFormData({...formData, description: e})} + /> + setFormData({...formData, area: e})} + /> + setFormData({...formData, population: e})} + /> + + + + ); } const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#25292e", - justifyContent: "flex-start", - alignItems: "center", - }, - image: { - width: 100, - height: 100, - borderStyle: "solid", - borderColor: "#fff", - borderWidth: 1, - }, -}); + container: { + flex: 1, + backgroundColor: "#25292e", + justifyContent: "flex-start", + alignItems: "center", + padding: 10, + }, + imageContainer: { + width: "100%", + alignItems: "flex-start", + marginVertical: 10, + }, + image: { + width: 150, + height: 150, + borderStyle: "solid", + borderColor: "#fff", + borderWidth: 1, + borderRadius: 5, + }, + imageMethodButtons: { + flexDirection: 'row', + justifyContent: 'space-between', + width: '100%', + marginVertical: 10, + }, + methodButton: { + flex: 1, + marginHorizontal: 5, + }, + label: { + marginTop: 10, + marginBottom: 10, + color: "#fff", + verticalAlign: "middle", + textAlign: "center", + } +}); \ No newline at end of file diff --git a/app/(tabs)/index.jsx b/app/(tabs)/index.jsx index a5d3d01..3f32506 100644 --- a/app/(tabs)/index.jsx +++ b/app/(tabs)/index.jsx @@ -20,10 +20,10 @@ export default function Index() { keyExtractor={(item) => item.id.toString()} renderItem={({ item }) => ( - + {item.name} diff --git a/app/location/[id].jsx b/app/location/[id].jsx index 9442be1..683cd19 100644 --- a/app/location/[id].jsx +++ b/app/location/[id].jsx @@ -1,4 +1,4 @@ -import { View, ScrollView, StyleSheet, ActivityIndicator } from "react-native"; +import { View, ScrollView, StyleSheet } from "react-native"; import { useEffect } from "react"; import { useTheme, Text, Card } from "react-native-paper"; import { useLocalSearchParams } from "expo-router"; @@ -33,7 +33,7 @@ export default function Location() {