KeyboardAvoidingView

ekran dodawania
This commit is contained in:
2025-06-09 11:18:02 +02:00
parent 8e6d7ca150
commit 2b31863ed3

View File

@@ -1,263 +1,269 @@
import { useState, useEffect } from "react"; import {useState, useEffect} from "react";
import { Image, StyleSheet } from "react-native"; import {Image, StyleSheet, KeyboardAvoidingView, Platform} from "react-native";
import { Button, ButtonText } from "@/components/ui/button"; import {Button, ButtonText} from "@/components/ui/button";
import { FormControl } from "@/components/ui/form-control"; import {FormControl} from "@/components/ui/form-control";
import { Input, InputField } from "@/components/ui/input"; import {Input, InputField} from "@/components/ui/input";
import { Text } from "@/components/ui/text"; import {Text} from "@/components/ui/text";
import { VStack } from "@/components/ui/vstack"; import {VStack} from "@/components/ui/vstack";
import { Textarea, TextareaInput } from "@/components/ui/textarea"; import {Textarea, TextareaInput} from "@/components/ui/textarea";
import { ScrollView } from "@gluestack-ui/themed"; import {ScrollView} from "@gluestack-ui/themed";
import * as ImagePicker from "expo-image-picker"; import * as ImagePicker from "expo-image-picker";
import { import {
Select, Select,
SelectTrigger, SelectTrigger,
SelectInput, SelectInput,
SelectIcon, SelectIcon,
SelectPortal, SelectPortal,
SelectBackdrop, SelectBackdrop,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectScrollView, SelectScrollView,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { ChevronDownIcon } from "@/components/ui/icon"; import {ChevronDownIcon} from "@/components/ui/icon";
import { useNoticesStore } from "@/store/noticesStore"; import {useNoticesStore} from "@/store/noticesStore";
import { listCategories } from "@/api/categories"; import {listCategories} from "@/api/categories";
import { useRouter } from "expo-router"; import {useRouter} from "expo-router";
export default function CreateNotice() { export default function CreateNotice() {
const router = useRouter(); const router = useRouter();
const { addNotice, fetchNotices } = useNoticesStore(); const {addNotice, fetchNotices} = useNoticesStore();
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [price, setPrice] = useState(""); const [price, setPrice] = useState("");
const [category, setCategory] = useState(""); const [category, setCategory] = useState("");
const [image, setImage] = useState([]); const [image, setImage] = useState([]);
const [selectItems, setSelectItems] = useState([]); const [selectItems, setSelectItems] = useState([]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
let isMounted = true; let isMounted = true;
const fetchSelectItems = async () => { const fetchSelectItems = async () => {
try { try {
let data = await listCategories(); let data = await listCategories();
if (isMounted && Array.isArray(data)) { if (isMounted && Array.isArray(data)) {
setSelectItems(data); setSelectItems(data);
}
} catch (error) {
console.error("Error fetching select items:", error);
}
};
fetchSelectItems();
return () => {
isMounted = false;
};
}, []);
const [error, setError] = useState({
title: false,
description: false,
price: false,
category: false,
});
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
image: {
width: 100,
height: 100,
},
});
const handleAddNotice = async () => {
setError({
title: !title,
description: !description,
price: !price,
category: !category,
});
if (!title || !description || !price || !category) {
console.log("Error in form");
return;
}
setIsLoading(true);
try {
const result = await addNotice({
title: title,
clientId: 1,
description: description,
price: price,
category: category,
status: "INACTIVE",
image: image,
});
if (result) {
console.log("Notice created successfully with ID: ", result.noticeId);
await fetchNotices();
clearForm();
router.push("/(tabs)/dashboard/userNotices");
}
} catch (error) {
console.error("Error creating notice. Error message: ", error.message);
} finally {
setIsLoading(false);
} }
} catch (error) {
console.error("Error fetching select items:", error);
}
}; };
fetchSelectItems(); const takePicture = async () => {
const {status} = await ImagePicker.requestCameraPermissionsAsync();
if (status !== "granted") {
return;
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: false,
});
return () => { if (!result.canceled && result.assets) {
isMounted = false; setImage(result.assets.map((asset) => asset.uri));
}
}; };
}, []);
const [error, setError] = useState({ const pickImage = async () => {
title: false, let result = await ImagePicker.launchImageLibraryAsync({
description: false, mediaTypes: "images",
price: false, selectionLimit: 8,
category: false, allowsEditing: false,
}); allowsMultipleSelection: true,
aspect: [4, 3],
quality: 0.5,
});
const styles = StyleSheet.create({ if (!result.canceled) {
container: { setImage(result.assets.map((asset) => asset.uri));
flex: 1, }
alignItems: "center", };
justifyContent: "center",
},
image: {
width: 100,
height: 100,
},
});
const handleAddNotice = async () => { const clearForm = () => {
setError({ setTitle("");
title: !title, setDescription("");
description: !description, setPrice("");
price: !price, setCategory("");
category: !category, setImage([]);
}); setError({
title: false,
description: false,
price: false,
category: false,
});
};
if (!title || !description || !price || !category) { return (
console.log("Error in form"); <KeyboardAvoidingView
return; behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
} style={{flex: 1}}
keyboardVerticalOffset={Platform.OS === 'ios' ? 64 : 0}
>
<ScrollView h="$80" w="$80">
<FormControl className="p-4 border rounded-lg border-outline-300">
<VStack space="xl">
<VStack space="md">
<Text className="text-typography-500">Zdjęcia</Text>
<Button onPress={pickImage}>
<ButtonText>Wybierz zdjęcia</ButtonText>
</Button>
<Button onPress={takePicture}>
<ButtonText>Zrób zdjęcie</ButtonText>
</Button>
<Text size="sm" bold="true">
Pierwsze zdjęcie będzie zdjęciem głównym
</Text>
{image && image.length > 0 && (
<VStack space="xs" className="flex-row flex-wrap">
{image.map((img, index) => (
<Image
key={index}
source={{uri: img}}
style={styles.image}
className="m-1"
/>
))}
</VStack>
)}
</VStack>
setIsLoading(true); <VStack space="xs">
try { <Text className="text-typography-500">Tytuł</Text>
const result = await addNotice({ <Input className="min-w-[250px]" isInvalid={error.title}>
title: title, <InputField
clientId: 1, type="text"
description: description, value={title}
price: price, onChangeText={(value) => setTitle(value)}
category: category, />
status: "INACTIVE", </Input>
image: image, </VStack>
});
if (result) { <VStack space="xs">
console.log("Notice created successfully with ID: ", result.noticeId); <Text className="text-typography-500">Opis</Text>
await fetchNotices(); <Textarea
clearForm(); size="md"
className="min-w-[250px] "
isInvalid={error.description}
>
<TextareaInput
placeholder="Opisz produkt"
value={description}
onChangeText={(value) => setDescription(value)}
/>
</Textarea>
</VStack>
router.push("/(tabs)/dashboard/userNotices"); <VStack space="xs">
} <Text className="text-typography-500">Cena</Text>
} catch (error) { <Input className="min-w-[250px]" isInvalid={error.price}>
console.error("Error creating notice. Error message: ", error.message); <InputField
} finally { type="text"
setIsLoading(false); value={price}
} onChangeText={(value) => setPrice(value)}
}; />
</Input>
const takePicture = async () => { </VStack>
const { status } = await ImagePicker.requestCameraPermissionsAsync(); <VStack space="xs">
if (status !== "granted") { <Text className="text-typography-500">Kategoria</Text>
return; <Select
} onValueChange={(value) => setCategory(value)}
const result = await ImagePicker.launchCameraAsync({ isInvalid={error.category}
allowsEditing: false, >
}); <SelectTrigger variant="outline" size="md">
<SelectInput placeholder="Wybierz kategorię"/>
if (!result.canceled && result.assets) { <SelectIcon className="mr-3" as={ChevronDownIcon}/>
setImage(result.assets.map((asset) => asset.uri)); </SelectTrigger>
} <SelectPortal>
}; <SelectBackdrop/>
<SelectContent style={{maxHeight: 400}}>
const pickImage = async () => { <SelectScrollView>
let result = await ImagePicker.launchImageLibraryAsync({ {selectItems.map((item) => (
mediaTypes: "images", <SelectItem
selectionLimit: 8, key={item.value}
allowsEditing: false, label={item.label}
allowsMultipleSelection: true, value={item.value}
aspect: [4, 3], />
quality: 0.5, ))}
}); </SelectScrollView>
</SelectContent>
if (!result.canceled) { </SelectPortal>
setImage(result.assets.map((asset) => asset.uri)); </Select>
} </VStack>
}; <Button
className="mt-5 w-full"
const clearForm = () => { onPress={handleAddNotice}
setTitle(""); disabled={isLoading}
setDescription(""); >
setPrice(""); <ButtonText className="text-typography-0">Dodaj</ButtonText>
setCategory(""); </Button>
setImage([]); </VStack>
setError({ </FormControl>
title: false, </ScrollView>
description: false, </KeyboardAvoidingView>
price: false, );
category: false,
});
};
return (
<ScrollView h="$80" w="$80">
<FormControl className="p-4 border rounded-lg border-outline-300">
<VStack space="xl">
<VStack space="md">
<Text className="text-typography-500">Zdjęcia</Text>
<Button onPress={pickImage}>
<ButtonText>Wybierz zdjęcia</ButtonText>
</Button>
<Button onPress={takePicture}>
<ButtonText>Zrób zdjęcie</ButtonText>
</Button>
<Text size="sm" bold="true">
Pierwsze zdjęcie będzie zdjęciem głównym
</Text>
{image && image.length > 0 && (
<VStack space="xs" className="flex-row flex-wrap">
{image.map((img, index) => (
<Image
key={index}
source={{ uri: img }}
style={styles.image}
className="m-1"
/>
))}
</VStack>
)}
</VStack>
<VStack space="xs">
<Text className="text-typography-500">Tytuł</Text>
<Input className="min-w-[250px]" isInvalid={error.title}>
<InputField
type="text"
value={title}
onChangeText={(value) => setTitle(value)}
/>
</Input>
</VStack>
<VStack space="xs">
<Text className="text-typography-500">Opis</Text>
<Textarea
size="md"
className="min-w-[250px] "
isInvalid={error.description}
>
<TextareaInput
placeholder="Opisz produkt"
value={description}
onChangeText={(value) => setDescription(value)}
/>
</Textarea>
</VStack>
<VStack space="xs">
<Text className="text-typography-500">Cena</Text>
<Input className="min-w-[250px]" isInvalid={error.price}>
<InputField
type="text"
value={price}
onChangeText={(value) => setPrice(value)}
/>
</Input>
</VStack>
<VStack space="xs">
<Text className="text-typography-500">Kategoria</Text>
<Select
onValueChange={(value) => setCategory(value)}
isInvalid={error.category}
>
<SelectTrigger variant="outline" size="md">
<SelectInput placeholder="Wybierz kategorię" />
<SelectIcon className="mr-3" as={ChevronDownIcon} />
</SelectTrigger>
<SelectPortal>
<SelectBackdrop />
<SelectContent style={{ maxHeight: 400 }}>
<SelectScrollView>
{selectItems.map((item) => (
<SelectItem
key={item.value}
label={item.label}
value={item.value}
/>
))}
</SelectScrollView>
</SelectContent>
</SelectPortal>
</Select>
</VStack>
<Button
className="mt-5 w-full"
onPress={handleAddNotice}
disabled={isLoading}
>
<ButtonText className="text-typography-0">Dodaj</ButtonText>
</Button>
</VStack>
</FormControl>
</ScrollView>
);
} }