diff --git a/Package.swift b/Package.swift index 64543fc..cdcf32e 100644 --- a/Package.swift +++ b/Package.swift @@ -9,6 +9,9 @@ let package = Package( products: [ .executable(name: "App", targets: ["App"]), .library(name: "ApiController", targets: ["ApiController"]), + .library(name: "ClimateZoneClient", targets: ["ClimateZoneClient"]), + .library(name: "CoreModels", targets: ["CoreModels"]), + .library(name: "LocationClient", targets: ["LocationClient"]), .library(name: "Routes", targets: ["Routes"]), .library(name: "Styleguide", targets: ["Styleguide"]), .library(name: "ViewController", targets: ["ViewController"]) @@ -59,6 +62,27 @@ let package = Package( ], swiftSettings: swiftSettings ), + .target( + name: "LocationClient", + dependencies: [ + .product(name: "Dependencies", package: "swift-dependencies"), + .product(name: "DependenciesMacros", package: "swift-dependencies") + ], + swiftSettings: swiftSettings + ), + .target( + name: "ClimateZoneClient", + dependencies: [ + .product(name: "Dependencies", package: "swift-dependencies"), + .product(name: "DependenciesMacros", package: "swift-dependencies") + ], + swiftSettings: swiftSettings + ), + .target( + name: "CoreModels", + dependencies: [], + swiftSettings: swiftSettings + ), .target( name: "HTMLSnapshotTesting", dependencies: [ @@ -67,9 +91,18 @@ let package = Package( ], swiftSettings: swiftSettings ), + .target( + name: "LocationClient", + dependencies: [ + .product(name: "Dependencies", package: "swift-dependencies"), + .product(name: "DependenciesMacros", package: "swift-dependencies") + ], + swiftSettings: swiftSettings + ), .target( name: "Routes", dependencies: [ + "CoreModels", .product(name: "CasePaths", package: "swift-case-paths"), .product(name: "Dependencies", package: "swift-dependencies"), .product(name: "Elementary", package: "elementary"), diff --git a/Sources/ClimateZoneClient/ClimateZoneClient.swift b/Sources/ClimateZoneClient/ClimateZoneClient.swift new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Routes/Models/ClimateZone.swift b/Sources/CoreModels/ClimateZone.swift similarity index 96% rename from Sources/Routes/Models/ClimateZone.swift rename to Sources/CoreModels/ClimateZone.swift index fc60a9f..a29ac47 100644 --- a/Sources/Routes/Models/ClimateZone.swift +++ b/Sources/CoreModels/ClimateZone.swift @@ -1,4 +1,4 @@ -// TODO: This should be renamed to ClimateZoneType. +import Foundation public enum ClimateZone { diff --git a/Sources/CoreModels/Cooridinates.swift b/Sources/CoreModels/Cooridinates.swift new file mode 100644 index 0000000..350735e --- /dev/null +++ b/Sources/CoreModels/Cooridinates.swift @@ -0,0 +1,11 @@ +/// Represents a location coordinates. +public struct Coordinates: Codable, Equatable, Sendable { + + public let latitude: Double + public let longitude: Double + + public init(latitude: Double, longitude: Double) { + self.latitude = latitude + self.longitude = longitude + } +} diff --git a/Sources/CoreModels/DesignTemperatures.swift b/Sources/CoreModels/DesignTemperatures.swift new file mode 100644 index 0000000..7387264 --- /dev/null +++ b/Sources/CoreModels/DesignTemperatures.swift @@ -0,0 +1,11 @@ +/// Represents design temperature conditions. +public struct DesignTemperatures: Codable, Equatable, Sendable { + + public let cooling: Double + public let heating: Double + + public init(cooling: Double, heating: Double) { + self.cooling = cooling + self.heating = heating + } +} diff --git a/Sources/CoreModels/Location.swift b/Sources/CoreModels/Location.swift new file mode 100644 index 0000000..897e100 --- /dev/null +++ b/Sources/CoreModels/Location.swift @@ -0,0 +1,27 @@ +import Foundation + +public struct Location: Codable, Equatable, Sendable { + + public let city: String + public let state: String + public let zipCode: String + public let stateCode: String + public let county: String + public let coordinates: Coordinates + + public init( + city: String, + state: String, + stateCode: String, + zipCode: String, + county: String, + coordinates: Coordinates + ) { + self.city = city + self.zipCode = zipCode + self.state = state + self.stateCode = stateCode + self.county = county + self.coordinates = coordinates + } +} diff --git a/Sources/LocationClient/LocationClient.swift b/Sources/LocationClient/LocationClient.swift new file mode 100644 index 0000000..e0ab038 --- /dev/null +++ b/Sources/LocationClient/LocationClient.swift @@ -0,0 +1,74 @@ +import Dependencies +import DependenciesMacros +import Foundation + +public extension DependencyValues { + var locationClient: LocationClient { + get { self[LocationClient.self] } + set { self[LocationClient.self] = newValue } + } +} + +@DependencyClient +public struct LocationClient: Sendable { + public var search: @Sendable (Int) async throws -> [Response] + + // TODO: Add ClimateZone.ZoneIdentifier?? + public struct Response: Codable, Equatable, Sendable { + + public let city: String + public let latitude: String + public let longitude: String + public let zipCode: String + public let state: String + public let stateCode: String + public let county: String + + public init( + city: String, + latitude: String, + longitude: String, + zipCode: String, + state: String, + stateCode: String, + county: String + ) { + self.city = city + self.latitude = latitude + self.longitude = longitude + self.zipCode = zipCode + self.state = state + self.stateCode = stateCode + self.county = county + } + + private enum CodingKeys: String, CodingKey { + case city + case latitude + case longitude + case zipCode = "postal_code" + case state + case stateCode = "state_code" + case county = "province" + } + } +} + +extension LocationClient: TestDependencyKey { + public static let testValue: LocationClient = Self() +} + +#if DEBUG + + public extension LocationClient.Response { + static let mock = Self( + city: "Monroe", + latitude: "39.4413000", + longitude: "-84.3652000", + zipCode: "45050", + state: "Ohio", + stateCode: "OH", + county: "Butler" + ) + } +#endif diff --git a/Sources/Routes/SiteRoutes.swift b/Sources/Routes/SiteRoutes.swift index cb0aaae..a0d6aec 100644 --- a/Sources/Routes/SiteRoutes.swift +++ b/Sources/Routes/SiteRoutes.swift @@ -1,4 +1,5 @@ import CasePaths +@_exported import CoreModels import Foundation import PsychrometricClient @preconcurrency import URLRouting