import DatabaseClient import Dependencies import Elementary import SharedModels import Vapor import VaporElementary struct VendorViewController: RouteCollection { @Dependency(\.database.vendors) var vendors @Dependency(\.database.vendorBranches) var vendorBranches func boot(routes: any RoutesBuilder) throws { let route = routes.protected.grouped("vendors") route.get(use: index) route.post(use: create) route.get("create", use: form) route.group(":id") { $0.get(use: detail) $0.put(use: update) $0.post("branches", use: createBranch(req:)) } } @Sendable func index(req: Request) async throws -> HTMLResponse { try await req.render { try await mainPage(VendorForm()) } } @Sendable func create(req: Request) async throws -> HTMLResponse { let vendor = try await vendors.create(req.content.decode(Vendor.Create.self)) let vendors = try await vendors.fetchAll(.withBranches) return await req.render { div(.class("container"), .id("content")) { VendorDetail(vendor: vendor) VendorTable(vendors: vendors) } } } @Sendable func form(req: Request) async throws -> HTMLResponse { await req.render { VendorForm(.float(shouldShow: true)) } } @Sendable func detail(req: Request) async throws -> HTMLResponse { guard let vendor = try await vendors.get(req.ensureIDPathComponent(), .withBranches) else { throw Abort(.badRequest, reason: "Vendor does not exist.") } let html = VendorDetail(vendor: vendor) guard req.isHtmxRequest else { return try await req.render { try await mainPage(html) } } return await req.render { html } } @Sendable func update(req: Request) async throws -> HTMLResponse { let vendor = try await vendors.update( req.ensureIDPathComponent(), with: req.content.decode(Vendor.Update.self), returnWithBranches: true ) return await req.render { VendorDetail(vendor: vendor) } } @Sendable func createBranch(req: Request) async throws -> HTMLResponse { let vendorID = try req.ensureIDPathComponent() let create = try req.content.decode(CreateBranch.self) let branch = try await vendorBranches.create(.init(name: create.name, vendorID: vendorID)) return await req.render { VendorDetail.BranchRow(branch: branch) } } @Sendable func deleteBranch(req: Request) async throws -> HTTPStatus { try await vendorBranches.delete(req.ensureIDPathComponent(key: "branchID")) return .ok } private func mainPage(_ html: C) async throws -> some SendableHTMLDocument where C: Sendable { let vendors = try await vendors.fetchAll(.withBranches) return MainPage(displayNav: true, route: .vendors) { div(.class("container"), .id("content")) { html VendorTable(vendors: vendors) } } } } struct CreateBranch: Content { let name: String }