feat(cards): implement full saved card management and transparent checkout
- ApiCardModels.swift: SavedCard, SaveCardPayload, CreditCardOrderPayload, etc. - ApiOrderModels.swift: add savedCardId, clientCpfCnpj, creditCard, creditCardHolderInfo to CreateOrderPayload; Codable for item/addon payloads - ApiService.swift: listCards, saveCard, updateCard, deleteCard, updateProfileCpf - AppState.ProfileState: add cpf field - CheckoutView: CardSelectionSheet (list saved cards + add new), rewrite PaymentCardView (submits order with card data), CardPaymentContext carries full order data - CheckoutView+Logic: buildCreateOrderPayload accepts card params, new loadSavedCards/confirmOrderWithSavedCard/handleOrderResponse helpers, redirect credit card confirm to CardSelectionSheet - OrdersView: CREDIT_CARD pending orders go to tracking (not card form, since card is now submitted with order) - UserProfileView: CPF field with mask, save via PATCH /api/customer/profile
This commit is contained in:
@@ -426,6 +426,43 @@ final class ApiService {
|
||||
)
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
|
||||
// MARK: - Cards
|
||||
|
||||
func listCards() async throws -> ApiEnvelope<[SavedCard]> {
|
||||
let req = ApiRequest(path: "/api/customer/cards", method: "GET", module: .customer, requiresAuth: true)
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
|
||||
func saveCard(payload: SaveCardPayload) async throws -> ApiEnvelope<SavedCardResult> {
|
||||
let body = try JSONEncoder().encode(payload)
|
||||
let req = ApiRequest(path: "/api/customer/cards", method: "POST", module: .customer, requiresAuth: true, body: body)
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
|
||||
func updateCard(cardId: String, payload: UpdateCardPayload) async throws -> ApiEnvelope<SavedCardResult> {
|
||||
let body = try JSONEncoder().encode(payload)
|
||||
let req = ApiRequest(path: "/api/customer/cards/\(cardId)", method: "PATCH", module: .customer, requiresAuth: true, body: body)
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
|
||||
func deleteCard(cardId: String) async throws -> ApiEnvelope<EmptyResult> {
|
||||
let req = ApiRequest(path: "/api/customer/cards/\(cardId)", method: "DELETE", module: .customer, requiresAuth: true)
|
||||
return try await sendEnvelope(req)
|
||||
}
|
||||
|
||||
// MARK: - Profile CPF
|
||||
|
||||
func updateProfileCpf(cpf: String) async throws -> ApiEnvelope<EmptyResult> {
|
||||
let payload = ["cpf": cpf]
|
||||
let body = try JSONEncoder().encode(payload)
|
||||
let req = ApiRequest(path: "/api/customer/profile", method: "PATCH", module: .customer, requiresAuth: true, body: body)
|
||||
let result: ApiEnvelope<EmptyResult> = try await sendEnvelope(req)
|
||||
if result.error == false {
|
||||
AppContentCache.shared.invalidate(prefix: profileCachePrefix)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
extension ApiService {
|
||||
static func decodeFlexibleString<K: CodingKey>(from container: KeyedDecodingContainer<K>, keys: [K]) -> String? {
|
||||
|
||||
Reference in New Issue
Block a user