refactor(mobile): intial addin of dockdoor scanning on mobile
This commit is contained in:
@@ -15,14 +15,14 @@
|
||||
"foregroundImage": "./assets/adaptive-icon-white.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"versionCode": 39,
|
||||
"versionCode": 42,
|
||||
"minSupportedVersionCode": 33,
|
||||
"predictiveBackGestureEnabled": false,
|
||||
"package": "net.alpla.lst.mobile",
|
||||
"permissions": [
|
||||
"android.permission.WRITE_EXTERNAL_STORAGE",
|
||||
"android.permission.READ_EXTERNAL_STORAGE"
|
||||
]
|
||||
"android.permission.WRITE_EXTERNAL_STORAGE",
|
||||
"android.permission.READ_EXTERNAL_STORAGE"
|
||||
]
|
||||
},
|
||||
"web": {
|
||||
"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/separator": "^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",
|
||||
"babel-preset-expo": "^55.0.18",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -5318,9 +5318,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.100.9",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.9.tgz",
|
||||
"integrity": "sha512-SJSFw1S8+kQ0+knv/XGfrbocWoAlT7vDKsSImtLx3ZPQmEcR46hkDjLSvynSy25N8Ms4tIEini1FuBd5k7IscQ==",
|
||||
"version": "5.100.14",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz",
|
||||
"integrity": "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -5328,12 +5328,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.100.9",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.9.tgz",
|
||||
"integrity": "sha512-Oa44XkaI3kCNN6ME0KByU3xT3SEUNOMfZpHxL6+wFoTm+OeUFYHKdeYVe0aOXlRDm/f15sgLwEt2HDorIdW8+A==",
|
||||
"version": "5.100.14",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz",
|
||||
"integrity": "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.100.9"
|
||||
"@tanstack/query-core": "5.100.14"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@rn-primitives/portal": "^1.4.0",
|
||||
"@rn-primitives/separator": "^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",
|
||||
"babel-preset-expo": "^55.0.18",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function TabsLayout() {
|
||||
onPress: async () => {
|
||||
// clear auth/session
|
||||
logoutScanner();
|
||||
router.replace("/(tabs)/scanner");
|
||||
router.replace("/");
|
||||
|
||||
// clear zustand/session stuff
|
||||
//useAuthStore.getState().reset();
|
||||
|
||||
@@ -1,26 +1,134 @@
|
||||
import React from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import * as Device from "expo-device";
|
||||
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() {
|
||||
const getInfo = async () => {
|
||||
const info = "ho";
|
||||
import { Card, CardContent } from "../../components/ui/card";
|
||||
import { getActiveLoadingOrders } from "../../lib/queryStuff/getActiveLoadingOrders";
|
||||
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 (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
//justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: 50,
|
||||
}}
|
||||
>
|
||||
<Text>Dock Scanning</Text>
|
||||
<Button onPress={getInfo}>
|
||||
<Text>Check info</Text>
|
||||
</Button>
|
||||
<View className="flex">
|
||||
<View
|
||||
style={{
|
||||
// flex: 1,
|
||||
//justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: 50,
|
||||
}}
|
||||
>
|
||||
<Text className="text-2xl text-bold">Dock Scanning</Text>
|
||||
<Button title="Update Loading Orders" onPress={updateLoadingOrders} />
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ export default function PPOO() {
|
||||
});
|
||||
}, [items, sortDir]);
|
||||
|
||||
//console.log(logsInfo);
|
||||
|
||||
return (
|
||||
<View className="flex items-center mt-2">
|
||||
<View className="flex m-2">
|
||||
@@ -61,7 +59,7 @@ export default function PPOO() {
|
||||
<Text>Loading PPOO...</Text>
|
||||
</View>
|
||||
) : (
|
||||
<SafeAreaView className="flex-1">
|
||||
<SafeAreaView className="flex">
|
||||
<ScrollView className="w-full">
|
||||
<View className="w-full flex-row flex-wrap gap-2 m-2">
|
||||
{sortedItems.map((i: any) => {
|
||||
|
||||
@@ -2,14 +2,18 @@ import { PortalHost } from "@rn-primitives/portal";
|
||||
import { Stack } from "expo-router";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import "../../global.css";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
import useDeviceLock from "../hooks/useDeviceCheck";
|
||||
import { useDeviceOrientationLock } from "../hooks/useDeviceOrientationLock";
|
||||
import { queryClient } from "../lib/queryStuff/queryClient";
|
||||
import { connectSocket } from "../lib/socket.io";
|
||||
import { zebraScanner } from "../lib/ZebraScanner";
|
||||
|
||||
export default function RootLayout() {
|
||||
useDeviceLock();
|
||||
useDeviceOrientationLock();
|
||||
|
||||
useEffect(() => {
|
||||
zebraScanner.ensureProfile();
|
||||
@@ -18,15 +22,18 @@ export default function RootLayout() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<StatusBar style="dark" />
|
||||
<Stack screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="index" />
|
||||
<Stack.Screen name="login" />
|
||||
<Stack.Screen name="setup" />
|
||||
<Stack.Screen name="updateScreen" />
|
||||
<Stack.Screen name="(tabs)" />
|
||||
</Stack>
|
||||
<PortalHost />
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StatusBar style="dark" />
|
||||
<Stack screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="index" />
|
||||
<Stack.Screen name="login" />
|
||||
<Stack.Screen name="setup" />
|
||||
<Stack.Screen name="updateScreen" />
|
||||
<Stack.Screen name="(tabs)" />
|
||||
</Stack>
|
||||
<PortalHost />
|
||||
</QueryClientProvider>
|
||||
|
||||
<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 { useRouter } from "expo-router";
|
||||
import { Settings } from "lucide-react-native";
|
||||
import { useState } from "react";
|
||||
import { Alert, Button, Text, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { ConfigButton } from "../components/ui/configButton";
|
||||
import { Input } from "../components/ui/input";
|
||||
import { useAppStore } from "../hooks/useAppStore";
|
||||
import { useMobileAuthStore } from "../hooks/useMobileAuth";
|
||||
@@ -52,11 +54,6 @@ export default function Login() {
|
||||
}
|
||||
};
|
||||
|
||||
const config = () => {
|
||||
console.log("config");
|
||||
return router.replace("/setup");
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@@ -67,9 +64,17 @@ export default function Login() {
|
||||
}}
|
||||
>
|
||||
<View className="flex items-center m-5">
|
||||
<Text style={{ fontSize: 20, fontWeight: "600" }}>
|
||||
LST Scanner Login
|
||||
</Text>
|
||||
<View className="flex flex-row">
|
||||
<View>
|
||||
<Text style={{ fontSize: 20, fontWeight: "600" }} className="mt-2">
|
||||
LST Scanner Login
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
<ConfigButton />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="w-64 p-4">
|
||||
<Input
|
||||
className="w-fit"
|
||||
@@ -89,7 +94,6 @@ export default function Login() {
|
||||
</View>
|
||||
<View className="flex gap-2 flex-row">
|
||||
<Button title="Login" onPress={onLogin} />
|
||||
<Button title="Config" onPress={config} />
|
||||
</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 Constants from "expo-constants";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { setApiConfig } from "../lib/apiHelper";
|
||||
import { devDelay } from "../lib/devMode";
|
||||
import { versionCheck } from "../lib/versionValidation";
|
||||
import { useAppStore } from "./useAppStore";
|
||||
@@ -26,6 +27,11 @@ export function useAppStartup() {
|
||||
const serverPort = useAppStore((s) => s.serverPort);
|
||||
const serverIp = useAppStore((s) => s.serverIp);
|
||||
|
||||
setApiConfig({
|
||||
serverIp,
|
||||
serverPort,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasHydrated) {
|
||||
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