From bf0fca1f95e3857e5340c9502ed5b3cd4382ab70 Mon Sep 17 00:00:00 2001 From: Ana Paula Flores Date: Sat, 27 Jan 2024 11:27:39 -0600 Subject: [PATCH] Login --- SwiftUIBasics/Views/SignUpView.swift | 95 ++++++++++++++++------------ 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/SwiftUIBasics/Views/SignUpView.swift b/SwiftUIBasics/Views/SignUpView.swift index 6cef5d9..55ee71f 100644 --- a/SwiftUIBasics/Views/SignUpView.swift +++ b/SwiftUIBasics/Views/SignUpView.swift @@ -1,56 +1,37 @@ -// -// SignUpView.swift -// SwiftUIBasics -// -// Created by Diplomado on 09/12/23. -// - import SwiftUI import Combine class SignUpViewModel: ObservableObject { // inputs - @Published var username: String = "" + @Published var email: String = "" @Published var password: String = "" @Published var passwordConfirm: String = "" // outputs - @Published var isValidUsernameLength: Bool = false - @Published var isValidPasswordLength: Bool = false - @Published var isValidPasswordUpperCase: Bool = false + @Published var isValidEmail: Bool = false + @Published var isValidPassword: Bool = false @Published var isValidPasswordMatch: Bool = false @Published var isValid: Bool = false private var cancelableSet: Set = [] init() { - $username - .receive(on: RunLoop.main) - .map { username in - return username.count >= 4 - } - .assign(to: \.isValidUsernameLength, on: self) - .store(in: &cancelableSet) - - $password + $email .receive(on: RunLoop.main) - .map { password in - return password.count >= 8 + .map { email in + let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" + let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailPattern) + return emailPredicate.evaluate(with: email) } - .assign(to: \.isValidPasswordLength, on: self) + .assign(to: \.isValidEmail, on: self) .store(in: &cancelableSet) $password .receive(on: RunLoop.main) .map { password in - let pattern = "[A-Z]" - if let _ = password.range(of: pattern, options: .regularExpression) { - return true - } else { - return false - } + return password.isValidPassword() } - .assign(to: \.isValidPasswordUpperCase, on: self) + .assign(to: \.isValidPassword, on: self) .store(in: &cancelableSet) Publishers.CombineLatest($password, $passwordConfirm) @@ -61,9 +42,9 @@ class SignUpViewModel: ObservableObject { .assign(to: \.isValidPasswordMatch, on: self) .store(in: &cancelableSet) - Publishers.CombineLatest4($isValidUsernameLength, $isValidPasswordLength, $isValidPasswordUpperCase, $isValidPasswordMatch) - .map { (a, b, c, d) in - return a && b && c && d + Publishers.CombineLatest3($isValidEmail, $isValidPassword, $isValidPasswordMatch) + .map { (a, b, c) in + return a && b && c } .assign(to: \.isValid, on: self) .store(in: &cancelableSet) @@ -78,21 +59,28 @@ struct SignUpView: View { Text("Create an account") .font(.system(.largeTitle, design: .rounded)) .bold() - .foregroundStyle(.maryBlue) + .foregroundColor(.maryBlue) .padding(.bottom, 30) - FormTextField(name: "Username", value: $vm.username) - RequirementText(text: "A minimum of 4 characters", isValid: vm.isValidUsernameLength) + FormTextField(name: "Email", value: $vm.email) + .keyboardType(.emailAddress) + RequirementText(text: "Valid email format", isValid: vm.isValidEmail) .padding() + FormTextField(name: "Password", value: $vm.password, isSecure: true) VStack { - RequirementText(text: "A minimum of 8 characters", isValid: vm.isValidPasswordLength) - RequirementText(text: "One uppercase letter", isValid: vm.isValidPasswordUpperCase) + RequirementText(text: "At least 8 characters", isValid: vm.isValidPassword) + RequirementText(text: "At least one uppercase letter", isValid: vm.password.containsUppercase()) + RequirementText(text: "At least one lowercase letter", isValid: vm.password.containsLowercase()) + RequirementText(text: "At least one symbol", isValid: vm.password.containsSymbol()) + RequirementText(text: "At least one number", isValid: vm.password.containsNumber()) } .padding() + FormTextField(name: "Confirm Password", value: $vm.passwordConfirm, isSecure: true) RequirementText(text: "Your confirm password should be the same as password", isValid: vm.isValidPasswordMatch) .padding() .padding(.bottom, 50) + Button(action: { print("Doing") // Proceed to the next screen @@ -104,7 +92,6 @@ struct SignUpView: View { .padding() .frame(minWidth: 0, maxWidth: .infinity) .background(vm.isValid ? .maryBlue :.turquoise) - // .background(LinearGradient(gradient: Gradient(colors: [.turquoise, .maryBlue]), startPoint: .leading, endPoint: .trailing)) .cornerRadius(10) .padding(.horizontal) } @@ -129,6 +116,32 @@ struct SignUpView: View { } } -#Preview { - SignUpView() +extension String { + func isValidPassword() -> Bool { + // Implement your password validation logic here + return self.count >= 8 + } + + func containsUppercase() -> Bool { + return self.rangeOfCharacter(from: .uppercaseLetters) != nil + } + + func containsLowercase() -> Bool { + return self.rangeOfCharacter(from: .lowercaseLetters) != nil + } + + func containsSymbol() -> Bool { + let symbolCharacterSet = CharacterSet(charactersIn: "!@#$%^&*()-_=+[]{}|;:'\",.<>/?`~") + return self.rangeOfCharacter(from: symbolCharacterSet) != nil + } + + func containsNumber() -> Bool { + return self.rangeOfCharacter(from: .decimalDigits) != nil + } +} + +struct SignUpView_Previews: PreviewProvider { + static var previews: some View { + SignUpView() + } }