import Fluent import Leaf import Vapor struct EmployeeViewController: RouteCollection { private let api = ApiController() func boot(routes: any RoutesBuilder) throws { let employees = routes.protected.grouped("employees") employees.get(use: index(req:)) employees.get("form", use: employeeForm(req:)) employees.post(use: postEmployeeForm(req:)) employees.group(":employeeID") { $0.get(use: editEmployee(req:)) $0.delete(use: deleteEmployee(req:)) $0.put(use: updateEmployee(req:)) $0.post("toggle-active", use: toggleActiveEmployee(req:)) } } @Sendable func index(req: Request) async throws -> View { return try await req.view.render("employees", EmployeesCTX(api: api, req: req)) } @Sendable func postEmployeeForm(req: Request) async throws -> View { _ = try await api.createEmployee(req: req) let employees = try await api.getSortedEmployees(req: req) return try await req.view.render("employee-table", ["employees": employees]) } @Sendable func toggleActiveEmployee(req: Request) async throws -> View { guard let employee = try await Employee.find(req.parameters.get("employeeID"), on: req.db) else { throw Abort(.notFound) } employee.active.toggle() try await employee.save(on: req.db) let employees = try await api.getSortedEmployees(req: req) return try await req.view.render("employee-table", ["employees": employees]) } @Sendable func deleteEmployee(req: Request) async throws -> View { _ = try await api.deleteEmployee(req: req) let employees = try await api.getSortedEmployees(req: req) return try await req.view.render("employee-table", ["employees": employees]) } @Sendable func editEmployee(req: Request) async throws -> View { guard let employee = try await Employee.find(req.parameters.get("employeeID"), on: req.db) else { throw Abort(.notFound) } return try await req.view.render("employee-form", EmployeeFormCTX(employee: employee.toDTO())) } @Sendable func updateEmployee(req: Request) async throws -> View { _ = try await api.updateEmployee(req: req) return try await req.view.render("employees", EmployeesCTX(oob: true, api: api, req: req)) } @Sendable func employeeForm(req: Request) async throws -> View { try await req.view.render("employee-form", EmployeeFormCTX()) } } private struct EmployeesCTX: Content { let oob: Bool let employees: [Employee.DTO] let form: EmployeeFormCTX init( oob: Bool = false, employee: Employee? = nil, api: ApiController, req: Request ) async throws { self.oob = oob self.employees = try await api.getSortedEmployees(req: req) self.form = .init(employee: employee.map { $0.toDTO() }) } } private struct EmployeeFormCTX: Content { let employee: Employee.DTO? let oob: Bool init(employee: Employee.DTO? = nil) { self.employee = employee self.oob = employee != nil } } private extension ApiController { func getSortedEmployees(req: Request) async throws -> [Employee.DTO] { var employees = try await employeesIndex(req: req) employees.sort { ($0.active ?? false) && !($1.active ?? false) } employees.sort { ($0.lastName ?? "") < ($1.lastName ?? "") } return employees } }