docs(scanner): added in instructions on how to update the scanner
only test2 stage now commands for now.
@@ -1,4 +1,5 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
|
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||||
import available from "./availableScanIds.route.js";
|
import available from "./availableScanIds.route.js";
|
||||||
import downloads from "./downloadApps.route.js";
|
import downloads from "./downloadApps.route.js";
|
||||||
import lanes from "./laneCheck.js";
|
import lanes from "./laneCheck.js";
|
||||||
@@ -10,13 +11,13 @@ import version from "./version.route.js";
|
|||||||
export const setupMobileRoutes = (baseUrl: string, app: Express) => {
|
export const setupMobileRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
|
|
||||||
app.use(`${baseUrl}/api/mobile/version`, version);
|
app.use(`${baseUrl}/api/mobile/version`, featureCheck("mobile"), version);
|
||||||
app.use(`${baseUrl}/api/mobile/apk`, downloads);
|
app.use(`${baseUrl}/api/mobile/apk`, featureCheck("mobile"), downloads);
|
||||||
app.use(`${baseUrl}/api/mobile/logs`, logs);
|
app.use(`${baseUrl}/api/mobile/logs`, featureCheck("mobile"), logs);
|
||||||
app.use(`${baseUrl}/api/mobile/auth`, authPin);
|
app.use(`${baseUrl}/api/mobile/auth`, featureCheck("mobile"), authPin);
|
||||||
app.use(`${baseUrl}/api/mobile/pin`, newPin);
|
app.use(`${baseUrl}/api/mobile/pin`, featureCheck("mobile"), newPin);
|
||||||
app.use(`${baseUrl}/api/mobile/laneCheck`, lanes);
|
app.use(`${baseUrl}/api/mobile/laneCheck`, featureCheck("mobile"), lanes);
|
||||||
app.use(`${baseUrl}/api/mobile/available`, available);
|
app.use(`${baseUrl}/api/mobile/available`, featureCheck("mobile"), available);
|
||||||
|
|
||||||
// all other system should be under /api/system/*
|
// all other system should be under /api/system/*
|
||||||
};
|
};
|
||||||
|
|||||||
BIN
frontend/public/imgs/docs/mobile/critical_update.png
Normal file
|
After Width: | Height: | Size: 483 KiB |
BIN
frontend/public/imgs/docs/mobile/ehs_homeScreen.png
Normal file
|
After Width: | Height: | Size: 613 KiB |
BIN
frontend/public/imgs/docs/mobile/ehs_menu.png
Normal file
|
After Width: | Height: | Size: 403 KiB |
BIN
frontend/public/imgs/docs/mobile/stagenow.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
frontend/public/imgs/docs/mobile/test2-1.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
frontend/public/imgs/docs/mobile/test2-2.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
frontend/public/imgs/docs/mobile/test2-3.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
frontend/public/imgs/docs/mobile/tools.png
Normal file
|
After Width: | Height: | Size: 268 KiB |
BIN
frontend/public/imgs/docs/mobile/update.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
frontend/public/stage-now/test2-stageNow.pdf
Normal file
@@ -1,11 +1,12 @@
|
|||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { Link, useRouterState } from "@tanstack/react-router";
|
import { Link, useRouterState } from "@tanstack/react-router";
|
||||||
import { ChevronRight } from "lucide-react";
|
import { ChevronRight, ScrollText } from "lucide-react";
|
||||||
|
import { getSettings } from "../../lib/queries/getSettings";
|
||||||
import {
|
import {
|
||||||
Collapsible,
|
Collapsible,
|
||||||
CollapsibleContent,
|
CollapsibleContent,
|
||||||
CollapsibleTrigger,
|
CollapsibleTrigger,
|
||||||
} from "../ui/collapsible";
|
} from "../ui/collapsible";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
@@ -19,43 +20,55 @@ import {
|
|||||||
useSidebar,
|
useSidebar,
|
||||||
} from "../ui/sidebar";
|
} from "../ui/sidebar";
|
||||||
|
|
||||||
const docs = [
|
|
||||||
{
|
|
||||||
title: "Notifications",
|
|
||||||
url: "/intro",
|
|
||||||
//icon,
|
|
||||||
isActive: window.location.pathname.includes("notifications") ?? false,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: "Reprints",
|
|
||||||
url: "/reprints",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "New Blocking order",
|
|
||||||
url: "/qualityBlocking",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Mobile",
|
|
||||||
url: "/updateInstructions",
|
|
||||||
isActive: false,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: "Settings",
|
|
||||||
url: "/mobile-settings",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
export default function DocBar() {
|
export default function DocBar() {
|
||||||
const { setOpen } = useSidebar();
|
const { setOpen } = useSidebar();
|
||||||
|
const { data: settings, isLoading } = useSuspenseQuery(getSettings());
|
||||||
const pathname = useRouterState({
|
const pathname = useRouterState({
|
||||||
select: (s) => s.location.pathname,
|
select: (s) => s.location.pathname,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isNotifications = pathname.includes("notifications");
|
const isNotifications = pathname.includes("notifications");
|
||||||
|
|
||||||
|
const docs = [
|
||||||
|
{
|
||||||
|
title: "Notifications",
|
||||||
|
url: "notifications/intro",
|
||||||
|
//icon,
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "Reprints",
|
||||||
|
icon: ScrollText,
|
||||||
|
url: "notifications/reprints",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "New Blocking order",
|
||||||
|
icon: ScrollText,
|
||||||
|
url: "notifications/qualityBlocking",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Mobile",
|
||||||
|
url: "mobile/updateInstructions",
|
||||||
|
isActive:
|
||||||
|
!isLoading &&
|
||||||
|
settings.filter((n: any) => n.name === "mobile")[0].active,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "Update Instructions",
|
||||||
|
icon: ScrollText,
|
||||||
|
url: "mobile/updateInstructions",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: "Settings",
|
||||||
|
// icon: ScrollText,
|
||||||
|
// url: "mobile/mobile-settings",
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupLabel>Docs</SidebarGroupLabel>
|
<SidebarGroupLabel>Docs</SidebarGroupLabel>
|
||||||
@@ -72,42 +85,45 @@ export default function DocBar() {
|
|||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{docs.map((item) => (
|
{docs.map((item) => (
|
||||||
<Collapsible
|
<>
|
||||||
key={item.title}
|
{item.isActive && (
|
||||||
asChild
|
<Collapsible
|
||||||
defaultOpen={isNotifications}
|
key={item.title}
|
||||||
className="group/collapsible"
|
asChild
|
||||||
>
|
defaultOpen={isNotifications}
|
||||||
<SidebarMenuItem>
|
className="group/collapsible"
|
||||||
<CollapsibleTrigger asChild>
|
>
|
||||||
<SidebarMenuButton tooltip={item.title}>
|
<SidebarMenuItem>
|
||||||
<Link
|
<CollapsibleTrigger asChild>
|
||||||
to={"/docs/$"}
|
<SidebarMenuButton tooltip={item.title}>
|
||||||
params={{ _splat: `notifications${item.url}` }}
|
<Link to={"/docs/$"} params={{ _splat: `${item.url}` }}>
|
||||||
>
|
{item.title}
|
||||||
{item.title}
|
</Link>
|
||||||
</Link>
|
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
||||||
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
</SidebarMenuButton>
|
||||||
</SidebarMenuButton>
|
</CollapsibleTrigger>
|
||||||
</CollapsibleTrigger>
|
<CollapsibleContent>
|
||||||
<CollapsibleContent>
|
<SidebarMenuSub>
|
||||||
<SidebarMenuSub>
|
{item.items?.map((subItem) => (
|
||||||
{item.items?.map((subItem) => (
|
<SidebarMenuSubItem key={subItem.title}>
|
||||||
<SidebarMenuSubItem key={subItem.title}>
|
<SidebarMenuSubButton asChild>
|
||||||
<SidebarMenuSubButton asChild>
|
<Link
|
||||||
<Link
|
to={"/docs/$"}
|
||||||
to={"/docs/$"}
|
params={{ _splat: `${subItem.url}` }}
|
||||||
params={{ _splat: `notifications${subItem.url}` }}
|
onClick={() => setOpen(false)}
|
||||||
>
|
>
|
||||||
{subItem.title}
|
<subItem.icon />
|
||||||
</Link>
|
<span>{subItem.title}</span>
|
||||||
</SidebarMenuSubButton>
|
</Link>
|
||||||
</SidebarMenuSubItem>
|
</SidebarMenuSubButton>
|
||||||
))}
|
</SidebarMenuSubItem>
|
||||||
</SidebarMenuSub>
|
))}
|
||||||
</CollapsibleContent>
|
</SidebarMenuSub>
|
||||||
</SidebarMenuItem>
|
</CollapsibleContent>
|
||||||
</Collapsible>
|
</SidebarMenuItem>
|
||||||
|
</Collapsible>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroupContent>
|
</SidebarGroupContent>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Link } from "@tanstack/react-router";
|
import { Link } from "@tanstack/react-router";
|
||||||
import { ScanText, ScrollText } from "lucide-react";
|
import { ScanText } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
@@ -10,14 +10,14 @@ import {
|
|||||||
useSidebar,
|
useSidebar,
|
||||||
} from "../ui/sidebar";
|
} from "../ui/sidebar";
|
||||||
|
|
||||||
export default function MobileBar({ session }: any) {
|
export default function MobileBar() {
|
||||||
const { setOpen } = useSidebar();
|
const { setOpen } = useSidebar();
|
||||||
const items = [
|
const items = [
|
||||||
{
|
// {
|
||||||
title: "Update Instructions",
|
// title: "Update Instructions",
|
||||||
url: "/",
|
// url: "/",
|
||||||
icon: ScrollText,
|
// icon: ScrollText,
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: "Scan Log",
|
title: "Scan Log",
|
||||||
url: "/",
|
url: "/",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
SidebarContent,
|
SidebarContent,
|
||||||
@@ -6,12 +7,14 @@ import {
|
|||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import { useSession } from "@/lib/auth-client";
|
import { useSession } from "@/lib/auth-client";
|
||||||
|
import { getSettings } from "../../lib/queries/getSettings";
|
||||||
import AdminSidebar from "./AdminBar";
|
import AdminSidebar from "./AdminBar";
|
||||||
import DocBar from "./DocBar";
|
import DocBar from "./DocBar";
|
||||||
import MobileBar from "./MobileBar";
|
import MobileBar from "./MobileBar";
|
||||||
|
|
||||||
export function AppSidebar() {
|
export function AppSidebar() {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
|
const { data: settings, isLoading } = useSuspenseQuery(getSettings());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sidebar
|
<Sidebar
|
||||||
@@ -24,7 +27,11 @@ export function AppSidebar() {
|
|||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
<DocBar />
|
<DocBar />
|
||||||
<MobileBar session={session} />
|
{!isLoading &&
|
||||||
|
settings.filter((n: any) => n.name === "mobile")[0].active && (
|
||||||
|
<MobileBar />
|
||||||
|
)}
|
||||||
|
|
||||||
{session &&
|
{session &&
|
||||||
(session.user.role === "admin" ||
|
(session.user.role === "admin" ||
|
||||||
session.user.role === "systemAdmin" ||
|
session.user.role === "systemAdmin" ||
|
||||||
|
|||||||
137
frontend/src/docs/mobile/updateInstructions.tsx
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { Separator } from "../../components/ui/separator";
|
||||||
|
|
||||||
|
export default function UpdateInstructions() {
|
||||||
|
const getFile = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
// 1. Fetch the file from the public folder
|
||||||
|
const response = await fetch(
|
||||||
|
`/lst/app/stage-now/${window.LST_CONFIG?.server}-stageNow.pdf`,
|
||||||
|
);
|
||||||
|
if (!response.ok) throw new Error("Network response was not ok");
|
||||||
|
|
||||||
|
// 2. Convert to blob
|
||||||
|
return await response.blob();
|
||||||
|
},
|
||||||
|
onSuccess: (blob) => {
|
||||||
|
// 3. Create a temporary anchor element to trigger download
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = `${window.LST_CONFIG?.server}-stageNow.pdf`; // Desired filename
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
// 4. Cleanup
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
document.body.removeChild(a);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row gap-2">
|
||||||
|
<div className="w-1/2">
|
||||||
|
<div className="flex flex-col gap-1 justify-center">
|
||||||
|
<div>
|
||||||
|
<p className="text-center text-3xl">
|
||||||
|
Updating the lst mobile scanner app
|
||||||
|
</p>
|
||||||
|
<p className="text-center text-sm">
|
||||||
|
NOTE: LST Mobile only works on TC8300
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Button
|
||||||
|
onClick={() => getFile.mutate()}
|
||||||
|
disabled={getFile.isPending}
|
||||||
|
>
|
||||||
|
{getFile.isPending ? "Downloading..." : "Get StageNow Codes"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Separator className="m-3" />
|
||||||
|
<div>
|
||||||
|
<p className="text-2xl text-center">
|
||||||
|
How to know the scanner has an update?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The bottom part of the scanner will show a red or orange bar
|
||||||
|
indicating there is an update. As shown below
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-row gap-2 justify-center">
|
||||||
|
<div className="w-1/2">
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/critical_update.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[50%] h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2">
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/update.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[50%] h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator className="m-3" />
|
||||||
|
<div>
|
||||||
|
<p className="text-2xl text-center">
|
||||||
|
To update the scanner follow the below steps.
|
||||||
|
</p>
|
||||||
|
<p>Step 1) Tap the 3 dots top right of the home screen</p>
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/ehs_homeScreen.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[25%] h-auto m-3"
|
||||||
|
/>
|
||||||
|
<p>Step 2) Tap tools</p>
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/ehs_menu.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[25%] h-auto m-3"
|
||||||
|
/>
|
||||||
|
<p>Step 3) Tap Stage Now</p>
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/tools.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[25%] h-auto m-3"
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
Step 4) Scan the 3 barcode's to the right or from the printed sheet
|
||||||
|
</p>
|
||||||
|
<img
|
||||||
|
src="/lst/app/imgs/docs/mobile/stagenow.png"
|
||||||
|
alt="Home"
|
||||||
|
className="max-w-[25%] h-auto m-3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p>Scan Commands</p>
|
||||||
|
<Separator className="m-3" />
|
||||||
|
<div className="flex flex-col justify-center">
|
||||||
|
<img
|
||||||
|
src={`/lst/app/imgs/docs/mobile/${window.LST_CONFIG?.server}-1.png`}
|
||||||
|
alt="Home"
|
||||||
|
className="m-3"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src={`/lst/app/imgs/docs/mobile/${window.LST_CONFIG?.server}-2.png`}
|
||||||
|
alt="Home"
|
||||||
|
className="m-3"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src={`/lst/app/imgs/docs/mobile/${window.LST_CONFIG?.server}-3.png`}
|
||||||
|
alt="Home"
|
||||||
|
className="m-3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export default function updateInstructions() {
|
|
||||||
return <div>updateInstructions</div>;
|
|
||||||
}
|
|
||||||
@@ -13,9 +13,7 @@ const docsMap: Record<string, ComponentType> = {};
|
|||||||
for (const path in modules) {
|
for (const path in modules) {
|
||||||
const mod = modules[path] as DocModule;
|
const mod = modules[path] as DocModule;
|
||||||
|
|
||||||
const slug = path
|
const slug = path.replace("../docs/", "").replace(".tsx", "");
|
||||||
.replace("../docs/", "")
|
|
||||||
.replace(".tsx", "");
|
|
||||||
|
|
||||||
// "notifications/intro"
|
// "notifications/intro"
|
||||||
docsMap[slug] = mod.default;
|
docsMap[slug] = mod.default;
|
||||||
@@ -23,4 +21,4 @@ for (const path in modules) {
|
|||||||
|
|
||||||
export function getDoc(slug: string) {
|
export function getDoc(slug: string) {
|
||||||
return docsMap[slug];
|
return docsMap[slug];
|
||||||
}
|
}
|
||||||
|
|||||||