feat(warehousing): ppoo monitoring added

this will monitor ppoo every 45 seconds as long as someone is on the page.

closes #13
This commit is contained in:
2026-05-27 20:52:34 -05:00
parent 6d0fb8aee4
commit 8b076949a7
11 changed files with 425 additions and 210 deletions

View File

@@ -1,210 +1,105 @@
import axios from "axios";
import { format } from "date-fns-tz";
import * as Device from "expo-device";
import { useFocusEffect } from "expo-router";
import type React from "react";
import { useCallback, useEffect, useState } from "react";
import { ScrollView, Text, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
import { GlobalFooter } from "../../components/UpdateFooter";
import { Button } from "../../components/ui/button";
import { Card, CardContent, CardHeader } from "../../components/ui/card";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { useAppStore } from "../../hooks/useAppStore";
import { scannerFeedback } from "../../lib/feedbackScan";
import { type ZebraScanResult, zebraScanner } from "../../lib/ZebraScanner";
Button,
ScrollView,
Text,
useWindowDimensions,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Card, CardContent } from "../../components/ui/card";
import { useSocketRoom } from "../../hooks/socket.io.hook";
const InfoRow = ({
label,
value,
}: {
label: string;
value: React.ReactNode;
}) => {
return (
<View className="flex-row justify-between gap-4 py-2 border-b border-gray-200">
<Text className="text-sm text-gray-500">{label}</Text>
<Text className="text-sm font-medium text-gray-900 text-right flex-1">
{value}
</Text>
</View>
);
type PPOO = {
type: string;
items: any;
createdAt: Date;
};
export default function PPOO() {
const [units, setUnits] = useState<any>(null);
const serverIp = useAppStore((s) => s.serverIp);
const { data } = useSocketRoom<any>("ppoo", undefined, "replace") as any;
const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
const handleScan = useCallback(
async (scan: ZebraScanResult) => {
setUnits(null);
await scannerFeedback({
type: "scan",
sound: true,
vibrate: true,
led: true,
});
if (!scan.data.startsWith("loc")) {
Toast.show({
type: "error",
text1: "Scan error",
text2: "The last scan was not a lane please try again",
});
const { width } = useWindowDimensions();
const isTablet =
Device.modelName?.toLowerCase().includes("et40") ||
Device.modelName?.toLowerCase().includes("et45");
return;
}
try {
const res = await axios.post(
`http://${serverIp.trim()}:3000/lst/api/mobile/lanecheck`,
{
lane: "loc#1#0<",
},
{
timeout: 5000,
},
);
if (res.status === 200) {
setUnits(res.data);
Toast.show({
type: "info",
text1: "Lane Data",
text2: "All Loading Units from this lane will be listed below",
});
}
} catch (error) {
console.log(error);
Toast.show({
type: "error",
text1: "Lane Data",
text2: "Error getting lane data please try again",
});
}
},
[serverIp.trim],
);
const columns = isTablet ? 3 : 1;
useFocusEffect(
useCallback(() => {
zebraScanner.startListening();
const gap = 8;
const cardWidth =
columns === 1 ? width - 16 : (width - gap * (columns + 1)) / columns;
const sub = zebraScanner.addScanListener((scan) => {
//console.log("SCAN:", scan);
handleScan(scan);
});
const items = data?.items ?? [];
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => {
const aDate = new Date(a.lastMovingDate).getTime();
const bDate = new Date(b.lastMovingDate).getTime();
return () => {
sub.remove();
zebraScanner.stopListening();
//setUnits(null);
};
}, [handleScan]),
);
return sortDir === "asc" ? aDate - bDate : bDate - aDate;
});
}, [items, sortDir]);
//console.log(logsInfo);
return (
<View
style={{
//justifyContent: "center",
alignItems: "center",
marginTop: 50,
}}
>
{units ? (
// <SafeAreaView className={`flex-1 w-full items-center`}>
// <ScrollView className="w-full flex-1">
// <View className="flex items-center gap-2 w-full">
// {units.data?.map((i: any, index: any) => (
// <View key={`${i.runningNumber}-${index}`}>
// <Text>example</Text>
// </View>
// ))}
// </View>
// </ScrollView>
// </SafeAreaView>
<SafeAreaView className={`w-full items-center`}>
<View style={{ padding: 2 }}>
<Text>There Are {units.data.length} units in PPOO</Text>
</View>
<ScrollView className="w-full" style={{ marginBottom: 20 }}>
<View>
{units.data.map((i, index) => (
<View
key={`${i.runningNumber}-${index}`}
style={{
justifyContent: "center",
margin: 2,
}}
>
<Dialog>
<DialogTrigger>
<Card
className="w-full"
style={{
borderColor:
i.state === "QualityBlocked" ? "red" : undefined,
borderWidth: 4,
}}
>
<CardContent>
<Text>
{i.articleId} - {i.articleName}
</Text>
<View className="flex items-center mt-2">
<View className="flex m-2">
<Button
onPress={() =>
setSortDir((prev) => (prev === "asc" ? "desc" : "asc"))
}
title={`Sort: ${sortDir}`}
/>
</View>
{sortedItems.length === 0 ? (
<View className="flex items-center">
<Text>Loading PPOO...</Text>
</View>
) : (
<SafeAreaView className="flex-1">
<ScrollView className="w-full">
<View className="w-full flex-row flex-wrap gap-2 m-2">
{sortedItems.map((i: any) => {
return (
<View key={i.runningNumber}>
<Card
//className={isTablet ? "w-[32%]" : "w-full"}
style={{
borderColor:
i.mainDefectId === 864
? "blue"
: i.state === "QualityBlocked"
? "red"
: undefined,
borderWidth: 4,
width: cardWidth,
}}
>
<CardContent>
<Text>
{i.articleId} - {i.articleName}
</Text>
<Text>
Running Number: {i.runningNumber ?? "Non barcoded"}
</Text>
</CardContent>
</Card>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>
Details for Article {i.articleId}, Rn:
{i.runningNumber ?? "Non barcoded"}{" "}
</DialogTitle>
<DialogDescription>
<InfoRow
label="Production Date"
value={format(i.productionDate, "MM/dd/yyyy HH:mm")}
/>
<InfoRow label="Quantity" value={i.quantity} />
{i.state === "QualityBlocked" && (
<InfoRow
label="Defect"
value={i.mainDefectGroupDescription}
/>
)}
{i.state === "QualityBlocked" && (
<InfoRow
label="Description"
value={i.mainDefectDescription}
/>
)}
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
</View>
))}
<Text>
Running Number: {i.runningNumber ?? "Non barcoded"}
</Text>
<Text>
Date: {format(i.lastMovingDate, "M/d/yyyy HH:mm")}
</Text>
</CardContent>
</Card>
</View>
);
})}
</View>
</ScrollView>
</SafeAreaView>
) : (
<View className="mt-50">
<Text className="text-2xl text-center">
Please scan a lane to see all Units that are in the lane.
</Text>
</View>
)}
<View>
<GlobalFooter />
</View>
</View>
);
}