Inventory.js (4488B)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import { useContext, useEffect, useState, useCallback } from "react"; import { ActivityIndicator, Alert, RefreshControl, ScrollView, Text, View, } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import AsyncStorage from "@react-native-async-storage/async-storage"; import ScreenHeader from "../components/ScreenHeader"; import ProduceCard from "../components/ProduceCard"; import { AuthContext } from "../AuthContext"; import { api } from "../services/api"; import styles, { colors } from "../styles"; const sortByLastAction = (a, b) => { const getLatestTimestamp = (produce) => { if (produce.actionHistory && produce.actionHistory.length > 0) return produce.actionHistory[produce.actionHistory.length - 1].timestamp; return produce.harvestDate; }; const timeA = getLatestTimestamp(a); const timeB = getLatestTimestamp(b); return new Date(timeB) - new Date(timeA); }; export default function InventoryScreen({ navigation, route }) { const { user } = useContext(AuthContext); const routeUserId = route.params?.userId || user?.id; const role = route.params?.role || user?.role; const [loading, setLoading] = useState(false); const [produces, setProduces] = useState([]); const [refreshing, setRefreshing] = useState(false); const CACHE_KEY = `@inventory_${routeUserId}`; const loadInventory = useCallback( async (isRefreshing = false) => { if (!isRefreshing) setLoading(true); try { const cachedData = await AsyncStorage.getItem(CACHE_KEY); if (cachedData && !isRefreshing) { const parsedData = JSON.parse(cachedData); parsedData.sort(sortByLastAction); setProduces(parsedData); } } catch (e) { console.error("Failed to load cache:", e); } try { let fetchedProduces; if (role.toUpperCase() === "INSPECTOR") { const userKey = `INSPECTOR-${routeUserId}`; const { user: userDetails } = await api.getUserDetails(userKey); const inspectedIds = userDetails.inspectedProduce || []; const producePromises = inspectedIds.map((pid) => api.getProduceById(pid).catch(() => null) ); const results = await Promise.all(producePromises); fetchedProduces = results .filter((res) => res && res.produce) .map((res) => res.produce); } else { const { produces: ownerProduces } = await api.getProduceByOwner(routeUserId); fetchedProduces = ownerProduces || []; } fetchedProduces.sort(sortByLastAction); setProduces(fetchedProduces); await AsyncStorage.setItem(CACHE_KEY, JSON.stringify(fetchedProduces)); } catch (err) { if (!produces.length) Alert.alert("Error", "Failed to fetch inventory"); console.error("Network fetch failed:", err.message); } finally { if (!isRefreshing) setLoading(false); } }, [role, routeUserId, CACHE_KEY] ); useEffect(() => { loadInventory(); }, [loadInventory]); const onRefresh = useCallback(async () => { setRefreshing(true); await loadInventory(true); setRefreshing(false); }, [loadInventory]); return ( <SafeAreaView style={styles.container}> <ScreenHeader title={route.params?.title || "My Inventory"} navigation={navigation} role={role} hideSearchButton={true} hideNotificationsButton={true} showBack={true} /> <ScrollView contentContainerStyle={{ padding: 12 }} refreshControl={ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} colors={[colors.darkGreen]} tintColor={colors.darkGreen} /> } > {loading && produces.length === 0 ? ( <View style={{ alignItems: "center", padding: 20 }}> <ActivityIndicator size="large" /> <Text>Loading Inventory...</Text> </View> ) : ( <> {produces.length === 0 ? ( <View style={{ marginTop: 20, alignItems: "center" }}> <Text style={{ color: colors.gray }}>No produce found</Text> </View> ) : ( produces.map((p) => <ProduceCard key={p.id} produce={p} />) )} </> )} </ScrollView> </SafeAreaView> ); } |