Hi there
Part 2.1 seeks to address the UX design for the "Try Something Else" screen. This occurs when a user has forgotten the password but then instead of having it sent they just change it.
Goal
1. The user selects Forgot Password from the Sign In Screen
2. They are provided with an option to have the email sent to them or
3. Have an option to Try Something else, thus entering their registered email address and a new password.
4. The email, password and confirm password are compulsory.
5. The entered email address should exist in the database
6. The password and confirm password should match
7. The minimum password length should be about 8 characters, used a character counter as a guide.
As you have noted from part 1,2 and 3 of this tutorial, we are almost doing the same thing, reading data from a database, validating and verifying some information and writing stuff back to the database, so the route is still the same.
Reproduction
Let's create the Change Password modal sheet.
Then we need to read the entered content, validate and verify it and then write the new password back to the database.
The actual method that does all the magic..
Things to remember...
1. The modal sheet is now built on ConnectPage and not on BuildPage
Part 2.1 seeks to address the UX design for the "Try Something Else" screen. This occurs when a user has forgotten the password but then instead of having it sent they just change it.
Goal
1. The user selects Forgot Password from the Sign In Screen
2. They are provided with an option to have the email sent to them or
3. Have an option to Try Something else, thus entering their registered email address and a new password.
4. The email, password and confirm password are compulsory.
5. The entered email address should exist in the database
6. The password and confirm password should match
7. The minimum password length should be about 8 characters, used a character counter as a guide.
As you have noted from part 1,2 and 3 of this tutorial, we are almost doing the same thing, reading data from a database, validating and verifying some information and writing stuff back to the database, so the route is still the same.
Reproduction
Let's create the Change Password modal sheet.
B4X:
Private Sub contLoginBuild() As ABMModalSheet
Dim contLogin As ABMModalSheet
Dim dSize As Int = ABM.MODALSHEET_SIZE_NORMAL
If ABMShared.IsPhone(page) Then dSize = ABM.MODALSHEET_SIZE_FULL
contLogin.Initialize(page, "contLogin", False, ABM.MODALSHEET_TYPE_NORMAL, "ms")
contLogin.Size = dSize
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, 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, 0, 0, ABM.VISIBILITY_ALL, "")
contLogin.Content.AddRows(1,True,"").AddCellsOSMPV(1, 0, 0, 0, 12, 12, 12, 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 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 lblheader As ABMLabel
lblheader.Initialize(page, "lblheader", $"{B}Change password{/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", $"Create a new, strong password that you don't use anywhere else"$, ABM.SIZE_PARAGRAPH, False, "")
lblsubheader.istextselectable = True
lblsubheader.supportemoji = False
contLogin.Content.Cell(3,1).AddComponent(lblsubheader)
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 txtpassword As ABMInput
txtpassword.Initialize(page, "txtpassword", ABM.INPUT_PASSWORD, "Password", False, "")
txtpassword.Tag = "txtpassword"
contLogin.Content.Cell(5,1).AddComponent(txtpassword)
Dim txtconfirmpassword As ABMInput
txtconfirmpassword.Initialize(page, "txtconfirmpassword", ABM.INPUT_PASSWORD, "Confirm Password", False, "")
txtconfirmpassword.Tag = "txtconfirmpassword"
contLogin.Content.Cell(6,1).AddComponent(txtconfirmpassword)
Dim btnChangePassword As ABMButton
btnChangePassword.InitializeRaised(page, "btnChangePassword", "", "", "Change Password", "")
btnChangePassword.Tag = "btnChangePassword"
btnChangePassword.UseFullCellWidth = True
btnChangePassword.Size = ABM.BUTTONSIZE_NORMAL
btnChangePassword.dropdownhidearrow = False
btnChangePassword.dropdownshowbelow = False
btnChangePassword.dropdownconstrainwidth = False
contLogin.Content.Cell(7,1).AddComponent(btnChangePassword)
Return contLogin
End Sub
Then we need to read the entered content, validate and verify it and then write the new password back to the database.
B4X:
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")
Dim txtpassword As ABMInput = contLogin.Content.Component("txtpassword")
Dim txtconfirmpassword As ABMInput = contLogin.Content.Component("txtconfirmpassword")
pMap.put("email", txtemail.Text)
pMap.put("password", txtpassword.Text)
pMap.put("confirmpassword", txtconfirmpassword.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
Dim stxtpassword As String
stxtpassword = gMap.get("password")
If stxtpassword = "null" Then stxtpassword = ""
If stxtpassword.Length = 0 Then
ABMShared.Warn(page,"Password cannot be blank. Please enter a value.")
Dim txtpassword As ABMInput = contLogin.Content.Component("txtpassword")
txtpassword.SetFocus
Return False
End If
Dim stxtconfirmpassword As String
stxtconfirmpassword = gMap.get("confirmpassword")
If stxtconfirmpassword = "null" Then stxtconfirmpassword = ""
If stxtconfirmpassword.Length = 0 Then
ABMShared.Warn(page,"Confirm Password cannot be blank. Please enter a value.")
Dim txtconfirmpassword As ABMInput = contLogin.Content.Component("txtconfirmpassword")
txtconfirmpassword.SetFocus
Return False
End If
Return True
End Sub
The actual method that does all the magic..
B4X:
Private Sub contLoginChangePassword() As Boolean
'define a map to hold the form contents
Dim m As Map
'read the form contents to a map
m = contLoginGetContents
'validate the form contents where required
If contLoginValidate(m) = False Then
Return False
End If
m.remove("id")
Dim email As String = m.getdefault("email","")
Dim password As String = m.getdefault("password","")
Dim confirmpassword As String = m.getdefault("confirmpassword","")
'the form contents are ok, continue with the change password process
'define the search criteria, fields must equal
Dim w As Map
Dim UserMap As Map
w.Initialize
Dim nk As String
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
If password <> confirmpassword Then
ABMShared.Warn(page,"The passwords DO NOT match, please correct this!")
Return False
End If
'The email has been found, update the passwords
UserMap.put("email",email)
UserMap.put("password",password)
UserMap.put("confirmpassword",confirmpassword)
Dim bUpdate As Boolean = ABMShared.SQLRecordUpdate(jSQL, "users", UserMap, "email", email)
If bUpdate = True Then
myToastId = myToastId + 1
page.ShowToast("toast" & myToastId, "toastgreen", "Password updated successfully.", 3000,False)
'Close the connection to the database
ABMShared.SQLClose(jSQL)
Return True
Else
myToastId = myToastId + 1
page.ShowToast("toast" & myToastId, "toastred", "Password could NOT be updated successfully.", 3000,False)
'Close the connection to the database
ABMShared.SQLClose(jSQL)
Return False
End If
End Sub
Things to remember...
1. The modal sheet is now built on ConnectPage and not on BuildPage
B4X:
Public Sub ConnectPage()
'connect navigation bar
ConnectNavigationBar
'add components for the page
AdminAccess
page.SetFontStack("arial,sans-serif")
' this page uses uploads, so needs some settings
page.ws.session.SetAttribute("abmcallback", Me)
page.ws.session.SetAttribute("abmdownloadfolder", DownloadFolder)
page.ws.session.SetAttribute("abmmaxsize", DownloadMaxSize)
page.AddModalSheetTemplate(contLoginBuild)
page.Refresh ' IMPORTANT
' NEW, because we use ShowLoaderType=ABM.LOADER_TYPE_MANUAL
page.FinishedLoading 'IMPORTANT
page.RestoreNavigationBarPosition
page.ShowModalSheet("contLogin")
End Sub