Skip to content

Commit 742f176

Browse files
authored
Merge pull request #1301 from firebase/feat/cleanup-fixes
feat: add validations for text inputs
2 parents 0a8514e + 0a76ec8 commit 742f176

File tree

12 files changed

+271
-102
lines changed

12 files changed

+271
-102
lines changed

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailAuthView.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ public struct EmailAuthView {
4646

4747
private var isValid: Bool {
4848
return if authService.authenticationFlow == .signIn {
49-
!email.isEmpty && !password.isEmpty
49+
FormValidators.email.isValid(input: email) && !password.isEmpty
5050
} else {
51-
!email.isEmpty && !password.isEmpty && password == confirmPassword
51+
FormValidators.email.isValid(input: email) &&
52+
FormValidators.atLeast6Characters.isValid(input: password) &&
53+
FormValidators.confirmPassword(password: password).isValid(input: confirmPassword)
5254
}
5355
}
5456

@@ -108,6 +110,10 @@ extension EmailAuthView: View {
108110
prompt: authService.string.emailInputLabel,
109111
keyboardType: .emailAddress,
110112
contentType: .emailAddress,
113+
validations: [
114+
FormValidators.email
115+
],
116+
maintainsValidationMessage: authService.authenticationFlow == .signUp,
111117
onSubmit: { _ in
112118
self.focus = .password
113119
},
@@ -122,7 +128,11 @@ extension EmailAuthView: View {
122128
label: authService.string.passwordFieldLabel,
123129
prompt: authService.string.passwordInputLabel,
124130
contentType: .password,
125-
sensitive: true,
131+
isSecureTextField: true,
132+
validations: authService.authenticationFlow == .signUp ? [
133+
FormValidators.atLeast6Characters
134+
] : [],
135+
maintainsValidationMessage: authService.authenticationFlow == .signUp,
126136
onSubmit: { _ in
127137
Task { try await signInWithEmailPassword() }
128138
},
@@ -149,7 +159,11 @@ extension EmailAuthView: View {
149159
label: authService.string.confirmPasswordFieldLabel,
150160
prompt: authService.string.confirmPasswordInputLabel,
151161
contentType: .password,
152-
sensitive: true,
162+
isSecureTextField: true,
163+
validations: [
164+
FormValidators.confirmPassword(password: password)
165+
],
166+
maintainsValidationMessage: true,
153167
onSubmit: { _ in
154168
Task { try await createUserWithEmailPassword() }
155169
},

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailLinkView.swift

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ public struct EmailLinkView {
2222
@Environment(\.accountConflictHandler) private var accountConflictHandler
2323
@Environment(\.reportError) private var reportError
2424
@State private var email = ""
25-
@State private var showModal = false
25+
@State private var showAlert = false
2626

2727
public init() {}
2828

2929
private func sendEmailLink() async throws {
3030
do {
3131
try await authService.sendEmailSignInLink(email: email)
32-
showModal = true
32+
showAlert = true
3333
} catch {
3434
if let errorHandler = reportError {
3535
errorHandler(error)
@@ -49,6 +49,9 @@ extension EmailLinkView: View {
4949
prompt: authService.string.emailInputLabel,
5050
keyboardType: .emailAddress,
5151
contentType: .emailAddress,
52+
validations: [
53+
FormValidators.email
54+
],
5255
leading: {
5356
Image(systemName: "at")
5457
}
@@ -71,24 +74,15 @@ extension EmailLinkView: View {
7174
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
7275
.navigationTitle(authService.string.signInWithEmailLinkViewTitle)
7376
.safeAreaPadding()
74-
.sheet(isPresented: $showModal) {
75-
VStack(spacing: 24) {
76-
Text(authService.string.signInWithEmailLinkViewMessage)
77-
.font(.headline)
78-
Button {
79-
showModal = false
80-
} label: {
81-
Text(authService.string.okButtonLabel)
82-
.padding(.vertical, 8)
83-
.frame(maxWidth: .infinity)
84-
}
85-
.buttonStyle(.borderedProminent)
86-
.padding([.top, .bottom], 8)
87-
.frame(maxWidth: .infinity)
77+
.alert(
78+
authService.string.signInWithEmailLinkViewTitle,
79+
isPresented: $showAlert
80+
) {
81+
Button(authService.string.okButtonLabel) {
82+
showAlert = false
8883
}
89-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
90-
.safeAreaPadding()
91-
.presentationDetents([.medium])
84+
} message: {
85+
Text(authService.string.signInWithEmailLinkViewMessage)
9286
}
9387
.onOpenURL { url in
9488
Task {

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EnterPhoneNumberView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ struct EnterPhoneNumberView: View {
3838
prompt: authService.string.enterPhoneNumberPlaceholder,
3939
keyboardType: .phonePad,
4040
contentType: .telephoneNumber,
41+
validations: [
42+
FormValidators.phoneNumber
43+
],
4144
onChange: { _ in }
4245
) {
4346
CountrySelector(

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EnterVerificationCodeView.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ struct EnterVerificationCodeView: View {
4949
.padding(.bottom)
5050
.frame(maxWidth: .infinity, alignment: .leading)
5151

52-
VerificationCodeInputField(code: $verificationCode)
52+
VerificationCodeInputField(
53+
code: $verificationCode,
54+
validations: [
55+
FormValidators.verificationCode
56+
],
57+
maintainsValidationMessage: true
58+
)
5359

5460
Button(action: {
5561
Task {

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/MFAEnrolmentView.swift

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ extension MFAEnrolmentView: View {
374374
prompt: authService.string.enterPhoneNumberPrompt,
375375
keyboardType: .phonePad,
376376
contentType: .telephoneNumber,
377+
validations: [
378+
FormValidators.phoneNumber
379+
],
380+
maintainsValidationMessage: true,
377381
onChange: { _ in }
378382
) {
379383
CountrySelector(
@@ -388,6 +392,10 @@ extension MFAEnrolmentView: View {
388392
text: $displayName,
389393
label: authService.string.displayNameFieldLabel,
390394
prompt: authService.string.enterDisplayNameForDevicePrompt,
395+
validations: [
396+
FormValidators.notEmpty(label: "Display name")
397+
],
398+
maintainsValidationMessage: true,
391399
leading: {
392400
Image(systemName: "person")
393401
}
@@ -430,17 +438,13 @@ extension MFAEnrolmentView: View {
430438
.multilineTextAlignment(.center)
431439
}
432440

433-
AuthTextField(
434-
text: $verificationCode,
435-
label: authService.string.verificationCodeFieldLabel,
436-
prompt: "Enter 6-digit code",
437-
keyboardType: .numberPad,
438-
contentType: .oneTimeCode,
439-
leading: {
440-
Image(systemName: "number")
441-
}
441+
VerificationCodeInputField(
442+
code: $verificationCode,
443+
validations: [
444+
FormValidators.verificationCode
445+
],
446+
maintainsValidationMessage: true
442447
)
443-
.focused($focus, equals: .verificationCode)
444448
.accessibilityIdentifier("verification-code-field")
445449

446450
Button {
@@ -579,23 +583,23 @@ extension MFAEnrolmentView: View {
579583
text: $displayName,
580584
label: authService.string.displayNameFieldLabel,
581585
prompt: authService.string.enterDisplayNameForAuthenticatorPrompt,
586+
validations: [
587+
FormValidators.notEmpty(label: "Display name")
588+
],
589+
maintainsValidationMessage: true,
582590
leading: {
583591
Image(systemName: "person")
584592
}
585593
)
586594
.accessibilityIdentifier("display-name-field")
587595

588-
AuthTextField(
589-
text: $totpCode,
590-
label: authService.string.verificationCodeFieldLabel,
591-
prompt: authService.string.enterCodeFromAppPrompt,
592-
keyboardType: .numberPad,
593-
contentType: .oneTimeCode,
594-
leading: {
595-
Image(systemName: "number")
596-
}
596+
VerificationCodeInputField(
597+
code: $totpCode,
598+
validations: [
599+
FormValidators.verificationCode
600+
],
601+
maintainsValidationMessage: true
597602
)
598-
.focused($focus, equals: .totpCode)
599603
.accessibilityIdentifier("totp-code-field")
600604

601605
Button {

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/PasswordPromptView.swift

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import FirebaseAuthUIComponents
1516
import FirebaseCore
1617
import SwiftUI
1718

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

3233
Divider()
3334

34-
LabeledContent {
35-
TextField(authService.string.passwordInputLabel, text: $password)
36-
.textInputAutocapitalization(.never)
37-
.disableAutocorrection(true)
38-
.submitLabel(.next)
39-
} label: {
40-
Image(systemName: "lock")
41-
}.padding(.vertical, 10)
42-
.background(Divider(), alignment: .bottom)
43-
.padding(.bottom, 4)
35+
AuthTextField(
36+
text: $password,
37+
label: authService.string.passwordFieldLabel,
38+
prompt: authService.string.passwordInputLabel,
39+
contentType: .password,
40+
isSecureTextField: true,
41+
onSubmit: { _ in
42+
if !password.isEmpty {
43+
coordinator.submit(password: password)
44+
}
45+
},
46+
leading: {
47+
Image(systemName: "lock")
48+
}
49+
)
50+
.submitLabel(.next)
4451

4552
Button(action: {
4653
coordinator.submit(password: password)

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/PasswordRecoveryView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ extension PasswordRecoveryView: View {
4444
prompt: authService.string.emailInputLabel,
4545
keyboardType: .emailAddress,
4646
contentType: .emailAddress,
47+
validations: [
48+
FormValidators.email
49+
],
4750
leading: {
4851
Image(systemName: "at")
4952
}

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/UpdatePasswordView.swift

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,24 @@ public struct UpdatePasswordView {
3232
@Environment(AuthService.self) private var authService
3333
@State private var password = ""
3434
@State private var confirmPassword = ""
35+
@State private var showAlert = false
3536

3637
@FocusState private var focus: FocusableField?
38+
3739
private var isValid: Bool {
38-
!password.isEmpty && password == confirmPassword
40+
FormValidators.atLeast6Characters.isValid(input: password) &&
41+
FormValidators.confirmPassword(password: password).isValid(input: confirmPassword)
42+
}
43+
44+
private func updatePassword() {
45+
Task {
46+
do {
47+
try await authService.updatePassword(to: confirmPassword)
48+
showAlert = true
49+
} catch {
50+
51+
}
52+
}
3953
}
4054
}
4155

@@ -48,7 +62,11 @@ extension UpdatePasswordView: View {
4862
label: "Type new password",
4963
prompt: authService.string.passwordInputLabel,
5064
contentType: .password,
51-
sensitive: true,
65+
isSecureTextField: true,
66+
validations: [
67+
FormValidators.atLeast6Characters
68+
],
69+
maintainsValidationMessage: true,
5270
leading: {
5371
Image(systemName: "lock")
5472
}
@@ -61,7 +79,11 @@ extension UpdatePasswordView: View {
6179
label: "Retype new password",
6280
prompt: authService.string.confirmPasswordInputLabel,
6381
contentType: .password,
64-
sensitive: true,
82+
isSecureTextField: true,
83+
validations: [
84+
FormValidators.confirmPassword(password: password)
85+
],
86+
maintainsValidationMessage: true,
6587
leading: {
6688
Image(systemName: "lock")
6789
}
@@ -70,15 +92,11 @@ extension UpdatePasswordView: View {
7092
.focused($focus, equals: .confirmPassword)
7193

7294
Button(action: {
73-
Task {
74-
try await authService.updatePassword(to: confirmPassword)
75-
authService.navigator.clear()
76-
}
95+
updatePassword()
7796
}, label: {
7897
Text(authService.string.updatePasswordButtonLabel)
7998
.padding(.vertical, 8)
8099
.frame(maxWidth: .infinity)
81-
82100
})
83101
.disabled(!isValid)
84102
.padding([.top, .bottom], 8)
@@ -88,6 +106,17 @@ extension UpdatePasswordView: View {
88106
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
89107
.safeAreaPadding()
90108
.navigationTitle(authService.string.passwordRecoveryTitle)
109+
.alert(
110+
"Password Updated",
111+
isPresented: $showAlert
112+
) {
113+
Button(authService.string.okButtonLabel) {
114+
showAlert = false
115+
authService.navigator.clear()
116+
}
117+
} message: {
118+
Text("Your password has been successfully updated.")
119+
}
91120
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
92121
PasswordPromptSheet(coordinator: authService.passwordPrompt)
93122
}

0 commit comments

Comments
 (0)