// Views/Auth/LoginView.swift // -------------------------- // The login screen shown when the user is not authenticated. import SwiftUI struct LoginView: View { @EnvironmentObject private var auth: AuthManager @State private var username = "" @State private var password = "" @FocusState private var focusedField: Field? private enum Field { case username, password } var body: some View { NavigationStack { ZStack { // Background Color(.systemGroupedBackground).ignoresSafeArea() VStack(spacing: 0) { Spacer() // ── Logo / Header ────────────────────────────────────── VStack(spacing: 12) { Image(systemName: "checkmark.seal.fill") .font(.system(size: 64)) .foregroundStyle(.blue) Text("JanitorialQC Inspector") .font(.largeTitle.bold()) Text("Janitorial Quality Control") .font(.subheadline) .foregroundStyle(.secondary) } .padding(.bottom, 48) // ── Login Form ───────────────────────────────────────── VStack(spacing: 16) { GroupBox { VStack(spacing: 0) { HStack { Image(systemName: "person") .foregroundStyle(.secondary) .frame(width: 24) TextField("Username", text: $username) .textInputAutocapitalization(.never) .autocorrectionDisabled() .focused($focusedField, equals: .username) .submitLabel(.next) .onSubmit { focusedField = .password } } .padding(.vertical, 12) Divider() HStack { Image(systemName: "lock") .foregroundStyle(.secondary) .frame(width: 24) SecureField("Password", text: $password) .focused($focusedField, equals: .password) .submitLabel(.go) .onSubmit { Task { await signIn() } } } .padding(.vertical, 12) } .padding(.horizontal, 4) } .frame(maxWidth: 400) // Error message if let error = auth.errorMessage { HStack { Image(systemName: "exclamationmark.triangle.fill") .foregroundStyle(.red) Text(error) .foregroundStyle(.red) .font(.callout) } .padding(.horizontal) } // Sign In button Button { Task { await signIn() } } label: { HStack { if auth.isLoading { ProgressView() .tint(.white) .padding(.trailing, 4) } Text("Sign In") .fontWeight(.semibold) } .frame(maxWidth: 400) .padding(.vertical, 14) } .buttonStyle(.borderedProminent) .controlSize(.large) .disabled(auth.isLoading || username.isEmpty || password.isEmpty) } Spacer() // ── App Version ──────────────────────────────────────── Text("JanitorialQC Inspector · Phase A") .font(.caption2) .foregroundStyle(.tertiary) .padding(.bottom, 24) } .padding(.horizontal, 32) } } } private func signIn() async { focusedField = nil await auth.login(username: username, password: password) } } #Preview { LoginView() .environmentObject(AuthManager.shared) }