feat(forklifts): added backend forklift stuff and frontend companies
This commit is contained in:
94
frontend/src/components/navBar/ForkliftSideBar.tsx
Normal file
94
frontend/src/components/navBar/ForkliftSideBar.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import {
|
||||
Building2,
|
||||
Forklift,
|
||||
Hourglass,
|
||||
ReceiptText,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import { userAccess } from "@/lib/authClient";
|
||||
import {
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "../ui/sidebar";
|
||||
import type { Items } from "./SideBarNav";
|
||||
|
||||
export default function ForkliftSideBar() {
|
||||
const items: Items[] = [
|
||||
{
|
||||
title: "Lease Companies",
|
||||
url: "/lst/app/forklifts/companies",
|
||||
icon: Building2,
|
||||
role: ["systemAdmin", "admin"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "Leases",
|
||||
url: "/lst/app/admin/settings",
|
||||
icon: ReceiptText,
|
||||
role: ["systemAdmin", "admin"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "Invoices",
|
||||
url: "/lst/app/admin/settings",
|
||||
icon: ReceiptText,
|
||||
role: ["systemAdmin", "admin", "manager"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "Repairs",
|
||||
url: "/lst/app/admin/settings",
|
||||
icon: Wrench,
|
||||
role: ["systemAdmin", "admin", "manager"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "Hours",
|
||||
url: "/lst/app/admin/settings",
|
||||
icon: Hourglass,
|
||||
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "Forklifts",
|
||||
url: "/lst/app/admin/modules",
|
||||
icon: Forklift,
|
||||
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
||||
module: "forklifts",
|
||||
active: true,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Forklifts</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{items.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<>
|
||||
{userAccess(item.module, item.role) && item.active && (
|
||||
<SidebarMenuButton asChild>
|
||||
<Link to={item.url}>
|
||||
<item.icon />
|
||||
<span>{item.title}</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Link, useRouterState } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import NewCompanyForm from "@/routes/_app/_forklifts/-components/NewCompany";
|
||||
import { useAuth, useLogout } from "../../lib/authClient";
|
||||
import { ModeToggle } from "../mode-toggle";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
|
||||
import { Button } from "../ui/button";
|
||||
import { Dialog, DialogContent } from "../ui/dialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -17,6 +20,7 @@ export default function Nav() {
|
||||
const logout = useLogout();
|
||||
const router = useRouterState();
|
||||
const currentPath = router.location.href;
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
return (
|
||||
<nav className="flex justify-end w-full shadow ">
|
||||
<div className="m-2 flex flex-row gap-1">
|
||||
@@ -33,6 +37,37 @@ export default function Nav() {
|
||||
<Button className="m-1">
|
||||
<Link to="/old">Old Version</Link>
|
||||
</Button>
|
||||
<div className="m-1">
|
||||
{location.pathname.includes("forklifts") && (
|
||||
<>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button>Forklifts</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>Forklift links</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
// just open the dialog when clicked
|
||||
setOpenDialog(true);
|
||||
}}
|
||||
>
|
||||
New Company
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{/* Dialog mounted outside the menu */}
|
||||
{openDialog && (
|
||||
<Dialog open={openDialog} onOpenChange={setOpenDialog}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<NewCompanyForm setOpenDialog={setOpenDialog} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{session ? (
|
||||
<div className="m-1">
|
||||
<DropdownMenu>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { userAccess } from "../../lib/authClient";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import { type UserRoles, userAccess } from "@/lib/authClient";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -8,17 +9,32 @@ import {
|
||||
SidebarTrigger,
|
||||
} from "../ui/sidebar";
|
||||
import Admin from "./Admin";
|
||||
import ForkliftSideBar from "./ForkliftSideBar";
|
||||
import { Header } from "./Header";
|
||||
|
||||
export type Items = {
|
||||
title: string;
|
||||
url: string;
|
||||
icon: LucideIcon;
|
||||
role: UserRoles["role"][];
|
||||
module: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
export default function SideBarNav() {
|
||||
return (
|
||||
<div className="flex min-h-screen">
|
||||
<Sidebar collapsible="icon">
|
||||
<Header />
|
||||
<SidebarContent>
|
||||
{userAccess(null, [
|
||||
"systemAdmin",
|
||||
"admin",
|
||||
"manager",
|
||||
"supervisor",
|
||||
]) && <ForkliftSideBar />}
|
||||
{userAccess(null, ["systemAdmin", "admin"]) && <Admin />}
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter>
|
||||
<SidebarMenuItem>
|
||||
<Link to={"/changelog"}>Changelog</Link>
|
||||
|
||||
@@ -16,16 +16,19 @@ import { Route as AppIndexRouteImport } from './routes/_app/index'
|
||||
import { Route as AppChangelogRouteImport } from './routes/_app/changelog'
|
||||
import { Route as OldOldRouteRouteImport } from './routes/_old/old/route'
|
||||
import { Route as MobileMobileLayoutRouteRouteImport } from './routes/_mobile/_mobileLayout/route'
|
||||
import { Route as AppForkliftsRouteRouteImport } from './routes/_app/_forklifts/route'
|
||||
import { Route as AppAdminLayoutRouteRouteImport } from './routes/_app/_adminLayout/route'
|
||||
import { Route as OldOldIndexRouteImport } from './routes/_old/old/index'
|
||||
import { Route as AppauthLoginRouteImport } from './routes/_app/(auth)/login'
|
||||
import { Route as OldOldRfidIndexRouteImport } from './routes/_old/old/rfid/index'
|
||||
import { Route as OldOldOcpIndexRouteImport } from './routes/_old/old/ocp/index'
|
||||
import { Route as MobileMobileLayoutMIndexRouteImport } from './routes/_mobile/_mobileLayout/m/index'
|
||||
import { Route as AppForkliftsForkliftsIndexRouteImport } from './routes/_app/_forklifts/forklifts/index'
|
||||
import { Route as AppauthUserIndexRouteImport } from './routes/_app/(auth)/user/index'
|
||||
import { Route as MobileMobileLayoutMRelocateRouteImport } from './routes/_mobile/_mobileLayout/m/relocate'
|
||||
import { Route as MobileMobileLayoutMDeliveryRouteImport } from './routes/_mobile/_mobileLayout/m/delivery'
|
||||
import { Route as MobileMobileLayoutMCyclecountsRouteImport } from './routes/_mobile/_mobileLayout/m/cyclecounts'
|
||||
import { Route as AppForkliftsForkliftsCompaniesRouteImport } from './routes/_app/_forklifts/forklifts/companies'
|
||||
import { Route as AppAdminLayoutAdminServersRouteImport } from './routes/_app/_adminLayout/admin/servers'
|
||||
import { Route as ApplogisticsLogisticsDeliveryScheduleRouteImport } from './routes/_app/(logistics)/logistics/deliverySchedule'
|
||||
import { Route as AppauthUserSignupRouteImport } from './routes/_app/(auth)/user/signup'
|
||||
@@ -74,6 +77,10 @@ const MobileMobileLayoutRouteRoute = MobileMobileLayoutRouteRouteImport.update({
|
||||
id: '/_mobile/_mobileLayout',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const AppForkliftsRouteRoute = AppForkliftsRouteRouteImport.update({
|
||||
id: '/_forklifts',
|
||||
getParentRoute: () => AppRouteRoute,
|
||||
} as any)
|
||||
const AppAdminLayoutRouteRoute = AppAdminLayoutRouteRouteImport.update({
|
||||
id: '/_adminLayout',
|
||||
getParentRoute: () => AppRouteRoute,
|
||||
@@ -109,6 +116,12 @@ const MobileMobileLayoutMIndexRoute =
|
||||
path: '/m/',
|
||||
getParentRoute: () => MobileMobileLayoutRouteRoute,
|
||||
} as any)
|
||||
const AppForkliftsForkliftsIndexRoute =
|
||||
AppForkliftsForkliftsIndexRouteImport.update({
|
||||
id: '/forklifts/',
|
||||
path: '/forklifts/',
|
||||
getParentRoute: () => AppForkliftsRouteRoute,
|
||||
} as any)
|
||||
const AppauthUserIndexRoute = AppauthUserIndexRouteImport.update({
|
||||
id: '/(auth)/user/',
|
||||
path: '/user/',
|
||||
@@ -132,6 +145,12 @@ const MobileMobileLayoutMCyclecountsRoute =
|
||||
path: '/m/cyclecounts',
|
||||
getParentRoute: () => MobileMobileLayoutRouteRoute,
|
||||
} as any)
|
||||
const AppForkliftsForkliftsCompaniesRoute =
|
||||
AppForkliftsForkliftsCompaniesRouteImport.update({
|
||||
id: '/forklifts/companies',
|
||||
path: '/forklifts/companies',
|
||||
getParentRoute: () => AppForkliftsRouteRoute,
|
||||
} as any)
|
||||
const AppAdminLayoutAdminServersRoute =
|
||||
AppAdminLayoutAdminServersRouteImport.update({
|
||||
id: '/servers',
|
||||
@@ -260,10 +279,12 @@ export interface FileRoutesByFullPath {
|
||||
'/user/signup': typeof AppauthUserSignupRoute
|
||||
'/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
'/m/relocate': typeof MobileMobileLayoutMRelocateRoute
|
||||
'/user': typeof AppauthUserIndexRoute
|
||||
'/forklifts': typeof AppForkliftsForkliftsIndexRoute
|
||||
'/m': typeof MobileMobileLayoutMIndexRoute
|
||||
'/old/ocp': typeof OldOldOcpIndexRoute
|
||||
'/old/rfid': typeof OldOldRfidIndexRoute
|
||||
@@ -292,10 +313,12 @@ export interface FileRoutesByTo {
|
||||
'/user/signup': typeof AppauthUserSignupRoute
|
||||
'/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
'/m/relocate': typeof MobileMobileLayoutMRelocateRoute
|
||||
'/user': typeof AppauthUserIndexRoute
|
||||
'/forklifts': typeof AppForkliftsForkliftsIndexRoute
|
||||
'/m': typeof MobileMobileLayoutMIndexRoute
|
||||
'/old/ocp': typeof OldOldOcpIndexRoute
|
||||
'/old/rfid': typeof OldOldRfidIndexRoute
|
||||
@@ -317,6 +340,7 @@ export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/_app': typeof AppRouteRouteWithChildren
|
||||
'/_app/_adminLayout': typeof AppAdminLayoutRouteRouteWithChildren
|
||||
'/_app/_forklifts': typeof AppForkliftsRouteRouteWithChildren
|
||||
'/_mobile/_mobileLayout': typeof MobileMobileLayoutRouteRouteWithChildren
|
||||
'/_old/old': typeof OldOldRouteRouteWithChildren
|
||||
'/_app/changelog': typeof AppChangelogRoute
|
||||
@@ -331,10 +355,12 @@ export interface FileRoutesById {
|
||||
'/_app/(auth)/user/signup': typeof AppauthUserSignupRoute
|
||||
'/_app/(logistics)/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/_app/_adminLayout/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/_app/_forklifts/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/_mobile/_mobileLayout/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/_mobile/_mobileLayout/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
'/_mobile/_mobileLayout/m/relocate': typeof MobileMobileLayoutMRelocateRoute
|
||||
'/_app/(auth)/user/': typeof AppauthUserIndexRoute
|
||||
'/_app/_forklifts/forklifts/': typeof AppForkliftsForkliftsIndexRoute
|
||||
'/_mobile/_mobileLayout/m/': typeof MobileMobileLayoutMIndexRoute
|
||||
'/_old/old/ocp/': typeof OldOldOcpIndexRoute
|
||||
'/_old/old/rfid/': typeof OldOldRfidIndexRoute
|
||||
@@ -366,10 +392,12 @@ export interface FileRouteTypes {
|
||||
| '/user/signup'
|
||||
| '/logistics/deliverySchedule'
|
||||
| '/admin/servers'
|
||||
| '/forklifts/companies'
|
||||
| '/m/cyclecounts'
|
||||
| '/m/delivery'
|
||||
| '/m/relocate'
|
||||
| '/user'
|
||||
| '/forklifts'
|
||||
| '/m'
|
||||
| '/old/ocp'
|
||||
| '/old/rfid'
|
||||
@@ -398,10 +426,12 @@ export interface FileRouteTypes {
|
||||
| '/user/signup'
|
||||
| '/logistics/deliverySchedule'
|
||||
| '/admin/servers'
|
||||
| '/forklifts/companies'
|
||||
| '/m/cyclecounts'
|
||||
| '/m/delivery'
|
||||
| '/m/relocate'
|
||||
| '/user'
|
||||
| '/forklifts'
|
||||
| '/m'
|
||||
| '/old/ocp'
|
||||
| '/old/rfid'
|
||||
@@ -422,6 +452,7 @@ export interface FileRouteTypes {
|
||||
| '__root__'
|
||||
| '/_app'
|
||||
| '/_app/_adminLayout'
|
||||
| '/_app/_forklifts'
|
||||
| '/_mobile/_mobileLayout'
|
||||
| '/_old/old'
|
||||
| '/_app/changelog'
|
||||
@@ -436,10 +467,12 @@ export interface FileRouteTypes {
|
||||
| '/_app/(auth)/user/signup'
|
||||
| '/_app/(logistics)/logistics/deliverySchedule'
|
||||
| '/_app/_adminLayout/admin/servers'
|
||||
| '/_app/_forklifts/forklifts/companies'
|
||||
| '/_mobile/_mobileLayout/m/cyclecounts'
|
||||
| '/_mobile/_mobileLayout/m/delivery'
|
||||
| '/_mobile/_mobileLayout/m/relocate'
|
||||
| '/_app/(auth)/user/'
|
||||
| '/_app/_forklifts/forklifts/'
|
||||
| '/_mobile/_mobileLayout/m/'
|
||||
| '/_old/old/ocp/'
|
||||
| '/_old/old/rfid/'
|
||||
@@ -501,6 +534,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof MobileMobileLayoutRouteRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/_app/_forklifts': {
|
||||
id: '/_app/_forklifts'
|
||||
path: ''
|
||||
fullPath: ''
|
||||
preLoaderRoute: typeof AppForkliftsRouteRouteImport
|
||||
parentRoute: typeof AppRouteRoute
|
||||
}
|
||||
'/_app/_adminLayout': {
|
||||
id: '/_app/_adminLayout'
|
||||
path: ''
|
||||
@@ -550,6 +590,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof MobileMobileLayoutMIndexRouteImport
|
||||
parentRoute: typeof MobileMobileLayoutRouteRoute
|
||||
}
|
||||
'/_app/_forklifts/forklifts/': {
|
||||
id: '/_app/_forklifts/forklifts/'
|
||||
path: '/forklifts'
|
||||
fullPath: '/forklifts'
|
||||
preLoaderRoute: typeof AppForkliftsForkliftsIndexRouteImport
|
||||
parentRoute: typeof AppForkliftsRouteRoute
|
||||
}
|
||||
'/_app/(auth)/user/': {
|
||||
id: '/_app/(auth)/user/'
|
||||
path: '/user'
|
||||
@@ -578,6 +625,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof MobileMobileLayoutMCyclecountsRouteImport
|
||||
parentRoute: typeof MobileMobileLayoutRouteRoute
|
||||
}
|
||||
'/_app/_forklifts/forklifts/companies': {
|
||||
id: '/_app/_forklifts/forklifts/companies'
|
||||
path: '/forklifts/companies'
|
||||
fullPath: '/forklifts/companies'
|
||||
preLoaderRoute: typeof AppForkliftsForkliftsCompaniesRouteImport
|
||||
parentRoute: typeof AppForkliftsRouteRoute
|
||||
}
|
||||
'/_app/_adminLayout/admin/servers': {
|
||||
id: '/_app/_adminLayout/admin/servers'
|
||||
path: '/servers'
|
||||
@@ -784,8 +838,22 @@ const AppAdminLayoutRouteRouteChildren: AppAdminLayoutRouteRouteChildren = {
|
||||
const AppAdminLayoutRouteRouteWithChildren =
|
||||
AppAdminLayoutRouteRoute._addFileChildren(AppAdminLayoutRouteRouteChildren)
|
||||
|
||||
interface AppForkliftsRouteRouteChildren {
|
||||
AppForkliftsForkliftsCompaniesRoute: typeof AppForkliftsForkliftsCompaniesRoute
|
||||
AppForkliftsForkliftsIndexRoute: typeof AppForkliftsForkliftsIndexRoute
|
||||
}
|
||||
|
||||
const AppForkliftsRouteRouteChildren: AppForkliftsRouteRouteChildren = {
|
||||
AppForkliftsForkliftsCompaniesRoute: AppForkliftsForkliftsCompaniesRoute,
|
||||
AppForkliftsForkliftsIndexRoute: AppForkliftsForkliftsIndexRoute,
|
||||
}
|
||||
|
||||
const AppForkliftsRouteRouteWithChildren =
|
||||
AppForkliftsRouteRoute._addFileChildren(AppForkliftsRouteRouteChildren)
|
||||
|
||||
interface AppRouteRouteChildren {
|
||||
AppAdminLayoutRouteRoute: typeof AppAdminLayoutRouteRouteWithChildren
|
||||
AppForkliftsRouteRoute: typeof AppForkliftsRouteRouteWithChildren
|
||||
AppChangelogRoute: typeof AppChangelogRoute
|
||||
AppIndexRoute: typeof AppIndexRoute
|
||||
AppauthLoginRoute: typeof AppauthLoginRoute
|
||||
@@ -798,6 +866,7 @@ interface AppRouteRouteChildren {
|
||||
|
||||
const AppRouteRouteChildren: AppRouteRouteChildren = {
|
||||
AppAdminLayoutRouteRoute: AppAdminLayoutRouteRouteWithChildren,
|
||||
AppForkliftsRouteRoute: AppForkliftsRouteRouteWithChildren,
|
||||
AppChangelogRoute: AppChangelogRoute,
|
||||
AppIndexRoute: AppIndexRoute,
|
||||
AppauthLoginRoute: AppauthLoginRoute,
|
||||
|
||||
@@ -159,16 +159,25 @@ function RouteComponent() {
|
||||
updateServer.mutate({ token, field, value: newValue });
|
||||
}
|
||||
};
|
||||
|
||||
let submitting = false;
|
||||
return (
|
||||
<Input
|
||||
value={localValue}
|
||||
onChange={(e) => setLocalValue(e.currentTarget.value)}
|
||||
onBlur={(e) => handleSubmit(e.currentTarget.value.trim())}
|
||||
onBlur={(e) => {
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
handleSubmit(e.currentTarget.value.trim());
|
||||
setTimeout(() => (submitting = false), 100); // reset after slight delay
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
handleSubmit(e.currentTarget.value.trim());
|
||||
e.currentTarget.blur(); // exit edit mode
|
||||
setTimeout(() => (submitting = false), 100);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DialogClose,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getCompanies } from "@/lib/querys/forklifts/getModules";
|
||||
import { useAppForm } from "../../../../lib/formStuff";
|
||||
|
||||
export default function NewCompanyForm({
|
||||
setOpenDialog,
|
||||
}: {
|
||||
setOpenDialog: any;
|
||||
}) {
|
||||
//const search = useSearch({ from: "/_app/(auth)/login" });
|
||||
const { refetch } = useQuery(getCompanies());
|
||||
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
try {
|
||||
await axios.post("/lst/api/forklifts/companies", {
|
||||
name: value.name,
|
||||
});
|
||||
form.reset();
|
||||
setOpenDialog(false);
|
||||
refetch();
|
||||
toast.success(`${value.name} was just created `);
|
||||
} catch (error) {
|
||||
// @ts-ignore
|
||||
if (!error.response.data.success) {
|
||||
// @ts-ignore
|
||||
toast.error(error?.response?.data.message);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
toast.error(error?.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create New Company</DialogTitle>
|
||||
<DialogDescription>Add the new Leasing company</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField
|
||||
name="name"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Company Name"
|
||||
inputType="string"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit">Submit</Button>
|
||||
</DialogFooter>
|
||||
</>
|
||||
);
|
||||
}
|
||||
282
frontend/src/routes/_app/_forklifts/forklifts/companies.tsx
Normal file
282
frontend/src/routes/_app/_forklifts/forklifts/companies.tsx
Normal file
@@ -0,0 +1,282 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import {
|
||||
createColumnHelper,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import axios from "axios";
|
||||
import { Activity, ArrowDown, ArrowUp } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { getCompanies } from "@/lib/querys/forklifts/getModules";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type Company = {
|
||||
id: string;
|
||||
name: string;
|
||||
active: boolean;
|
||||
};
|
||||
export const Route = createFileRoute("/_app/_forklifts/forklifts/companies")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
const updateCompanyItem = async (
|
||||
id: string,
|
||||
data: Record<string, string | number | boolean | null>,
|
||||
) => {
|
||||
try {
|
||||
const res = await axios.patch(`/lst/api/forklifts/companies/${id}`, data, {
|
||||
withCredentials: true,
|
||||
});
|
||||
toast.success(`Company just updated`);
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Error in updating company");
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
function RouteComponent() {
|
||||
const {
|
||||
data: companyData = [],
|
||||
isLoading,
|
||||
refetch,
|
||||
} = useQuery(getCompanies());
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const columnHelper = createColumnHelper<Company>();
|
||||
const submitting = useRef(false);
|
||||
|
||||
const updateCompany = useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
field,
|
||||
value,
|
||||
}: {
|
||||
id: string;
|
||||
field: string;
|
||||
value: string | number | boolean | null;
|
||||
}) => updateCompanyItem(id, { [field]: value }),
|
||||
|
||||
onSuccess: () => {
|
||||
// refetch or update cache
|
||||
refetch();
|
||||
},
|
||||
});
|
||||
const columns = [
|
||||
columnHelper.accessor("name", {
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<span className="flex flex-row gap-2">Name</span>
|
||||
{column.getIsSorted() === "asc" ? (
|
||||
<ArrowUp className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowDown className="ml-2 h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
cell: ({ row, getValue }) => {
|
||||
const initialValue = String(getValue() ?? "");
|
||||
const [localValue, setLocalValue] = useState(initialValue);
|
||||
const id = row.original.id;
|
||||
const field = "name";
|
||||
|
||||
useEffect(() => setLocalValue(initialValue), [initialValue]);
|
||||
|
||||
const handleSubmit = (newValue: string) => {
|
||||
if (newValue !== initialValue) {
|
||||
setLocalValue(newValue);
|
||||
updateCompany.mutate({ id, field, value: newValue });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Input
|
||||
value={localValue}
|
||||
onChange={(e) => setLocalValue(e.currentTarget.value)}
|
||||
onBlur={(e) => {
|
||||
if (!submitting.current) {
|
||||
submitting.current = true;
|
||||
handleSubmit(e.currentTarget.value.trim());
|
||||
setTimeout(() => (submitting.current = false), 100); // reset after slight delay
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
submitting.current = true;
|
||||
handleSubmit(e.currentTarget.value.trim());
|
||||
e.currentTarget.blur(); // will trigger blur, but we ignore it
|
||||
setTimeout(() => (submitting.current = false), 100);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("active", {
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<span className="flex flex-row gap-2">
|
||||
<Activity />
|
||||
Active
|
||||
</span>
|
||||
{column.getIsSorted() === "asc" ? (
|
||||
<ArrowUp className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowDown className="ml-2 h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
cell: ({ row, getValue }) => {
|
||||
const active = getValue<boolean>();
|
||||
const id = row.original.id;
|
||||
const field = "active";
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={active ? "true" : "false"}
|
||||
onValueChange={(value) => {
|
||||
const newValue = value === "true";
|
||||
updateCompany.mutate({ id, field, value: newValue });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger
|
||||
className={cn(
|
||||
"w-[100px]",
|
||||
active
|
||||
? "border-green-500 text-green-600"
|
||||
: "border-gray-400 text-gray-500",
|
||||
)}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="true">True</SelectItem>
|
||||
<SelectItem value="false">False</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const table = useReactTable({
|
||||
data: companyData,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
//renderSubComponent: ({ row }: { row: any }) => <ExpandedRow row={row} />,
|
||||
//getRowCanExpand: () => true,
|
||||
state: {
|
||||
sorting,
|
||||
},
|
||||
});
|
||||
if (isLoading) {
|
||||
return <div className="m-auto">Loading user data</div>;
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div className="w-fit">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
<React.Fragment key={row.id}>
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
|
||||
{/* {row.getIsExpanded() && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={row.getVisibleCells().length}>
|
||||
{renderSubComponent({ row })}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)} */}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
9
frontend/src/routes/_app/_forklifts/forklifts/index.tsx
Normal file
9
frontend/src/routes/_app/_forklifts/forklifts/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/_app/_forklifts/forklifts/')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/_app/_forklifts/"!</div>
|
||||
}
|
||||
19
frontend/src/routes/_app/_forklifts/route.tsx
Normal file
19
frontend/src/routes/_app/_forklifts/route.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createFileRoute, Outlet } from "@tanstack/react-router";
|
||||
import { checkUserAccess } from "@/lib/authClient";
|
||||
|
||||
export const Route = createFileRoute("/_app/_forklifts")({
|
||||
beforeLoad: async () =>
|
||||
checkUserAccess({
|
||||
allowedRoles: ["admin", "systemAdmin", "manager", "supervisor"],
|
||||
moduleName: "forklifts", // optional
|
||||
}),
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div>
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -14,12 +14,9 @@ import {
|
||||
} from "../../../../../lib/authClient";
|
||||
|
||||
import { AdminSideBar } from "./side-components/admin";
|
||||
import { EomSideBar } from "./side-components/eom";
|
||||
import { ForkliftSideBar } from "./side-components/forklift";
|
||||
import { Header } from "./side-components/header";
|
||||
import { LogisticsSideBar } from "./side-components/logistics";
|
||||
import { ProductionSideBar } from "./side-components/production";
|
||||
import { QualitySideBar } from "./side-components/quality";
|
||||
|
||||
export function AppSidebar() {
|
||||
const { session } = useAuth();
|
||||
@@ -36,9 +33,9 @@ export function AppSidebar() {
|
||||
<LogisticsSideBar user={session?.user as any} userRoles={userRoles} />
|
||||
{userAccess(null, ["systemAdmin"]) && (
|
||||
<>
|
||||
<ForkliftSideBar />
|
||||
{/* <ForkliftSideBar />
|
||||
<EomSideBar />
|
||||
<QualitySideBar />
|
||||
<QualitySideBar /> */}
|
||||
<AdminSideBar />
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user