feat: Begins po detail.
This commit is contained in:
@@ -301,3 +301,38 @@ tr.htmx-swapping td {
|
|||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-row button {
|
||||||
|
border: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: grey;
|
||||||
|
background-color: inherit;
|
||||||
|
font-size: 1.3em;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-row button:hover {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-detail {
|
||||||
|
border: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: grey;
|
||||||
|
background-color: inherit;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.po-detail table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: none;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.po-detail td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: #00ffcc;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="sidepanel" id="sidepanel">
|
<div class="sidepanel" id="sidepanel">
|
||||||
<a href="javscript:void(0)" class="closebtn" onclick="closeSidepanel()">×</a>
|
<a href="javscript:void(0)" class="closebtn" onclick="closeSidepanel()">×</a>
|
||||||
<a hx-get="/purchase-orders"
|
<a hx-get="/purchase-orders?page=1&limit=50"
|
||||||
hx-target="body"
|
hx-target="body"
|
||||||
hx-push-url="true"
|
hx-push-url="true"
|
||||||
>
|
>
|
||||||
|
|||||||
46
Resources/Views/purchaseOrders/detail.leaf
Normal file
46
Resources/Views/purchaseOrders/detail.leaf
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<div id="po-detail" class="container">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Purchase Order:</h3></td>
|
||||||
|
<td><h3>#(purchaseOrder.id)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Work Order:</h3></td>
|
||||||
|
<td><h3>#(purchaseOrder.workOrder)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Customer:</h3></td>
|
||||||
|
<td><h3>#(purchaseOrder.customer)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Vendor:</h3></td>
|
||||||
|
<td><h3>#capitalized(purchaseOrder.vendorBranch.vendor.name) - #capitalized(purchaseOrder.vendorBranch.name)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Materials:</h3></td>
|
||||||
|
<td><h3>#(purchaseOrder.materials)<h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Created For:</h3></td>
|
||||||
|
<td><h3>#capitalized(purchaseOrder.createdFor.firstName) #capitalized(purchaseOrder.createdFor.lastName)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Truck Stock:</h3></td>
|
||||||
|
<td><h3>#capitalized(purchaseOrder.truckStock)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Created By:</h3></td>
|
||||||
|
<td><h3>#(purchaseOrder.createdBy.username)</h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Date:</h3></td>
|
||||||
|
<td><h3>#date(purchaseOrder.createdAt)<h3></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label"><h3>Updated:</h3></td>
|
||||||
|
<td><h3>#date(purchaseOrder.updatedAt)<h3></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -8,6 +8,28 @@
|
|||||||
#extend("form-container"): #export("formContent"):
|
#extend("form-container"): #export("formContent"):
|
||||||
#extend("purchaseOrders/form", form)
|
#extend("purchaseOrders/form", form)
|
||||||
#endexport #endextend
|
#endexport #endextend
|
||||||
|
<div class="btn-row">
|
||||||
|
#if(hasPrevious):
|
||||||
|
<button hx-get="/purchase-orders?page=#(page - 1)&limit=#(limit)"
|
||||||
|
hx-target="body"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-push-url="true"
|
||||||
|
style="float: left;"
|
||||||
|
>
|
||||||
|
‹ Previous
|
||||||
|
</button>
|
||||||
|
#endif
|
||||||
|
#if(hasNext):
|
||||||
|
<button hx-get="/purchase-orders?page=#(page + 1)&limit=#(limit)"
|
||||||
|
hx-target="body"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-push-url="true"
|
||||||
|
style="float: right;"
|
||||||
|
>
|
||||||
|
Next ›
|
||||||
|
</button>
|
||||||
|
#endif
|
||||||
|
</div>
|
||||||
#extend("purchaseOrders/table")
|
#extend("purchaseOrders/table")
|
||||||
</div>
|
</div>
|
||||||
#endexport
|
#endexport
|
||||||
|
|||||||
@@ -7,7 +7,14 @@
|
|||||||
<td>#capitalized(createdFor.firstName) #capitalized(createdFor.lastName)</td>
|
<td>#capitalized(createdFor.firstName) #capitalized(createdFor.lastName)</td>
|
||||||
<td>#(createdBy.username)</td>
|
<td>#(createdBy.username)</td>
|
||||||
<td>#capitalized(truckStock)</td>
|
<td>#capitalized(truckStock)</td>
|
||||||
<td>
|
<td style="text-align: center;">
|
||||||
<!-- TODO: add buttons here -->
|
<!-- TODO: add buttons here -->
|
||||||
|
<button class="btn btn-detail"
|
||||||
|
hx-get="/purchase-orders/#(id)"
|
||||||
|
hx-target="#home-content"
|
||||||
|
hx-push-url="true"
|
||||||
|
>
|
||||||
|
›
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -12,24 +12,36 @@ struct PurchaseOrderViewController: RouteCollection {
|
|||||||
|
|
||||||
pos.get(use: index(req:))
|
pos.get(use: index(req:))
|
||||||
pos.post(use: create(req:))
|
pos.post(use: create(req:))
|
||||||
|
pos.group(":id") {
|
||||||
|
$0.get(use: detail(req:))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use pageinated version.
|
|
||||||
@Sendable
|
@Sendable
|
||||||
func index(req: Request) async throws -> View {
|
func index(req: Request) async throws -> View {
|
||||||
let purchaseOrders = try await api2.fetchAll(on: req.db)
|
let params = try? req.query.decode(PurchaseOrderIndex.self)
|
||||||
|
let purchaseOrdersPage = try await api2.fetchPage(params?.page ?? 1, limit: params?.limit ?? 50, on: req.db)
|
||||||
let branches = try await self.branches.getBranches(req: req)
|
let branches = try await self.branches.getBranches(req: req)
|
||||||
let employees = try await employeesApi.index(req: req)
|
let employees = try await employeesApi.index(req: req)
|
||||||
req.logger.debug("Branches: \(branches)")
|
req.logger.debug("Branches: \(branches)")
|
||||||
return try await req.view.render(
|
return try await req.view.render(
|
||||||
"purchaseOrders/index",
|
"purchaseOrders/index",
|
||||||
PurchaseOrderCTX(
|
PurchaseOrderCTX(
|
||||||
purchaseOrders: purchaseOrders,
|
page: purchaseOrdersPage,
|
||||||
form: .create(branches: branches, employees: employees)
|
form: .create(branches: branches, employees: employees)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Sendable
|
||||||
|
func detail(req: Request) async throws -> View {
|
||||||
|
guard let id = req.parameters.get("id", as: PurchaseOrder.IDValue.self) else {
|
||||||
|
throw Abort(.badRequest, reason: "Id not supplied.")
|
||||||
|
}
|
||||||
|
let purchaseOrder = try await api2.get(id: id, on: req.db)
|
||||||
|
return try await req.view.render("purchaseOrders/detail", ["purchaseOrder": purchaseOrder])
|
||||||
|
}
|
||||||
|
|
||||||
@Sendable
|
@Sendable
|
||||||
func create(req: Request) async throws -> View {
|
func create(req: Request) async throws -> View {
|
||||||
try PurchaseOrder.FormCreate.validate(content: req)
|
try PurchaseOrder.FormCreate.validate(content: req)
|
||||||
@@ -40,9 +52,33 @@ struct PurchaseOrderViewController: RouteCollection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct PurchaseOrderIndex: Content {
|
||||||
|
let page: Int?
|
||||||
|
let limit: Int?
|
||||||
|
}
|
||||||
|
|
||||||
private struct PurchaseOrderCTX: Content {
|
private struct PurchaseOrderCTX: Content {
|
||||||
let purchaseOrders: [PurchaseOrder.DTO]
|
let purchaseOrders: [PurchaseOrder.DTO]
|
||||||
|
let page: Int
|
||||||
|
let limit: Int
|
||||||
|
let hasNext: Bool
|
||||||
|
let hasPrevious: Bool
|
||||||
let form: PurchaseOrderFormCTX?
|
let form: PurchaseOrderFormCTX?
|
||||||
|
|
||||||
|
init(page: Page<PurchaseOrder.DTO>, form: PurchaseOrderFormCTX?) {
|
||||||
|
self.purchaseOrders = page.items
|
||||||
|
self.page = page.metadata.page
|
||||||
|
self.limit = page.metadata.per
|
||||||
|
self.hasNext = page.metadata.hasNext
|
||||||
|
self.hasPrevious = page.metadata.page > 1
|
||||||
|
self.form = form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension PageMetadata {
|
||||||
|
var hasNext: Bool {
|
||||||
|
total > (page * per)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct PurchaseOrderFormCTX: Content {
|
private struct PurchaseOrderFormCTX: Content {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ struct UserFormCTX: Content {
|
|||||||
htmxForm: .init(
|
htmxForm: .init(
|
||||||
formClass: "user-form",
|
formClass: "user-form",
|
||||||
formId: "user-form",
|
formId: "user-form",
|
||||||
htmxTargetUrl: .post("/login\(next != nil ? "?next=\(next!)" : "")"),
|
htmxTargetUrl: .post("/login\((next != nil && next != "/") ? "?next=\(next!)" : "")"),
|
||||||
htmxTarget: "body",
|
htmxTarget: "body",
|
||||||
htmxPushUrl: true,
|
htmxPushUrl: true,
|
||||||
htmxResetAfterRequest: true,
|
htmxResetAfterRequest: true,
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ struct ViewController: RouteCollection {
|
|||||||
func getLogin(req: Request) async throws -> View {
|
func getLogin(req: Request) async throws -> View {
|
||||||
req.logger.debug("Login Query: \(req.url.query ?? "n/a")")
|
req.logger.debug("Login Query: \(req.url.query ?? "n/a")")
|
||||||
let params = try? req.query.decode(LoginParameter.self)
|
let params = try? req.query.decode(LoginParameter.self)
|
||||||
return try await req.view.render("login", UserFormCTX.signIn(next: params?.next))
|
return try await req.view.render(
|
||||||
|
"login", UserFormCTX.signIn(next: params?.next)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Sendable
|
@Sendable
|
||||||
@@ -95,6 +97,7 @@ private struct UserForm: Content {
|
|||||||
|
|
||||||
enum HomeRoute: String, Content {
|
enum HomeRoute: String, Content {
|
||||||
case employees
|
case employees
|
||||||
|
case purchaseOrders
|
||||||
case users
|
case users
|
||||||
case vendors
|
case vendors
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user