Files
ArtisanConnectFrontend/ArtisanConnect/app/(tabs)/notice/create.jsx
2025-06-09 11:18:02 +02:00

270 lines
9.9 KiB
JavaScript

import {useState, useEffect} from "react";
import {Image, StyleSheet, KeyboardAvoidingView, Platform} from "react-native";
import {Button, ButtonText} from "@/components/ui/button";
import {FormControl} from "@/components/ui/form-control";
import {Input, InputField} from "@/components/ui/input";
import {Text} from "@/components/ui/text";
import {VStack} from "@/components/ui/vstack";
import {Textarea, TextareaInput} from "@/components/ui/textarea";
import {ScrollView} from "@gluestack-ui/themed";
import * as ImagePicker from "expo-image-picker";
import {
Select,
SelectTrigger,
SelectInput,
SelectIcon,
SelectPortal,
SelectBackdrop,
SelectContent,
SelectItem,
SelectScrollView,
} from "@/components/ui/select";
import {ChevronDownIcon} from "@/components/ui/icon";
import {useNoticesStore} from "@/store/noticesStore";
import {listCategories} from "@/api/categories";
import {useRouter} from "expo-router";
export default function CreateNotice() {
const router = useRouter();
const {addNotice, fetchNotices} = useNoticesStore();
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [price, setPrice] = useState("");
const [category, setCategory] = useState("");
const [image, setImage] = useState([]);
const [selectItems, setSelectItems] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
let isMounted = true;
const fetchSelectItems = async () => {
try {
let data = await listCategories();
if (isMounted && Array.isArray(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);
}
};
const takePicture = async () => {
const {status} = await ImagePicker.requestCameraPermissionsAsync();
if (status !== "granted") {
return;
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: false,
});
if (!result.canceled && result.assets) {
setImage(result.assets.map((asset) => asset.uri));
}
};
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: "images",
selectionLimit: 8,
allowsEditing: false,
allowsMultipleSelection: true,
aspect: [4, 3],
quality: 0.5,
});
if (!result.canceled) {
setImage(result.assets.map((asset) => asset.uri));
}
};
const clearForm = () => {
setTitle("");
setDescription("");
setPrice("");
setCategory("");
setImage([]);
setError({
title: false,
description: false,
price: false,
category: false,
});
};
return (
<KeyboardAvoidingView
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>
<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>
</KeyboardAvoidingView>
);
}