[2026-07-resubmission] Add guest browsing flow with App Attest session for App Review resubmission
Adds a pre-login public store locator (guest session via DeviceCheck/App Attest, keychain-backed token storage) so the app no longer forces sign-in before showing any content, plus updated support URL metadata.
This commit is contained in:
@@ -14,6 +14,8 @@ struct ProfileView: View {
|
||||
@State var openAddressesOnboarding = false
|
||||
@State var onboardingMessage: String? = nil
|
||||
@State var showLogoutAlert = false
|
||||
@State var showDeleteAccountAlert = false
|
||||
@State var isDeletingAccount = false
|
||||
@State private var openOrders = false
|
||||
let tabBarClearance: CGFloat = 120
|
||||
|
||||
@@ -87,6 +89,25 @@ struct ProfileView: View {
|
||||
.padding(.top, 10)
|
||||
.padding(.horizontal, 20)
|
||||
|
||||
Button(action: { showDeleteAccountAlert = true }) {
|
||||
HStack(spacing: 10) {
|
||||
if isDeletingAccount {
|
||||
ProgressView()
|
||||
.tint(Color.red)
|
||||
} else {
|
||||
Image(systemName: "trash.fill")
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
}
|
||||
Text("Excluir Conta")
|
||||
.font(AppTypography.body)
|
||||
}
|
||||
.foregroundStyle(Color.red.opacity(0.7))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(isDeletingAccount)
|
||||
.padding(.top, 2)
|
||||
.padding(.horizontal, 20)
|
||||
|
||||
Text("Versão 1.0b")
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.foregroundStyle(AppColors.textMuted)
|
||||
@@ -130,6 +151,14 @@ struct ProfileView: View {
|
||||
} message: {
|
||||
Text("Tem certeza que deseja sair da sua conta?")
|
||||
}
|
||||
.alert("Excluir sua conta?", isPresented: $showDeleteAccountAlert) {
|
||||
Button("Cancelar", role: .cancel) {}
|
||||
Button("Excluir", role: .destructive) {
|
||||
Task { await deleteAccount() }
|
||||
}
|
||||
} message: {
|
||||
Text("Essa ação é permanente. Seus dados de perfil, endereços, cartões e favoritos serão excluídos e não poderão ser recuperados.")
|
||||
}
|
||||
.onAppear {
|
||||
guard let message = appState.address.onboardingMessage else {
|
||||
return
|
||||
@@ -251,6 +280,78 @@ struct ProfileView: View {
|
||||
appState = AppState()
|
||||
root = .auth
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func deleteAccount() async {
|
||||
guard isDeletingAccount == false else { return }
|
||||
isDeletingAccount = true
|
||||
defer { isDeletingAccount = false }
|
||||
|
||||
do {
|
||||
let response = try await ApiService().deleteAccount()
|
||||
guard response.error == false else {
|
||||
SnackbarCenter.shared.show(
|
||||
title: response.message ?? "Não foi possível excluir sua conta.",
|
||||
style: .error,
|
||||
icon: "xmark.octagon.fill",
|
||||
duration: 3.5
|
||||
)
|
||||
return
|
||||
}
|
||||
logout()
|
||||
} catch {
|
||||
SnackbarCenter.shared.show(
|
||||
title: "Não foi possível excluir sua conta. Tente novamente.",
|
||||
style: .error,
|
||||
icon: "xmark.octagon.fill",
|
||||
duration: 3.5
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ProfileLoggedOutView: View {
|
||||
@Binding var root: RootFlow
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 18) {
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "person.crop.circle.badge.questionmark")
|
||||
.font(.system(size: 56, weight: .regular))
|
||||
.foregroundStyle(AppColors.textMuted)
|
||||
|
||||
Text("Entre na sua conta")
|
||||
.font(AppTypography.heading2)
|
||||
.foregroundStyle(AppColors.textPrimary)
|
||||
|
||||
Text("Faça login ou cadastre-se para ver seu perfil, pedidos e endereços.")
|
||||
.font(AppTypography.body)
|
||||
.foregroundStyle(AppColors.textMuted)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 32)
|
||||
|
||||
Button {
|
||||
root = .auth
|
||||
} label: {
|
||||
Text("Entrar ou Cadastrar")
|
||||
.font(AppTypography.heading3)
|
||||
.foregroundStyle(AppColors.textInverse)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 14)
|
||||
.background(AppColors.primary)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.padding(.horizontal, 32)
|
||||
.padding(.top, 8)
|
||||
|
||||
Spacer()
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(AppColors.backgroundLight)
|
||||
}
|
||||
}
|
||||
|
||||
struct ProfileMenuRow: View {
|
||||
|
||||
Reference in New Issue
Block a user