This commit is contained in:
Daniel Arantes Loverde
2026-06-12 16:47:18 -03:00
parent 35418cc4a2
commit 8b9ebdcb44
6 changed files with 150 additions and 8 deletions

View File

@@ -487,6 +487,9 @@
"Escolha o tamanho da sua fome" : {
"comment" : "A label displayed below the pizza size selection.",
"isCommentAutoGenerated" : true
},
"Escolha seu sabor" : {
},
"Este sabor não possui adicionais." : {
"comment" : "A message displayed when a pizza flavor does not have any add-ons.",
@@ -888,7 +891,16 @@
},
"Pizza de varios sabores" : {
"comment" : "A title displayed above the main content of the view.",
"isCommentAutoGenerated" : true
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Escolha seu sabor"
}
}
}
},
"Política de Privacidade" : {
"comment" : "The title of the privacy policy section.",

View File

@@ -231,7 +231,7 @@ struct PizzaProductDetailSheet: View {
)
.clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusXL, style: .continuous))
Text("Pizza de varios sabores")
Text("Escolha seu sabor")
.font(AppTypography.heading2)
.foregroundStyle(AppColors.textPrimary)
@@ -291,7 +291,7 @@ struct PizzaProductDetailSheet: View {
id: cartItemId,
productId: selectedFlavorProducts.first?.id ?? category.id,
storeId: storeId,
name: "Pizza de varios sabores",
name: "Escolha seu sabor",
imageURL: representativeImage,
details: selectedDetailsText,
choices: pizzaChoices.isEmpty ? nil : pizzaChoices,

View File

@@ -286,7 +286,7 @@ extension StoreDetailView {
StoreCatalogListItem(
id: "\(category.id)::pizza-summary",
product: first,
title: "Pizza de varios sabores",
title: "Escolha seu sabor",
description: "Escolha o tamanho da sua fome",
imageURL: representativeImage ?? first.image,
isPizzaSummary: true,

View File

@@ -198,6 +198,7 @@ struct UserProfileView: View {
let cleanEmail = email.trimmingCharacters(in: .whitespacesAndNewlines)
let normalizedPhone = normalizePhoneNumberForAPI(phone)
let cleanPhoto = profilePicture.trimmingCharacters(in: .whitespacesAndNewlines)
let newPhoto = cleanPhoto.hasPrefix("data:") ? cleanPhoto : nil
isSaving = true
defer { isSaving = false }
@@ -207,7 +208,7 @@ struct UserProfileView: View {
name: cleanName,
email: cleanEmail,
phoneNumber: normalizedPhone,
profilePicture: cleanPhoto.isEmpty ? nil : cleanPhoto
profilePicture: newPhoto
)
if response.error {
@@ -231,10 +232,26 @@ struct UserProfileView: View {
let cleanCpf = cpf.filter(\.isNumber)
if cleanCpf.count == 11 {
appState.profile.cpf = cleanCpf
Task<Void, Never> {
do { _ = try await ApiService().updateProfileCpf(cpf: cleanCpf) } catch {}
guard isValidCPF(cleanCpf) else {
SnackbarCenter.shared.show(
title: "CPF inválido. Verifique e tente novamente.",
style: .error,
icon: "xmark.octagon.fill",
duration: 3.0
)
return
}
let cpfResponse = try await ApiService().updateProfileCpf(cpf: cleanCpf)
if cpfResponse.error {
SnackbarCenter.shared.show(
title: cpfResponse.message ?? "Não foi possível atualizar o CPF.",
style: .error,
icon: "xmark.octagon.fill",
duration: 3.0
)
return
}
appState.profile.cpf = cleanCpf
}
SessionStateStore.setActiveUserKey(
SessionStateStore.makeUserKey(profileId: appState.profile.id, email: appState.profile.email)
@@ -291,6 +308,20 @@ struct UserProfileView: View {
}
}
private func isValidCPF(_ digits: String) -> Bool {
guard digits.count == 11, digits.unicodeScalars.allSatisfy({ CharacterSet.decimalDigits.contains($0) }) else { return false }
guard Set(digits).count > 1 else { return false }
func checkDigit(_ d: String, _ length: Int) -> Bool {
let sum = d.prefix(length).enumerated().reduce(0) { acc, pair in
acc + (Int(String(pair.element)) ?? 0) * (length + 1 - pair.offset)
}
let rem = (sum * 10) % 11
let expected = rem == 10 ? 0 : rem
return Int(String(d[d.index(d.startIndex, offsetBy: length)])) == expected
}
return checkDigit(digits, 9) && checkDigit(digits, 10)
}
#if os(iOS)
@MainActor
private func applySelectedPhoto(_ item: PhotosPickerItem?) async {