This commit is contained in:
Daniel Arantes Loverde
2026-06-05 16:32:08 -03:00
parent e62bd60e9a
commit 18818f909a
27 changed files with 1440 additions and 137 deletions

View File

@@ -15,32 +15,25 @@ struct CustomerProfileUpdatePayload: Encodable {
}
struct CustomerIdentityUpdatePayload: Encodable {
let name: String
let email: String
let phoneNumber: String
let name: String?
let email: String?
let phoneNumber: String?
let profilePicture: String?
let addressBook: [CustomerAddressPayload]
enum CodingKeys: String, CodingKey {
case name
case email
case phoneNumber
case phone
case profilePicture
case profile_picture
case addressBook = "address_book"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(email, forKey: .email)
try container.encode(phoneNumber, forKey: .phoneNumber)
try container.encode(phoneNumber, forKey: .phone)
try container.encode(addressBook, forKey: .addressBook)
try container.encodeIfPresent(name, forKey: .name)
try container.encodeIfPresent(email, forKey: .email)
try container.encodeIfPresent(phoneNumber, forKey: .phoneNumber)
if let profilePicture, profilePicture.isEmpty == false {
try container.encode(profilePicture, forKey: .profilePicture)
try container.encode(profilePicture, forKey: .profile_picture)
}
}
}

View File

