refactor(opendock): added some new goodies to the app to help manage releases
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m24s

This commit is contained in:
2026-06-09 21:09:03 -05:00
parent 8fcb2c66ed
commit c0a7d4a125
15 changed files with 3286 additions and 72 deletions

View File

@@ -0,0 +1,221 @@
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute, redirect } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table";
import { formatInTimeZone } from "date-fns-tz";
import { Trash } from "lucide-react";
import { Suspense, useState } from "react";
import { toast } from "sonner";
import { Button } from "../../../components/ui/button";
import { Spinner } from "../../../components/ui/spinner";
import { api } from "../../../lib/apiHelper";
import { authClient } from "../../../lib/auth-client";
import { opendockApt } from "../../../lib/queries/openDockApt";
import { permissionQuery } from "../../../lib/queries/permsCheck";
import LstTable from "../../../lib/tableStuff/LstTable";
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
export const Route = createFileRoute("/transportation/opendock/releases")({
beforeLoad: async ({ location }) => {
const { data: session } = await authClient.getSession();
//const allowedRole = ["systemAdmin", "admin", "manager"];
const canAccess = await authClient.admin.hasPermission({
permissions: {
openDock: ["create"],
},
});
if (!session?.user) {
throw redirect({
to: "/",
search: {
redirect: location.href,
},
});
}
//if (!allowedRole.includes(session.user.role as string)) {
if (!canAccess) {
throw redirect({
to: "/",
});
}
return { user: session.user };
},
component: RouteComponent,
});
const OpendockApts = () => {
const { data, refetch } = useSuspenseQuery(opendockApt());
const { data: canReadOpenDock = false } = useQuery(
permissionQuery({
openDock: ["update"],
}),
);
const columnHelper = createColumnHelper<any>();
const columns = [
columnHelper.accessor("release", {
header: ({ column }) => (
<SearchableHeader column={column} title="Release" searchable={true} />
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor(
(row) =>
row.appointment.customFields.find((x: any) => x.name === "strArticle")
?.value ?? "",
{
id: "article",
header: ({ column }) => (
<SearchableHeader column={column} title="Article" searchable={true} />
),
filterFn: "includesString",
cell: (i) => i.getValue(),
},
),
columnHelper.accessor("appointment.status", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Current Opendock status"
searchable={true}
/>
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor("upd_date", {
header: ({ column }) => (
<SearchableHeader column={column} title="Last Updated" />
),
filterFn: "includesString",
cell: (i) => {
function isDateValid(date: any) {
return date instanceof Date && !isNaN(date.getTime());
}
const trueDate = isDateValid(new Date(i.getValue()))
? formatInTimeZone(
i.getValue(),
`${window.LST_CONFIG?.timezone}`,
"MM/dd/yyyy HH:mm:ss",
)
: "invalid time";
return <span>{trueDate}</span>;
},
}),
];
if (canReadOpenDock) {
columns.push(
columnHelper.accessor("deleteRelease", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Delete Link"
searchable={false}
/>
),
filterFn: "includesString",
cell: (i) => {
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
const [activeToggle, setActiveToggle] = useState(false);
const onTrigger = async () => {
setActiveToggle(true);
try {
const res = await api.delete(
`/opendock/${i.row.original.id}`,
{
withCredentials: true,
timeout: 5000,
validateStatus: () => true,
},
);
if (res.data.success) {
toast.success(
`Release: ${i.row.original.release} was deleted.`,
);
refetch();
setActiveToggle(false);
}
if (!res.data.success) {
toast.error(
`Release: ${i.row.original.release} encountered an error when trying to delete: ${res.data.message}`,
);
refetch();
setActiveToggle(false);
}
} catch (error) {
setActiveToggle(false);
console.error(error);
}
};
return (
<div>
<div className="flex items-center space-x-2">
<Button
variant="destructive"
disabled={
activeToggle ||
i.row.original.appointment.status !== "Scheduled"
}
onClick={onTrigger}
>
{activeToggle ? (
<span>
<Spinner />
</span>
) : (
<span>
<Trash />
</span>
)}
</Button>
</div>
</div>
);
},
}),
);
}
return (
<div>
<div>
<div className="flex justify-end m-2">
{/* <Suspense
fallback={
<div>
<p>Loading...</p>
</div>
}
>
<NewArticleLink refetch={refetch} />
</Suspense> */}
</div>
<div>
<LstTable data={data} columns={columns} pageSize={50} />
</div>
</div>
</div>
);
};
function RouteComponent() {
return (
<Suspense fallback={<SkellyTable />}>
<OpendockApts />
</Suspense>
);
}

View File

@@ -68,9 +68,9 @@ function RouteComponent() {
<div className="flex justify-center">
<p>Please select an active loading order for {dockData[0].name}</p>
</div>
<div className="flex justify-center mt-5 gap-2">
<div className="flex flex-row justify-center mt-5 gap-2">
{loadingPlans && loadingPlans.length > 0 ? (
<div>
<div className="flex flex-row gap-3">
{loadingPlans.map((i: any) => {
return (
<Card key={i.id} className="max-w-96">
@@ -140,7 +140,8 @@ function RouteComponent() {
)
}
disabled={
dockData[0].currentLoadingOrder === "" ? true : false
dockData[0].currentLoadingOrder === "" ||
dockData[0].currentLoadingOrder !== i.id.toString()
}
>
Finish Loading

View File

@@ -1,4 +1,4 @@
import { useSuspenseQuery } from "@tanstack/react-query";
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table";
import { formatInTimeZone } from "date-fns-tz";
@@ -9,6 +9,7 @@ import { api } from "../../../../lib/apiHelper";
import { useAppForm } from "../../../../lib/formSutff";
import { getActiveLoadingOrders } from "../../../../lib/queries/getActiveDockScanners";
import { getActiveDockScanners } from "../../../../lib/queries/getActiveLoadingOrders";
import { permissionQuery } from "../../../../lib/queries/permsCheck";
import LstTable from "../../../../lib/tableStuff/LstTable";
import SearchableHeader from "../../../../lib/tableStuff/SearchableHeader";
import { finishLoadingOrder } from "..";
@@ -27,6 +28,12 @@ function RouteComponent() {
const { data, refetch } = useSuspenseQuery(getActiveDockScanners());
const { data: loadingPlanItems, refetch: refetchActiveLoading } =
useSuspenseQuery(getActiveLoadingOrders());
const { data: canReadWarehouse = false } = useQuery(
permissionQuery({
warehouse: ["delete"],
}),
);
const columnHelper = createColumnHelper<any>();
const column = [
@@ -119,6 +126,7 @@ function RouteComponent() {
(x: any) => x.id === Number(data[0].currentLoadingOrder),
)
: [];
return (
<div>
<div>
@@ -138,7 +146,7 @@ function RouteComponent() {
)}
</p>
</div>
<div className="max-w-1/2 flex flex-col">
<div className="flex flex-col">
<div>
<form
onSubmit={(e) => {
@@ -166,29 +174,32 @@ function RouteComponent() {
</div>
</form>
</div>
<div className="flex justify-end mr-3 ">
<Button
type="button"
onClick={() => {
finishLoadingOrder(
String(data[0].currentLoadingOrder),
dockScans,
refetch,
refetchActiveLoading,
);
clearRoom();
}}
disabled={
loadingPlan ||
loadingPlan[0].loadingPlanItems[0].loadedQuantityLUs !==
loadingPlan[0].loadingPlanItems[0].plannedQuantityLUs
}
>
Finish Loading order
</Button>
<Button onClick={() => clearRoom()}>Clear Table</Button>
</div>
{loadingPlan && loadingPlan.length > 0 && (
<div className="flex mb-2 gap-2">
<Button
type="button"
onClick={() => {
finishLoadingOrder(
String(data[0].currentLoadingOrder),
dockScans,
refetch,
refetchActiveLoading,
);
clearRoom();
}}
disabled={
(loadingPlan && loadingPlan.length < 0) ||
loadingPlan[0].loadingPlanItems[0].loadedQuantityLUs !==
loadingPlan[0].loadingPlanItems[0].plannedQuantityLUs
}
>
Finish Loading order
</Button>
{canReadWarehouse && (
<Button onClick={() => clearRoom()}>Clear Table</Button>
)}
</div>
)}
</div>
<div>
<LstTable data={logs} columns={column} pageSize={50} />