Fix login

This commit is contained in:
Daniel Arantes Loverde
2026-02-21 18:51:39 -03:00
parent 0f5ad4c268
commit 3a3dc7217b
17 changed files with 1296 additions and 91 deletions

View File

@@ -0,0 +1,287 @@
import Foundation
struct AppOrderSummary: Decodable, Identifiable {
let id: String
let shortId: String?
let total: Double?
let status: String?
let paymentStatus: String?
let paymentMethod: String?
let deliveryType: String?
let storeName: String?
let createdAt: String?
let updatedAt: String?
enum CodingKeys: String, CodingKey {
case id
case shortId
case total
case status
case paymentStatus
case paymentMethod
case deliveryType
case storeName
case createdAt
case updatedAt
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
shortId = try? container.decode(String.self, forKey: .shortId)
total = ApiService.decodeFlexibleDouble(from: container, keys: [.total])
status = try? container.decode(String.self, forKey: .status)
paymentStatus = try? container.decode(String.self, forKey: .paymentStatus)
paymentMethod = try? container.decode(String.self, forKey: .paymentMethod)
deliveryType = try? container.decode(String.self, forKey: .deliveryType)
storeName = try? container.decode(String.self, forKey: .storeName)
createdAt = try? container.decode(String.self, forKey: .createdAt)
updatedAt = try? container.decode(String.self, forKey: .updatedAt)
}
}
struct PublicOrderResult: Codable, Identifiable {
let id: String
let shortId: String?
let status: String?
let paymentStatus: String?
let paymentMethod: String?
let deliveryType: String?
let total: Double?
let storeName: String?
let createdAt: String?
let updatedAt: String?
let otp: String?
let customerOtp: String?
let confirmOtp: String?
let items: [PublicOrderItem]
let timeline: [PublicOrderTimelineEvent]
enum CodingKeys: String, CodingKey {
case id
case shortId
case status
case paymentStatus
case paymentMethod
case deliveryType
case total
case storeName
case createdAt
case updatedAt
case otp
case customerOtp
case confirmOtp
case items
case timeline
}
init(
id: String,
shortId: String? = nil,
status: String? = nil,
paymentStatus: String? = nil,
paymentMethod: String? = nil,
deliveryType: String? = nil,
total: Double? = nil,
storeName: String? = nil,
createdAt: String? = nil,
updatedAt: String? = nil,
otp: String? = nil,
customerOtp: String? = nil,
confirmOtp: String? = nil,
items: [PublicOrderItem] = [],
timeline: [PublicOrderTimelineEvent] = []
) {
self.id = id
self.shortId = shortId
self.status = status
self.paymentStatus = paymentStatus
self.paymentMethod = paymentMethod
self.deliveryType = deliveryType
self.total = total
self.storeName = storeName
self.createdAt = createdAt
self.updatedAt = updatedAt
self.otp = otp
self.customerOtp = customerOtp
self.confirmOtp = confirmOtp
self.items = items
self.timeline = timeline
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
shortId = try? container.decode(String.self, forKey: .shortId)
status = try? container.decode(String.self, forKey: .status)
paymentStatus = try? container.decode(String.self, forKey: .paymentStatus)
paymentMethod = try? container.decode(String.self, forKey: .paymentMethod)
deliveryType = try? container.decode(String.self, forKey: .deliveryType)
total = ApiService.decodeFlexibleDouble(from: container, keys: [.total])
storeName = try? container.decode(String.self, forKey: .storeName)
createdAt = try? container.decode(String.self, forKey: .createdAt)
updatedAt = try? container.decode(String.self, forKey: .updatedAt)
otp = try? container.decode(String.self, forKey: .otp)
customerOtp = try? container.decode(String.self, forKey: .customerOtp)
confirmOtp = try? container.decode(String.self, forKey: .confirmOtp)
items = (try? container.decode([PublicOrderItem].self, forKey: .items)) ?? []
timeline = (try? container.decode([PublicOrderTimelineEvent].self, forKey: .timeline)) ?? []
}
var displayOtpCode: String? {
let values = [customerOtp, otp, confirmOtp]
for value in values {
let trimmed = (value ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty == false { return trimmed }
}
return nil
}
var isInDeliveryRoute: Bool {
let normalized = (status ?? "").uppercased()
if normalized.contains("OUT_FOR_DELIVERY") { return true }
if normalized.contains("EM_ROTA") { return true }
if normalized.contains("ON_ROUTE") { return true }
if normalized.contains("ROTA") { return true }
return false
}
var isFinalStatus: Bool {
let normalized = (status ?? "").uppercased()
return normalized == "COMPLETED" || normalized == "CANCELED" || normalized == "REFUNDED"
}
var isPaymentConfirmed: Bool {
let payment = (paymentStatus ?? "").uppercased()
let currentStatus = (status ?? "").uppercased()
if Self.looksConfirmed(payment) || Self.looksConfirmed(currentStatus) {
return true
}
// Fallback: alguns ambientes atualizam apenas a timeline primeiro.
if timeline.contains(where: { event in
let statusValue = (event.status ?? "").uppercased()
let messageValue = (event.message ?? "").uppercased()
return Self.looksConfirmed(statusValue) || Self.looksConfirmed(messageValue)
}) {
return true
}
return false
}
private static func looksConfirmed(_ value: String) -> Bool {
if value.isEmpty { return false }
if value.contains("PENDING") || value.contains("AWAIT") { return false }
if value.contains("FAILED") || value.contains("ERROR") { return false }
if value.contains("CANCEL") || value.contains("REFUND") { return false }
if value.contains("CONFIRM") { return true }
if value.contains("APPROV") { return true }
if value.contains("PAID") { return true }
if value.contains("RECEIV") { return true }
return value == "SUCCESS" || value == "DONE"
}
}
struct PublicOrderItem: Codable, Identifiable {
let id: String
let name: String?
let qty: Int?
let price: Double?
enum CodingKeys: String, CodingKey {
case id
case name
case qty
case quantity
case price
}
init(id: String = UUID().uuidString, name: String?, qty: Int?, price: Double?) {
self.id = id
self.name = name
self.qty = qty
self.price = 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)
qty = ApiService.decodeFlexibleInt(from: container, keys: [.qty, .quantity])
price = ApiService.decodeFlexibleDouble(from: container, keys: [.price])
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(name, forKey: .name)
try container.encodeIfPresent(qty, forKey: .qty)
try container.encodeIfPresent(price, forKey: .price)
}
}
struct PublicOrderTimelineEvent: Codable, Identifiable {
let id: String
let status: String?
let message: String?
let time: String?
enum CodingKeys: String, CodingKey {
case id
case status
case message
case time
case createdAt
case updatedAt
}
init(id: String = UUID().uuidString, status: String?, message: String?, time: String?) {
self.id = id
self.status = status
self.message = message
self.time = time
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = (try? container.decode(String.self, forKey: .id)) ?? UUID().uuidString
status = try? container.decode(String.self, forKey: .status)
message = try? container.decode(String.self, forKey: .message)
time = (try? container.decode(String.self, forKey: .time))
?? (try? container.decode(String.self, forKey: .createdAt))
?? (try? container.decode(String.self, forKey: .updatedAt))
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(status, forKey: .status)
try container.encodeIfPresent(message, forKey: .message)
try container.encodeIfPresent(time, forKey: .time)
}
}
struct OrderRealtimeUpdate: Decodable {
let id: String?
let shortId: String?
let storeId: String?
let userId: String?
let status: String?
let paymentStatus: String?
let updatedAt: String?
}
extension CreateOrderResult {
func asPublicOrderResult() -> PublicOrderResult {
PublicOrderResult(
id: id ?? UUID().uuidString,
shortId: shortId,
status: status,
paymentStatus: paymentStatus,
paymentMethod: paymentMethod
)
}
}