import Dependencies import Elementary import Fluent import SharedModels import Vapor import VaporElementary struct PurchaseOrderSearchViewController: RouteCollection { @Dependency(\.database.employees) var employees @Dependency(\.database.vendorBranches) var vendorBranches @Dependency(\.database.purchaseOrders) var purchaseOrders func boot(routes: any RoutesBuilder) throws { let route = routes.protected.grouped("purchase-orders", "search") route.get(use: index) route.post(use: post) } @Sendable func index(req: Request) async throws -> HTMLResponse { let query = try? req.query.decode(FormQuery.self) let html = PurchaseOrderSearch(context: query?.context) if query?.table == true || !req.isHtmxRequest { return await req.render { mainPage(search: html) } } return await req.render { html } } @Sendable func post(req: Request) async throws -> HTMLResponse { let context = try req.content.decode(PurchaseOrderSearchContent.self) let results = try await purchaseOrders.search(context.toDatabaseQuery(), .init(page: 1, per: 25)) return await req.render { PurchaseOrderTable(page: results, context: .search, searchContext: nil) } } func mainPage(search: PurchaseOrderSearch = .init()) -> some SendableHTMLDocument { MainPage(displayNav: true, route: .purchaseOrders) { div(.class("container"), .id("purchase-order-content")) { search PurchaseOrderTable(page: .init(items: [], metadata: .init(page: 0, per: 50, total: 0))) } } } } extension PurchaseOrderSearchContent { func toDatabaseQuery() throws -> PurchaseOrder.SearchContext { switch context { case .employee: guard let createdForID else { throw Abort(.badRequest, reason: "Employee id not provided") } return .employee(createdForID) case .customer: guard let search, !search.isEmpty else { throw Abort(.badRequest, reason: "Customer search string is empty.") } return .customer(search) case .vendor: guard let vendorBranchID else { throw Abort(.badRequest, reason: "Vendor branch id not provided.") } return .vendor(vendorBranchID) } } } private struct FormQuery: Content { let context: PurchaseOrderSearchContext let table: Bool? }