segregate files
This commit is contained in:
412
pedi-foods/Sources/PediFoods/Services/ApiModels.swift
Normal file
412
pedi-foods/Sources/PediFoods/Services/ApiModels.swift
Normal file
@@ -0,0 +1,412 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - DTOs
|
||||
|
||||
struct EmptyResult: Decodable {}
|
||||
|
||||
struct RegistrationResult: Decodable {
|
||||
let id: String?
|
||||
let name: String?
|
||||
let email: String?
|
||||
}
|
||||
|
||||
struct LoginResult: Decodable {
|
||||
let token: String
|
||||
let customer: CustomerProfile?
|
||||
}
|
||||
|
||||
struct CustomerProfile: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let email: String
|
||||
let phoneNumber: String?
|
||||
let profilePicture: String?
|
||||
let addressBook: [CustomerAddress]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case email
|
||||
case phoneNumber
|
||||
case profilePicture
|
||||
case addressBook = "address_book"
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomerAddress: Decodable {
|
||||
let id: String?
|
||||
let label: String?
|
||||
let address: String?
|
||||
let number: String?
|
||||
let complement: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let zipCode: String?
|
||||
let latLong: [Double]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case label
|
||||
case address
|
||||
case number
|
||||
case complement
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case zipCode
|
||||
case latLong = "lat_long"
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreSummary: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let logo: String?
|
||||
let cover: String?
|
||||
let category: String?
|
||||
let rating: Double?
|
||||
let deliveryTime: String?
|
||||
let deliveryFee: Double?
|
||||
let distance: Double?
|
||||
let isOpen: Bool?
|
||||
let statusLabel: String?
|
||||
}
|
||||
|
||||
struct StoreInfoResult: Decodable {
|
||||
let isOpen: Bool?
|
||||
let statusLabel: String?
|
||||
let deliveryTime: String?
|
||||
let minOrder: Double?
|
||||
let address: StoreAddressInfo?
|
||||
let paymentMethods: StorePaymentMethodsInfo?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case isOpen
|
||||
case statusLabel
|
||||
case deliveryTime
|
||||
case minOrder
|
||||
case address
|
||||
case paymentMethods
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
isOpen = try? container.decode(Bool.self, forKey: .isOpen)
|
||||
statusLabel = try? container.decode(String.self, forKey: .statusLabel)
|
||||
deliveryTime = try? container.decode(String.self, forKey: .deliveryTime)
|
||||
minOrder = ApiService.decodeFlexibleDouble(from: container, keys: [.minOrder])
|
||||
address = try? container.decode(StoreAddressInfo.self, forKey: .address)
|
||||
paymentMethods = try? container.decode(StorePaymentMethodsInfo.self, forKey: .paymentMethods)
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddressInfo: Decodable {
|
||||
let street: String?
|
||||
let number: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let latitude: Double?
|
||||
let longitude: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case street
|
||||
case number
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case latitude
|
||||
case longitude
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
street = try? container.decode(String.self, forKey: .street)
|
||||
number = try? container.decode(String.self, forKey: .number)
|
||||
neighborhood = try? container.decode(String.self, forKey: .neighborhood)
|
||||
city = try? container.decode(String.self, forKey: .city)
|
||||
state = try? container.decode(String.self, forKey: .state)
|
||||
latitude = ApiService.decodeFlexibleDouble(from: container, keys: [.latitude])
|
||||
longitude = ApiService.decodeFlexibleDouble(from: container, keys: [.longitude])
|
||||
}
|
||||
}
|
||||
|
||||
struct StorePaymentMethodsInfo: Decodable {
|
||||
let acceptPix: Bool?
|
||||
let acceptCash: Bool?
|
||||
let acceptCreditCard: Bool?
|
||||
let acceptDebitCard: Bool?
|
||||
}
|
||||
|
||||
struct StoreCatalogCategory: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let products: [StoreCatalogProduct]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case products
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Categoria"
|
||||
products = (try? container.decode([StoreCatalogProduct].self, forKey: .products)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreCatalogProduct: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let description: String?
|
||||
let image: String?
|
||||
let price: Double?
|
||||
let originalPrice: Double?
|
||||
let addonGroups: [StoreAddonGroup]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case description
|
||||
case desc
|
||||
case image
|
||||
case cover
|
||||
case photo
|
||||
case price
|
||||
case originalPrice
|
||||
case oldPrice
|
||||
case addonGroups
|
||||
case addons
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Produto"
|
||||
description = (try? container.decode(String.self, forKey: .description)) ?? (try? container.decode(String.self, forKey: .desc))
|
||||
image = (try? container.decode(String.self, forKey: .image))
|
||||
?? (try? container.decode(String.self, forKey: .cover))
|
||||
?? (try? container.decode(String.self, forKey: .photo))
|
||||
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
|
||||
originalPrice = ApiService.decodeFlexibleDouble(from: container, keys: [.originalPrice, .oldPrice])
|
||||
addonGroups = (try? container.decode([StoreAddonGroup].self, forKey: .addonGroups))
|
||||
?? (try? container.decode([StoreAddonGroup].self, forKey: .addons))
|
||||
?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddonGroup: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let minSelectors: Int?
|
||||
let maxSelectors: Int?
|
||||
let items: [StoreAddonItem]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case minSelectors
|
||||
case maxSelectors
|
||||
case items
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Adicionais"
|
||||
minSelectors = try? container.decode(Int.self, forKey: .minSelectors)
|
||||
maxSelectors = try? container.decode(Int.self, forKey: .maxSelectors)
|
||||
items = (try? container.decode([StoreAddonItem].self, forKey: .items)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddonItem: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let price: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case price
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Item"
|
||||
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
|
||||
}
|
||||
}
|
||||
|
||||
struct PublicCategory: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let icon: String?
|
||||
}
|
||||
|
||||
struct CustomerProfileUpdatePayload: Encodable {
|
||||
let addressBook: [CustomerAddressPayload]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case addressBook = "address_book"
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomerAddressPayload: Encodable {
|
||||
let label: String?
|
||||
let address: String?
|
||||
let number: String?
|
||||
let complement: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let zipCode: String?
|
||||
let latLong: [Double]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case label
|
||||
case address
|
||||
case number
|
||||
case complement
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case zipCode
|
||||
case latLong = "lat_long"
|
||||
}
|
||||
|
||||
init(from address: CustomerAddress) {
|
||||
self.label = address.label
|
||||
self.address = address.address
|
||||
self.number = address.number
|
||||
self.complement = address.complement
|
||||
self.neighborhood = address.neighborhood
|
||||
self.city = address.city
|
||||
self.state = address.state
|
||||
self.zipCode = address.zipCode
|
||||
self.latLong = address.latLong
|
||||
}
|
||||
}
|
||||
|
||||
struct CepLookupResult: Decodable {
|
||||
let zipCode: String?
|
||||
let street: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let complement: String?
|
||||
let latitude: Double?
|
||||
let longitude: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case zipCode
|
||||
case cep
|
||||
case zip
|
||||
case normalized
|
||||
case raw
|
||||
case street
|
||||
case logradouro
|
||||
case address
|
||||
case neighborhood
|
||||
case bairro
|
||||
case district
|
||||
case city
|
||||
case cidade
|
||||
case localidade
|
||||
case state
|
||||
case estado
|
||||
case uf
|
||||
case complement
|
||||
case complemento
|
||||
case latitude
|
||||
case lat
|
||||
case longitude
|
||||
case lng
|
||||
}
|
||||
|
||||
enum NormalizedKeys: String, CodingKey {
|
||||
case cep
|
||||
case logradouro
|
||||
case bairro
|
||||
case cidade
|
||||
case uf
|
||||
case latitude
|
||||
case longitude
|
||||
}
|
||||
|
||||
enum RawKeys: String, CodingKey {
|
||||
case cep
|
||||
case address
|
||||
case district
|
||||
case city
|
||||
case state
|
||||
case lat
|
||||
case lng
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let normalizedContainer = try? container.nestedContainer(keyedBy: NormalizedKeys.self, forKey: .normalized)
|
||||
let rawContainer = try? container.nestedContainer(keyedBy: RawKeys.self, forKey: .raw)
|
||||
|
||||
let directZip = CepLookupResult.decodeString(from: container, keys: [.zipCode, .cep, .zip])
|
||||
let directStreet = CepLookupResult.decodeString(from: container, keys: [.street, .logradouro, .address])
|
||||
let directNeighborhood = CepLookupResult.decodeString(from: container, keys: [.neighborhood, .bairro, .district])
|
||||
let directCity = CepLookupResult.decodeString(from: container, keys: [.city, .cidade, .localidade])
|
||||
let directState = CepLookupResult.decodeString(from: container, keys: [.state, .estado, .uf])
|
||||
let directComplement = CepLookupResult.decodeString(from: container, keys: [.complement, .complemento])
|
||||
let directLatitude = CepLookupResult.decodeFlexibleDouble(from: container, keys: [.latitude, .lat])
|
||||
let directLongitude = CepLookupResult.decodeFlexibleDouble(from: container, keys: [.longitude, .lng])
|
||||
|
||||
let normalizedZip = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cep]) }
|
||||
let normalizedStreet = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.logradouro]) }
|
||||
let normalizedNeighborhood = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.bairro]) }
|
||||
let normalizedCity = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cidade]) }
|
||||
let normalizedState = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.uf]) }
|
||||
let normalizedLatitude = normalizedContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.latitude]) }
|
||||
let normalizedLongitude = normalizedContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.longitude]) }
|
||||
|
||||
let rawZip = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cep]) }
|
||||
let rawStreet = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.address]) }
|
||||
let rawNeighborhood = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.district]) }
|
||||
let rawCity = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.city]) }
|
||||
let rawState = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.state]) }
|
||||
let rawLatitude = rawContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.lat]) }
|
||||
let rawLongitude = rawContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.lng]) }
|
||||
|
||||
zipCode = directZip ?? normalizedZip ?? rawZip
|
||||
street = directStreet ?? normalizedStreet ?? rawStreet
|
||||
neighborhood = directNeighborhood ?? normalizedNeighborhood ?? rawNeighborhood
|
||||
city = directCity ?? normalizedCity ?? rawCity
|
||||
state = directState ?? normalizedState ?? rawState
|
||||
complement = directComplement
|
||||
latitude = directLatitude ?? normalizedLatitude ?? rawLatitude
|
||||
longitude = directLongitude ?? normalizedLongitude ?? rawLongitude
|
||||
}
|
||||
|
||||
private static func decodeString<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> String? {
|
||||
for key in keys {
|
||||
if let value = try? container.decode(String.self, forKey: key) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func decodeFlexibleDouble<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> Double? {
|
||||
for key in keys {
|
||||
if let value = try? container.decode(Double.self, forKey: key) {
|
||||
return value
|
||||
}
|
||||
if let valueAsString = try? container.decode(String.self, forKey: key),
|
||||
let parsed = Double(valueAsString.replacingOccurrences(of: ",", with: ".")) {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -236,419 +236,7 @@ final class ApiService {
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - DTOs
|
||||
|
||||
struct EmptyResult: Decodable {}
|
||||
|
||||
struct RegistrationResult: Decodable {
|
||||
let id: String?
|
||||
let name: String?
|
||||
let email: String?
|
||||
}
|
||||
|
||||
struct LoginResult: Decodable {
|
||||
let token: String
|
||||
let customer: CustomerProfile?
|
||||
}
|
||||
|
||||
struct CustomerProfile: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let email: String
|
||||
let phoneNumber: String?
|
||||
let profilePicture: String?
|
||||
let addressBook: [CustomerAddress]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case email
|
||||
case phoneNumber
|
||||
case profilePicture
|
||||
case addressBook = "address_book"
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomerAddress: Decodable {
|
||||
let id: String?
|
||||
let label: String?
|
||||
let address: String?
|
||||
let number: String?
|
||||
let complement: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let zipCode: String?
|
||||
let latLong: [Double]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case label
|
||||
case address
|
||||
case number
|
||||
case complement
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case zipCode
|
||||
case latLong = "lat_long"
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreSummary: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let logo: String?
|
||||
let cover: String?
|
||||
let category: String?
|
||||
let rating: Double?
|
||||
let deliveryTime: String?
|
||||
let deliveryFee: Double?
|
||||
let distance: Double?
|
||||
let isOpen: Bool?
|
||||
let statusLabel: String?
|
||||
}
|
||||
|
||||
struct StoreInfoResult: Decodable {
|
||||
let isOpen: Bool?
|
||||
let statusLabel: String?
|
||||
let deliveryTime: String?
|
||||
let minOrder: Double?
|
||||
let address: StoreAddressInfo?
|
||||
let paymentMethods: StorePaymentMethodsInfo?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case isOpen
|
||||
case statusLabel
|
||||
case deliveryTime
|
||||
case minOrder
|
||||
case address
|
||||
case paymentMethods
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
isOpen = try? container.decode(Bool.self, forKey: .isOpen)
|
||||
statusLabel = try? container.decode(String.self, forKey: .statusLabel)
|
||||
deliveryTime = try? container.decode(String.self, forKey: .deliveryTime)
|
||||
minOrder = ApiService.decodeFlexibleDouble(from: container, keys: [.minOrder])
|
||||
address = try? container.decode(StoreAddressInfo.self, forKey: .address)
|
||||
paymentMethods = try? container.decode(StorePaymentMethodsInfo.self, forKey: .paymentMethods)
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddressInfo: Decodable {
|
||||
let street: String?
|
||||
let number: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let latitude: Double?
|
||||
let longitude: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case street
|
||||
case number
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case latitude
|
||||
case longitude
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
street = try? container.decode(String.self, forKey: .street)
|
||||
number = try? container.decode(String.self, forKey: .number)
|
||||
neighborhood = try? container.decode(String.self, forKey: .neighborhood)
|
||||
city = try? container.decode(String.self, forKey: .city)
|
||||
state = try? container.decode(String.self, forKey: .state)
|
||||
latitude = ApiService.decodeFlexibleDouble(from: container, keys: [.latitude])
|
||||
longitude = ApiService.decodeFlexibleDouble(from: container, keys: [.longitude])
|
||||
}
|
||||
}
|
||||
|
||||
struct StorePaymentMethodsInfo: Decodable {
|
||||
let acceptPix: Bool?
|
||||
let acceptCash: Bool?
|
||||
let acceptCreditCard: Bool?
|
||||
let acceptDebitCard: Bool?
|
||||
}
|
||||
|
||||
struct StoreCatalogCategory: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let products: [StoreCatalogProduct]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case products
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Categoria"
|
||||
products = (try? container.decode([StoreCatalogProduct].self, forKey: .products)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreCatalogProduct: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let description: String?
|
||||
let image: String?
|
||||
let price: Double?
|
||||
let originalPrice: Double?
|
||||
let addonGroups: [StoreAddonGroup]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case description
|
||||
case desc
|
||||
case image
|
||||
case cover
|
||||
case photo
|
||||
case price
|
||||
case originalPrice
|
||||
case oldPrice
|
||||
case addonGroups
|
||||
case addons
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Produto"
|
||||
description = (try? container.decode(String.self, forKey: .description)) ?? (try? container.decode(String.self, forKey: .desc))
|
||||
image = (try? container.decode(String.self, forKey: .image))
|
||||
?? (try? container.decode(String.self, forKey: .cover))
|
||||
?? (try? container.decode(String.self, forKey: .photo))
|
||||
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
|
||||
originalPrice = ApiService.decodeFlexibleDouble(from: container, keys: [.originalPrice, .oldPrice])
|
||||
addonGroups = (try? container.decode([StoreAddonGroup].self, forKey: .addonGroups))
|
||||
?? (try? container.decode([StoreAddonGroup].self, forKey: .addons))
|
||||
?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddonGroup: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let minSelectors: Int?
|
||||
let maxSelectors: Int?
|
||||
let items: [StoreAddonItem]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case minSelectors
|
||||
case maxSelectors
|
||||
case items
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Adicionais"
|
||||
minSelectors = try? container.decode(Int.self, forKey: .minSelectors)
|
||||
maxSelectors = try? container.decode(Int.self, forKey: .maxSelectors)
|
||||
items = (try? container.decode([StoreAddonItem].self, forKey: .items)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
struct StoreAddonItem: Decodable, Identifiable {
|
||||
let id: String
|
||||
let name: String
|
||||
let price: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case price
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
|
||||
name = (try? container.decode(String.self, forKey: .name)) ?? "Item"
|
||||
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
|
||||
}
|
||||
}
|
||||
|
||||
struct PublicCategory: Decodable {
|
||||
let id: String
|
||||
let name: String
|
||||
let icon: String?
|
||||
}
|
||||
|
||||
struct CustomerProfileUpdatePayload: Encodable {
|
||||
let addressBook: [CustomerAddressPayload]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case addressBook = "address_book"
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomerAddressPayload: Encodable {
|
||||
let label: String?
|
||||
let address: String?
|
||||
let number: String?
|
||||
let complement: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let zipCode: String?
|
||||
let latLong: [Double]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case label
|
||||
case address
|
||||
case number
|
||||
case complement
|
||||
case neighborhood
|
||||
case city
|
||||
case state
|
||||
case zipCode
|
||||
case latLong = "lat_long"
|
||||
}
|
||||
|
||||
init(from address: CustomerAddress) {
|
||||
self.label = address.label
|
||||
self.address = address.address
|
||||
self.number = address.number
|
||||
self.complement = address.complement
|
||||
self.neighborhood = address.neighborhood
|
||||
self.city = address.city
|
||||
self.state = address.state
|
||||
self.zipCode = address.zipCode
|
||||
self.latLong = address.latLong
|
||||
}
|
||||
}
|
||||
|
||||
struct CepLookupResult: Decodable {
|
||||
let zipCode: String?
|
||||
let street: String?
|
||||
let neighborhood: String?
|
||||
let city: String?
|
||||
let state: String?
|
||||
let complement: String?
|
||||
let latitude: Double?
|
||||
let longitude: Double?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case zipCode
|
||||
case cep
|
||||
case zip
|
||||
case normalized
|
||||
case raw
|
||||
case street
|
||||
case logradouro
|
||||
case address
|
||||
case neighborhood
|
||||
case bairro
|
||||
case district
|
||||
case city
|
||||
case cidade
|
||||
case localidade
|
||||
case state
|
||||
case estado
|
||||
case uf
|
||||
case complement
|
||||
case complemento
|
||||
case latitude
|
||||
case lat
|
||||
case longitude
|
||||
case lng
|
||||
}
|
||||
|
||||
enum NormalizedKeys: String, CodingKey {
|
||||
case cep
|
||||
case logradouro
|
||||
case bairro
|
||||
case cidade
|
||||
case uf
|
||||
case latitude
|
||||
case longitude
|
||||
}
|
||||
|
||||
enum RawKeys: String, CodingKey {
|
||||
case cep
|
||||
case address
|
||||
case district
|
||||
case city
|
||||
case state
|
||||
case lat
|
||||
case lng
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let normalizedContainer = try? container.nestedContainer(keyedBy: NormalizedKeys.self, forKey: .normalized)
|
||||
let rawContainer = try? container.nestedContainer(keyedBy: RawKeys.self, forKey: .raw)
|
||||
|
||||
let directZip = CepLookupResult.decodeString(from: container, keys: [.zipCode, .cep, .zip])
|
||||
let directStreet = CepLookupResult.decodeString(from: container, keys: [.street, .logradouro, .address])
|
||||
let directNeighborhood = CepLookupResult.decodeString(from: container, keys: [.neighborhood, .bairro, .district])
|
||||
let directCity = CepLookupResult.decodeString(from: container, keys: [.city, .cidade, .localidade])
|
||||
let directState = CepLookupResult.decodeString(from: container, keys: [.state, .estado, .uf])
|
||||
let directComplement = CepLookupResult.decodeString(from: container, keys: [.complement, .complemento])
|
||||
let directLatitude = CepLookupResult.decodeFlexibleDouble(from: container, keys: [.latitude, .lat])
|
||||
let directLongitude = CepLookupResult.decodeFlexibleDouble(from: container, keys: [.longitude, .lng])
|
||||
|
||||
let normalizedZip = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cep]) }
|
||||
let normalizedStreet = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.logradouro]) }
|
||||
let normalizedNeighborhood = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.bairro]) }
|
||||
let normalizedCity = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cidade]) }
|
||||
let normalizedState = normalizedContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.uf]) }
|
||||
let normalizedLatitude = normalizedContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.latitude]) }
|
||||
let normalizedLongitude = normalizedContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.longitude]) }
|
||||
|
||||
let rawZip = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.cep]) }
|
||||
let rawStreet = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.address]) }
|
||||
let rawNeighborhood = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.district]) }
|
||||
let rawCity = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.city]) }
|
||||
let rawState = rawContainer.flatMap { CepLookupResult.decodeString(from: $0, keys: [.state]) }
|
||||
let rawLatitude = rawContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.lat]) }
|
||||
let rawLongitude = rawContainer.flatMap { CepLookupResult.decodeFlexibleDouble(from: $0, keys: [.lng]) }
|
||||
|
||||
zipCode = directZip ?? normalizedZip ?? rawZip
|
||||
street = directStreet ?? normalizedStreet ?? rawStreet
|
||||
neighborhood = directNeighborhood ?? normalizedNeighborhood ?? rawNeighborhood
|
||||
city = directCity ?? normalizedCity ?? rawCity
|
||||
state = directState ?? normalizedState ?? rawState
|
||||
complement = directComplement
|
||||
latitude = directLatitude ?? normalizedLatitude ?? rawLatitude
|
||||
longitude = directLongitude ?? normalizedLongitude ?? rawLongitude
|
||||
}
|
||||
|
||||
private static func decodeString<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> String? {
|
||||
for key in keys {
|
||||
if let value = try? container.decode(String.self, forKey: key) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func decodeFlexibleDouble<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> Double? {
|
||||
for key in keys {
|
||||
if let value = try? container.decode(Double.self, forKey: key) {
|
||||
return value
|
||||
}
|
||||
if let valueAsString = try? container.decode(String.self, forKey: key),
|
||||
let parsed = Double(valueAsString.replacingOccurrences(of: ",", with: ".")) {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private extension ApiService {
|
||||
extension ApiService {
|
||||
static func decodeFlexibleDouble<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> Double? {
|
||||
for key in keys {
|
||||
if let value = try? container.decode(Double.self, forKey: key) {
|
||||
|
||||
Reference in New Issue
Block a user