import SwiftUI struct AuthView: View { @EnvironmentObject private var model: AppModel @State private var registering = false @State private var login = "" @State private var password = "" @State private var form = RegistrationForm() var body: some View { ScrollView { VStack(spacing: 14) { HStack { Image("Logo") .resizable() .scaledToFit() .frame(height: 58) Spacer() LanguageButton() } .padding(.bottom, 18) if registering { registrationForm } else { loginForm } } .padding(22) } .scrollDismissesKeyboard(.interactively) .background(KTheme.background) } private var loginForm: some View { VStack(alignment: .leading, spacing: 14) { Text(model.text("Zaloguj się", "Sign in")).font(.largeTitle.bold()) Text(model.text("Twoja karta i punkty będą dostępne po zalogowaniu.", "Your card and points will be available after signing in.")) .foregroundStyle(.secondary) KasztelanField(title: model.text("E-mail lub login", "Email or username"), text: $login, keyboard: .emailAddress, contentType: .username) KasztelanField(title: model.text("Hasło", "Password"), text: $password, secure: true, contentType: .password) Button(model.text("Zaloguj", "Sign in")) { guard !login.trimmingCharacters(in: .whitespaces).isEmpty, !password.isEmpty else { model.errorMessage = model.text("Wpisz login i hasło.", "Enter your username and password.") return } Task { await model.login(login: login, password: password) } } .buttonStyle(PrimaryButtonStyle()) Link(destination: URL(string: "https://kasztelan.co.uk/forgot/")!) { HStack(spacing: 8) { Image(systemName: "key.fill") Text(model.text("Nie pamiętasz hasła?", "Forgot your password?")) } .font(.subheadline.bold()) .foregroundStyle(KTheme.orange) .frame(maxWidth: .infinity, minHeight: 46) } .accessibilityLabel(model.text("Otwórz resetowanie hasła", "Open password reset")) Button(model.text("Załóż konto", "Create account")) { registering = true } .frame(maxWidth: .infinity, minHeight: 50) .background(KTheme.panel) .clipShape(RoundedRectangle(cornerRadius: 16)) } } private var registrationForm: some View { VStack(alignment: .leading, spacing: 12) { Text(model.text("Załóż konto", "Create account")).font(.largeTitle.bold()) KasztelanField(title: model.text("Imię", "First name"), text: $form.firstName, contentType: .givenName) KasztelanField(title: model.text("Nazwisko", "Last name"), text: $form.lastName, contentType: .familyName) KasztelanField(title: "E-mail", text: $form.email, keyboard: .emailAddress, contentType: .emailAddress) KasztelanField(title: model.text("Hasło", "Password"), text: $form.password, secure: true, contentType: .newPassword) KasztelanField(title: model.text("Telefon UK lub PL", "UK or Polish phone number"), text: $form.mobile, keyboard: .phonePad, contentType: .telephoneNumber) KasztelanField(title: model.text("Kod pocztowy UK", "UK postcode"), text: $form.postcode, contentType: .postalCode) KasztelanField(title: model.text("Data urodzenia: RRRR-MM-DD", "Date of birth: YYYY-MM-DD"), text: dateBinding, keyboard: .numberPad) KasztelanField(title: model.text("Numer karty (opcjonalnie)", "Card number (optional)"), text: $form.cardNumber, keyboard: .numberPad) Toggle(model.text("Akceptuję regulamin", "I accept the terms"), isOn: $form.acceptsTerms) .tint(KTheme.orange) HStack(spacing: 16) { Link(model.text("Regulamin", "Terms"), destination: URL(string: "https://kasztelan.co.uk/regulamin/")!) Link(model.text("Polityka prywatności", "Privacy policy"), destination: URL(string: "https://kasztelan.co.uk/privacy-policy/")!) } .font(.subheadline.bold()) .foregroundStyle(KTheme.orange) Button(model.text("Utwórz konto", "Create account")) { Task { await model.register(form) } } .buttonStyle(PrimaryButtonStyle()) Button(model.text("Mam już konto", "I already have an account")) { registering = false } .frame(maxWidth: .infinity, minHeight: 50) .background(KTheme.panel) .clipShape(RoundedRectangle(cornerRadius: 16)) } } private var dateBinding: Binding { Binding( get: { form.dob }, set: { form.dob = Self.formatDateInput($0) } ) } static func formatDateInput(_ input: String) -> String { let digits = String(input.filter(\.isNumber).prefix(8)) var result = "" for (index, character) in digits.enumerated() { if index == 4 || index == 6 { result.append("-") } result.append(character) } return result } } struct LanguageButton: View { @EnvironmentObject private var model: AppModel var body: some View { Button { model.language = model.language == .pl ? .en : .pl } label: { Text(model.language == .pl ? "EN" : "PL") .font(.subheadline.bold()) .foregroundStyle(KTheme.orange) .frame(width: 44, height: 44, alignment: .center) .background(KTheme.panel, in: Circle()) .contentShape(Circle()) } .buttonStyle(.plain) .accessibilityLabel(model.text("Zmień język na angielski", "Change language to Polish")) } }