matiru
Blockchain-Based Supply Chain Transparency for Agricultural Producegit clone https://github.com/maydayv7/matiru
frontend/components/ImageUploader.js (2847B)
1import { useState, forwardRef, useImperativeHandle } from "react";
2import {
3 ActivityIndicator,
4 Alert,
5 Button,
6 Image,
7 Platform,
8 Text,
9 View,
10} from "react-native";
11import { launchImageLibraryAsync } from "expo-image-picker";
12import { api } from "../services/api";
13import { colors } from "../styles";
14
15const ImageUploader = forwardRef(({ token }, ref) => {
16 const [imageAsset, setImageAsset] = useState(null);
17 const [isUploading, setIsUploading] = useState(false);
18
19 useImperativeHandle(ref, () => ({
20 upload: async () => {
21 if (!imageAsset) return null;
22 setIsUploading(true);
23 try {
24 const imageUrl = await handleUpload();
25 return imageUrl;
26 } catch (error) {
27 Alert.alert("Upload Failed", error.message);
28 return null;
29 } finally {
30 setIsUploading(false);
31 }
32 },
33 reset: () => {
34 setImageAsset(null);
35 setIsUploading(false);
36 },
37 }));
38
39 const pickImage = async () => {
40 const result = await launchImageLibraryAsync({
41 allowsEditing: true,
42 quality: 0.7,
43 mediaTypes: "Images",
44 });
45 if (!result.canceled) setImageAsset(result.assets[0]);
46 };
47
48 const handleUpload = async () => {
49 const data = new FormData();
50 if (Platform.OS === "web") {
51 const response = await fetch(imageAsset.uri);
52 const blob = await response.blob();
53 const fileName = imageAsset.fileName || `web-image-${Date.now()}.jpg`;
54 data.append("image", blob, fileName);
55 } else {
56 data.append("image", {
57 uri: imageAsset.uri,
58 type: imageAsset.mimeType || "image/jpeg",
59 name:
60 imageAsset.fileName ||
61 imageAsset.uri.split("/").pop() ||
62 `image-${Date.now()}.jpg`,
63 });
64 }
65 const responseData = await api.uploadImage(data, token);
66 return responseData.url;
67 };
68
69 const removeImage = () => {
70 setImageAsset(null);
71 };
72
73 return (
74 <View style={{ marginVertical: 10 }}>
75 {imageAsset && (
76 <View>
77 <Image
78 source={{ uri: imageAsset.uri }}
79 style={{
80 width: "100%",
81 height: 200,
82 resizeMode: "contain",
83 marginBottom: 10,
84 }}
85 />
86 <Button
87 title="Remove Image"
88 color={colors.danger}
89 onPress={removeImage}
90 />
91 </View>
92 )}
93
94 {isUploading ? (
95 <View style={{ alignItems: "center", padding: 20 }}>
96 <ActivityIndicator size="large" color={colors.darkGreen} />
97 <Text>Uploading...</Text>
98 </View>
99 ) : (
100 !imageAsset && (
101 <Button
102 title="Pick Image"
103 color={colors.darkGreen}
104 onPress={pickImage}
105 />
106 )
107 )}
108 </View>
109 );
110});
111
112export default ImageUploader;