matiru

Blockchain-Based Supply Chain Transparency for Agricultural Produce
commit 8e01d04de7f2ee3c3f2c9394129fa634d5cfa378
parent e1e3e3debcf35fc84e6096a2f40c1b155e8c3743
Author: maydayv7 <maydayv7@gmail.com>
Date:   Sun,  5 Oct 2025 15:54:59 +0530

fix(frontend): Search overflow

Diffstat:
Mchaincode/index.js | 6+++---
Mfrontend/components/LocationPicker.js | 2+-
Mfrontend/components/Scanner.js | 2+-
Mfrontend/components/ScreenHeader.js | 2+-
Mfrontend/screens/Search.js | 237+++++++++++++++++++++++++++++++++++++++++++------------------------------------
5 files changed, 136 insertions(+), 113 deletions(-)

diff --git a/chaincode/index.js b/chaincode/index.js @@ -99,11 +99,11 @@ class ProduceContract extends Contract { } // Update location - async updateLocation(ctx, produceId, actorId, newLocationOrInTransit) { + async updateLocation(ctx, produceId, actorId, newLocation) { const produce = await this._getState(ctx, produceId); - if (newLocationOrInTransit === "In Transit") produce.status = "In Transit"; + if (newLocation === "In Transit") produce.status = "In Transit"; else { - produce.currentLocation = newLocationOrInTransit; + produce.currentLocation = newLocation; if (produce.status === "Harvested") produce.status = "In Transit"; } diff --git a/frontend/components/LocationPicker.js b/frontend/components/LocationPicker.js @@ -14,7 +14,7 @@ export default function LocationPicker({ value, onChange }) { try { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== "granted") { - Alert.alert("Permission denied", "Enable location services."); + Alert.alert("Permission denied", "Enable location services"); return; } diff --git a/frontend/components/Scanner.js b/frontend/components/Scanner.js @@ -27,7 +27,7 @@ export default function Scanner({ value, onChange }) { const handleScanned = ({ data }) => { if (!data) { - Alert.alert("Scan Failed", "No data found in QR code."); + Alert.alert("Scan Failed", "No data found in QR code"); return; } diff --git a/frontend/components/ScreenHeader.js b/frontend/components/ScreenHeader.js @@ -27,7 +27,7 @@ export default function ScreenHeader({ /> </TouchableOpacity> ) : ( - <View style={{ width: 28 }} /> // spacer + <View style={{ width: 28 }} /> )} <Text style={styles.title}>{title}</Text> diff --git a/frontend/screens/Search.js b/frontend/screens/Search.js @@ -10,7 +10,10 @@ import { TouchableOpacity, View, } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; +import { + SafeAreaView, + useSafeAreaInsets, +} from "react-native-safe-area-context"; import RNPickerSelect from "react-native-picker-select"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import ScreenHeader from "../components/ScreenHeader"; @@ -34,6 +37,8 @@ const DetailRow = ({ icon, label, value }) => ( ); export default function SearchScreen({ navigation }) { + const insets = useSafeAreaInsets(); + const [tab, setTab] = useState("Produce"); const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); @@ -161,7 +166,7 @@ export default function SearchScreen({ navigation }) { <DetailRow icon="cash" label="Price" - value={`$${produce.pricePerUnit} / ${produce.qtyUnit}`} + value={`₹${produce.pricePerUnit} / ${produce.qtyUnit}`} /> <DetailRow icon="account-circle-outline" @@ -171,16 +176,20 @@ export default function SearchScreen({ navigation }) { </View> </View> <View style={local.splitRow}> - <DetailRow - icon="calendar-arrow-left" - label="Date of Harvest" - value={new Date(produce.harvestDate).toLocaleDateString()} - /> - <DetailRow - icon="calendar-arrow-right" - label="Date of Expiry" - value={new Date(produce.expiryDate).toLocaleDateString()} - /> + <View style={{ flex: 1, marginRight: 8 }}> + <DetailRow + icon="calendar-arrow-left" + label="Date of Harvest" + value={new Date(produce.harvestDate).toLocaleDateString()} + /> + </View> + <View style={{ flex: 1, marginLeft: 8 }}> + <DetailRow + icon="calendar-arrow-right" + label="Date of Expiry" + value={new Date(produce.expiryDate).toLocaleDateString()} + /> + </View> </View> <View style={local.badgesRow}> <View style={{ flexDirection: "row", flexWrap: "wrap" }}> @@ -243,108 +252,122 @@ export default function SearchScreen({ navigation }) { ); return ( - <SafeAreaView style={styles.container}> - <ScreenHeader - title="Global Search" - navigation={navigation} - hideSearchButton={true} - showBack={true} - /> + <SafeAreaView style={styles.container} edges={["top", "left", "right"]}> + <ScrollView + style={{ flex: 1 }} + contentContainerStyle={{ + flexGrow: 1, + paddingBottom: insets.bottom, + paddingHorizontal: 4, + }} + keyboardShouldPersistTaps="handled" + nestedScrollEnabled={true} + showsVerticalScrollIndicator={true} + scrollIndicatorInsets={{ bottom: insets.bottom }} + > + <ScreenHeader + title="Global Search" + navigation={navigation} + hideSearchButton={true} + showBack={true} + /> - <View style={local.searchContainer}> - <Text - style={{ - marginBottom: 12, - color: colors.darkGreen, - textAlign: "center", - }} - > - Search for information about any produce or user in the supply chain - </Text> - <View style={{ flexDirection: "row", justifyContent: "space-around" }}> - {["Produce", "User"].map((t) => ( - <TouchableOpacity - key={t} - style={[ - local.tabButton, - { - backgroundColor: - tab === t ? colors.darkGreen : colors.lightGreen, - }, - ]} - onPress={() => { - setTab(t); - setResult(null); - setProduceId(""); - setUserId(""); - setUserRole("FARMER"); - }} - > - <MaterialCommunityIcons - name={t === "Produce" ? "leaf" : "account-badge"} - size={20} - color={tab === t ? "white" : colors.darkGreen} - /> - <Text + <View style={local.searchContainer}> + <Text + style={{ + marginBottom: 12, + color: colors.darkGreen, + textAlign: "center", + }} + > + Search for information about any produce or user in the supply chain + </Text> + + <View + style={{ flexDirection: "row", justifyContent: "space-around" }} + > + {["Produce", "User"].map((t) => ( + <TouchableOpacity + key={t} style={[ - local.tabText, - { color: tab === t ? "white" : colors.darkGreen }, + local.tabButton, + { + backgroundColor: + tab === t ? colors.darkGreen : colors.lightGreen, + }, ]} + onPress={() => { + setTab(t); + setResult(null); + setProduceId(""); + setUserId(""); + setUserRole("FARMER"); + }} > - {t} - </Text> - </TouchableOpacity> - ))} - </View> - - {tab === "Produce" ? ( - <Scanner value={produceId} onChange={setProduceId} /> - ) : ( - <View> - <Text style={[local.detailLabel, { marginTop: 20 }]}> - 1. Select Role - </Text> - <RNPickerSelect - onValueChange={(value) => setUserRole(value)} - items={[ - { label: "Farmer", value: "FARMER" }, - { label: "Distributor", value: "DISTRIBUTOR" }, - { label: "Retailer", value: "RETAILER" }, - { label: "Inspector", value: "INSPECTOR" }, - ]} - style={pickerSelectStyles} - value={userRole} - useNativeAndroidPickerStyle={false} - placeholder={{}} - /> - <Text - style={[local.detailLabel, { marginTop: 20, marginBottom: 6 }]} - > - 2. Enter User ID - </Text> - <TextInput - style={styles.input} - placeholder="e.g. farmer1, distributor_xyz" - value={userId} - onChangeText={setUserId} - /> + <MaterialCommunityIcons + name={t === "Produce" ? "leaf" : "account-badge"} + size={20} + color={tab === t ? "white" : colors.darkGreen} + /> + <Text + style={[ + local.tabText, + { color: tab === t ? "white" : colors.darkGreen }, + ]} + > + {t} + </Text> + </TouchableOpacity> + ))} </View> - )} - <TouchableOpacity - style={[styles.primaryButton, { marginTop: 20 }]} - onPress={fetchResult} - disabled={loading} - > - {loading ? ( - <ActivityIndicator color="white" /> + {tab === "Produce" ? ( + <Scanner value={produceId} onChange={setProduceId} /> ) : ( - <Text style={styles.buttonText}>Search</Text> + <View> + <Text style={[local.detailLabel, { marginTop: 20 }]}> + 1. Select Role + </Text> + <RNPickerSelect + onValueChange={(value) => setUserRole(value)} + items={[ + { label: "Farmer", value: "FARMER" }, + { label: "Distributor", value: "DISTRIBUTOR" }, + { label: "Retailer", value: "RETAILER" }, + { label: "Inspector", value: "INSPECTOR" }, + ]} + style={pickerSelectStyles} + value={userRole} + useNativeAndroidPickerStyle={false} + placeholder={{}} + /> + <Text + style={[local.detailLabel, { marginTop: 20, marginBottom: 6 }]} + > + 2. Enter User ID + </Text> + <TextInput + style={styles.input} + placeholder="e.g. farmer1, distributor_xyz" + value={userId} + onChangeText={setUserId} + /> + </View> )} - </TouchableOpacity> - </View> - <ScrollView contentContainerStyle={{ paddingHorizontal: 4 }}> + <TouchableOpacity + style={[styles.primaryButton, { marginTop: 20 }]} + onPress={fetchResult} + disabled={loading} + > + {loading ? ( + <ActivityIndicator color="white" /> + ) : ( + <Text style={styles.buttonText}>Search</Text> + )} + </TouchableOpacity> + </View> + {loading && ( <ActivityIndicator size="large" @@ -362,7 +385,7 @@ export default function SearchScreen({ navigation }) { ) : ( <View style={local.card}> <Text style={{ textAlign: "center", fontWeight: "500" }}> - No results found for the provided ID. + No results found for provided ID </Text> </View> ))} @@ -447,7 +470,7 @@ const local = StyleSheet.create({ detailsContainer: { flex: 1, marginLeft: 16, - height: "100%", + minHeight: 120, justifyContent: "space-around", }, detailItem: {