import SwiftUI struct LoginView: View { @EnvironmentObject var authManager: AuthManager @State private var email = "" @State private var password = "" @State private var name = "" @State private var isLoading = false @State private var errorMessage = "" @State private var showPassword = false @State private var isRegistering = false var body: some View { ZStack { Color(hex: "0a0a1a") .ignoresSafeArea() VStack(spacing: 32) { VStack(spacing: 8) { Text("⚡").font(.system(size: 60)) Text("Pulse").font(.largeTitle.bold()).foregroundColor(.white) Text(isRegistering ? "Создать аккаунт" : "Управление жизнью") .font(.subheadline).foregroundColor(.white.opacity(0.6)) }.padding(.top, 60) VStack(spacing: 16) { if isRegistering { TextField("Имя", text: $name) .autocorrectionDisabled() .padding() .background(Color.white.opacity(0.1)) .cornerRadius(12) .foregroundColor(.white) } TextField("Email", text: $email) .keyboardType(.emailAddress) .autocapitalization(.none) .autocorrectionDisabled() .padding() .background(Color.white.opacity(0.1)) .cornerRadius(12) .foregroundColor(.white) HStack { Group { if showPassword { TextField("Пароль", text: $password) .autocapitalization(.none) .autocorrectionDisabled() } else { SecureField("Пароль", text: $password) } } .foregroundColor(.white) Button(action: { showPassword.toggle() }) { Image(systemName: showPassword ? "eye.slash.fill" : "eye.fill") .foregroundColor(.white.opacity(0.6)) } } .padding() .background(Color.white.opacity(0.1)) .cornerRadius(12) if !errorMessage.isEmpty { Text(errorMessage) .foregroundColor(.red) .font(.caption) .multilineTextAlignment(.center) } Button(action: isRegistering ? register : login) { if isLoading { ProgressView().tint(.black) } else { Text(isRegistering ? "Зарегистрироваться" : "Войти") .font(.headline).foregroundColor(.black) } } .frame(maxWidth: .infinity) .padding() .background(Color(hex: "00d4aa")) .cornerRadius(12) .disabled(isLoading || email.isEmpty || password.isEmpty) // Toggle login/register HStack { Text(isRegistering ? "Уже есть аккаунт?" : "Нет аккаунта?") .foregroundColor(.white.opacity(0.6)) .font(.footnote) Button(action: { isRegistering.toggle() errorMessage = "" }) { Text(isRegistering ? "Войти" : "Зарегистрироваться") .font(.footnote.bold()) .foregroundColor(Color(hex: "00d4aa")) } } } .padding(.horizontal, 24) Spacer() } } } func login() { isLoading = true; errorMessage = "" Task { do { let response = try await APIService.shared.login( email: email.trimmingCharacters(in: .whitespaces), password: password ) await MainActor.run { authManager.login(token: response.authToken, user: response.user) } } catch let error as APIError { await MainActor.run { errorMessage = error.errorDescription ?? "Ошибка"; isLoading = false } } catch { await MainActor.run { errorMessage = "Ошибка: \(error.localizedDescription)"; isLoading = false } } } } func register() { isLoading = true; errorMessage = "" Task { do { let response = try await APIService.shared.register( email: email.trimmingCharacters(in: .whitespaces), password: password, name: name ) await MainActor.run { authManager.login(token: response.authToken, user: response.user) } } catch let error as APIError { await MainActor.run { errorMessage = error.errorDescription ?? "Ошибка"; isLoading = false } } catch { await MainActor.run { errorMessage = "Ошибка: \(error.localizedDescription)"; isLoading = false } } } } }