@@ -4,6 +4,13 @@ import Foundation
struct EmptyResult: Decodable {}
struct ProfilePatchEnvelope: Decodable {
let error: Bool
let code: String?
let message: String?
let profilePictureUrl: String?
}
struct RegistrationResult: Decodable {
let id: String?
let name: String?

View File

@@ -40,6 +40,10 @@ struct AppOrderSummary: Decodable, Identifiable {
case storeLogo
case store_logo
case logo
case storeImage
case store_image
case storeImageUrl
case logoUrl
case date
case createdAt
case updatedAt
@@ -62,7 +66,7 @@ struct AppOrderSummary: Decodable, Identifiable {
deliveryType = ApiService.decodeFlexibleString(from: container, keys: [.deliveryType])
storeName = ApiService.decodeFlexibleString(from: container, keys: [.storeName])
storePhone = ApiService.decodeFlexibleString(from: container, keys: [.storePhone])
storeLogoURL = ApiService.decodeFlexibleString(from: container, keys: [.storeLogo, .store_logo, .logo])
storeLogoURL = ApiService.decodeFlexibleString(from: container, keys: [.storeLogo, .store_logo, .logo, .storeImage, .store_image, .storeImageUrl, .logoUrl])
let fallbackDate = ApiService.decodeFlexibleString(from: container, keys: [.date])
createdAt = ApiService.decodeFlexibleString(from: container, keys: [.createdAt]) ?? fallbackDate
updatedAt = ApiService.decodeFlexibleString(from: container, keys: [.updatedAt]) ?? fallbackDate
@@ -97,6 +101,7 @@ struct PublicOrderResult: Codable, Identifiable {
let customerOtp: String?
let confirmOtp: String?
let cancellationReason: String?
let fullAddress: String?
let deliveryAddress: PublicOrderDeliveryAddress?
let review: PublicOrderReview?
let items: [PublicOrderItem]
@@ -133,12 +138,17 @@ struct PublicOrderResult: Codable, Identifiable {
case storeLogo
case store_logo
case logo
case storeImage
case store_image
case storeImageUrl
case logoUrl
case createdAt
case updatedAt
case otp
case customerOtp
case confirmOtp
case cancellationReason
case fullAddress
case address
case deliveryAddress
case delivery_address
@@ -148,6 +158,8 @@ struct PublicOrderResult: Codable, Identifiable {
case orderReview
case items
case timeline
case history
case orderedAt
}
init(
@@ -178,6 +190,7 @@ struct PublicOrderResult: Codable, Identifiable {
customerOtp: String? = nil,
confirmOtp: String? = nil,
cancellationReason: String? = nil,
fullAddress: String? = nil,
deliveryAddress: PublicOrderDeliveryAddress? = nil,
review: PublicOrderReview? = nil,
items: [PublicOrderItem] = [],
@@ -210,6 +223,7 @@ struct PublicOrderResult: Codable, Identifiable {
self.customerOtp = customerOtp
self.confirmOtp = confirmOtp
self.cancellationReason = cancellationReason
self.fullAddress = fullAddress
self.deliveryAddress = deliveryAddress
self.review = review
self.items = items
@@ -248,13 +262,14 @@ struct PublicOrderResult: Codable, Identifiable {
total = ApiService.decodeFlexibleDouble(from: container, keys: [.total])
storeName = ApiService.decodeFlexibleString(from: container, keys: [.storeName])
storePhone = ApiService.decodeFlexibleString(from: container, keys: [.storePhone])
storeLogoURL = ApiService.decodeFlexibleString(from: container, keys: [.storeLogo, .store_logo, .logo])
createdAt = ApiService.decodeFlexibleString(from: container, keys: [.createdAt])
storeLogoURL = ApiService.decodeFlexibleString(from: container, keys: [.storeLogo, .store_logo, .logo, .storeImage, .store_image, .storeImageUrl, .logoUrl])
createdAt = ApiService.decodeFlexibleString(from: container, keys: [.createdAt, .orderedAt])
updatedAt = ApiService.decodeFlexibleString(from: container, keys: [.updatedAt])
otp = ApiService.decodeFlexibleString(from: container, keys: [.otp])
customerOtp = ApiService.decodeFlexibleString(from: container, keys: [.customerOtp])
confirmOtp = ApiService.decodeFlexibleString(from: container, keys: [.confirmOtp])
cancellationReason = ApiService.decodeFlexibleString(from: container, keys: [.cancellationReason])
fullAddress = ApiService.decodeFlexibleString(from: container, keys: [.fullAddress])
deliveryAddress = (try? container.decode(PublicOrderDeliveryAddress.self, forKey: .address))
?? (try? container.decode(PublicOrderDeliveryAddress.self, forKey: .deliveryAddress))
?? (try? container.decode(PublicOrderDeliveryAddress.self, forKey: .delivery_address))
@@ -263,7 +278,9 @@ struct PublicOrderResult: Codable, Identifiable {
review = (try? container.decode(PublicOrderReview.self, forKey: .review))
?? (try? container.decode(PublicOrderReview.self, forKey: .orderReview))
items = (try? container.decode([PublicOrderItem].self, forKey: .items)) ?? []
timeline = (try? container.decode([PublicOrderTimelineEvent].self, forKey: .timeline)) ?? []
timeline = (try? container.decode([PublicOrderTimelineEvent].self, forKey: .timeline))
?? (try? container.decode([PublicOrderTimelineEvent].self, forKey: .history))
?? []
}
func encode(to encoder: Encoder) throws {
@@ -294,6 +311,7 @@ struct PublicOrderResult: Codable, Identifiable {
try container.encodeIfPresent(customerOtp, forKey: .customerOtp)
try container.encodeIfPresent(confirmOtp, forKey: .confirmOtp)
try container.encodeIfPresent(cancellationReason, forKey: .cancellationReason)
try container.encodeIfPresent(fullAddress, forKey: .fullAddress)
try container.encodeIfPresent(deliveryAddress, forKey: .address)
try container.encodeIfPresent(review, forKey: .review)
try container.encode(items, forKey: .items)
@@ -537,20 +555,23 @@ struct PublicOrderReview: Codable {
struct PublicOrderItem: Codable, Identifiable {
let id: String
let productId: String?
let name: String?
let qty: Int?
let price: Double?
enum CodingKeys: String, CodingKey {
case id
case productId
case name
case qty
case quantity
case price
}
init(id: String = UUID().uuidString, name: String?, qty: Int?, price: Double?) {
init(id: String = UUID().uuidString, productId: String? = nil, name: String?, qty: Int?, price: Double?) {
self.id = id
self.productId = productId
self.name = name
self.qty = qty
self.price = price
@@ -559,6 +580,7 @@ struct PublicOrderItem: Codable, Identifiable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
productId = try? container.decode(String.self, forKey: .productId)
name = try? container.decode(String.self, forKey: .name)
qty = ApiService.decodeFlexibleInt(from: container, keys: [.qty, .quantity])
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
@@ -567,6 +589,7 @@ struct PublicOrderItem: Codable, Identifiable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(productId, forKey: .productId)
try container.encodeIfPresent(name, forKey: .name)
try container.encodeIfPresent(qty, forKey: .qty)
try container.encodeIfPresent(price, forKey: .price)
@@ -581,6 +604,7 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
let completed: Bool?
let message: String?
let time: String?
let date: String?
enum CodingKeys: String, CodingKey {
case id
@@ -589,7 +613,9 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
case active
case completed
case message
case event
case time
case date
case createdAt
case updatedAt
}
@@ -601,7 +627,8 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
active: Bool? = nil,
completed: Bool? = nil,
message: String?,
time: String?
time: String?,
date: String? = nil
) {
self.id = id
self.status = status
@@ -610,6 +637,7 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
self.completed = completed
self.message = message
self.time = time
self.date = date
}
init(from decoder: Decoder) throws {
@@ -619,10 +647,12 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
label = try? container.decode(String.self, forKey: .label)
active = try? container.decode(Bool.self, forKey: .active)
completed = try? container.decode(Bool.self, forKey: .completed)
message = try? container.decode(String.self, forKey: .message)
message = (try? container.decode(String.self, forKey: .message))
?? (try? container.decode(String.self, forKey: .event))
time = (try? container.decode(String.self, forKey: .time))
?? (try? container.decode(String.self, forKey: .createdAt))
?? (try? container.decode(String.self, forKey: .updatedAt))
date = try? container.decode(String.self, forKey: .date)
}
func encode(to encoder: Encoder) throws {
@@ -634,6 +664,7 @@ struct PublicOrderTimelineEvent: Codable, Identifiable {
try container.encodeIfPresent(completed, forKey: .completed)
try container.encodeIfPresent(message, forKey: .message)
try container.encodeIfPresent(time, forKey: .time)
try container.encodeIfPresent(date, forKey: .date)
}
}

View File

@@ -155,28 +155,17 @@ final class ApiService {
return envelope
}
func updateCustomerProfile(name: String, email: String, phoneNumber: String, profilePicture: String?) async throws -> ApiEnvelope<CustomerProfile> {
let currentProfile = try await profile(forceRefresh: true)
guard currentProfile.error == false, let customer = currentProfile.result else {
throw NetworkError.invalidResponse
}
func updateCustomerProfile(name: String, email: String, phoneNumber: String, profilePicture: String?) async throws -> ProfilePatchEnvelope {
let payload = CustomerIdentityUpdatePayload(
name: name,
email: email,
phoneNumber: phoneNumber,
profilePicture: profilePicture,
addressBook: (customer.addressBook ?? []).map(CustomerAddressPayload.init(from:))
name: name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? nil : name,
email: email.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? nil : email,
phoneNumber: phoneNumber.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? nil : phoneNumber,
profilePicture: profilePicture
)
let body = try JSONEncoder().encode(payload)
let req = ApiRequest(path: "/api/customer/\(customer.id)", method: "POST", module: .customer, requiresAuth: true, body: body)
let envelope: ApiEnvelope<CustomerProfile> = try await sendEnvelope(req)
let scopedProfileKey = "\(profileCachePrefix)\(scopedCacheSuffix())"
if envelope.error == false, envelope.result != nil {
AppContentCache.shared.set(envelope, for: scopedProfileKey, ttl: AppCacheTTL.twoHours)
} else {
invalidateFavoritesCache()
}
let req = ApiRequest(path: "/api/customer/profile", method: "PATCH", module: .customer, requiresAuth: true, body: body)
let envelope: ProfilePatchEnvelope = try await send(req)
AppContentCache.shared.invalidate(prefix: profileCachePrefix)
return envelope
}