From 9f63b96c80297ee6686e783365433de053b79169 Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Sat, 3 Jan 2026 17:02:21 -0500 Subject: [PATCH] WIP: Working rooms table and form for project. --- Sources/DatabaseClient/Rooms.swift | 27 ++++++------------- Sources/ManualDCore/Room.swift | 19 ++++++------- Sources/ManualDCore/Routes/ViewRoute.swift | 18 ++++++++++++- Sources/ViewController/Live.swift | 18 ++++++++++--- .../Views/Project/ProjectView.swift | 4 ++- .../ViewController/Views/Rooms/RoomForm.swift | 12 +++++++-- .../Views/Rooms/RoomsView.swift | 24 +++++------------ 7 files changed, 68 insertions(+), 54 deletions(-) diff --git a/Sources/DatabaseClient/Rooms.swift b/Sources/DatabaseClient/Rooms.swift index 65d550f..227ab19 100644 --- a/Sources/DatabaseClient/Rooms.swift +++ b/Sources/DatabaseClient/Rooms.swift @@ -53,8 +53,7 @@ extension Room.Create { return .init( name: name, heatingLoad: heatingLoad, - coolingTotal: coolingTotal, - coolingSensible: coolingSensible, + coolingLoad: coolingLoad, registerCount: registerCount, projectID: projectID ) @@ -67,12 +66,9 @@ extension Room.Create { guard heatingLoad >= 0 else { throw ValidationError("Room heating load should not be less than 0.") } - guard coolingTotal >= 0 else { + guard coolingLoad >= 0 else { throw ValidationError("Room cooling total should not be less than 0.") } - guard coolingSensible >= 0 else { - throw ValidationError("Room cooling sensible should not be less than 0.") - } guard registerCount >= 1 else { throw ValidationError("Room cooling sensible should not be less than 1.") } @@ -88,8 +84,7 @@ extension Room { .id() .field("name", .string, .required) .field("heatingLoad", .double, .required) - .field("coolingTotal", .double, .required) - .field("coolingSensible", .double, .required) + .field("coolingLoad", .double, .required) .field("registerCount", .int8, .required) .field("createdAt", .datetime) .field("updatedAt", .datetime) @@ -117,11 +112,8 @@ final class RoomModel: Model, @unchecked Sendable { @Field(key: "heatingLoad") var heatingLoad: Double - @Field(key: "coolingTotal") - var coolingTotal: Double - - @Field(key: "coolingSensible") - var coolingSensible: Double + @Field(key: "coolingLoad") + var coolingLoad: Double @Field(key: "registerCount") var registerCount: Int @@ -141,8 +133,7 @@ final class RoomModel: Model, @unchecked Sendable { id: UUID? = nil, name: String, heatingLoad: Double, - coolingTotal: Double, - coolingSensible: Double, + coolingLoad: Double, registerCount: Int, createdAt: Date? = nil, updatedAt: Date? = nil, @@ -151,8 +142,7 @@ final class RoomModel: Model, @unchecked Sendable { self.id = id self.name = name self.heatingLoad = heatingLoad - self.coolingTotal = coolingTotal - self.coolingSensible = coolingSensible + self.coolingLoad = coolingLoad self.registerCount = registerCount self.createdAt = createdAt self.updatedAt = updatedAt @@ -165,11 +155,10 @@ final class RoomModel: Model, @unchecked Sendable { projectID: $project.id, name: name, heatingLoad: heatingLoad, - coolingLoad: .init(total: coolingTotal, sensible: coolingSensible), + coolingLoad: coolingLoad, registerCount: registerCount, createdAt: createdAt!, updatedAt: updatedAt! ) - } } diff --git a/Sources/ManualDCore/Room.swift b/Sources/ManualDCore/Room.swift index 6981917..28513e9 100644 --- a/Sources/ManualDCore/Room.swift +++ b/Sources/ManualDCore/Room.swift @@ -6,7 +6,7 @@ public struct Room: Codable, Equatable, Identifiable, Sendable { public let projectID: Project.ID public let name: String public let heatingLoad: Double - public let coolingLoad: CoolingLoad + public let coolingLoad: Double public let registerCount: Int public let createdAt: Date public let updatedAt: Date @@ -16,7 +16,7 @@ public struct Room: Codable, Equatable, Identifiable, Sendable { projectID: Project.ID, name: String, heatingLoad: Double, - coolingLoad: CoolingLoad, + coolingLoad: Double, registerCount: Int = 1, createdAt: Date, updatedAt: Date @@ -39,23 +39,20 @@ extension Room { public let projectID: Project.ID public let name: String public let heatingLoad: Double - public let coolingTotal: Double - public let coolingSensible: Double + public let coolingLoad: Double public let registerCount: Int public init( projectID: Project.ID, name: String, heatingLoad: Double, - coolingTotal: Double, - coolingSensible: Double, + coolingLoad: Double, registerCount: Int = 1 ) { self.projectID = projectID self.name = name self.heatingLoad = heatingLoad - self.coolingTotal = coolingTotal - self.coolingSensible = coolingSensible + self.coolingLoad = coolingLoad self.registerCount = registerCount } } @@ -70,7 +67,7 @@ extension Room { projectID: UUID(0), name: "Kitchen", heatingLoad: 12345, - coolingLoad: .init(total: 12345, sensible: 12345), + coolingLoad: 1234, registerCount: 2, createdAt: Date(), updatedAt: Date() @@ -80,7 +77,7 @@ extension Room { projectID: UUID(1), name: "Bedroom - 1", heatingLoad: 12345, - coolingLoad: .init(total: 12345, sensible: 12345), + coolingLoad: 1456, registerCount: 1, createdAt: Date(), updatedAt: Date() @@ -90,7 +87,7 @@ extension Room { projectID: UUID(2), name: "Family Room", heatingLoad: 12345, - coolingLoad: .init(total: 12345, sensible: 12345), + coolingLoad: 1673, registerCount: 3, createdAt: Date(), updatedAt: Date() diff --git a/Sources/ManualDCore/Routes/ViewRoute.swift b/Sources/ManualDCore/Routes/ViewRoute.swift index b42752a..845a440 100644 --- a/Sources/ManualDCore/Routes/ViewRoute.swift +++ b/Sources/ManualDCore/Routes/ViewRoute.swift @@ -104,8 +104,9 @@ extension SiteRoute.View { extension SiteRoute.View { public enum RoomRoute: Equatable, Sendable { - case form(dismiss: Bool = false) + case form(Project.ID, dismiss: Bool = false) case index(Project.ID) + case submit(Room.Create) static let rootPath = "rooms" @@ -117,6 +118,7 @@ extension SiteRoute.View { } Method.get Query { + Field("projectID") { Project.ID.parser() } Field("dismiss", default: false) { Bool.parser() } } } @@ -127,6 +129,20 @@ extension SiteRoute.View { Field("projectID") { Project.ID.parser() } } } + Route(.case(Self.submit)) { + Path { rootPath } + Method.post + Body { + FormData { + Field("projectID") { Project.ID.parser() } + Field("name", .string) + Field("heatingLoad") { Double.parser() } + Field("coolingLoad") { Double.parser() } + Field("registerCount") { Digits() } + } + .map(.memberwise(Room.Create.init)) + } + } } } } diff --git a/Sources/ViewController/Live.swift b/Sources/ViewController/Live.swift index ea21176..d8849eb 100644 --- a/Sources/ViewController/Live.swift +++ b/Sources/ViewController/Live.swift @@ -120,13 +120,25 @@ extension SiteRoute.View.RoomRoute { @Dependency(\.database) var database switch self { - case .form(let dismiss): - return RoomForm(dismiss: dismiss) + + case .form(let projectID, let dismiss): + return RoomForm(dismiss: dismiss, projectID: projectID) + case .index(let projectID): let rooms = try await database.rooms.fetch(projectID) return request.view { ProjectView(projectID: projectID, activeTab: .rooms) { - RoomsView(rooms: rooms) + RoomsView(projectID: projectID, rooms: rooms) + } + } + + case .submit(let form): + request.logger.debug("New room form submitted.") + let _ = try await database.rooms.create(form) + let rooms = try await database.rooms.fetch(form.projectID) + return request.view { + ProjectView(projectID: form.projectID, activeTab: .rooms) { + RoomsView(projectID: form.projectID, rooms: rooms) } } } diff --git a/Sources/ViewController/Views/Project/ProjectView.swift b/Sources/ViewController/Views/Project/ProjectView.swift index c99fca3..810c38e 100644 --- a/Sources/ViewController/Views/Project/ProjectView.swift +++ b/Sources/ViewController/Views/Project/ProjectView.swift @@ -3,6 +3,8 @@ import ElementaryHTMX import ManualDCore import Styleguide +// TODO: Need a back button to navigate to all projects table. + struct ProjectView: HTML, Sendable where Inner: Sendable { let projectID: Project.ID let activeTab: Sidebar.ActiveTab @@ -54,7 +56,7 @@ struct Sidebar: HTML { } .attributes(.class("p-4")) - row(title: "Project", icon: .mapPin, route: .project(.index)) + row(title: "Project", icon: .mapPin, route: .project(.detail(projectID))) .attributes(.data("active", value: active == .projects ? "true" : "false")) row(title: "Rooms", icon: .doorClosed, route: .room(.index(projectID))) diff --git a/Sources/ViewController/Views/Rooms/RoomForm.swift b/Sources/ViewController/Views/Rooms/RoomForm.swift index 51c72b5..25902df 100644 --- a/Sources/ViewController/Views/Rooms/RoomForm.swift +++ b/Sources/ViewController/Views/Rooms/RoomForm.swift @@ -9,11 +9,19 @@ import Styleguide struct RoomForm: HTML, Sendable { let dismiss: Bool + let projectID: Project.ID var body: some HTML { ModalForm(id: "roomForm", dismiss: dismiss) { h1(.class("text-3xl font-bold pb-6")) { "Room" } - form { + // TODO: Use htmx here. + form( + .method(.post), + .action(route: .room(.index(projectID))) + ) { + div(.class("hidden")) { + input(.name("projectID"), .id("projectID"), .value("\(projectID)")) + } div { label(.for("name")) { "Name:" } Input(id: "name", placeholder: "Room Name") @@ -40,7 +48,7 @@ struct RoomForm: HTML, Sendable { div(.class("space-x-4")) { CancelButton() .attributes( - .hx.get(route: .room(.form(dismiss: true))), + .hx.get(route: .room(.form(projectID, dismiss: true))), .hx.target("#roomForm"), .hx.swap(.outerHTML) ) diff --git a/Sources/ViewController/Views/Rooms/RoomsView.swift b/Sources/ViewController/Views/Rooms/RoomsView.swift index 215729c..abf4992 100644 --- a/Sources/ViewController/Views/Rooms/RoomsView.swift +++ b/Sources/ViewController/Views/Rooms/RoomsView.swift @@ -5,7 +5,10 @@ import Foundation import ManualDCore import Styleguide +// TODO: Calculate rooms sensible based on project wide SHR. + struct RoomsView: HTML, Sendable { + let projectID: Project.ID let rooms: [Room] var body: some HTML { @@ -17,7 +20,7 @@ struct RoomsView: HTML, Sendable { .data("tip", value: "Add room") ) { button( - .hx.get(route: .room(.form(dismiss: false))), + .hx.get(route: .room(.form(projectID, dismiss: false))), .hx.target("#roomForm"), .hx.swap(.outerHTML), .class("btn btn-primary w-[40px] text-2xl") @@ -35,7 +38,6 @@ struct RoomsView: HTML, Sendable { th { Label("Name") } th { Label("Heating Load") } th { Label("Cooling Total") } - th { Label("Cooling Sensible") } th { Label("Register Count") } } } @@ -48,13 +50,9 @@ struct RoomsView: HTML, Sendable { .attributes(.class("text-error")) } td { - Number(room.coolingLoad.total) + Number(room.coolingLoad) .attributes(.class("text-success")) } - td { - Number(room.coolingLoad.sensible) - .attributes(.class("text-info")) - } td { Number(room.registerCount) } @@ -72,16 +70,12 @@ struct RoomsView: HTML, Sendable { .attributes( .class("badge badge-outline badge-success badge-xl")) } - td { - Number(rooms.coolingSensibleTotal) - .attributes(.class("badge badge-outline badge-info badge-xl")) - } td {} } } } } - RoomForm(dismiss: true) + RoomForm(dismiss: true, projectID: projectID) } } @@ -93,10 +87,6 @@ extension Array where Element == Room { } var coolingTotal: Double { - reduce(into: 0) { $0 += $1.coolingLoad.total } - } - - var coolingSensibleTotal: Double { - reduce(into: 0) { $0 += $1.coolingLoad.sensible } + reduce(into: 0) { $0 += $1.coolingLoad } } }