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
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m24s
This commit is contained in:
@@ -40,6 +40,11 @@ export default function TransportationBar() {
|
||||
icon: link,
|
||||
url: "/transportation/opendock",
|
||||
},
|
||||
{
|
||||
title: "Active releases",
|
||||
icon: link,
|
||||
url: "/transportation/opendock/releases",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
23
frontend/src/lib/queries/openDockApt.ts
Normal file
23
frontend/src/lib/queries/openDockApt.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "../apiHelper";
|
||||
|
||||
export function opendockApt() {
|
||||
return queryOptions({
|
||||
queryKey: ["opendockApt"],
|
||||
queryFn: () => fetch(),
|
||||
staleTime: 5000,
|
||||
refetchOnWindowFocus: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
}
|
||||
|
||||
const fetch = async () => {
|
||||
if (window.location.hostname === "localhost") {
|
||||
await new Promise((res) => setTimeout(res, 1500));
|
||||
}
|
||||
|
||||
const { data } = await api.get("/opendock?daysCreated=90");
|
||||
|
||||
return data.data;
|
||||
};
|
||||
@@ -25,6 +25,7 @@ import { Route as authLoginRouteImport } from './routes/(auth)/login'
|
||||
import { Route as WarehouseDockdoorscanningIndexRouteImport } from './routes/warehouse/dockdoorscanning/index'
|
||||
import { Route as TransportationOpendockIndexRouteImport } from './routes/transportation/opendock/index'
|
||||
import { Route as WarehouseDockdoorscanningDockRouteImport } from './routes/warehouse/dockdoorscanning/$dock'
|
||||
import { Route as TransportationOpendockReleasesRouteImport } from './routes/transportation/opendock/releases'
|
||||
import { Route as authUserSignupRouteImport } from './routes/(auth)/user.signup'
|
||||
import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user.resetpassword'
|
||||
import { Route as authUserProfileRouteImport } from './routes/(auth)/user.profile'
|
||||
@@ -113,6 +114,12 @@ const WarehouseDockdoorscanningDockRoute =
|
||||
path: '/warehouse/dockdoorscanning/$dock',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const TransportationOpendockReleasesRoute =
|
||||
TransportationOpendockReleasesRouteImport.update({
|
||||
id: '/transportation/opendock/releases',
|
||||
path: '/transportation/opendock/releases',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const authUserSignupRoute = authUserSignupRouteImport.update({
|
||||
id: '/(auth)/user/signup',
|
||||
path: '/user/signup',
|
||||
@@ -152,6 +159,7 @@ export interface FileRoutesByFullPath {
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/user/signup': typeof authUserSignupRoute
|
||||
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
|
||||
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
|
||||
'/transportation/opendock/': typeof TransportationOpendockIndexRoute
|
||||
'/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute
|
||||
@@ -174,6 +182,7 @@ export interface FileRoutesByTo {
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/user/signup': typeof authUserSignupRoute
|
||||
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
|
||||
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
|
||||
'/transportation/opendock': typeof TransportationOpendockIndexRoute
|
||||
'/warehouse/dockdoorscanning': typeof WarehouseDockdoorscanningIndexRoute
|
||||
@@ -197,6 +206,7 @@ export interface FileRoutesById {
|
||||
'/(auth)/user/profile': typeof authUserProfileRoute
|
||||
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/(auth)/user/signup': typeof authUserSignupRoute
|
||||
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
|
||||
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
|
||||
'/transportation/opendock/': typeof TransportationOpendockIndexRoute
|
||||
'/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute
|
||||
@@ -221,6 +231,7 @@ export interface FileRouteTypes {
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
| '/user/signup'
|
||||
| '/transportation/opendock/releases'
|
||||
| '/warehouse/dockdoorscanning/$dock'
|
||||
| '/transportation/opendock/'
|
||||
| '/warehouse/dockdoorscanning/'
|
||||
@@ -243,6 +254,7 @@ export interface FileRouteTypes {
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
| '/user/signup'
|
||||
| '/transportation/opendock/releases'
|
||||
| '/warehouse/dockdoorscanning/$dock'
|
||||
| '/transportation/opendock'
|
||||
| '/warehouse/dockdoorscanning'
|
||||
@@ -265,6 +277,7 @@ export interface FileRouteTypes {
|
||||
| '/(auth)/user/profile'
|
||||
| '/(auth)/user/resetpassword'
|
||||
| '/(auth)/user/signup'
|
||||
| '/transportation/opendock/releases'
|
||||
| '/warehouse/dockdoorscanning/$dock'
|
||||
| '/transportation/opendock/'
|
||||
| '/warehouse/dockdoorscanning/'
|
||||
@@ -288,6 +301,7 @@ export interface RootRouteChildren {
|
||||
authUserProfileRoute: typeof authUserProfileRoute
|
||||
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
||||
authUserSignupRoute: typeof authUserSignupRoute
|
||||
TransportationOpendockReleasesRoute: typeof TransportationOpendockReleasesRoute
|
||||
WarehouseDockdoorscanningDockRoute: typeof WarehouseDockdoorscanningDockRoute
|
||||
TransportationOpendockIndexRoute: typeof TransportationOpendockIndexRoute
|
||||
WarehouseDockdoorscanningIndexRoute: typeof WarehouseDockdoorscanningIndexRoute
|
||||
@@ -408,6 +422,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof WarehouseDockdoorscanningDockRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/transportation/opendock/releases': {
|
||||
id: '/transportation/opendock/releases'
|
||||
path: '/transportation/opendock/releases'
|
||||
fullPath: '/transportation/opendock/releases'
|
||||
preLoaderRoute: typeof TransportationOpendockReleasesRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/(auth)/user/signup': {
|
||||
id: '/(auth)/user/signup'
|
||||
path: '/user/signup'
|
||||
@@ -456,6 +477,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
authUserProfileRoute: authUserProfileRoute,
|
||||
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
||||
authUserSignupRoute: authUserSignupRoute,
|
||||
TransportationOpendockReleasesRoute: TransportationOpendockReleasesRoute,
|
||||
WarehouseDockdoorscanningDockRoute: WarehouseDockdoorscanningDockRoute,
|
||||
TransportationOpendockIndexRoute: TransportationOpendockIndexRoute,
|
||||
WarehouseDockdoorscanningIndexRoute: WarehouseDockdoorscanningIndexRoute,
|
||||
|
||||
221
frontend/src/routes/transportation/opendock/releases.tsx
Normal file
221
frontend/src/routes/transportation/opendock/releases.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user