refactor(scanner): more scanner admin stuff

This commit is contained in:
2026-05-13 20:51:22 -05:00
parent 2616acf106
commit eb950d2c29
7 changed files with 242 additions and 26 deletions

View File

@@ -1,6 +1,12 @@
import { Router } from "express"; import { Router } from "express";
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
import {
type SqlQuery,
sqlQuerySelector,
} from "../prodSql/prodSqlQuerySelector.utils.js";
import { runProdApi } from "../utils/prodEndpoint.utils.js"; import { runProdApi } from "../utils/prodEndpoint.utils.js";
import { apiReturn } from "../utils/returnHelper.utils.js"; import { apiReturn, returnFunc } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
const router = Router(); const router = Router();
@@ -9,7 +15,27 @@ router.post("/", async (req, res) => {
const lane = body.lane.split("#"); const lane = body.lane.split("#");
console.log(lane[2]); // check if the plant has warehousing activated
const featureQ = sqlQuerySelector(`featureCheck`) as SqlQuery;
const { data: fd, error: fe } = await tryCatch(
prodQuery(featureQ.query, `Running feature check`),
);
if (fe) {
return returnFunc({
success: false,
level: "error",
module: "datamart",
subModule: "query",
message: `feature check failed`,
data: fe as any,
notify: false,
});
}
console.log(fd);
const laneData = await runProdApi({ const laneData = await runProdApi({
method: "post", method: "post",
endpoint: "/public/v1.1/Warehousing/GetWarehouseUnits", endpoint: "/public/v1.1/Warehousing/GetWarehouseUnits",

View File

@@ -1,25 +1,25 @@
import { keepPreviousData, queryOptions } from "@tanstack/react-query"; import { keepPreviousData, queryOptions } from "@tanstack/react-query";
import axios from "axios"; import { api } from "../apiHelper";
export function getScanUsers() { export function getScanUsers() {
return queryOptions({ return queryOptions({
queryKey: ["getScanUsers"], queryKey: ["getScanUsers"],
queryFn: () => fetch(), queryFn: () => dataFetch(),
staleTime: 5000, staleTime: 5000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
placeholderData: keepPreviousData, placeholderData: keepPreviousData,
}); });
} }
const fetch = async () => { const dataFetch = async () => {
if (window.location.hostname === "localhost") { if (window.location.hostname === "localhost") {
await new Promise((res) => setTimeout(res, 1500)); await new Promise((res) => setTimeout(res, 1500));
} }
const { data } = await axios.get("/lst/api/mobile/auth/user", { const { data } = await api.get("/mobile/auth/user");
withCredentials: true, if (!data.success) {
timeout: 5000, throw new Error(data.message ?? "Failed to load scan users");
}); }
return data.data; return data.data ?? [];
}; };

View File

@@ -1,5 +1,6 @@
import { keepPreviousData, queryOptions } from "@tanstack/react-query"; import { keepPreviousData, queryOptions } from "@tanstack/react-query";
import axios from "axios";
import { api } from "../apiHelper";
export function getScannerIds() { export function getScannerIds() {
return queryOptions({ return queryOptions({
@@ -16,10 +17,7 @@ const fetch = async () => {
await new Promise((res) => setTimeout(res, 1500)); await new Promise((res) => setTimeout(res, 1500));
} }
const { data } = await axios.get("/lst/api/mobile/available", { const { data } = await api.get("/mobile/available");
withCredentials: true,
timeout: 5000,
});
return data.data; return data.data;
}; };

View File

@@ -3,7 +3,7 @@ import { createFileRoute, redirect } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table"; import { createColumnHelper } from "@tanstack/react-table";
import axios from "axios"; import axios from "axios";
import { format } from "date-fns-tz"; import { format } from "date-fns-tz";
import { CircleFadingArrowUp, Trash } from "lucide-react"; import { Trash } from "lucide-react";
import { Suspense, useState } from "react"; import { Suspense, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
@@ -19,7 +19,7 @@ import NewScanUser from "./-components/NewScanUser";
export const Route = createFileRoute("/admin/scanUsers")({ export const Route = createFileRoute("/admin/scanUsers")({
beforeLoad: async ({ location }) => { beforeLoad: async ({ location }) => {
const { data: session } = await authClient.getSession(); const { data: session } = await authClient.getSession();
const allowedRole = ["systemAdmin", "admin"]; const allowedRole = ["systemAdmin", "admin", "manager"];
if (!session?.user) { if (!session?.user) {
throw redirect({ throw redirect({
@@ -111,7 +111,7 @@ const ScanUserTable = () => {
<div> <div>
<EditableCellInput <EditableCellInput
value={getValue()} value={getValue()}
id={row.original.name} id={row.original.id}
field="value" field="value"
onSubmit={({ id, field, value }) => { onSubmit={({ id, field, value }) => {
updateSetting.mutate({ id, field, value }); updateSetting.mutate({ id, field, value });

View File

@@ -15,7 +15,7 @@
"foregroundImage": "./assets/adaptive-icon-white.png", "foregroundImage": "./assets/adaptive-icon-white.png",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"versionCode": 34, "versionCode": 37,
"minSupportedVersionCode": 33, "minSupportedVersionCode": 33,
"predictiveBackGestureEnabled": false, "predictiveBackGestureEnabled": false,
"package": "net.alpla.lst.mobile" "package": "net.alpla.lst.mobile"

View File

@@ -22,7 +22,7 @@ export default function TabsLayout() {
const isUnlocked = useMobileAuthStore((s) => s.isUnlocked); const isUnlocked = useMobileAuthStore((s) => s.isUnlocked);
const port = parseInt(serverPort || "0", 10) >= 50000; const port = parseInt(serverPort || "0", 10) >= 50000;
console.log(port);
if (!port) { if (!port) {
if (!user || !isUnlocked) { if (!user || !isUnlocked) {
return <Redirect href="/login" />; return <Redirect href="/login" />;
@@ -58,14 +58,14 @@ export default function TabsLayout() {
// }, // },
}} }}
/> />
<Tabs.Screen {/* <Tabs.Screen
name="ppoo" name="ppoo"
options={{ options={{
title: "PPOO", title: "PPOO",
href: isNormalScanner ? null : "/(tabs)/ppoo", href: isNormalScanner ? null : "/(tabs)/ppoo",
tabBarIcon: ({ color, size }) => <Boxes size={size} color={color} />, tabBarIcon: ({ color, size }) => <Boxes size={size} color={color} />,
}} }}
/> /> */}
<Tabs.Screen <Tabs.Screen
name="laneCheck" name="laneCheck"
options={{ options={{

View File

@@ -1,18 +1,210 @@
import React from "react"; import axios from "axios";
import { Text, View } from "react-native"; import { format } from "date-fns-tz";
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 { Button } from "../../components/ui/button";
import { Card, CardContent, CardHeader } from "../../components/ui/card";
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";
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>
);
};
export default function PPOO() { export default function PPOO() {
const [units, setUnits] = useState<any>(null);
const serverIp = useAppStore((s) => s.serverIp);
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",
});
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],
);
useFocusEffect(
useCallback(() => {
zebraScanner.startListening();
const sub = zebraScanner.addScanListener((scan) => {
//console.log("SCAN:", scan);
handleScan(scan);
});
return () => {
sub.remove();
zebraScanner.stopListening();
//setUnits(null);
};
}, [handleScan]),
);
return ( return (
<View <View
style={{ style={{
flex: 1,
//justifyContent: "center", //justifyContent: "center",
alignItems: "center", alignItems: "center",
marginTop: 50, marginTop: 50,
}} }}
> >
<Text>Ppo checks</Text> {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>
<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>
))}
</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> </View>
); );
} }