matiru
Blockchain-Based Supply Chain Transparency for Agricultural Producegit clone https://github.com/maydayv7/matiru
frontend/screens/Retailer.js (5370B)
1import { useContext, useState } from "react";
2import {
3 Alert,
4 ScrollView,
5 Text,
6 TextInput,
7 TouchableOpacity,
8 View,
9} from "react-native";
10import { SafeAreaView } from "react-native-safe-area-context";
11
12import ScreenHeader from "../components/ScreenHeader";
13import ActionButton from "../components/ActionButton";
14import Scanner from "../components/Scanner";
15import LocationPicker from "../components/LocationPicker";
16import TransferOwnershipForm from "../components/TransferOwnershipForm";
17
18import { api } from "../services/api";
19import styles from "../styles";
20import { AuthContext } from "../AuthContext";
21
22export default function RetailerScreen({ navigation, route }) {
23 const { user } = useContext(AuthContext);
24 const userId = route.params?.userId || user?.id;
25 const token = user?.token;
26
27 const [active, setActive] = useState(null);
28 const [produceId, setProduceId] = useState("");
29 const [location, setLocation] = useState("");
30 const [pricePerUnit, setPricePerUnit] = useState("");
31 const [storageConditions, setStorageConditions] = useState("");
32
33 const resetCommon = () => {
34 setProduceId("");
35 };
36
37 const updateLocation = async () => {
38 try {
39 await api.updateLocation(
40 {
41 produceId,
42 actorId: userId,
43 newLocation: location,
44 },
45 token
46 );
47 Alert.alert("Location Updated", "Location updated successfully");
48 resetCommon();
49 setLocation("");
50 setActive(null);
51 } catch (err) {
52 Alert.alert("Error", err.message);
53 }
54 };
55
56 const transferOwnership = async ({
57 produceId,
58 newOwnerId,
59 qty,
60 salePrice,
61 onComplete,
62 }) => {
63 if (!produceId || !newOwnerId || !qty)
64 return Alert.alert(
65 "Error",
66 "Please provide Produce ID, New Owner ID, and Quantity."
67 );
68 try {
69 await api.transferOwnership(
70 {
71 produceId,
72 newOwnerId,
73 qty: parseFloat(qty),
74 salePrice: parseFloat(salePrice),
75 },
76 token
77 );
78 Alert.alert("Transferred", "Transfer successful");
79 onComplete();
80 setActive(null);
81 } catch (err) {
82 Alert.alert("Error", err.message);
83 }
84 };
85
86 const updateDetails = async () => {
87 try {
88 await api.updateDetails(
89 {
90 produceId,
91 actorId: userId,
92 details: {
93 pricePerUnit: parseFloat(pricePerUnit),
94 storageConditions: storageConditions
95 ? storageConditions.split(",").map((c) => c.trim())
96 : [],
97 },
98 },
99 token
100 );
101 Alert.alert("Updated Details", "Produce details updated successfully");
102 resetCommon();
103 setPricePerUnit("");
104 setStorageConditions("");
105 setActive(null);
106 } catch (err) {
107 Alert.alert("Error", err.message);
108 }
109 };
110
111 return (
112 <SafeAreaView style={styles.container}>
113 <ScreenHeader
114 title="Retailer Dashboard"
115 navigation={navigation}
116 role="Retailer"
117 />
118 <ScrollView>
119 <View style={styles.actionGrid}>
120 <ActionButton
121 icon="map-marker"
122 text="Update Location"
123 onPress={() => setActive("location")}
124 />
125 <ActionButton
126 icon="cash"
127 text="Sell / Transfer"
128 onPress={() => setActive("transfer")}
129 />
130 <ActionButton
131 icon="update"
132 text="Update Details"
133 onPress={() => setActive("update")}
134 />
135 </View>
136
137 {active === "location" && (
138 <View>
139 <Scanner value={produceId} onChange={setProduceId} />
140 <LocationPicker value={location} onChange={setLocation} />
141 <TouchableOpacity
142 style={styles.primaryButton}
143 onPress={updateLocation}
144 >
145 <Text style={styles.buttonText}>Update Location</Text>
146 </TouchableOpacity>
147 </View>
148 )}
149
150 {active === "transfer" && (
151 <TransferOwnershipForm onSubmit={transferOwnership} />
152 )}
153
154 {active === "update" && (
155 <View>
156 <Scanner value={produceId} onChange={setProduceId} />
157 <TextInput
158 style={styles.input}
159 placeholder="New Price Per Unit"
160 keyboardType="numeric"
161 value={pricePerUnit}
162 onChangeText={setPricePerUnit}
163 />
164 <TextInput
165 style={styles.input}
166 placeholder="Storage Conditions (comma separated)"
167 value={storageConditions}
168 onChangeText={setStorageConditions}
169 />
170 <TouchableOpacity
171 style={styles.primaryButton}
172 onPress={updateDetails}
173 >
174 <Text style={styles.buttonText}>Update</Text>
175 </TouchableOpacity>
176 </View>
177 )}
178 </ScrollView>
179
180 <View style={{ padding: 12 }}>
181 <TouchableOpacity
182 style={styles.secondaryButton}
183 onPress={() =>
184 navigation.navigate("Inventory", {
185 userId,
186 role: "Retailer",
187 })
188 }
189 >
190 <Text style={styles.secondaryButtonText}>View Inventory</Text>
191 </TouchableOpacity>
192 </View>
193 </SafeAreaView>
194 );
195}