feat: Moves vendor branch views to their own files, starts to implement snapshot testing for html

This commit is contained in:
2025-01-21 09:51:11 -05:00
parent 40726c8bd7
commit 97b231767e
15 changed files with 231 additions and 71 deletions

View File

@@ -117,11 +117,13 @@ enum IDKey: CustomStringConvertible {
}
enum Branch: CustomStringConvertible {
case list
case form
case row(id: VendorBranch.ID)
var description: String {
switch self {
case .list: return "list"
case .form: return "form"
case let .row(id): return id.uuidString
}
@@ -148,7 +150,7 @@ enum IDKey: CustomStringConvertible {
var description: String {
switch self {
case let .content: return "content"
case .content: return "content"
case let .row(id): return "\(id)"
case .search: return "search"
case .table: return "table"

View File

@@ -1,4 +1,6 @@
import Elementary
import SharedModels
import URLRouting
struct ToggleFormButton: HTML {
var content: some HTML<HTMLTag.a> {
@@ -24,6 +26,13 @@ enum Button {
}
}
static func close(id: IDKey, resetURL route: ViewRoute? = nil) -> some HTML<HTMLTag.button> {
close(
id: id.description,
resetURL: route != nil ? ViewRoute.router.path(for: route!) : nil
)
}
static func update() -> some HTML<HTMLTag.button> {
button(.class("btn-update")) { "Update" }
}

View File

@@ -10,4 +10,9 @@ enum Img {
static func search(width: Int = 30, height: Int = 30) -> some HTML<HTMLTag.img> {
img(.src("/images/search.svg"), .width(width), .height(height))
}
@Sendable
static func trashCan(width: Int = 30, height: Int = 30) -> some HTML<HTMLTag.img> {
img(.src("/images/trash-can.svg"), .width(width), .height(height))
}
}

View File

@@ -0,0 +1,34 @@
import Elementary
import ElementaryHTMX
import SharedModels
struct VendorBranchForm: HTML {
let vendorID: Vendor.ID
var content: some HTML {
form(
.id(.branch(.form)),
.hx.post(route: .vendorBranch(.index())),
.hx.target(.id(.branch(.list))),
.hx.swap(.beforeEnd),
.hx.on(.afterRequest, .ifSuccessful(.resetForm))
) {
input(.type(.hidden), .name("vendorID"), .value(vendorID.uuidString))
input(
.type(.text), .class("col-9"), .name("name"), .placeholder("Add branch..."), .required,
// .hx.post(route: .vendorBranch(.index())),
.hx.trigger(.event(.keyup).changed().delay("800ms")) // ,
// .hx.target(.id(.branch(.list))),
// .hx.swap(.beforeEnd),
// .custom(name: "hx-on::after-request", value: "if(event.detail.successful) this.reset();")
)
button(
.type(.submit),
.class("btn-secondary"),
.style("float: right; padding: 10px 50px;"),
.hx.target(.id(.branch(.list))),
.hx.swap(.beforeEnd)
) { "+" }
}
}
}

View File

@@ -0,0 +1,46 @@
import Elementary
import ElementaryHTMX
import SharedModels
struct VendorBranchList: HTML {
let vendorID: Vendor.ID
let branches: [VendorBranch]?
var content: some HTML {
if let branches {
ul(.id(.branch(.list))) {
for branch in branches {
Row(branch: branch)
}
}
} else {
div(
.hx.get(route: .vendorBranch(.index(for: vendorID))),
.hx.target(.this),
.hx.indicator(".hx-indicator"),
.hx.trigger(.event(.revealed))
) {
Img.spinner().attributes(.class("hx-indicator"))
}
}
}
struct Row: HTML {
let branch: VendorBranch
var content: some HTML<HTMLTag.li> {
li(.id(.branch(.row(id: branch.id))), .class("branch-row")) {
span(.class("label")) { branch.name.capitalized }
button(
.class("btn"),
.hx.delete(route: .vendorBranch(.delete(id: branch.id))),
.hx.target(.id(.branch(.row(id: branch.id)))),
.hx.swap(.outerHTML.transition(true).swap("0.5s"))
) {
Img.trashCan().attributes(.style("margin-top: 5px;"))
}
}
}
}
}

View File

@@ -2,7 +2,6 @@ import Elementary
import ElementaryHTMX
import SharedModels
// TODO: Lazy Load branches when view appears.
struct VendorDetail: HTML {
let vendor: Vendor
@@ -11,8 +10,8 @@ struct VendorDetail: HTML {
Float(shouldDisplay: true) {
VendorForm(.formOnly(vendor))
h2(.style("margin-left: 20px; font-size: 1.5em;"), .class("label")) { "Branches" }
branchForm
branches
VendorBranchForm(vendorID: vendor.id)
VendorBranchList(vendorID: vendor.id, branches: nil)
} closeButton: {
Button.close(id: "float")
.attributes(
@@ -23,61 +22,4 @@ struct VendorDetail: HTML {
)
}
}
// TODO: What route for here??
var branchForm: some HTML {
form(
.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
// .hx.post(route: .vendorBranch(.index(for: vendor.id))),
.hx.trigger(.event(.keyup).changed().delay("800ms")),
.hx.target("#branches"),
.hx.swap(.beforeEnd) // ,
// .custom(name: "hx-on::after-request", value: "if(event.detail.successful) this.reset();")
)
button(
.type(.submit),
.class("btn-secondary"),
.style("float: right; padding: 10px 50px;"),
.hx.target("#branch-table"),
.hx.swap(.beforeEnd)
) { "+" }
}
}
var branches: some HTML {
ul(.id("branches")) {
for branch in vendor.branches ?? [] {
BranchRow(branch: branch)
}
}
}
struct BranchRow: HTML {
let branch: VendorBranch
var content: some HTML<HTMLTag.li> {
li(.id(.branch(.row(id: branch.id))), .class("branch-row")) {
span(.class("label")) { branch.name.capitalized }
button(
.class("btn"),
.hx.delete(route: .vendorBranch(.delete(id: branch.id))),
.hx.target(.id(.branch(.row(id: branch.id)))),
.hx.swap(.outerHTML.transition(true).swap("0.5s"))
) {
img(.src("/images/trash-can.svg"), .width(30), .height(30), .style("margin-top: 5px;"))
}
}
}
}
}