111 lines
3.7 KiB
Swift
111 lines
3.7 KiB
Swift
import SwiftUI
|
|
|
|
/// "Registrieren" screen. On success this does NOT sign the user in — the
|
|
/// backend requires the emailed confirmation link to be opened first, exactly
|
|
/// like the web signup flow (see `AppState.signup(name:email:password:)`) —
|
|
/// so success routes to `VerificationPendingView` via `onSignupSucceeded`,
|
|
/// not into `AppState`.
|
|
struct SignupView: View {
|
|
@EnvironmentObject private var appState: AppState
|
|
|
|
var onSignupSucceeded: (_ email: String) -> Void
|
|
var onSwitchToLogin: () -> Void
|
|
|
|
@State private var name = ""
|
|
@State private var email = ""
|
|
@State private var password = ""
|
|
@State private var isSubmitting = false
|
|
|
|
private var canSubmit: Bool {
|
|
!email.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
|
&& !password.isEmpty
|
|
&& !isSubmitting
|
|
}
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: ZenithSpacing.md) {
|
|
Text("Konto erstellen")
|
|
.zenithHeadlineLgStyle()
|
|
.padding(.top, ZenithSpacing.lg)
|
|
|
|
VStack(spacing: ZenithSpacing.sm) {
|
|
ZenithTextField(
|
|
label: "Name (optional)",
|
|
text: $name,
|
|
textContentType: .name,
|
|
autocapitalization: .words
|
|
)
|
|
|
|
ZenithTextField(
|
|
label: "E-Mail",
|
|
text: $email,
|
|
keyboardType: .emailAddress,
|
|
textContentType: .username,
|
|
autocapitalization: .never,
|
|
autocorrectionDisabled: true
|
|
)
|
|
|
|
ZenithTextField(
|
|
label: "Passwort",
|
|
text: $password,
|
|
isSecure: true,
|
|
textContentType: .newPassword
|
|
)
|
|
}
|
|
|
|
if let error = appState.lastError {
|
|
Text(error)
|
|
.zenithBodySmStyle(color: .zenithError)
|
|
.multilineTextAlignment(.center)
|
|
}
|
|
|
|
Button {
|
|
Task { await submit() }
|
|
} label: {
|
|
Group {
|
|
if isSubmitting {
|
|
ProgressView()
|
|
.tint(.white)
|
|
} else {
|
|
Text("Konto erstellen")
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.buttonStyle(.zenithPrimary)
|
|
.disabled(!canSubmit)
|
|
|
|
Button("Schon ein Konto? Anmelden") {
|
|
appState.lastError = nil
|
|
onSwitchToLogin()
|
|
}
|
|
.buttonStyle(.zenithPlain)
|
|
.padding(.top, ZenithSpacing.xs)
|
|
}
|
|
.padding(.horizontal, ZenithSpacing.md)
|
|
.padding(.bottom, ZenithSpacing.lg)
|
|
}
|
|
.scrollDismissesKeyboard(.interactively)
|
|
.background(Color.zenithBg)
|
|
}
|
|
|
|
private func submit() async {
|
|
guard canSubmit else { return }
|
|
isSubmitting = true
|
|
defer { isSubmitting = false }
|
|
|
|
let trimmedEmail = email.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
let succeeded = await appState.signup(
|
|
name: trimmedName.isEmpty ? nil : trimmedName,
|
|
email: trimmedEmail,
|
|
password: password
|
|
)
|
|
if succeeded {
|
|
onSignupSucceeded(trimmedEmail)
|
|
}
|
|
}
|
|
}
|