import ManaAuthUI import ManaCore import SwiftUI struct AccountView: View { @Environment(AuthClient.self) private var auth @Environment(ManaAuthGate.self) private var authGate @State private var showChangeEmail = false @State private var showChangePassword = false @State private var showDeleteAccount = false var body: some View { ZStack { CardsTheme.background.ignoresSafeArea() Group { switch auth.status { case .signedIn: signedInContent case .guest, .signedOut, .error, .unknown: guestContent case .signingIn, .twoFactorRequired: ProgressView().tint(CardsTheme.primary) } } } .navigationTitle("Account") #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif .manaBrand(CardsBrand.manaBrand) .sheet(isPresented: $showChangeEmail) { ManaChangeEmailView( auth: auth, callbackUniversalLink: URL(string: "https://cardecky.mana.how/auth/email-changed"), onDone: { showChangeEmail = false } ) .manaBrand(CardsBrand.manaBrand) } .sheet(isPresented: $showChangePassword) { ManaChangePasswordView( auth: auth, onDone: { showChangePassword = false } ) .manaBrand(CardsBrand.manaBrand) } .sheet(isPresented: $showDeleteAccount) { ManaDeleteAccountView( auth: auth, onDone: { showDeleteAccount = false } ) .manaBrand(CardsBrand.manaBrand) } } private var signedInContent: some View { VStack(spacing: 20) { Image(systemName: "person.crop.circle.fill") .resizable() .frame(width: 80, height: 80) .foregroundStyle(CardsTheme.primary) if let email = auth.currentEmail { Text(email) .font(.headline) .foregroundStyle(CardsTheme.foreground) } VStack(spacing: 12) { NavigationLink { SettingsView() } label: { rowLabel("Einstellungen", systemImage: "gear") } .buttonStyle(.plain) Button { showChangeEmail = true } label: { rowLabel("Email ändern", systemImage: "envelope") } .buttonStyle(.plain) Button { showChangePassword = true } label: { rowLabel("Passwort ändern", systemImage: "key") } .buttonStyle(.plain) ManaTwoFactorAccountRow(auth: auth) .padding(.vertical, 12) .padding(.horizontal, 16) .background(CardsTheme.surface, in: RoundedRectangle(cornerRadius: 8)) .overlay( RoundedRectangle(cornerRadius: 8) .stroke(CardsTheme.border, lineWidth: 1) ) } .padding(.horizontal, 32) Spacer() Button(role: .destructive) { // Logout behält die Guest-Identity → App bleibt im // anonymen Modus nutzbar (lokale Decks, Marketplace // browsen). Wer „alles vergessen" will, nutzt // „Account löschen". Task { await auth.signOut(keepGuestMode: true) } } label: { Text("Abmelden") .frame(maxWidth: .infinity) .padding(.vertical, 12) .background(CardsTheme.error.opacity(0.1), in: RoundedRectangle(cornerRadius: 8)) .foregroundStyle(CardsTheme.error) } .padding(.horizontal, 32) // App-Store-Guideline 5.1.1(v): jede App mit Sign-Up MUSS // eine Account-Löschung anbieten. Button(role: .destructive) { showDeleteAccount = true } label: { Text("Account löschen…") .font(.footnote) .foregroundStyle(CardsTheme.mutedForeground) } .padding(.bottom, 16) } .padding(.top, 48) } private var guestContent: some View { VStack(spacing: 20) { Image(systemName: "person.crop.circle.dashed") .resizable() .frame(width: 80, height: 80) .foregroundStyle(CardsTheme.mutedForeground) VStack(spacing: 8) { Text("Du nutzt Cardecky anonym") .font(.headline) .foregroundStyle(CardsTheme.foreground) Text( """ Marketplace und lokale Decks funktionieren ohne Konto. \ Für KI-Karten, eigene Decks im Cloud-Sync und Marketplace-\ Veröffentlichung brauchst du ein Konto. """ ) .font(.subheadline) .foregroundStyle(CardsTheme.mutedForeground) .multilineTextAlignment(.center) } .padding(.horizontal, 32) VStack(spacing: 12) { Button { // Trigger ohne pending-Action — wir wollen einfach // das Sign-In-Sheet öffnen. `require` mit no-op // schaltet die Sheet-Logik des Gates ein. authGate.require(reason: "account-tab") {} } label: { Text("Anmelden / Konto erstellen") .frame(maxWidth: .infinity) .padding(.vertical, 14) .background(CardsTheme.primary, in: RoundedRectangle(cornerRadius: 10)) .foregroundStyle(.white) } .buttonStyle(.plain) NavigationLink { SettingsView() } label: { rowLabel("Einstellungen", systemImage: "gear") } .buttonStyle(.plain) } .padding(.horizontal, 32) Spacer() } .padding(.top, 48) } private func rowLabel(_ title: String, systemImage: String) -> some View { Label(title, systemImage: systemImage) .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 12) .padding(.horizontal, 16) .background(CardsTheme.surface, in: RoundedRectangle(cornerRadius: 8)) .foregroundStyle(CardsTheme.foreground) .overlay( RoundedRectangle(cornerRadius: 8) .stroke(CardsTheme.border, lineWidth: 1) ) } } #Preview { NavigationStack { AccountView() .environment(AuthClient(config: AppConfig.manaAppConfig)) } }