import Foundation import ManaCore import Observation /// State-Maschine für ``ManaSignUpView``. Wraps `AuthClient.register`. /// /// Bei `requireEmailVerification: true` (Default in mana-auth) ist die /// erfolgreiche Registrierung kein Login — der Server hat die Verify- /// Mail verschickt, der User muss klicken. `status` wird in dem Fall /// `.awaitingVerification(email:)` — die View zeigt den Hinweis-Screen. @MainActor @Observable public final class SignUpViewModel { public enum Status: Equatable, Sendable { case idle case registering /// Registrierung erfolgreich, Verify-Mail unterwegs. case awaitingVerification(email: String) /// Registrierung erfolgreich UND Server hat Tokens geliefert /// (z.B. mit `requireEmailVerification: false`). User ist /// eingeloggt. case signedIn case error(String) } public var email: String = "" public var name: String = "" public var password: String = "" public private(set) var status: Status = .idle private let auth: AuthClient private let sourceAppUrl: URL? public init(auth: AuthClient, sourceAppUrl: URL? = nil) { self.auth = auth self.sourceAppUrl = sourceAppUrl } public var canSubmit: Bool { guard !trimmedEmail.isEmpty, !password.isEmpty else { return false } if case .registering = status { return false } return true } public var isRegistering: Bool { if case .registering = status { return true } return false } /// Passwort-Mindest-Check vor dem Server-Call. mana-auth /// (Better Auth) gibt heute `WEAK_PASSWORD` zurück wenn das /// Passwort < 8 Zeichen ist — wir spiegeln das clientseitig /// damit der User keinen Round-Trip braucht. public var passwordHint: String? { guard !password.isEmpty else { return nil } if password.count < 8 { return "Passwort muss mindestens 8 Zeichen lang sein." } return nil } private var trimmedEmail: String { email.trimmingCharacters(in: .whitespacesAndNewlines) } public func submit() async { let emailTrim = trimmedEmail let nameTrim = name.trimmingCharacters(in: .whitespacesAndNewlines) guard !emailTrim.isEmpty, !password.isEmpty else { return } if let hint = passwordHint { status = .error(hint) return } status = .registering do { try await auth.register( email: emailTrim, password: password, name: nameTrim.isEmpty ? nil : nameTrim, sourceAppUrl: sourceAppUrl ) password = "" switch auth.status { case .signedIn: status = .signedIn default: status = .awaitingVerification(email: emailTrim) } } catch let error as AuthError { status = .error(error.errorDescription ?? "Registrierung fehlgeschlagen") } catch { status = .error(String(describing: error)) } } }