feat: Adds api route tests. Tested user interface works as expected, still needs some work on vendors form.

This commit is contained in:
2025-01-20 16:44:12 -05:00
parent affd9b5d81
commit 410bbae1c8
23 changed files with 537 additions and 121 deletions

View File

@@ -169,10 +169,12 @@ enum IDKey: CustomStringConvertible {
}
enum Vendor: CustomStringConvertible {
case form
case row(id: SharedModels.Vendor.ID)
var description: String {
switch self {
case .form: return "form"
case let .row(id): return "\(id)"
}
}

View File

@@ -52,15 +52,23 @@ struct LoggedIn: HTML {
let next: String?
var content: some HTML {
div(
.hx.get(next ?? ViewRoute.router.path(for: .purchaseOrder(.index))),
.hx.get(nextRoute ?? ViewRoute.router.path(for: .purchaseOrder(.index))),
.hx.pushURL(true),
.hx.target("body"),
.hx.target(.body),
.hx.trigger(.event(.revealed)),
.hx.indicator(".hx-indicator")
) {
Img.spinner().attributes(.class("hx-indicator"))
}
}
// HACK: to get search route to work after login.
var nextRoute: String? {
if let next, next.contains("search") {
return ViewRoute.router.path(for: .purchaseOrder(.search(.index(context: .employee, table: true))))
}
return next
}
}
struct RouteHeaderView: HTML {

View File

@@ -45,7 +45,7 @@ struct PurchaseOrderTable: HTML {
if context != .search {
Button.add()
.attributes(
.hx.get(route: .purchaseOrder(.index)), .hx.target(.id(.float)),
.hx.get(route: .purchaseOrder(.form)), .hx.target(.id(.float)),
.hx.swap(.outerHTML), .hx.pushURL(true)
)
}
@@ -79,9 +79,12 @@ struct PurchaseOrderTable: HTML {
for purchaseOrder in page.items {
Row(purchaseOrder: purchaseOrder)
}
if page.metadata.pageCount > page.metadata.page {
// We set page to 0 when we're on search, but have not completed the search
// form yet, so don't add the infinite scroll row / trigger otherwise it will
// load the first page, which is not what we want, but we need the empty table
// to be available once the search form is completed.
if page.metadata.page > 0, page.metadata.pageCount > page.metadata.page {
tr(
// .hx.get("/purchase-orders/next?page=\(page.metadata.page + 1)&limit=\(page.metadata.per)"),
.hx.get(route: .purchaseOrder(.page(page: page.metadata.page + 1, limit: page.metadata.per))),
.hx.trigger(.event(.revealed)),
.hx.swap(.outerHTML.transition(true).swap("1s")),

View File

@@ -23,7 +23,7 @@ struct UserForm: HTML, Sendable {
.hx.post(context.targetURL),
.hx.pushURL(context.pushURL),
.hx.target(context.target),
.hx.swap(.outerHTML),
.hx.swap(context == .create ? .afterBegin.transition(true).swap("0.5s") : .outerHTML),
.hx.on(
.afterRequest,
.ifSuccessful(.resetForm, .toggleContent(.float))
@@ -92,12 +92,12 @@ struct UserForm: HTML, Sendable {
}
}
var target: String {
var target: HXTarget {
switch self {
case .create:
return "next table"
return .id(.user(.table))
case .login:
return "body"
return .body
}
}

View File

@@ -6,7 +6,7 @@ import Vapor
struct EmployeeSelect: HTML {
let employees: [Employee]?
let context: SelectContext
let context: ViewRoute.SelectContext
var content: some HTML {
if let employees {
@@ -18,7 +18,7 @@ struct EmployeeSelect: HTML {
.attributes(.style("margin-left: 15px;"), when: context == .purchaseOrderSearch)
} else {
div(
.hx.get("/select/employee?context=\(context.rawValue)"),
.hx.get(route: .employee(.select(context: context))),
.hx.target("this"),
.hx.swap(.outerHTML.transition(true).swap("0.5s")),
.hx.indicator("next .hx-indicator"),
@@ -42,11 +42,11 @@ struct EmployeeSelect: HTML {
struct VendorBranchSelect: HTML {
let branches: [VendorBranch.Detail]?
let context: SelectContext
let context: ViewRoute.SelectContext
var content: some HTML {
if let branches {
select(.name("vendorBranchID"), .class(context.classString)) {
select(.name("vendorBranchID"), .class("col-4")) {
for branch in branches {
option(.value(branch.id.uuidString)) { "\(branch.vendor.name) - \(branch.name)" }
}
@@ -54,8 +54,8 @@ struct VendorBranchSelect: HTML {
.attributes(.style("margin-left: 15px;"), when: context == .purchaseOrderSearch)
} else {
div(
.hx.get("/select/vendor-branches?context=\(context.rawValue)"),
.hx.target("this"),
.hx.get(route: .vendorBranch(.select(context: context))),
.hx.target(.this),
.hx.swap(.outerHTML.transition(true).swap("0.5s")),
.hx.indicator("next .hx-indicator"),
.hx.trigger(.event(.revealed)),
@@ -75,10 +75,11 @@ struct VendorBranchSelect: HTML {
}
}
enum SelectContext: String, Codable, Content {
case purchaseOrderForm
case purchaseOrderSearch
// enum SelectContext: String, Codable, Content {
// case purchaseOrderForm
// case purchaseOrderSearch
extension ViewRoute.SelectContext {
var classString: String {
switch self {
case .purchaseOrderForm: return "col-3"

View File

@@ -26,15 +26,15 @@ struct VendorDetail: HTML {
// TODO: What route for here??
var branchForm: some HTML {
// TODO: Add hidden input field with vendor id.
form(
.id("branch-form"),
.hx.post("/vendors/\(vendor.id)/branches"),
.id(.branch(.form)),
.hx.post("/vendors/branches"),
.hx.target("#branches"),
.hx.swap(.beforeEnd),
.hx.on(.afterRequest, .ifSuccessful(.resetForm))
// .custom(name: "hx-on::after-request", value: "if(event.detail.successful) this.reset();")
) {
input(.type(.hidden), .name("vendorID"), .value(vendor.id.uuidString))
input(
.type(.text), .class("col-9"), .name("name"), .placeholder("Add branch..."), .required,
// FIX: route

View File

@@ -40,7 +40,7 @@ struct VendorForm: HTML {
func makeForm(vendor: Vendor?) -> some HTML {
form(
.id("vendor-form"),
.id(.vendor(.form)),
vendor != nil ? .hx.put(route: targetURL) : .hx.post(route: targetURL),
.hx.target("#content"),
.hx.swap(.outerHTML)
@@ -63,7 +63,7 @@ struct VendorForm: HTML {
.style("font-size: 1.25em; padding: 10px 20px; border-radius: 10px;"),
.hx.delete(route: .vendor(.delete(id: vendor.id))),
.hx.confirm("Are you sure you want to delete this vendor?"),
.hx.target("#vendor_\(vendor.id)"),
.hx.target(.id(.vendor(.row(id: vendor.id)))),
.hx.swap(.outerHTML.transition(true).swap("1s")),
.custom(
name: "hx-on::after-request",