Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ public struct EmailAuthView {

private var isValid: Bool {
return if authService.authenticationFlow == .signIn {
!email.isEmpty && !password.isEmpty
FormValidators.email.isValid(input: email) && !password.isEmpty
} else {
!email.isEmpty && !password.isEmpty && password == confirmPassword
FormValidators.email.isValid(input: email) &&
FormValidators.atLeast6Characters.isValid(input: password) &&
FormValidators.confirmPassword(password: password).isValid(input: confirmPassword)
}
}

Expand Down Expand Up @@ -108,6 +110,10 @@ extension EmailAuthView: View {
prompt: authService.string.emailInputLabel,
keyboardType: .emailAddress,
contentType: .emailAddress,
validations: [
FormValidators.email
],
maintainsValidationMessage: authService.authenticationFlow == .signUp,
onSubmit: { _ in
self.focus = .password
},
Expand All @@ -122,7 +128,11 @@ extension EmailAuthView: View {
label: authService.string.passwordFieldLabel,
prompt: authService.string.passwordInputLabel,
contentType: .password,
sensitive: true,
isSecureTextField: true,
validations: authService.authenticationFlow == .signUp ? [
FormValidators.atLeast6Characters
] : [],
maintainsValidationMessage: authService.authenticationFlow == .signUp,
onSubmit: { _ in
Task { try await signInWithEmailPassword() }
},
Expand All @@ -149,7 +159,11 @@ extension EmailAuthView: View {
label: authService.string.confirmPasswordFieldLabel,
prompt: authService.string.confirmPasswordInputLabel,
contentType: .password,
sensitive: true,
isSecureTextField: true,
validations: [
FormValidators.confirmPassword(password: password)
],
maintainsValidationMessage: true,
onSubmit: { _ in
Task { try await createUserWithEmailPassword() }
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ public struct EmailLinkView {
@Environment(\.accountConflictHandler) private var accountConflictHandler
@Environment(\.reportError) private var reportError
@State private var email = ""
@State private var showModal = false
@State private var showAlert = false

public init() {}

private func sendEmailLink() async throws {
do {
try await authService.sendEmailSignInLink(email: email)
showModal = true
showAlert = true
} catch {
if let errorHandler = reportError {
errorHandler(error)
Expand All @@ -49,6 +49,9 @@ extension EmailLinkView: View {
prompt: authService.string.emailInputLabel,
keyboardType: .emailAddress,
contentType: .emailAddress,
validations: [
FormValidators.email
],
leading: {
Image(systemName: "at")
}
Expand All @@ -71,24 +74,15 @@ extension EmailLinkView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.navigationTitle(authService.string.signInWithEmailLinkViewTitle)
.safeAreaPadding()
.sheet(isPresented: $showModal) {
VStack(spacing: 24) {
Text(authService.string.signInWithEmailLinkViewMessage)
.font(.headline)
Button {
showModal = false
} label: {
Text(authService.string.okButtonLabel)
.padding(.vertical, 8)
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.padding([.top, .bottom], 8)
.frame(maxWidth: .infinity)
.alert(
authService.string.signInWithEmailLinkViewTitle,
isPresented: $showAlert
) {
Button(authService.string.okButtonLabel) {
showAlert = false
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.safeAreaPadding()
.presentationDetents([.medium])
} message: {
Text(authService.string.signInWithEmailLinkViewMessage)
}
.onOpenURL { url in
Task {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct EnterPhoneNumberView: View {
prompt: authService.string.enterPhoneNumberPlaceholder,
keyboardType: .phonePad,
contentType: .telephoneNumber,
validations: [
FormValidators.phoneNumber
],
onChange: { _ in }
) {
CountrySelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ struct EnterVerificationCodeView: View {
.padding(.bottom)
.frame(maxWidth: .infinity, alignment: .leading)

VerificationCodeInputField(code: $verificationCode)
VerificationCodeInputField(
code: $verificationCode,
validations: [
FormValidators.verificationCode
],
maintainsValidationMessage: true
)

Button(action: {
Task {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ extension MFAEnrolmentView: View {
prompt: authService.string.enterPhoneNumberPrompt,
keyboardType: .phonePad,
contentType: .telephoneNumber,
validations: [
FormValidators.phoneNumber
],
maintainsValidationMessage: true,
onChange: { _ in }
) {
CountrySelector(
Expand All @@ -388,6 +392,10 @@ extension MFAEnrolmentView: View {
text: $displayName,
label: authService.string.displayNameFieldLabel,
prompt: authService.string.enterDisplayNameForDevicePrompt,
validations: [
FormValidators.notEmpty(label: "Display name")
],
maintainsValidationMessage: true,
leading: {
Image(systemName: "person")
}
Expand Down Expand Up @@ -430,17 +438,13 @@ extension MFAEnrolmentView: View {
.multilineTextAlignment(.center)
}

AuthTextField(
text: $verificationCode,
label: authService.string.verificationCodeFieldLabel,
prompt: "Enter 6-digit code",
keyboardType: .numberPad,
contentType: .oneTimeCode,
leading: {
Image(systemName: "number")
}
VerificationCodeInputField(
code: $verificationCode,
validations: [
FormValidators.verificationCode
],
maintainsValidationMessage: true
)
.focused($focus, equals: .verificationCode)
.accessibilityIdentifier("verification-code-field")

Button {
Expand Down Expand Up @@ -579,23 +583,23 @@ extension MFAEnrolmentView: View {
text: $displayName,
label: authService.string.displayNameFieldLabel,
prompt: authService.string.enterDisplayNameForAuthenticatorPrompt,
validations: [
FormValidators.notEmpty(label: "Display name")
],
maintainsValidationMessage: true,
leading: {
Image(systemName: "person")
}
)
.accessibilityIdentifier("display-name-field")

AuthTextField(
text: $totpCode,
label: authService.string.verificationCodeFieldLabel,
prompt: authService.string.enterCodeFromAppPrompt,
keyboardType: .numberPad,
contentType: .oneTimeCode,
leading: {
Image(systemName: "number")
}
VerificationCodeInputField(
code: $totpCode,
validations: [
FormValidators.verificationCode
],
maintainsValidationMessage: true
)
.focused($focus, equals: .totpCode)
.accessibilityIdentifier("totp-code-field")

Button {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import FirebaseAuthUIComponents
import FirebaseCore
import SwiftUI

Expand All @@ -31,16 +32,22 @@ extension PasswordPromptSheet: View {

Divider()

LabeledContent {
TextField(authService.string.passwordInputLabel, text: $password)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.submitLabel(.next)
} label: {
Image(systemName: "lock")
}.padding(.vertical, 10)
.background(Divider(), alignment: .bottom)
.padding(.bottom, 4)
AuthTextField(
text: $password,
label: authService.string.passwordFieldLabel,
prompt: authService.string.passwordInputLabel,
contentType: .password,
isSecureTextField: true,
onSubmit: { _ in
if !password.isEmpty {
coordinator.submit(password: password)
}
},
leading: {
Image(systemName: "lock")
}
)
.submitLabel(.next)

Button(action: {
coordinator.submit(password: password)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ extension PasswordRecoveryView: View {
prompt: authService.string.emailInputLabel,
keyboardType: .emailAddress,
contentType: .emailAddress,
validations: [
FormValidators.email
],
leading: {
Image(systemName: "at")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,24 @@ public struct UpdatePasswordView {
@Environment(AuthService.self) private var authService
@State private var password = ""
@State private var confirmPassword = ""
@State private var showAlert = false

@FocusState private var focus: FocusableField?

private var isValid: Bool {
!password.isEmpty && password == confirmPassword
FormValidators.atLeast6Characters.isValid(input: password) &&
FormValidators.confirmPassword(password: password).isValid(input: confirmPassword)
}

private func updatePassword() {
Task {
do {
try await authService.updatePassword(to: confirmPassword)
showAlert = true
} catch {

}
}
}
}

Expand All @@ -48,7 +62,11 @@ extension UpdatePasswordView: View {
label: "Type new password",
prompt: authService.string.passwordInputLabel,
contentType: .password,
sensitive: true,
isSecureTextField: true,
validations: [
FormValidators.atLeast6Characters
],
maintainsValidationMessage: true,
leading: {
Image(systemName: "lock")
}
Expand All @@ -61,7 +79,11 @@ extension UpdatePasswordView: View {
label: "Retype new password",
prompt: authService.string.confirmPasswordInputLabel,
contentType: .password,
sensitive: true,
isSecureTextField: true,
validations: [
FormValidators.confirmPassword(password: password)
],
maintainsValidationMessage: true,
leading: {
Image(systemName: "lock")
}
Expand All @@ -70,15 +92,11 @@ extension UpdatePasswordView: View {
.focused($focus, equals: .confirmPassword)

Button(action: {
Task {
try await authService.updatePassword(to: confirmPassword)
authService.navigator.clear()
}
updatePassword()
}, label: {
Text(authService.string.updatePasswordButtonLabel)
.padding(.vertical, 8)
.frame(maxWidth: .infinity)

})
.disabled(!isValid)
.padding([.top, .bottom], 8)
Expand All @@ -88,6 +106,17 @@ extension UpdatePasswordView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.safeAreaPadding()
.navigationTitle(authService.string.passwordRecoveryTitle)
.alert(
"Password Updated",
isPresented: $showAlert
) {
Button(authService.string.okButtonLabel) {
showAlert = false
authService.navigator.clear()
}
} message: {
Text("Your password has been successfully updated.")
}
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
PasswordPromptSheet(coordinator: authService.passwordPrompt)
}
Expand Down
Loading
Loading