feat(invoice form): added new invoice form
This commit is contained in:
@@ -12,10 +12,10 @@ post {
|
||||
|
||||
body:json {
|
||||
{
|
||||
"leaseNumber":"500-50489192",
|
||||
"leaseNumber":"40829107-1",
|
||||
"startDate": "11/08/2023",
|
||||
"endDate": "11/12/2025",
|
||||
"companyId": "b34c6684-ec35-4364-acef-0c1570faf123"
|
||||
"companyId": "59c4eaa3-55db-4348-a033-f2fcd91a91d1"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,26 +53,28 @@ router.post("/", async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
// this will be the total invoice amount minus each forklift this way we can keep the total amount in here plus forklifts seperated
|
||||
const totalAmount = (
|
||||
validatedForklifts.reduce((sum, f) => sum + Number(f.amount || 0), 0) -
|
||||
req.body.totalInvoice
|
||||
).toString();
|
||||
// const totalAmount = (
|
||||
// validatedForklifts.reduce((sum, f) => sum + Number(f.amount || 0), 0) -
|
||||
// req.body.totalInvoice
|
||||
// ).toString();
|
||||
|
||||
const { data, error } = await tryCatch(
|
||||
db
|
||||
.insert(leaseInvoices)
|
||||
.values({
|
||||
...invoiceData,
|
||||
add_date: sql`NOW()`,
|
||||
totalAmount: req.body.totalAmount,
|
||||
uploadedBy: req.user!.username || "lst_user",
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: leaseInvoices.invoiceNumber,
|
||||
set: {
|
||||
totalAmount,
|
||||
invoiceDate: invoiceData.invoiceDate,
|
||||
uploadedBy: req.user!.username || "lst_user",
|
||||
},
|
||||
})
|
||||
// .onConflictDoUpdate({
|
||||
// target: leaseInvoices.invoiceNumber,
|
||||
// set: {
|
||||
// totalAmount,
|
||||
// invoiceDate: invoiceData.invoiceDate,
|
||||
// uploadedBy: req.user!.username || "lst_user",
|
||||
// },
|
||||
// })
|
||||
.returning(),
|
||||
);
|
||||
|
||||
@@ -80,18 +82,21 @@ router.post("/", async (req: Request, res: Response) => {
|
||||
const err: DrizzleError = error;
|
||||
return res.status(400).json({
|
||||
message: `Error adding lease`,
|
||||
error: err.cause,
|
||||
// @ts-ignore
|
||||
error: err.cause.detail,
|
||||
});
|
||||
}
|
||||
|
||||
const invoiceId = data[0]?.id;
|
||||
console.log(validatedForklifts);
|
||||
const forkliftInvoices = validatedForklifts.map((f) => {
|
||||
return {
|
||||
invoiceId,
|
||||
forkliftId: f.forklift_id,
|
||||
amount: f.amount,
|
||||
};
|
||||
});
|
||||
|
||||
const forkliftInvoices = validatedForklifts.map((f) => ({
|
||||
invoiceId,
|
||||
forkliftId: f.forklift_Id,
|
||||
amount: f.amount,
|
||||
}));
|
||||
console.log(forkliftInvoices);
|
||||
if (validatedForklifts.length > 0) {
|
||||
await db.insert(leaseInvoiceForklifts).values(forkliftInvoices);
|
||||
// .onConflictDoUpdate({
|
||||
|
||||
@@ -10,12 +10,14 @@ import { tryCatch } from "../../../../pkg/utils/tryCatch.js";
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (req: Request, res: Response) => {
|
||||
const lease = req.query.lease;
|
||||
|
||||
const conditions = [];
|
||||
|
||||
if (lease !== undefined) {
|
||||
conditions.push(eq(leases.leaseNumber, `${lease}`));
|
||||
if (req.query.lease !== undefined) {
|
||||
conditions.push(eq(leases.leaseNumber, `${req.query.lease}`));
|
||||
}
|
||||
|
||||
if (req.query.companyId !== undefined) {
|
||||
conditions.push(eq(leases.companyId, `${req.query.companyId}`));
|
||||
}
|
||||
|
||||
//conditions.push(eq(forkliftCompanies.active, true));
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function ForkliftSideBar() {
|
||||
},
|
||||
{
|
||||
title: "Invoices",
|
||||
url: "/lst/app/admin/settings",
|
||||
url: "/lst/app/forklifts/invoices",
|
||||
icon: ReceiptText,
|
||||
role: ["systemAdmin", "admin", "manager"],
|
||||
module: "forklifts",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Link, useRouterState } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import NewCompanyForm from "@/routes/_app/_forklifts/-components/NewCompany";
|
||||
import NewInvoice from "@/routes/_app/_forklifts/-components/NewInvoice";
|
||||
import NewLeaseForm from "@/routes/_app/_forklifts/-components/NewLease";
|
||||
import { useAuth, useLogout } from "../../lib/authClient";
|
||||
import { ModeToggle } from "../mode-toggle";
|
||||
@@ -23,6 +24,7 @@ export default function Nav() {
|
||||
const currentPath = router.location.href;
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [openLeaseDialog, setOpenLeaseDialog] = useState(false);
|
||||
const [openInvoiceDialog, setOpenInvoiceDialog] = useState(false);
|
||||
return (
|
||||
<nav className="flex justify-end w-full shadow ">
|
||||
<div className="m-2 flex flex-row gap-1">
|
||||
@@ -65,6 +67,14 @@ export default function Nav() {
|
||||
>
|
||||
New Lease
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
// just open the dialog when clicked
|
||||
setOpenInvoiceDialog(true);
|
||||
}}
|
||||
>
|
||||
New Invoice
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{/* Company */}
|
||||
@@ -85,6 +95,16 @@ export default function Nav() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
{openInvoiceDialog && (
|
||||
<Dialog
|
||||
open={openInvoiceDialog}
|
||||
onOpenChange={setOpenInvoiceDialog}
|
||||
>
|
||||
<DialogContent className="sm:max-w-fit">
|
||||
<NewInvoice setOpenInvoiceDialog={setOpenInvoiceDialog} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { FieldErrors } from "./FieldErrors";
|
||||
|
||||
type DateFieldProps = {
|
||||
label: string;
|
||||
required: boolean;
|
||||
};
|
||||
export const DateField = ({ label }: DateFieldProps) => {
|
||||
const field = useFieldContext<any>();
|
||||
@@ -37,6 +38,7 @@ export const DateField = ({ label }: DateFieldProps) => {
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
//required={required}
|
||||
captionLayout="dropdown"
|
||||
startMonth={new Date(new Date().getFullYear() - 10, 0)}
|
||||
endMonth={new Date(new Date().getFullYear() + 20, 0)}
|
||||
|
||||
17
frontend/src/lib/querys/forklifts/getInvoices.ts
Normal file
17
frontend/src/lib/querys/forklifts/getInvoices.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getInvoices() {
|
||||
return queryOptions({
|
||||
queryKey: ["getInvoices"],
|
||||
queryFn: () => fetch(),
|
||||
staleTime: 5000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetch = async () => {
|
||||
const { data } = await axios.get("/lst/api/forklifts/invoices");
|
||||
|
||||
return data.data;
|
||||
};
|
||||
@@ -29,6 +29,7 @@ import { Route as MobileMobileLayoutMRelocateRouteImport } from './routes/_mobil
|
||||
import { Route as MobileMobileLayoutMDeliveryRouteImport } from './routes/_mobile/_mobileLayout/m/delivery'
|
||||
import { Route as MobileMobileLayoutMCyclecountsRouteImport } from './routes/_mobile/_mobileLayout/m/cyclecounts'
|
||||
import { Route as AppForkliftsForkliftsLeasesRouteImport } from './routes/_app/_forklifts/forklifts/leases'
|
||||
import { Route as AppForkliftsForkliftsInvoicesRouteImport } from './routes/_app/_forklifts/forklifts/invoices'
|
||||
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'
|
||||
@@ -152,6 +153,12 @@ const AppForkliftsForkliftsLeasesRoute =
|
||||
path: '/forklifts/leases',
|
||||
getParentRoute: () => AppForkliftsRouteRoute,
|
||||
} as any)
|
||||
const AppForkliftsForkliftsInvoicesRoute =
|
||||
AppForkliftsForkliftsInvoicesRouteImport.update({
|
||||
id: '/forklifts/invoices',
|
||||
path: '/forklifts/invoices',
|
||||
getParentRoute: () => AppForkliftsRouteRoute,
|
||||
} as any)
|
||||
const AppForkliftsForkliftsCompaniesRoute =
|
||||
AppForkliftsForkliftsCompaniesRouteImport.update({
|
||||
id: '/forklifts/companies',
|
||||
@@ -287,6 +294,7 @@ export interface FileRoutesByFullPath {
|
||||
'/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/forklifts/invoices': typeof AppForkliftsForkliftsInvoicesRoute
|
||||
'/forklifts/leases': typeof AppForkliftsForkliftsLeasesRoute
|
||||
'/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
@@ -322,6 +330,7 @@ export interface FileRoutesByTo {
|
||||
'/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/forklifts/invoices': typeof AppForkliftsForkliftsInvoicesRoute
|
||||
'/forklifts/leases': typeof AppForkliftsForkliftsLeasesRoute
|
||||
'/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
@@ -365,6 +374,7 @@ export interface FileRoutesById {
|
||||
'/_app/(logistics)/logistics/deliverySchedule': typeof ApplogisticsLogisticsDeliveryScheduleRoute
|
||||
'/_app/_adminLayout/admin/servers': typeof AppAdminLayoutAdminServersRoute
|
||||
'/_app/_forklifts/forklifts/companies': typeof AppForkliftsForkliftsCompaniesRoute
|
||||
'/_app/_forklifts/forklifts/invoices': typeof AppForkliftsForkliftsInvoicesRoute
|
||||
'/_app/_forklifts/forklifts/leases': typeof AppForkliftsForkliftsLeasesRoute
|
||||
'/_mobile/_mobileLayout/m/cyclecounts': typeof MobileMobileLayoutMCyclecountsRoute
|
||||
'/_mobile/_mobileLayout/m/delivery': typeof MobileMobileLayoutMDeliveryRoute
|
||||
@@ -403,6 +413,7 @@ export interface FileRouteTypes {
|
||||
| '/logistics/deliverySchedule'
|
||||
| '/admin/servers'
|
||||
| '/forklifts/companies'
|
||||
| '/forklifts/invoices'
|
||||
| '/forklifts/leases'
|
||||
| '/m/cyclecounts'
|
||||
| '/m/delivery'
|
||||
@@ -438,6 +449,7 @@ export interface FileRouteTypes {
|
||||
| '/logistics/deliverySchedule'
|
||||
| '/admin/servers'
|
||||
| '/forklifts/companies'
|
||||
| '/forklifts/invoices'
|
||||
| '/forklifts/leases'
|
||||
| '/m/cyclecounts'
|
||||
| '/m/delivery'
|
||||
@@ -480,6 +492,7 @@ export interface FileRouteTypes {
|
||||
| '/_app/(logistics)/logistics/deliverySchedule'
|
||||
| '/_app/_adminLayout/admin/servers'
|
||||
| '/_app/_forklifts/forklifts/companies'
|
||||
| '/_app/_forklifts/forklifts/invoices'
|
||||
| '/_app/_forklifts/forklifts/leases'
|
||||
| '/_mobile/_mobileLayout/m/cyclecounts'
|
||||
| '/_mobile/_mobileLayout/m/delivery'
|
||||
@@ -645,6 +658,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AppForkliftsForkliftsLeasesRouteImport
|
||||
parentRoute: typeof AppForkliftsRouteRoute
|
||||
}
|
||||
'/_app/_forklifts/forklifts/invoices': {
|
||||
id: '/_app/_forklifts/forklifts/invoices'
|
||||
path: '/forklifts/invoices'
|
||||
fullPath: '/forklifts/invoices'
|
||||
preLoaderRoute: typeof AppForkliftsForkliftsInvoicesRouteImport
|
||||
parentRoute: typeof AppForkliftsRouteRoute
|
||||
}
|
||||
'/_app/_forklifts/forklifts/companies': {
|
||||
id: '/_app/_forklifts/forklifts/companies'
|
||||
path: '/forklifts/companies'
|
||||
@@ -860,12 +880,14 @@ const AppAdminLayoutRouteRouteWithChildren =
|
||||
|
||||
interface AppForkliftsRouteRouteChildren {
|
||||
AppForkliftsForkliftsCompaniesRoute: typeof AppForkliftsForkliftsCompaniesRoute
|
||||
AppForkliftsForkliftsInvoicesRoute: typeof AppForkliftsForkliftsInvoicesRoute
|
||||
AppForkliftsForkliftsLeasesRoute: typeof AppForkliftsForkliftsLeasesRoute
|
||||
AppForkliftsForkliftsIndexRoute: typeof AppForkliftsForkliftsIndexRoute
|
||||
}
|
||||
|
||||
const AppForkliftsRouteRouteChildren: AppForkliftsRouteRouteChildren = {
|
||||
AppForkliftsForkliftsCompaniesRoute: AppForkliftsForkliftsCompaniesRoute,
|
||||
AppForkliftsForkliftsInvoicesRoute: AppForkliftsForkliftsInvoicesRoute,
|
||||
AppForkliftsForkliftsLeasesRoute: AppForkliftsForkliftsLeasesRoute,
|
||||
AppForkliftsForkliftsIndexRoute: AppForkliftsForkliftsIndexRoute,
|
||||
}
|
||||
|
||||
264
frontend/src/routes/_app/_forklifts/-components/NewInvoice.tsx
Normal file
264
frontend/src/routes/_app/_forklifts/-components/NewInvoice.tsx
Normal file
@@ -0,0 +1,264 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { format } from "date-fns";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DialogClose,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useAppForm } from "@/lib/formStuff";
|
||||
import { getCompanies } from "@/lib/querys/forklifts/getCompanies";
|
||||
import { getInvoices } from "@/lib/querys/forklifts/getInvoices";
|
||||
|
||||
type CompanyData = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export default function NewInvoice({
|
||||
setOpenInvoiceDialog,
|
||||
}: {
|
||||
setOpenInvoiceDialog: any;
|
||||
}) {
|
||||
const { refetch } = useQuery(getInvoices());
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
companyName: "",
|
||||
leaseId: "",
|
||||
invoiceNumber: "",
|
||||
invoiceDate: "",
|
||||
totalAmount: "",
|
||||
forklifts: [{ forklift_id: "", serialNumber: "", amount: "" }],
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
const updatedForklifts = value.forklifts.map(
|
||||
({ serialNumber, ...rest }) => rest,
|
||||
);
|
||||
const postData = {
|
||||
leaseId: value.leaseId,
|
||||
invoiceNumber: value.invoiceNumber,
|
||||
invoiceDate: format(value.invoiceDate, "MM/dd/yyyy"),
|
||||
totalAmount: value.totalAmount,
|
||||
forklifts: updatedForklifts,
|
||||
};
|
||||
console.log(postData);
|
||||
try {
|
||||
await axios.post("/lst/api/forklifts/invoices", postData);
|
||||
form.reset();
|
||||
setOpenInvoiceDialog(false);
|
||||
refetch();
|
||||
toast.success(`${value.invoiceNumber} was just created `);
|
||||
} catch (error) {
|
||||
// @ts-ignore
|
||||
console.log(error);
|
||||
// @ts-ignore
|
||||
if (!error.response.data.success) {
|
||||
// @ts-ignore
|
||||
toast.error(<span>{error?.response?.data.error}</span>);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
toast.error(error?.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const { data: c, isLoading: ce } = useQuery(getCompanies());
|
||||
|
||||
let companyName = form.getFieldValue("companyName");
|
||||
|
||||
const { data: l = [], refetch: lf } = useQuery({
|
||||
queryKey: ["lease", companyName],
|
||||
queryFn: async () => {
|
||||
//if (!companyName) return [];
|
||||
const { data } = await axios.get(
|
||||
`/lst/api/forklifts/leases?companyId=${companyName}`,
|
||||
);
|
||||
return data.data;
|
||||
},
|
||||
enabled: !!companyName, // only run if nameId has value
|
||||
});
|
||||
|
||||
if (ce) return <div>Loading Companies</div>;
|
||||
|
||||
// remap the companies to fit out select field
|
||||
const companyMap = c.map((i: CompanyData) => {
|
||||
return { value: i.id, label: i.name };
|
||||
});
|
||||
|
||||
const leaseMap = l.map((i: any) => {
|
||||
return { value: i.id, label: i.leaseNumber };
|
||||
});
|
||||
|
||||
const onValueChange = (value: string) => {
|
||||
companyName = value;
|
||||
lf();
|
||||
form.setFieldValue("leaseId", "");
|
||||
};
|
||||
|
||||
let forkliftArray = [];
|
||||
const onLeaseChange = (value: string) => {
|
||||
const selectedLease = l.find((lease: any) => lease.id === value);
|
||||
|
||||
forkliftArray =
|
||||
selectedLease?.forklifts.length > 0
|
||||
? selectedLease.forklifts.map((f: any) => ({
|
||||
forklift_id: f.forklift_id,
|
||||
amount: 0,
|
||||
serialNumber: f.serialNumber,
|
||||
}))
|
||||
: [
|
||||
// {
|
||||
// forklift_id: "missing",
|
||||
// amount: 0,
|
||||
// serialNumber: "Missing forklift",
|
||||
// },
|
||||
];
|
||||
form.setFieldValue("forklifts", forkliftArray);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create New Lease</DialogTitle>
|
||||
<DialogDescription>
|
||||
Select the company this lease will be for, lease number, start and end
|
||||
date
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField
|
||||
name="companyName"
|
||||
listeners={{
|
||||
onChange: ({ value }) => {
|
||||
onValueChange(value);
|
||||
},
|
||||
}}
|
||||
children={(field) => (
|
||||
<field.SelectField
|
||||
label="Select Company"
|
||||
placeholder="Companies"
|
||||
options={companyMap}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<form.AppField
|
||||
name="leaseId"
|
||||
listeners={{
|
||||
onChange: ({ value }) => {
|
||||
onLeaseChange(value);
|
||||
},
|
||||
}}
|
||||
children={(field) => (
|
||||
<field.SelectField
|
||||
label="Select Lease"
|
||||
placeholder="LeaseNumber"
|
||||
options={leaseMap}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="w-5/6 m-2">
|
||||
<form.AppField
|
||||
name="invoiceNumber"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Enter Invoice Number"
|
||||
inputType="string"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-5/6 m-2">
|
||||
<form.AppField
|
||||
name="totalAmount"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Enter Invoice Amount"
|
||||
inputType="decimal"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<form.AppField
|
||||
name="invoiceDate"
|
||||
children={(field) => (
|
||||
<field.DateField label="Invoice Date" required={true} />
|
||||
)}
|
||||
/>
|
||||
|
||||
<hr className="mt-2 mb-2" />
|
||||
{/* Dynamic forklift section */}
|
||||
<div className="space-y-3 mt-4">
|
||||
<form.Field
|
||||
name="forklifts"
|
||||
mode="array"
|
||||
children={(field) => (
|
||||
<>
|
||||
<Label>Forklifts</Label>
|
||||
{field.state.value.map((fx, index) => (
|
||||
<form.AppField
|
||||
key={fx.forklift_id}
|
||||
name={`forklifts[${index}].amount`}
|
||||
children={(subField) => (
|
||||
<div className="flex flex-row gap-2">
|
||||
<Label htmlFor={subField.name}>{fx.serialNumber}</Label>
|
||||
<Input
|
||||
className="w-1/4"
|
||||
id={subField.name}
|
||||
value={subField.state.value ?? ""}
|
||||
onChange={(e) => {
|
||||
// update this subfield’s amount
|
||||
subField.handleChange(e.target.value);
|
||||
|
||||
// if you also want to store the forklift_id with it
|
||||
field.handleChange(
|
||||
field.state.value.map((val, i) =>
|
||||
i === index
|
||||
? { ...val, amount: e.target.value }
|
||||
: val,
|
||||
),
|
||||
);
|
||||
}}
|
||||
onBlur={subField.handleBlur}
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Map out the input filed based on the forklift id */}
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
form.reset();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit">Submit</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -108,11 +108,13 @@ export default function NewLeaseForm({
|
||||
<div className="flex flex-row gap-2 mt-2 mb-2">
|
||||
<form.AppField
|
||||
name="startDate"
|
||||
children={(field) => <field.DateField label="Start Date" />}
|
||||
children={(field) => (
|
||||
<field.DateField label="Start Date" required />
|
||||
)}
|
||||
/>
|
||||
<form.AppField
|
||||
name="endDate"
|
||||
children={(field) => <field.DateField label="End Date" />}
|
||||
children={(field) => <field.DateField label="End Date" required />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
115
frontend/src/routes/_app/_forklifts/forklifts/invoices.tsx
Normal file
115
frontend/src/routes/_app/_forklifts/forklifts/invoices.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { format } from "date-fns";
|
||||
import { ArrowDown, ArrowUp } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { getInvoices } from "@/lib/querys/forklifts/getInvoices";
|
||||
import TableNoExpand from "@/lib/tableStuff/TableNoExpand";
|
||||
|
||||
type Invoices = {
|
||||
id: string;
|
||||
invoiceNumber: string;
|
||||
invoiceDate: Date;
|
||||
totalAmount: string;
|
||||
add_date: Date;
|
||||
};
|
||||
|
||||
export const Route = createFileRoute("/_app/_forklifts/forklifts/invoices")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const { data: invoiceData = [], isLoading } = useQuery(getInvoices());
|
||||
|
||||
const columnHelper = createColumnHelper<Invoices>();
|
||||
//const submitting = useRef(false);
|
||||
console.log(invoiceData);
|
||||
const columns = [
|
||||
columnHelper.accessor("invoiceNumber", {
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<span className="flex flex-row gap-2">Invoice Number</span>
|
||||
{column.getIsSorted() === "asc" ? (
|
||||
<ArrowUp className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowDown className="ml-2 h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("totalAmount", {
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<span className="flex flex-row gap-2">Total Amount</span>
|
||||
{column.getIsSorted() === "asc" ? (
|
||||
<ArrowUp className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowDown className="ml-2 h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("invoiceDate", {
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<span className="flex flex-row gap-2">Invoice Date</span>
|
||||
{column.getIsSorted() === "asc" ? (
|
||||
<ArrowUp className="ml-2 h-4 w-4" />
|
||||
) : (
|
||||
<ArrowDown className="ml-2 h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
cell: ({ getValue }) => {
|
||||
const raw = getValue() as string | Date;
|
||||
const date = typeof raw === "string" ? new Date(raw) : (raw as Date);
|
||||
if (isNaN(date.getTime())) return "Invalid date";
|
||||
return <span>{format(date, "MM/dd/yyyy")}</span>;
|
||||
},
|
||||
}),
|
||||
// columnHelper.accessor("add_date", {
|
||||
// header: ({ column }) => {
|
||||
// return (
|
||||
// <Button
|
||||
// variant="ghost"
|
||||
// onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
// >
|
||||
// <span className="flex flex-row gap-2">Start Date</span>
|
||||
// {column.getIsSorted() === "asc" ? (
|
||||
// <ArrowUp className="ml-2 h-4 w-4" />
|
||||
// ) : (
|
||||
// <ArrowDown className="ml-2 h-4 w-4" />
|
||||
// )}
|
||||
// </Button>
|
||||
// );
|
||||
// },
|
||||
// cell: ({ getValue }) => {
|
||||
// const raw = getValue() as string | Date;
|
||||
// const date = typeof raw === "string" ? new Date(raw) : (raw as Date);
|
||||
// if (isNaN(date.getTime())) return "Invalid date";
|
||||
// return <span>{format(date, "MM/dd/yyyy")}</span>;
|
||||
// },
|
||||
//}),
|
||||
];
|
||||
|
||||
if (isLoading) {
|
||||
return <div className="m-auto">Loading user data</div>;
|
||||
}
|
||||
return <TableNoExpand data={invoiceData} columns={columns} />;
|
||||
}
|
||||
@@ -65,7 +65,6 @@ let lotColumns = [
|
||||
];
|
||||
export default function Lots() {
|
||||
const { data, isError, isLoading } = useQuery(getlots());
|
||||
|
||||
const { session } = useAuth();
|
||||
//const { settings } = useSettingStore();
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function ManualPrintForm() {
|
||||
const { settings } = useSettingStore();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const [printing, setPrinting] = useState(false);
|
||||
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||
// const serverUrl = `http://${server}:${serverPort}`;
|
||||
|
||||
@@ -59,6 +59,7 @@ export default function ManualPrintForm() {
|
||||
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
|
||||
const logdataUrl = `/lst/old/api/ocp/manuallabellog`;
|
||||
setIsSubmitting(true);
|
||||
setPrinting(true);
|
||||
axios
|
||||
.post(logdataUrl, logData, {})
|
||||
.then((d) => {
|
||||
@@ -71,11 +72,13 @@ export default function ManualPrintForm() {
|
||||
reset();
|
||||
setOpen(false);
|
||||
setIsSubmitting(false);
|
||||
setPrinting(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e.response.status === 500) {
|
||||
toast.error(`Internal Server error please try again.`);
|
||||
setIsSubmitting(false);
|
||||
setPrinting(false);
|
||||
return { sucess: false };
|
||||
}
|
||||
|
||||
@@ -97,6 +100,7 @@ export default function ManualPrintForm() {
|
||||
const closeForm = () => {
|
||||
reset();
|
||||
setOpen(false);
|
||||
setPrinting(false);
|
||||
};
|
||||
return (
|
||||
<Dialog
|
||||
@@ -106,13 +110,14 @@ export default function ManualPrintForm() {
|
||||
reset();
|
||||
}
|
||||
setOpen(isOpen);
|
||||
setPrinting(true);
|
||||
// toast.message("Model was something", {
|
||||
// description: isOpen ? "Modal is open" : "Modal is closed",
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" disabled={printing}>
|
||||
<Tag className="h-[16px] w-[16px]" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
Reference in New Issue
Block a user