Hi again
This is the second installment of the above mentioned article. In this part we will look into the "Forgot Password" UX design and some additional things.
Part 2.1
Goal
Reproduction
Creating a modal sheet is simple as discussed in the previous article about this activity.
1.1 Creating this Forgot Password Modal Sheet.
Next we call this method on BuildPage and then show the ModalSheet when the page is connected. As the email is compulsory we need to validate it too.
As soon as the Next Button is selected, the process of verifying the entered email address against the database starts.
the contLoginForgotPassword sub is called. I decided to try out a ResumableSub inside an ABMaterial project. The code compiles well.
The above code, gets the contents of the modal sheet, checks if its valid and also verifies it against a database. When the user record is found that matches the email address, the password is read and these are sent to the user via email. The sub call is SendEmail saved in ABMShared.
The EmailAccounts table stores settings for email accounts that can be used to send emails in our app. There can only be 1 active account to send emails from at anytime. The settings are read from that table, these provide the smtp server, the port, the username and password to use to send the email.
I usually test these settings via b4j first and then save them as default in my webapp.
The option to try something else has been provided to enable the user to change their password, should they remember it. This will be Part 2.1 of this article.
Disclaimer:
This article is mostly about UX design with specific attention to ModalSheets for this purpose. A try to work with ResumableSub was undertaken here to send the email to the user. For now its still a dololo experience. #investigating. The header/footer components of the ModalSheet are not used for this exercise. The adding of the components on the modal sheet is not sequential (this is not recommended) as on ConnectPage, the last modalsheet element is added then others added after.
Related Article: Enabling Users to get their lost passwords
Ta!
This is the second installment of the above mentioned article. In this part we will look into the "Forgot Password" UX design and some additional things.
Part 2.1
Goal
- When a user selects Forgot Password in the Sign In screen, the Forgot Password screen should appear.
- The email entered by the user is compulsory. After the user enters their email address and selects Next
- The email will be read from an existing user table and it found should be sent to the user via email.
- The email settings for the smtp should be read from a pre-defined table and used to initialize smtp.
- The user is provided an option to Try something else, this activates a screen to Change the password.
Reproduction
Creating a modal sheet is simple as discussed in the previous article about this activity.
1.1 Creating this Forgot Password Modal Sheet.
B4X:
Private Sub contLoginBuild() As ABMModalSheet
Dim contLogin As ABMModalSheet
contLogin.Initialize(page, "contLogin", False, ABM.MODALSHEET_TYPE_NORMAL, "ms")
contLogin.Size = ABM.MODALSHEET_SIZE_NORMAL
contLogin.IsDismissible = False
contLogin.IsTextSelectable = True
contLogin.Content.AddRows(1,True,"").AddCells12(1, "")
contLogin.Content.AddRows(1,True,"").AddCellsOSMPV(1, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, ABM.VISIBILITY_ALL, "")
contLogin.Content.AddRows(1,True,"").AddCellsOSMPV(1, 0, 0, 0, 12, 12, 12, 0, 0, 10, 0, ABM.VISIBILITY_ALL, "")
contLogin.Content.AddRows(1,True,"").AddCellsOSMPV(1, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, ABM.VISIBILITY_ALL, "")
contLogin.Content.AddRows(1,True,"").AddCellsOSMPV(1, 0, 0, 0, 6, 6, 6, 0, 0, 10, 0, ABM.VISIBILITY_ALL, "").AddCellsOSMPV(1, 0, 0, 0, 6, 6, 6, 0, 0, 10, 10, ABM.VISIBILITY_ALL, "")
contLogin.Header.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
contLogin.Content.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
contLogin.Footer.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
'Add components to ModalSheet
Dim lblTrySomethingElse As ABMLabel
lblTrySomethingElse.Initialize(page, "lblTrySomethingElse", $"{C:#993333}{I}Try something else?{/I}{/C}"$, ABM.SIZE_PARAGRAPH, False, "")
lblTrySomethingElse.Clickable = True
lblTrySomethingElse.SetCursor(ABM.CURSOR_POINTING)
lblTrySomethingElse.istextselectable = True
lblTrySomethingElse.supportemoji = False
contLogin.Content.Cell(5,1).AddComponent(lblTrySomethingElse)
Dim imglogo As ABMImage
imglogo.Initialize(page, "imglogo", "../images/logo.png?"& DateTime.Now, 1)
imglogo.Tag = "imglogo"
imglogo.IsResponsive = False
imglogo.IsCircular = False
imglogo.IsClickable = False
imglogo.IsMaterialBoxed = False
contLogin.Content.Cell(2,1).AddComponent(imglogo)
Dim txtemail As ABMInput
txtemail.Initialize(page, "txtemail", ABM.INPUT_EMAIL, "Email Address", False, "")
txtemail.Tag = "txtemail"
contLogin.Content.Cell(4,1).AddComponent(txtemail)
Dim btnNext As ABMButton
btnNext.InitializeRaised(page, "btnNext", "", "", "Next", "")
btnNext.Tag = "btnNext"
btnNext.UseFullCellWidth = True
btnNext.Size = ABM.BUTTONSIZE_NORMAL
btnNext.dropdownhidearrow = False
btnNext.dropdownshowbelow = False
btnNext.dropdownconstrainwidth = False
contLogin.Content.Cell(5,2).AddComponent(btnNext)
Dim lblheader As ABMLabel
lblheader.Initialize(page, "lblheader", $"{B}Account help{/B}"$, ABM.SIZE_PARAGRAPH, False, "")
lblheader.istextselectable = True
lblheader.supportemoji = False
contLogin.Content.Cell(3,1).AddComponent(lblheader)
Dim lblsubheader As ABMLabel
lblsubheader.Initialize(page, "lblsubheader", $"If {B}registered{/B} with us, your password will be emailed"$, ABM.SIZE_PARAGRAPH, False, "")
lblsubheader.istextselectable = True
lblsubheader.supportemoji = False
contLogin.Content.Cell(3,1).AddComponent(lblsubheader)
Return contLogin
End Sub
Next we call this method on BuildPage and then show the ModalSheet when the page is connected. As the email is compulsory we need to validate it too.
B4X:
'Get the contents of the modal sheet input components and save to a map
Sub contLoginGetContents() As Map
Dim pMap As Map
pMap.Initialize
Dim contLogin As ABMModalSheet
contLogin = page.ModalSheet("contLogin")
Dim txtemail As ABMInput = contLogin.Content.Component("txtemail")
pMap.put("email", txtemail.Text)
Return pMap
End Sub
'Get the contents of the modal sheet from GetContents and check validity
Sub contLoginValidate(gMap As Map) As Boolean
Dim contLogin As ABMModalSheet
contLogin = page.ModalSheet("contLogin")
Dim stxtemail As String
stxtemail = gMap.get("email")
If stxtemail = "null" Then stxtemail = ""
If stxtemail.Length = 0 Then
ABMShared.Warn(page,"Email Address cannot be blank. Please enter a value.")
Dim txtemail As ABMInput = contLogin.Content.Component("txtemail")
txtemail.SetFocus
Return False
End If
Return True
End Sub
As soon as the Next Button is selected, the process of verifying the entered email address against the database starts.
B4X:
'An ABMButton has been clicked
Sub btnNext_Clicked(Target As String)
Wait For (contLoginForgotPassword) Complete(Result As Boolean)
If Result = False Then Return
ABMShared.NavigateToPage(ws, ABMPageId, "../frmTellForgotPassword/frmTellForgotPassword.html")
End Sub
the contLoginForgotPassword sub is called. I decided to try out a ResumableSub inside an ABMaterial project. The code compiles well.
B4X:
Private Sub contLoginForgotPassword() As ResumableSub
'define a map to hold the form contents
Dim m As Map
'read the form contents to a map
m = contLoginGetContents
Dim email As String
email = m.get("email")
If email = "null" Then email = ""
If email.Length = 0 Then
ABMShared.Warn(page,"Email cannot be blank. Please enter a value.")
Return False
End If
'the form contents are ok, send login credentials to user
'define the search criteria, fields must equal
Dim w As Map
Dim nk As String
w.Initialize
nk = "email="
w.put(nk, email)
'Get connection from current pool if MySQL/MSSQL
Dim jSQL As SQL = ABMShared.SQLGet
Dim UserMap As Map = ABMShared.SQLSelectRecordWhereMap(jSQL,"users", w)
If UserMap.IsInitialized = False Then
ABMShared.Warn(page,"The Email specified could not be found in our records, please specify the correct email.")
Return False
End If
'The email has been found, send the details to the user
Dim username As String
username = UserMap.get("username")
Dim password As String
password = UserMap.get("password")
Try
' start smtp to send the emails
Dim sbody As String = "Good Day||Someone or you requested your Sign In credentials.||Your UserName is: " & username & "||Your Password is: " & password & "||Development Team|"
sbody = ABMShared.Replace(sbody,"|",CRLF)
Wait For (ABMShared.SendEmail(email, "askteencoach: Sign In Credentials", sbody)) Complete(Result As Boolean)
If Result = False Then
myToastId = myToastId + 1
page.ShowToast("toast" & myToastId, "toastred", "Sign In Credentials could not be emailed!", 3000,False)
Else
myToastId = myToastId + 1
page.ShowToast("toast" & myToastId, "toastgreen", "Sign In Credentials emailed successfully.", 3000,False)
End If
'Close the connection to the database
ABMShared.SQLClose(jSQL)
Return Result
Catch
myToastId = myToastId + 1
page.ShowToast("toast" & myToastId, "toastred", "Email could not be sent, please try again.", 3000,False)
Return False
End Try
End Sub
The above code, gets the contents of the modal sheet, checks if its valid and also verifies it against a database. When the user record is found that matches the email address, the password is read and these are sent to the user via email. The sub call is SendEmail saved in ABMShared.
B4X:
Sub GetEmailSettings() As Map
Dim es As Map
es.Initialize
Dim jSQL As SQL = SQLGet
'get first available account, there should be 1
Dim id As String = SQLSelectSingleResult(jSQL, "select id from EmailAccounts where active = 1", Null)
If id = "" Then Return es
'read the email settings first
es = SQLRecordRead(jSQL,"EmailAccounts", "id", id)
Return es
End Sub
Sub SendEmail(toEmail As String, subject As String, msg As String) As ResumableSub
Try
'read the email settings first
Dim es As Map = GetEmailSettings
Dim sserver As String = es.GetDefault("server","")
Dim sport As String = es.GetDefault("port","25")
Dim susername As String = es.GetDefault("username","")
Dim spassword As String = es.GetDefault("password","")
Dim sStartTLSMode As String = es.GetDefault("starttlsmode","0")
Dim sUseSSL As String = es.GetDefault("usessl","0")
'start sending the email
esmtp.Initialize(sserver, sport, susername, spassword, "smtp")
esmtp.To.Add(toEmail)
esmtp.Body = msg
esmtp.Subject = subject
If sStartTLSMode = "1" Then
esmtp.StartTLSMode = True
Else
esmtp.StartTLSMode = False
End If
If sUseSSL = "1" Then
esmtp.UseSSL = True
Else
esmtp.UseSSL = False
End If
Wait For (esmtp.Send) smtp_MessageSent(Success As Boolean)
Return Success
Catch
Return False
End Try
End Sub
Sub smtp_MessageSent(Success As Boolean)
Log(Success)
End Sub
The EmailAccounts table stores settings for email accounts that can be used to send emails in our app. There can only be 1 active account to send emails from at anytime. The settings are read from that table, these provide the smtp server, the port, the username and password to use to send the email.
I usually test these settings via b4j first and then save them as default in my webapp.
The option to try something else has been provided to enable the user to change their password, should they remember it. This will be Part 2.1 of this article.
Disclaimer:
This article is mostly about UX design with specific attention to ModalSheets for this purpose. A try to work with ResumableSub was undertaken here to send the email to the user. For now its still a dololo experience. #investigating. The header/footer components of the ModalSheet are not used for this exercise. The adding of the components on the modal sheet is not sequential (this is not recommended) as on ConnectPage, the last modalsheet element is added then others added after.
Related Article: Enabling Users to get their lost passwords
Ta!
Attachments
Last edited: