segregate files

This commit is contained in:
Daniel Arantes Loverde
2026-02-13 11:01:54 -03:00
parent 4a40936293
commit d7b8b1864a
20 changed files with 2653 additions and 1923 deletions

View 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
}
}