matiru

Blockchain-Based Supply Chain Transparency for Agricultural Produce

frontend/screens/Distributor.js (6482B)


  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 DistributorScreen({ 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 [reason, setReason] = useState("");
 31  const [newStatus, setNewStatus] = useState("");
 32  const [storageConditions, setStorageConditions] = useState("");
 33
 34  const resetCommon = () => {
 35    setProduceId("");
 36  };
 37
 38  const updateLocation = async () => {
 39    try {
 40      await api.updateLocation(
 41        {
 42          produceId,
 43          actorId: userId,
 44          newLocation: location,
 45        },
 46        token
 47      );
 48      Alert.alert("Location Updated", "Location updated successfully");
 49      resetCommon();
 50      setLocation("");
 51      setActive(null);
 52    } catch (err) {
 53      Alert.alert("Error", err.message);
 54    }
 55  };
 56
 57  const transferOwnership = async ({
 58    produceId,
 59    newOwnerId,
 60    qty,
 61    salePrice,
 62    onComplete,
 63  }) => {
 64    if (!produceId || !newOwnerId || !qty)
 65      return Alert.alert(
 66        "Error",
 67        "Please provide Produce ID, New Owner ID, and Quantity."
 68      );
 69    try {
 70      await api.transferOwnership(
 71        {
 72          produceId,
 73          newOwnerId,
 74          qty: parseFloat(qty),
 75          salePrice: parseFloat(salePrice),
 76        },
 77        token
 78      );
 79      Alert.alert("Transferred", "Ownership transferred successfully");
 80      onComplete();
 81      setActive(null);
 82    } catch (err) {
 83      Alert.alert("Error", err.message);
 84    }
 85  };
 86
 87  const markAsUnavailable = async () => {
 88    try {
 89      await api.markAsUnavailable(
 90        { produceId, actorId: userId, reason, newStatus },
 91        token
 92      );
 93      Alert.alert("Marked Unavailable", "Produce marked as unavailable");
 94      resetCommon();
 95      setReason("");
 96      setNewStatus("");
 97      setActive(null);
 98    } catch (err) {
 99      Alert.alert("Error", err.message);
100    }
101  };
102
103  const updateStorageConditions = async () => {
104    try {
105      await api.updateDetails(
106        {
107          produceId,
108          actorId: userId,
109          details: {
110            storageConditions: storageConditions
111              ? storageConditions.split(",").map((c) => c.trim())
112              : [],
113          },
114        },
115        token
116      );
117      Alert.alert("Updated", "Storage conditions updated successfully");
118      resetCommon();
119      setStorageConditions("");
120      setActive(null);
121    } catch (err) {
122      Alert.alert("Error", err.message);
123    }
124  };
125
126  return (
127    <SafeAreaView style={styles.container}>
128      <ScreenHeader
129        title="Distributor Dashboard"
130        navigation={navigation}
131        role="Distributor"
132      />
133      <ScrollView>
134        <View style={styles.actionGrid}>
135          <ActionButton
136            icon="map-marker"
137            text="Update Location"
138            onPress={() => setActive("location")}
139          />
140          <ActionButton
141            icon="cash"
142            text="Transfer Ownership"
143            onPress={() => setActive("transfer")}
144          />
145          <ActionButton
146            icon="cancel"
147            text="Mark Unavailable"
148            onPress={() => setActive("remove")}
149          />
150          <ActionButton
151            icon="thermometer"
152            text="Update Storage"
153            onPress={() => setActive("storage")}
154          />
155        </View>
156
157        {active === "location" && (
158          <View>
159            <Scanner value={produceId} onChange={setProduceId} />
160            <LocationPicker value={location} onChange={setLocation} />
161            <TouchableOpacity
162              style={styles.primaryButton}
163              onPress={updateLocation}
164            >
165              <Text style={styles.buttonText}>Update Location</Text>
166            </TouchableOpacity>
167          </View>
168        )}
169
170        {active === "transfer" && (
171          <TransferOwnershipForm onSubmit={transferOwnership} />
172        )}
173
174        {active === "remove" && (
175          <View>
176            <Scanner value={produceId} onChange={setProduceId} />
177            <TextInput
178              style={styles.input}
179              placeholder="Reason"
180              value={reason}
181              onChangeText={setReason}
182            />
183            <TextInput
184              style={styles.input}
185              placeholder="New Status (e.g. Removed, Missing)"
186              value={newStatus}
187              onChangeText={setNewStatus}
188            />
189            <TouchableOpacity
190              style={styles.primaryButton}
191              onPress={markAsUnavailable}
192            >
193              <Text style={styles.buttonText}>Mark as Unavailable</Text>
194            </TouchableOpacity>
195          </View>
196        )}
197
198        {active === "storage" && (
199          <View>
200            <Scanner value={produceId} onChange={setProduceId} />
201            <TextInput
202              style={styles.input}
203              placeholder="Storage Conditions (comma separated)"
204              value={storageConditions}
205              onChangeText={setStorageConditions}
206            />
207            <TouchableOpacity
208              style={styles.primaryButton}
209              onPress={updateStorageConditions}
210            >
211              <Text style={styles.buttonText}>Update Storage Conditions</Text>
212            </TouchableOpacity>
213          </View>
214        )}
215      </ScrollView>
216
217      <View style={{ padding: 12 }}>
218        <TouchableOpacity
219          style={styles.secondaryButton}
220          onPress={() =>
221            navigation.navigate("Inventory", {
222              userId,
223              role: "Distributor",
224            })
225          }
226        >
227          <Text style={styles.secondaryButtonText}>View Inventory</Text>
228        </TouchableOpacity>
229      </View>
230    </SafeAreaView>
231  );
232}