refactor(mobile): intial addin of dockdoor scanning on mobile
This commit is contained in:
@@ -15,14 +15,14 @@
|
|||||||
"foregroundImage": "./assets/adaptive-icon-white.png",
|
"foregroundImage": "./assets/adaptive-icon-white.png",
|
||||||
"backgroundColor": "#ffffff"
|
"backgroundColor": "#ffffff"
|
||||||
},
|
},
|
||||||
"versionCode": 39,
|
"versionCode": 42,
|
||||||
"minSupportedVersionCode": 33,
|
"minSupportedVersionCode": 33,
|
||||||
"predictiveBackGestureEnabled": false,
|
"predictiveBackGestureEnabled": false,
|
||||||
"package": "net.alpla.lst.mobile",
|
"package": "net.alpla.lst.mobile",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"android.permission.WRITE_EXTERNAL_STORAGE",
|
"android.permission.WRITE_EXTERNAL_STORAGE",
|
||||||
"android.permission.READ_EXTERNAL_STORAGE"
|
"android.permission.READ_EXTERNAL_STORAGE"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"output": "static",
|
"output": "static",
|
||||||
|
|||||||
16
lstMobile/package-lock.json
generated
16
lstMobile/package-lock.json
generated
@@ -16,7 +16,7 @@
|
|||||||
"@rn-primitives/portal": "^1.4.0",
|
"@rn-primitives/portal": "^1.4.0",
|
||||||
"@rn-primitives/separator": "^1.4.0",
|
"@rn-primitives/separator": "^1.4.0",
|
||||||
"@rn-primitives/slot": "^1.4.0",
|
"@rn-primitives/slot": "^1.4.0",
|
||||||
"@tanstack/react-query": "^5.99.0",
|
"@tanstack/react-query": "^5.100.14",
|
||||||
"axios": "^1.15.0",
|
"axios": "^1.15.0",
|
||||||
"babel-preset-expo": "^55.0.18",
|
"babel-preset-expo": "^55.0.18",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
@@ -5318,9 +5318,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.100.9",
|
"version": "5.100.14",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.9.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz",
|
||||||
"integrity": "sha512-SJSFw1S8+kQ0+knv/XGfrbocWoAlT7vDKsSImtLx3ZPQmEcR46hkDjLSvynSy25N8Ms4tIEini1FuBd5k7IscQ==",
|
"integrity": "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -5328,12 +5328,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query": {
|
"node_modules/@tanstack/react-query": {
|
||||||
"version": "5.100.9",
|
"version": "5.100.14",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.9.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz",
|
||||||
"integrity": "sha512-Oa44XkaI3kCNN6ME0KByU3xT3SEUNOMfZpHxL6+wFoTm+OeUFYHKdeYVe0aOXlRDm/f15sgLwEt2HDorIdW8+A==",
|
"integrity": "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.100.9"
|
"@tanstack/query-core": "5.100.14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@rn-primitives/portal": "^1.4.0",
|
"@rn-primitives/portal": "^1.4.0",
|
||||||
"@rn-primitives/separator": "^1.4.0",
|
"@rn-primitives/separator": "^1.4.0",
|
||||||
"@rn-primitives/slot": "^1.4.0",
|
"@rn-primitives/slot": "^1.4.0",
|
||||||
"@tanstack/react-query": "^5.99.0",
|
"@tanstack/react-query": "^5.100.14",
|
||||||
"axios": "^1.15.0",
|
"axios": "^1.15.0",
|
||||||
"babel-preset-expo": "^55.0.18",
|
"babel-preset-expo": "^55.0.18",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default function TabsLayout() {
|
|||||||
onPress: async () => {
|
onPress: async () => {
|
||||||
// clear auth/session
|
// clear auth/session
|
||||||
logoutScanner();
|
logoutScanner();
|
||||||
router.replace("/(tabs)/scanner");
|
router.replace("/");
|
||||||
|
|
||||||
// clear zustand/session stuff
|
// clear zustand/session stuff
|
||||||
//useAuthStore.getState().reset();
|
//useAuthStore.getState().reset();
|
||||||
|
|||||||
@@ -1,26 +1,134 @@
|
|||||||
import React from "react";
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { Text, View } from "react-native";
|
import * as Device from "expo-device";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Link } from "expo-router";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ScrollView,
|
||||||
|
Text,
|
||||||
|
useWindowDimensions,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
import Toast from "react-native-toast-message";
|
||||||
|
|
||||||
export default function LaneCheck() {
|
import { Card, CardContent } from "../../components/ui/card";
|
||||||
const getInfo = async () => {
|
import { getActiveLoadingOrders } from "../../lib/queryStuff/getActiveLoadingOrders";
|
||||||
const info = "ho";
|
import { getDocks } from "../../lib/queryStuff/getDocks";
|
||||||
|
|
||||||
console.log(info);
|
export default function DockScan() {
|
||||||
|
const { data } = useSuspenseQuery(getDocks());
|
||||||
|
const {
|
||||||
|
data: loadingOrders,
|
||||||
|
refetch,
|
||||||
|
isLoading,
|
||||||
|
} = useSuspenseQuery(getActiveLoadingOrders());
|
||||||
|
const { width } = useWindowDimensions();
|
||||||
|
const isTablet =
|
||||||
|
Device.modelName?.toLowerCase().includes("et40") ||
|
||||||
|
Device.modelName?.toLowerCase().includes("et45");
|
||||||
|
|
||||||
|
const columns = isTablet ? 3 : 1;
|
||||||
|
|
||||||
|
const gap = 8;
|
||||||
|
const cardWidth =
|
||||||
|
columns === 1 ? width - 16 : (width - gap * (columns + 1)) / columns;
|
||||||
|
|
||||||
|
const updateLoadingOrders = () => {
|
||||||
|
refetch();
|
||||||
|
Toast.show({
|
||||||
|
type: "success",
|
||||||
|
text1: `Refreshing Loading Orders`,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<SafeAreaView>
|
||||||
|
<Text>Loading...</Text>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<View
|
<View className="flex">
|
||||||
style={{
|
<View
|
||||||
flex: 1,
|
style={{
|
||||||
//justifyContent: "center",
|
// flex: 1,
|
||||||
alignItems: "center",
|
//justifyContent: "center",
|
||||||
marginTop: 50,
|
alignItems: "center",
|
||||||
}}
|
marginTop: 50,
|
||||||
>
|
}}
|
||||||
<Text>Dock Scanning</Text>
|
>
|
||||||
<Button onPress={getInfo}>
|
<Text className="text-2xl text-bold">Dock Scanning</Text>
|
||||||
<Text>Check info</Text>
|
<Button title="Update Loading Orders" onPress={updateLoadingOrders} />
|
||||||
</Button>
|
</View>
|
||||||
|
<View>
|
||||||
|
<SafeAreaView className="flex">
|
||||||
|
<ScrollView className="w-full">
|
||||||
|
<View className="w-full flex-row flex-wrap gap-2 m-2">
|
||||||
|
{data.map((i: any) => {
|
||||||
|
const loadingPlan =
|
||||||
|
i.currentLoadingOrder !== ""
|
||||||
|
? loadingOrders.filter(
|
||||||
|
(x: any) => x.id === Number(i.currentLoadingOrder),
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={i.id}>
|
||||||
|
<Link
|
||||||
|
href={{
|
||||||
|
pathname: "/dock/[id]",
|
||||||
|
params: {
|
||||||
|
id: i.dockId.toString(),
|
||||||
|
currentLoading: i.currentLoadingOrder,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
borderWidth: 4,
|
||||||
|
width: cardWidth,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<Text>{i.name}</Text>
|
||||||
|
{i.currentLoadingOrder === "" ? (
|
||||||
|
<Text>Tap to active new loading order</Text>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
<Text>
|
||||||
|
Current Loading order : {i.currentLoadingOrder}
|
||||||
|
</Text>
|
||||||
|
{loadingPlan && loadingPlan.length > 0 && (
|
||||||
|
<View>
|
||||||
|
<Text>
|
||||||
|
{`${loadingPlan[0].loadingPlanItems[0].articleId} - ${loadingPlan[0].loadingPlanItems[0].articleDescription}`}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
Current Loaded :{" "}
|
||||||
|
{
|
||||||
|
loadingPlan[0].loadingPlanItems[0]
|
||||||
|
.loadedQuantityLUs
|
||||||
|
}{" "}
|
||||||
|
/{" "}
|
||||||
|
{
|
||||||
|
loadingPlan[0].loadingPlanItems[0]
|
||||||
|
.plannedQuantityLUs
|
||||||
|
}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Link>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaView>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ export default function PPOO() {
|
|||||||
});
|
});
|
||||||
}, [items, sortDir]);
|
}, [items, sortDir]);
|
||||||
|
|
||||||
//console.log(logsInfo);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className="flex items-center mt-2">
|
<View className="flex items-center mt-2">
|
||||||
<View className="flex m-2">
|
<View className="flex m-2">
|
||||||
@@ -61,7 +59,7 @@ export default function PPOO() {
|
|||||||
<Text>Loading PPOO...</Text>
|
<Text>Loading PPOO...</Text>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<SafeAreaView className="flex-1">
|
<SafeAreaView className="flex">
|
||||||
<ScrollView className="w-full">
|
<ScrollView className="w-full">
|
||||||
<View className="w-full flex-row flex-wrap gap-2 m-2">
|
<View className="w-full flex-row flex-wrap gap-2 m-2">
|
||||||
{sortedItems.map((i: any) => {
|
{sortedItems.map((i: any) => {
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ import { PortalHost } from "@rn-primitives/portal";
|
|||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
import { StatusBar } from "expo-status-bar";
|
import { StatusBar } from "expo-status-bar";
|
||||||
import "../../global.css";
|
import "../../global.css";
|
||||||
|
import { QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
import useDeviceLock from "../hooks/useDeviceCheck";
|
import useDeviceLock from "../hooks/useDeviceCheck";
|
||||||
|
import { useDeviceOrientationLock } from "../hooks/useDeviceOrientationLock";
|
||||||
|
import { queryClient } from "../lib/queryStuff/queryClient";
|
||||||
import { connectSocket } from "../lib/socket.io";
|
import { connectSocket } from "../lib/socket.io";
|
||||||
import { zebraScanner } from "../lib/ZebraScanner";
|
import { zebraScanner } from "../lib/ZebraScanner";
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
useDeviceLock();
|
useDeviceLock();
|
||||||
|
useDeviceOrientationLock();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
zebraScanner.ensureProfile();
|
zebraScanner.ensureProfile();
|
||||||
@@ -18,15 +22,18 @@ export default function RootLayout() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StatusBar style="dark" />
|
<QueryClientProvider client={queryClient}>
|
||||||
<Stack screenOptions={{ headerShown: false }}>
|
<StatusBar style="dark" />
|
||||||
<Stack.Screen name="index" />
|
<Stack screenOptions={{ headerShown: false }}>
|
||||||
<Stack.Screen name="login" />
|
<Stack.Screen name="index" />
|
||||||
<Stack.Screen name="setup" />
|
<Stack.Screen name="login" />
|
||||||
<Stack.Screen name="updateScreen" />
|
<Stack.Screen name="setup" />
|
||||||
<Stack.Screen name="(tabs)" />
|
<Stack.Screen name="updateScreen" />
|
||||||
</Stack>
|
<Stack.Screen name="(tabs)" />
|
||||||
<PortalHost />
|
</Stack>
|
||||||
|
<PortalHost />
|
||||||
|
</QueryClientProvider>
|
||||||
|
|
||||||
<Toast />
|
<Toast />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
169
lstMobile/src/app/dock/[id].tsx
Normal file
169
lstMobile/src/app/dock/[id].tsx
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
import * as Device from "expo-device";
|
||||||
|
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Pressable,
|
||||||
|
ScrollView,
|
||||||
|
Text,
|
||||||
|
useWindowDimensions,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
import Toast from "react-native-toast-message";
|
||||||
|
import { Card, CardContent } from "../../components/ui/card";
|
||||||
|
import { api } from "../../lib/apiHelper";
|
||||||
|
import { getActiveLoadingOrders } from "../../lib/queryStuff/getActiveLoadingOrders";
|
||||||
|
|
||||||
|
export default function DockPage() {
|
||||||
|
const { id, currentLoading } = useLocalSearchParams<{
|
||||||
|
id: string;
|
||||||
|
currentLoading: string;
|
||||||
|
}>();
|
||||||
|
const router = useRouter();
|
||||||
|
const [active] = useState(currentLoading !== "");
|
||||||
|
|
||||||
|
const { width } = useWindowDimensions();
|
||||||
|
const isTablet =
|
||||||
|
Device.modelName?.toLowerCase().includes("et40") ||
|
||||||
|
Device.modelName?.toLowerCase().includes("et45");
|
||||||
|
|
||||||
|
const columns = isTablet ? 3 : 1;
|
||||||
|
|
||||||
|
const gap = 8;
|
||||||
|
const cardWidth =
|
||||||
|
columns === 1 ? width - 16 : (width - gap * (columns + 1)) / columns;
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: loadingOrders,
|
||||||
|
refetch,
|
||||||
|
isLoading,
|
||||||
|
} = useSuspenseQuery(getActiveLoadingOrders());
|
||||||
|
|
||||||
|
const dockFilter = loadingOrders.filter((i: any) => i.dockId === Number(id));
|
||||||
|
|
||||||
|
// add in start loading order, if this is already on the dock we will disabled and change to view current pallets
|
||||||
|
const startLoad = async (loadingOrder: string, dockId: string) => {
|
||||||
|
try {
|
||||||
|
const res = await api.post("/dockDoor/startLoad", {
|
||||||
|
loadingOrder,
|
||||||
|
dockId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
Toast.show({ type: "success", text1: res.data.message });
|
||||||
|
refetch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Toast.show({
|
||||||
|
type: "error",
|
||||||
|
text1: JSON.stringify(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const endLoad = async (loadingOrder: string, dockId: string) => {
|
||||||
|
try {
|
||||||
|
const res = await api.post("/dockDoor/endLoad", {
|
||||||
|
loadingOrder,
|
||||||
|
dockId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
Toast.show({ type: "success", text1: res.data.message });
|
||||||
|
refetch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Toast.show({
|
||||||
|
type: "error",
|
||||||
|
text1: JSON.stringify(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// add in ending loading order disabeled until all pallets are loaded.
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<SafeAreaView>
|
||||||
|
<Text>Loading</Text>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<SafeAreaView>
|
||||||
|
<View className="flex flex-row justify-between gap-1 ml-1 mr-1">
|
||||||
|
<View>
|
||||||
|
<Pressable
|
||||||
|
onPress={() => router.back()}
|
||||||
|
className="self-start rounded-xl bg-gray-200 px-4 py-2"
|
||||||
|
>
|
||||||
|
<Text className="font-semibold">← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text className="text-xl mt-1">{dockFilter[0].dockDescription}</Text>
|
||||||
|
<View>
|
||||||
|
<Pressable
|
||||||
|
onPress={() =>
|
||||||
|
router.push({
|
||||||
|
pathname: "/dock/scans/[scanner]",
|
||||||
|
params: {
|
||||||
|
scanner: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="self-start rounded-xl bg-gray-200 px-4 py-2"
|
||||||
|
>
|
||||||
|
<Text className="font-semibold">Scans</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<ScrollView>
|
||||||
|
<View className="w-full flex-row flex-wrap gap-2 m-2">
|
||||||
|
{dockFilter.map((i: any) => {
|
||||||
|
return (
|
||||||
|
<View key={i.id}>
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
borderWidth: 4,
|
||||||
|
width: cardWidth,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<View>
|
||||||
|
<Text>Loading Order: {dockFilter[0].id}</Text>
|
||||||
|
<Text>
|
||||||
|
{`${dockFilter[0].loadingPlanItems[0].articleId} - ${dockFilter[0].loadingPlanItems[0].articleDescription}`}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
Current Loaded :{" "}
|
||||||
|
{dockFilter[0].loadingPlanItems[0].loadedQuantityLUs} /{" "}
|
||||||
|
{dockFilter[0].loadingPlanItems[0].plannedQuantityLUs}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View className="mt-2 flex flex-row gap-2 justify-between">
|
||||||
|
<Button
|
||||||
|
title="Start Load"
|
||||||
|
onPress={() =>
|
||||||
|
startLoad(dockFilter[0].id.toString(), id)
|
||||||
|
}
|
||||||
|
disabled={active}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title="End Load"
|
||||||
|
onPress={() => endLoad(dockFilter[0].id.toString(), id)}
|
||||||
|
disabled={active}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
71
lstMobile/src/app/dock/scans/[scanner].tsx
Normal file
71
lstMobile/src/app/dock/scans/[scanner].tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||||
|
import { Pressable, Text, View } from "react-native";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
import { Card } from "../../../components/ui/card";
|
||||||
|
import { useSocketRoom } from "../../../hooks/socket.io.hook";
|
||||||
|
import { getActiveLoadingOrders } from "../../../lib/queryStuff/getActiveLoadingOrders";
|
||||||
|
|
||||||
|
export default function DockPage() {
|
||||||
|
const { scanner } = useLocalSearchParams<{
|
||||||
|
scanner: string;
|
||||||
|
}>();
|
||||||
|
const { data: loadingOrders, isLoading } = useSuspenseQuery(
|
||||||
|
getActiveLoadingOrders(),
|
||||||
|
);
|
||||||
|
const { data } = useSocketRoom<any>(
|
||||||
|
`dockDoorLoading:${scanner}`,
|
||||||
|
undefined,
|
||||||
|
"append",
|
||||||
|
) as any;
|
||||||
|
const dockFilter = loadingOrders.filter(
|
||||||
|
(i: any) => i.dockId === Number(scanner),
|
||||||
|
);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<SafeAreaView>
|
||||||
|
<Text>Loading...</Text>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<SafeAreaView className="w-full">
|
||||||
|
<View className="flex flex-row justify-between gap-1 ml-1 mr-1">
|
||||||
|
<View>
|
||||||
|
<Pressable
|
||||||
|
onPress={() => router.back()}
|
||||||
|
className="self-start rounded-xl bg-gray-200 px-4 py-2"
|
||||||
|
>
|
||||||
|
<Text className="font-semibold">← Back</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text className="text-xl mt-1">{dockFilter[0].dockDescription}</Text>
|
||||||
|
<View>
|
||||||
|
<Pressable
|
||||||
|
onPress={() =>
|
||||||
|
router.replace({
|
||||||
|
pathname: "/(tabs)/dockScan",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="self-start rounded-xl bg-gray-200 px-4 py-2"
|
||||||
|
>
|
||||||
|
<Text className="font-semibold">Docks</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
{data.map((i: any, index: any) => {
|
||||||
|
return (
|
||||||
|
<View key={index} className="m-2">
|
||||||
|
<Card>
|
||||||
|
<Text>{JSON.stringify(i)}</Text>
|
||||||
|
</Card>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
|
import { Settings } from "lucide-react-native";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Alert, Button, Text, View } from "react-native";
|
import { Alert, Button, Text, View } from "react-native";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
|
import { ConfigButton } from "../components/ui/configButton";
|
||||||
import { Input } from "../components/ui/input";
|
import { Input } from "../components/ui/input";
|
||||||
import { useAppStore } from "../hooks/useAppStore";
|
import { useAppStore } from "../hooks/useAppStore";
|
||||||
import { useMobileAuthStore } from "../hooks/useMobileAuth";
|
import { useMobileAuthStore } from "../hooks/useMobileAuth";
|
||||||
@@ -52,11 +54,6 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = () => {
|
|
||||||
console.log("config");
|
|
||||||
return router.replace("/setup");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
@@ -67,9 +64,17 @@ export default function Login() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View className="flex items-center m-5">
|
<View className="flex items-center m-5">
|
||||||
<Text style={{ fontSize: 20, fontWeight: "600" }}>
|
<View className="flex flex-row">
|
||||||
LST Scanner Login
|
<View>
|
||||||
</Text>
|
<Text style={{ fontSize: 20, fontWeight: "600" }} className="mt-2">
|
||||||
|
LST Scanner Login
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<ConfigButton />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
<View className="w-64 p-4">
|
<View className="w-64 p-4">
|
||||||
<Input
|
<Input
|
||||||
className="w-fit"
|
className="w-fit"
|
||||||
@@ -89,7 +94,6 @@ export default function Login() {
|
|||||||
</View>
|
</View>
|
||||||
<View className="flex gap-2 flex-row">
|
<View className="flex gap-2 flex-row">
|
||||||
<Button title="Login" onPress={onLogin} />
|
<Button title="Login" onPress={onLogin} />
|
||||||
<Button title="Config" onPress={config} />
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
20
lstMobile/src/components/ui/configButton.tsx
Normal file
20
lstMobile/src/components/ui/configButton.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { useRouter } from "expo-router";
|
||||||
|
import { Settings } from "lucide-react-native";
|
||||||
|
import { Pressable } from "react-native";
|
||||||
|
|
||||||
|
export function ConfigButton() {
|
||||||
|
const router = useRouter();
|
||||||
|
const config = () => {
|
||||||
|
console.log("config");
|
||||||
|
return router.replace("/setup");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
onPress={config}
|
||||||
|
className="h-12 w-12 items-center justify-center rounded-x"
|
||||||
|
>
|
||||||
|
<Settings color="black" size={24} />
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Constants from "expo-constants";
|
import Constants from "expo-constants";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { setApiConfig } from "../lib/apiHelper";
|
||||||
import { devDelay } from "../lib/devMode";
|
import { devDelay } from "../lib/devMode";
|
||||||
import { versionCheck } from "../lib/versionValidation";
|
import { versionCheck } from "../lib/versionValidation";
|
||||||
import { useAppStore } from "./useAppStore";
|
import { useAppStore } from "./useAppStore";
|
||||||
@@ -26,6 +27,11 @@ export function useAppStartup() {
|
|||||||
const serverPort = useAppStore((s) => s.serverPort);
|
const serverPort = useAppStore((s) => s.serverPort);
|
||||||
const serverIp = useAppStore((s) => s.serverIp);
|
const serverIp = useAppStore((s) => s.serverIp);
|
||||||
|
|
||||||
|
setApiConfig({
|
||||||
|
serverIp,
|
||||||
|
serverPort,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!hasHydrated) {
|
if (!hasHydrated) {
|
||||||
setStatus("loading");
|
setStatus("loading");
|
||||||
|
|||||||
32
lstMobile/src/hooks/useDeviceOrientationLock.ts
Normal file
32
lstMobile/src/hooks/useDeviceOrientationLock.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import * as Device from "expo-device";
|
||||||
|
import * as ScreenOrientation from "expo-screen-orientation";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const LANDSCAPE_MODELS = ["ET45", "ET40"]; // tablets
|
||||||
|
const PORTRAIT_MODELS = ["TC21", "TC26", "TC8300"]; // scanners
|
||||||
|
|
||||||
|
const isTabletModel = (modelName?: string | null) => {
|
||||||
|
const model = modelName?.toUpperCase() ?? "";
|
||||||
|
|
||||||
|
return LANDSCAPE_MODELS.some((m) => model.includes(m));
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useDeviceOrientationLock() {
|
||||||
|
useEffect(() => {
|
||||||
|
async function lockOrientation() {
|
||||||
|
try {
|
||||||
|
const model = Device.modelName;
|
||||||
|
|
||||||
|
await ScreenOrientation.lockAsync(
|
||||||
|
isTabletModel(model)
|
||||||
|
? ScreenOrientation.OrientationLock.LANDSCAPE
|
||||||
|
: ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Failed to lock orientation", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lockOrientation();
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
63
lstMobile/src/lib/apiHelper.ts
Normal file
63
lstMobile/src/lib/apiHelper.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
type ApiConfig = {
|
||||||
|
serverIp: string;
|
||||||
|
serverPort: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
let currentConfig: ApiConfig | null = null;
|
||||||
|
|
||||||
|
export function setApiConfig(config: ApiConfig) {
|
||||||
|
currentConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBaseUrl() {
|
||||||
|
if (!currentConfig) {
|
||||||
|
throw new Error("API config not initialized");
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
`http://${currentConfig.serverIp}:${currentConfig.serverPort}/lst/api`,
|
||||||
|
);
|
||||||
|
return `http://${currentConfig.serverIp}:${currentConfig.serverPort}/lst/api`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const api = axios.create({
|
||||||
|
timeout: 15000,
|
||||||
|
});
|
||||||
|
|
||||||
|
api.interceptors.request.use((config) => {
|
||||||
|
config.baseURL = getBaseUrl();
|
||||||
|
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
const isNetworkError =
|
||||||
|
error.code === "ERR_NETWORK" ||
|
||||||
|
error.code === "ECONNABORTED" ||
|
||||||
|
error.message === "Network Error" ||
|
||||||
|
error.message === "Failed to fetch" ||
|
||||||
|
!error.response;
|
||||||
|
|
||||||
|
// unauthorized
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
router.replace("/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
// forbidden
|
||||||
|
if (error.response?.status === 403) {
|
||||||
|
router.replace("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
// app/server offline
|
||||||
|
if (isNetworkError) {
|
||||||
|
router.replace("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
21
lstMobile/src/lib/queryStuff/getActiveLoadingOrders.ts
Normal file
21
lstMobile/src/lib/queryStuff/getActiveLoadingOrders.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
||||||
|
import { api } from "../apiHelper";
|
||||||
|
|
||||||
|
export function getActiveLoadingOrders() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["getActiveLoadingOrders"],
|
||||||
|
queryFn: () => dataFetch(),
|
||||||
|
staleTime: 5000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataFetch = async () => {
|
||||||
|
const { data } = await api.get("/dockDoor/activeLoadingOrders");
|
||||||
|
if (!data.success) {
|
||||||
|
throw new Error(data.message ?? "Failed to load articles");
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
21
lstMobile/src/lib/queryStuff/getDocks.ts
Normal file
21
lstMobile/src/lib/queryStuff/getDocks.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
||||||
|
import { api } from "../apiHelper";
|
||||||
|
|
||||||
|
export function getDocks() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["getDocks"],
|
||||||
|
queryFn: () => dataFetch(),
|
||||||
|
staleTime: 5000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataFetch = async () => {
|
||||||
|
const { data } = await api.get("/dockDoor/scanners");
|
||||||
|
if (!data.success) {
|
||||||
|
throw new Error(data.message ?? "Failed to load articles");
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
17
lstMobile/src/lib/queryStuff/queryClient.ts
Normal file
17
lstMobile/src/lib/queryStuff/queryClient.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { QueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
export const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: 30_000,
|
||||||
|
gcTime: 5 * 60_000,
|
||||||
|
retry: 2,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
refetchOnReconnect: true,
|
||||||
|
refetchOnMount: false,
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
retry: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user