7 Commits

Author SHA1 Message Date
e61038e004 chore(release): 0.0.2-alpha.9
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 2m42s
Release and Build Image / release (push) Successful in 28s
2026-05-06 13:34:30 -05:00
d99449ddc4 test(scanner): lane check
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m41s
2026-05-06 13:30:58 -05:00
3552ca31f9 build(builds): changed to ip as its on the same server
Some checks failed
Build and Push LST Docker Image / docker (push) Failing after 4s
2026-05-06 12:27:20 -05:00
b578f05d64 build(release): bypass cloudflare upload limit
Some checks failed
Build and Push LST Docker Image / docker (push) Failing after 3m43s
2026-05-06 12:17:42 -05:00
4ca74de279 refactor(mobile): valildation of server after each scan
Some checks failed
Build and Push LST Docker Image / docker (push) Failing after 3m40s
2026-05-06 12:10:14 -05:00
12412536d1 refactor(scanner): finished login stuff for current routes 2026-05-06 12:09:47 -05:00
a38e2e0339 refactor(scanner): added in running number 2026-05-06 12:09:09 -05:00
22 changed files with 2394 additions and 91 deletions

View File

@@ -12,20 +12,20 @@ jobs:
steps: steps:
- name: Checkout (local) - name: Checkout (local)
run: | run: |
git clone https://git.tuffraid.net/cowch/lst_v3.git . git clone http://10.75.9.150:3100/cowch/lst_v3.git .
git checkout ${{ gitea.sha }} git checkout ${{ gitea.sha }}
- name: Login to registry - name: Login to registry
run: echo "${{ secrets.PASSWORD }}" | docker login git.tuffraid.net -u "cowch" --password-stdin run: echo "${{ secrets.PASSWORD }}" | docker login 10.75.9.150:3100 -u "cowch" --password-stdin
- name: Build image - name: Build image
run: | run: |
docker build \ docker build \
-t git.tuffraid.net/cowch/lst_v3:latest \ -t 10.75.9.150:3100/cowch/lst_v3:latest \
-t git.tuffraid.net/cowch/lst_v3:${{ gitea.sha }} \ -t 10.75.9.150:3100/cowch/lst_v3:${{ gitea.sha }} \
. .
- name: Push - name: Push
run: | run: |
docker push git.tuffraid.net/cowch/lst_v3:latest docker push 10.75.9.150:3100/cowch/lst_v3:latest
docker push git.tuffraid.net/cowch/lst_v3:${{ gitea.sha }} docker push 10.75.9.150:3100/cowch/lst_v3:${{ gitea.sha }}

View File

@@ -14,12 +14,12 @@ jobs:
# Examples: # Examples:
# http://gitea.internal.lan:3000 # http://gitea.internal.lan:3000
# https://gitea-origin.yourdomain.local # https://gitea-origin.yourdomain.local
GITEA_INTERNAL_URL: "https://git.tuffraid.net" GITEA_INTERNAL_URL: "http://10.75.9.150:3100" #"https://git.tuffraid.net"
# Internal/origin registry host. Usually same host as above, but without protocol. # Internal/origin registry host. Usually same host as above, but without protocol.
# Example: # Example:
# gitea.internal:3000 # gitea.internal:3000
REGISTRY_HOST: "git.tuffraid.net" REGISTRY_HOST: "10.75.9.150:3100" #"git.tuffraid.net"
steps: steps:
- name: Check out repository - name: Check out repository

View File

@@ -1,5 +1,25 @@
# All Changes to LST can be found below. # All Changes to LST can be found below.
## [0.0.2-alpha.9](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.8...v0.0.2-alpha.9) (2026-05-06)
### 🛠️ Code Refactor
* **mobile:** valildation of server after each scan ([4ca74de](https://git.tuffraid.net/cowch/lst_v3/commits/4ca74de2795cea7244e38697d16afe2822164ed6))
* **scanner:** added in running number ([a38e2e0](https://git.tuffraid.net/cowch/lst_v3/commits/a38e2e033977b725538e9a9046098d94194d549e))
* **scanner:** finished login stuff for current routes ([1241253](https://git.tuffraid.net/cowch/lst_v3/commits/12412536d10981013053c39d156c6c9cb0babd11))
### 📝 Testing Code
* **scanner:** lane check ([d99449d](https://git.tuffraid.net/cowch/lst_v3/commits/d99449ddc4e2777c1b0fe9189ba0a7c01fe1dd8f))
### 📈 Project Builds
* **builds:** changed to ip as its on the same server ([3552ca3](https://git.tuffraid.net/cowch/lst_v3/commits/3552ca31f9f7b3bcbe557a145e7eb154bfdae79c))
* **release:** bypass cloudflare upload limit ([b578f05](https://git.tuffraid.net/cowch/lst_v3/commits/b578f05d6482f9b6f30febeee6ab0b708a70f68b))
## [0.0.2-alpha.8](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.7...v0.0.2-alpha.8) (2026-05-06) ## [0.0.2-alpha.8](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.7...v0.0.2-alpha.8) (2026-05-06)

View File

@@ -9,6 +9,7 @@ export const scanLog = pgTable("scan_log", {
message: text("message").notNull(), message: text("message").notNull(),
prompt: text("prompt"), prompt: text("prompt"),
commandDescription: text("command_description"), commandDescription: text("command_description"),
runningNumber: text("running_number").default("0"),
status: text("status"), status: text("status"),
lines: jsonb("lines").default([]), lines: jsonb("lines").default([]),
add_Date: timestamp("add_Date").defaultNow(), add_Date: timestamp("add_Date").defaultNow(),

View File

@@ -0,0 +1,37 @@
import { Router } from "express";
import { db } from "../db/db.controller.js";
import { scanLog } from "../db/schema/scanlog.schema.js";
import { apiReturn } from "../utils/returnHelper.utils.js";
const router = Router();
router.post("/", async (req, res) => {
const body = req.body;
const newLog = await db
.insert(scanLog)
.values({
scannerId: body.scannerId,
message: body.message,
prompt: body.prompt,
commandDescription: body.commandDescription,
status: body.status,
lines: body.lines,
user: body.user,
runningNumber: body.runningNumber,
})
.returning();
return apiReturn(res, {
success: true,
level: "info",
module: "mobile",
subModule: "scan logs",
message: `New log from ${body.scannerId}`,
data: newLog,
status: 200,
});
});
export default router;

View File

@@ -263,6 +263,10 @@ r.patch("/user/:id", requireAuth, async (req, res) => {
updates.active = req.body.active; updates.active = req.body.active;
} }
if (req.body?.excludedCommand !== undefined) {
updates.excludedCommand = req.body.excludedCommand;
}
if (req.body?.role !== undefined) { if (req.body?.role !== undefined) {
updates.role = req.body.role; updates.role = req.body.role;
} }

View File

@@ -18,6 +18,8 @@ router.post("/", async (req, res) => {
commandDescription: body.commandDescription, commandDescription: body.commandDescription,
status: body.status, status: body.status,
lines: body.lines, lines: body.lines,
user: body.user,
runningNumber: body.runningNumber,
}) })
.returning(); .returning();

View File

@@ -15,8 +15,8 @@
"foregroundImage": "./assets/adaptive-icon-white.png", "foregroundImage": "./assets/adaptive-icon-white.png",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"versionCode": 24, "versionCode": 30,
"minSupportedVersionCode": 21, "minSupportedVersionCode": 26,
"predictiveBackGestureEnabled": false, "predictiveBackGestureEnabled": false,
"package": "net.alpla.lst.mobile" "package": "net.alpla.lst.mobile"
}, },

View File

@@ -15,10 +15,12 @@ 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 (!user || (!isUnlocked && !port)) { if (!port) {
if (!user || !isUnlocked) {
return <Redirect href="/login" />; return <Redirect href="/login" />;
} }
}
const isNormalScanner = parseInt(serverPort || "0", 10) >= 50000; const isNormalScanner = parseInt(serverPort || "0", 10) >= 50000;

View File

@@ -2,7 +2,7 @@ import axios from "axios";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { useState } from "react"; import { useState } from "react";
import { Button, Text, View } from "react-native"; import { Alert, Button, Text, View } from "react-native";
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";
@@ -38,6 +38,7 @@ export default function Login() {
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
Alert.alert("Login Error", `Invalid pin please try again`);
} }
}; };
@@ -70,7 +71,7 @@ export default function Login() {
</View> </View>
</View> </View>
<View> <View>
<Text> <Text className="p-3">
Warning: If you are logged into another scanner you will encounter Warning: If you are logged into another scanner you will encounter
scan errors, please do not try to log into more than 1 scanner at a scan errors, please do not try to log into more than 1 scanner at a
time. time.

View File

@@ -25,6 +25,8 @@ export default function Setup() {
const server = useServerStore((s) => s.serverVersion); const server = useServerStore((s) => s.serverVersion);
// TODO: if on lst version and the user is manager or admin just login
const authCheck = () => { const authCheck = () => {
if (pin === "6971") { if (pin === "6971") {
setAuth(true); setAuth(true);

View File

@@ -7,6 +7,7 @@ import { useMobileAuthStore } from "../hooks/useMobileAuth";
import { useScannerStore } from "../hooks/useScannerStore"; import { useScannerStore } from "../hooks/useScannerStore";
import { scannerFeedback } from "../lib/feedbackScan"; import { scannerFeedback } from "../lib/feedbackScan";
import { sendTcpMessage } from "../lib/tcpScan"; import { sendTcpMessage } from "../lib/tcpScan";
import { versionCheck } from "../lib/versionValidation";
import { type ZebraScanResult, zebraScanner } from "../lib/ZebraScanner"; import { type ZebraScanResult, zebraScanner } from "../lib/ZebraScanner";
import { ScannedLabelBox } from "./ScannedLabels"; import { ScannedLabelBox } from "./ScannedLabels";
import { GlobalFooter } from "./UpdateFooter"; import { GlobalFooter } from "./UpdateFooter";
@@ -45,10 +46,15 @@ export default function LSTScanner() {
scan.data.toLowerCase().includes(cmd.toLowerCase()), scan.data.toLowerCase().includes(cmd.toLowerCase()),
); );
console.log(user?.excludedCommand);
if (isAlphaStart && isExcluded) { if (isAlphaStart && isExcluded) {
Alert.alert( Alert.alert(
`Command: ${scan.data} is not allowed to be used, please contact logistics if this is an error`, "Command not allowed",
`Command: ${scan.data}\n\nPlease contact logistics if this is an error`,
); );
return;
} }
let commandToSend = `${STX}${user?.scannerId}@${scan.data}${ETX}`; let commandToSend = `${STX}${user?.scannerId}@${scan.data}${ETX}`;
@@ -68,16 +74,24 @@ export default function LSTScanner() {
const scanned = (await sendTcpMessage( const scanned = (await sendTcpMessage(
commandToSend, commandToSend,
serverIp, serverIp,
parseInt(serverPort || "0", 10), 50004,
)) as any; )) as any;
// send the logs to lst but allow it to time out if it dose not exist just bc. // send the logs to lst but allow it to time out if it dose not exist just bc.
const logInfo = { ...scanned, user: user?.name };
try { try {
await axios.post( await axios.post(`http://${serverIp.trim()}:3000/lst/api/mobile/logs`, {
`http://${serverIp.trim()}:3000/lst/api/mobile/logs`, scannerId: user?.scannerId ?? "0",
logInfo, message: scanned.data.message,
); prompt: scanned.data.prompt,
commandDescription: scanned.data.commandDescription,
status: scanned.data.status,
lines: scanned.data.lines,
user: user?.name ?? "prodScan",
runningNumber: scan.data.startsWith("000")
? parseInt(scan.data.slice(10, -1) || "000", 10).toString()
: "0",
});
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
@@ -90,7 +104,15 @@ export default function LSTScanner() {
vibrate: true, vibrate: true,
led: true, led: true,
}); });
setBGColor("bg-green-500"); setBGColor("bg-green-500");
// version check
versionCheck();
// auth update
useMobileAuthStore.getState().updateLastScan();
setTimeout(() => { setTimeout(() => {
setBGColor(null); setBGColor(null);
}, 1 * 1000); }, 1 * 1000);
@@ -117,7 +139,6 @@ export default function LSTScanner() {
}, },
[ [
serverIp, serverIp,
serverPort,
setLastScan, setLastScan,
user?.scannerId, user?.scannerId,
user?.name, user?.name,

View File

@@ -3,9 +3,11 @@ import { format } from "date-fns-tz";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Text, View } from "react-native"; import { Text, View } from "react-native";
import { useAppStore } from "../hooks/useAppStore"; import { useAppStore } from "../hooks/useAppStore";
import { useMobileAuthStore } from "../hooks/useMobileAuth";
import { useScannerStore } from "../hooks/useScannerStore"; import { useScannerStore } from "../hooks/useScannerStore";
import { scannerFeedback } from "../lib/feedbackScan"; import { scannerFeedback } from "../lib/feedbackScan";
import { sendTcpMessage } from "../lib/tcpScan"; import { sendTcpMessage } from "../lib/tcpScan";
import { versionCheck } from "../lib/versionValidation";
import { type ZebraScanResult, zebraScanner } from "../lib/ZebraScanner"; import { type ZebraScanResult, zebraScanner } from "../lib/ZebraScanner";
import { ScannedLabelBox } from "./ScannedLabels"; import { ScannedLabelBox } from "./ScannedLabels";
import { GlobalFooter } from "./UpdateFooter"; import { GlobalFooter } from "./UpdateFooter";
@@ -52,11 +54,16 @@ export default function ProdScanner() {
parseInt(serverPort || "0", 10), parseInt(serverPort || "0", 10),
)) as any; )) as any;
// send the logs to lst but allow it to time out if it dose not exist just bc. // send the logs to lst but allow it to time out if it dose not exist just bc.
const data = {
...scanned.data,
runningNumber: scan.data.startsWith("000")
? parseInt(scan.data.slice(10, -1) || "000", 10).toString()
: "0",
};
try { try {
await axios.post( await axios.post(
`http://${serverIp.trim()}:3000/lst/api/mobile/logs`, `http://${serverIp.trim()}:3000/lst/api/mobile/logs`,
scanned, data,
); );
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -71,6 +78,13 @@ export default function ProdScanner() {
led: true, led: true,
}); });
setBGColor("bg-green-500"); setBGColor("bg-green-500");
// version check
versionCheck();
// auth update
useMobileAuthStore.getState().updateLastScan();
setTimeout(() => { setTimeout(() => {
setBGColor(null); setBGColor(null);
}, 1 * 1000); }, 1 * 1000);

View File

@@ -2,6 +2,7 @@ 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 { devDelay } from "../lib/devMode"; import { devDelay } from "../lib/devMode";
import { versionCheck } from "../lib/versionValidation";
import { useAppStore } from "./useAppStore"; import { useAppStore } from "./useAppStore";
import { useServerStore } from "./useServerCheck"; import { useServerStore } from "./useServerCheck";
@@ -24,7 +25,6 @@ export function useAppStartup() {
const hasHydrated = useAppStore((s) => s.hasHydrated); const hasHydrated = useAppStore((s) => s.hasHydrated);
const serverPort = useAppStore((s) => s.serverPort); const serverPort = useAppStore((s) => s.serverPort);
const serverIp = useAppStore((s) => s.serverIp); const serverIp = useAppStore((s) => s.serverIp);
const setServerVersion = useServerStore((s) => s.setServerVersion);
useEffect(() => { useEffect(() => {
if (!hasHydrated) { if (!hasHydrated) {
@@ -62,29 +62,7 @@ export function useAppStartup() {
return; return;
} }
const port = await versionCheck();
parseInt(serverPort || "0", 10) >= 50000 ? "3000" : serverPort;
try {
const res = await axios.get(
`http://${serverIp}:${port}/lst/api/mobile/version`,
{ timeout: 5000 },
);
if (res.status === 200) {
setServerVersion(res.data);
}
const build = Constants.expoConfig?.android?.versionCode ?? 1;
if (build < res.data.minSupportedVersionCode) {
setStartupRoute("/updateScreen");
setReady(true);
return;
}
} catch (error) {
console.log("Version check error:", error);
}
setStatus("scannerMode"); setStatus("scannerMode");
await devDelay(1500); await devDelay(1500);
@@ -123,7 +101,7 @@ export function useAppStartup() {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [hasHydrated, serverIp, serverPort, setServerVersion]); }, [hasHydrated, serverIp, serverPort]);
return { return {
ready, ready,

View File

@@ -19,7 +19,11 @@ export default function useDeviceLock() {
nextAppState === "background" || nextAppState === "inactive"; nextAppState === "background" || nextAppState === "inactive";
if (wasActive && isNowInactive) { if (wasActive && isNowInactive) {
useMobileAuthStore.getState().lock(); const auth = useMobileAuthStore.getState();
if (auth.shouldLockForIdle()) {
auth.lock();
}
} }
appStateRef.current = nextAppState; appStateRef.current = nextAppState;

View File

@@ -1,5 +1,7 @@
import { create } from "zustand"; import { create } from "zustand";
const ONE_HOUR = 1000 * 60 * 60;
type MobileUser = { type MobileUser = {
id: string; id: string;
name: string; name: string;
@@ -11,19 +13,40 @@ type MobileUser = {
type AuthState = { type AuthState = {
user: MobileUser | null; user: MobileUser | null;
isUnlocked: boolean; isUnlocked: boolean;
lastScanAt: number | null;
setUser: (user: MobileUser) => void; setUser: (user: MobileUser) => void;
updateLastScan: () => void;
lock: () => void; lock: () => void;
logout: () => void; logout: () => void;
shouldLockForIdle: () => boolean;
}; };
export const useMobileAuthStore = create<AuthState>((set) => ({ export const useMobileAuthStore = create<AuthState>((set, get) => ({
user: null, user: null,
isUnlocked: false, isUnlocked: false,
lastScanAt: null,
setUser: (user) => set({ user, isUnlocked: true }), setUser: (user) =>
set({
user,
isUnlocked: true,
lastScanAt: Date.now(),
}),
updateLastScan: () => set({ lastScanAt: Date.now() }),
lock: () => set({ isUnlocked: false }), lock: () => set({ isUnlocked: false }),
logout: () => set({ user: null, isUnlocked: false }), logout: () =>
set({
user: null,
isUnlocked: false,
lastScanAt: null,
}),
shouldLockForIdle: () => {
const lastScanAt = get().lastScanAt;
if (!lastScanAt) return true;
return Date.now() - lastScanAt > ONE_HOUR;
},
})); }));

View File

@@ -1,4 +1,6 @@
import axios from "axios";
import { useAppStore } from "../hooks/useAppStore";
import { useServerStore } from "../hooks/useServerCheck";
export type ServerVersionInfo = { export type ServerVersionInfo = {
packageName: string; packageName: string;
@@ -18,7 +20,7 @@ export type StartupStatus =
export function evaluateVersion( export function evaluateVersion(
appBuildCode: number, appBuildCode: number,
server: ServerVersionInfo server: ServerVersionInfo,
): StartupStatus { ): StartupStatus {
if (appBuildCode < server.minSupportedVersionCode) { if (appBuildCode < server.minSupportedVersionCode) {
return { return {
@@ -41,3 +43,31 @@ export function evaluateVersion(
server, server,
}; };
} }
export const versionCheck = async () => {
const { setServerVersion } = useServerStore.getState();
const { serverPort, serverIp } = useAppStore.getState();
const port = parseInt(serverPort || "0", 10) >= 50000 ? "3000" : serverPort;
try {
const res = await axios.get(
`http://${serverIp}:${port}/lst/api/mobile/version`,
{ timeout: 5000 },
);
if (res.status === 200) {
setServerVersion(res.data);
}
// const build = Constants.expoConfig?.android?.versionCode ?? 1;
// if (build < res.data.minSupportedVersionCode) {
// setStartupRoute("/updateScreen");
// setReady(true);
// return;
// }
} catch (error) {
console.log("Version check error:", error);
}
};

View File

@@ -0,0 +1 @@
ALTER TABLE "scan_log" ADD COLUMN "running_number" text DEFAULT '0';

File diff suppressed because it is too large Load Diff

View File

@@ -330,6 +330,13 @@
"when": 1778059910210, "when": 1778059910210,
"tag": "0046_chemical_the_leader", "tag": "0046_chemical_the_leader",
"breakpoints": true "breakpoints": true
},
{
"idx": 47,
"version": "7",
"when": 1778068577325,
"tag": "0047_spotty_queen_noir",
"breakpoints": true
} }
] ]
} }

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "lst_v3", "name": "lst_v3",
"version": "0.0.2-alpha.8", "version": "0.0.2-alpha.9",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "lst_v3", "name": "lst_v3",
"version": "0.0.2-alpha.8", "version": "0.0.2-alpha.9",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@dotenvx/dotenvx": "^1.57.0", "@dotenvx/dotenvx": "^1.57.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "lst_v3", "name": "lst_v3",
"version": "0.0.2-alpha.8", "version": "0.0.2-alpha.9",
"description": "The tool that supports us in our everyday alplaprod", "description": "The tool that supports us in our everyday alplaprod",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {