# 12 August Report
## Progress
Time: **08:55**
Event: Entering the lab
---
### Forgot password and Reset password page on User App
Time: **10:26**
- Create Forgot Password and Reset Password in user app project to help the users if they forgot their account password.
- To access the both page, user can get it from Login Page
<center>
<img src="https://raw.githubusercontent.com/aru1702/images/master/ntust-documentation/43-01.JPG" style="max-width: 250px" />
</center>
<br>
- If user click the "*Forgot password?*" it will direct to forgot password page
- New UI has been implement in order to make it more simple
- In **HTML** (we can check the rest of code on Github):
```htmlmixed=
<div class="section">
<div class="title">
<h3><b>LOG IN</b></h3>
</div>
<div>
<ion-item>
<ion-label position="floating">Email Address</ion-label>
<ion-input type="email" [(ngModel)]="email"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Password</ion-label>
<ion-input type="password" [(ngModel)]="password"></ion-input>
</ion-item>
</div>
<div (click)="recovery()" class="forgot-link">
<i>Forgot password?</i>
</div>
<div class="btn-yes">
<ion-button class="i-btn-yes" fill="solid" expand="block" (click)="login()">Login</ion-button>
</div>
<div>
<p>New user? <ion-text (click)="registerlink()" color="primary"><b>SIGN UP</b></ion-text></p>
</div>
</div>
```
- In **SCSS** (stylesheet for HTML):
```css=
.title {
text-align: center;
margin-bottom: 24px;
border-bottom: solid #00000055 1px
}
.forgot-link {
text-align: right;
color: rgba(0, 0, 0, 0.75);
margin-top: 30px
}
p {
text-align: center;
line-height: 1.4;
padding: 0px 5px;
}
```
- Forgot password, page when user enter his email address to get verification code.
- Display:
<center>
<img src="https://raw.githubusercontent.com/aru1702/images/master/ntust-documentation/43-02.JPG" style="max-width: 250px" />
</center>
<br>
- If user click **CONTINUE** button, it will sends the email address to the API to generate the verification code.
- **RESET** button is added for scenario when user has the verification code but accidentally go back to previous page, this button will re-direct the user to Reset Password page.
- In **forgot-password.page.html**:
```htmlmixed=
<ion-content class="i-theme1">
<div class="icon-cancel">
<img src="assets/cancel/rectangle-black@3x.png" alt="cancel" (click)="backFunc()">
</div>
<div class="header">
<img
class="img-header"
src="assets/acuo-icons/rectangle_2@3x.png"
alt="acuo-icons">
</div>
<div class="section">
<div class="title">
<h3><b>FORGOT PASSWORD</b></h3>
</div>
<p>We will send a verification code to reset your password.</p>
<div>
<ion-item>
<ion-label position="floating">Email Address</ion-label>
<ion-input type="email" [(ngModel)]="email"></ion-input>
</ion-item>
</div>
<div class="btn-yes">
<ion-button class="i-btn-yes" fill="solid" expand="block" (click)="reset(true)">CONTINUE</ion-button>
</div>
<p>Already have code? <ion-text (click)="reset(false)" color="primary"><b>RESET</b></ion-text></p>
</div>
</ion-content>
```
- In **forgot-password.page.scss**:
```css=
.i-theme1 {
--background: #bdbdbd;
--color: #000000;
}
.btn-yes {
margin: 30px 0px;
}
.i-btn-yes {
--background: #259ed6;
--color: #ffffff;
}
.icon-cancel {
text-align: right;
margin-top: 15px;
margin-right: 15px;
}
.header {
text-align: center;
font-weight: bold;
margin-bottom: 50px;
}
.img-header {
max-height: 60px;
max-width: 100%;
}
.section {
background: #ffffff;
color: #2c2c2c;
border-radius: 10px;
margin: 50px 25px 75px;
padding: 10px;
}
.title {
text-align: center;
margin-bottom: 24px;
border-bottom: solid #00000055 1px
}
.forgot-link {
text-align: right;
color: rgba(0, 0, 0, 0.75);
margin-top: 30px
}
p {
text-align: center;
line-height: 1.4;
padding: 0px 5px;
}
```
- Reset password, page when user enter his email, new password, and verification code.
- Display:
<center>
<img src="https://raw.githubusercontent.com/aru1702/images/master/ntust-documentation/43-03.JPG" style="max-width: 250px" />
</center>
<br>
- Because of every of authentication pages (Login, Register, Forgot Password, and Reset Password) use the similar template, each of them will has same style and code.
- In **reset-password.page.html**
```htmlmixed=
<ion-content class="i-theme1">
<div class="icon-cancel">
<img src="assets/cancel/rectangle-black@3x.png" alt="cancel" (click)="backFunc()">
</div>
<div class="header">
<img
class="img-header"
src="assets/acuo-icons/rectangle_2@3x.png"
alt="acuo-icons">
</div>
<div class="section">
<div class="title">
<h3><b>RESET PASSWORD</b></h3>
</div>
<div>
<ion-item>
<ion-label position="floating">Email Address</ion-label>
<ion-input type="email" [(ngModel)]="email"></ion-input>
</ion-item>
</div>
<div>
<ion-item>
<ion-label position="floating">New Password</ion-label>
<ion-input type="password" [(ngModel)]="password"></ion-input>
</ion-item>
</div>
<div>
<ion-item>
<ion-label position="floating">Re-type New Password</ion-label>
<ion-input type="password" [(ngModel)]="re_password"></ion-input>
</ion-item>
</div>
<div>
<ion-item>
<ion-label position="floating">Verification Code</ion-label>
<ion-input type="text" [(ngModel)]="verif_code"></ion-input>
</ion-item>
</div>
<div class="btn-yes">
<ion-button class="i-btn-yes" fill="solid" expand="block" (click)="reset()">RESET</ion-button>
</div>
</div>
</ion-content>
```
- In **reset-password.page.scss**
```css=
.i-theme1 {
--background: #bdbdbd;
--color: #000000;
}
.btn-yes {
margin: 30px 0px;
}
.i-btn-yes {
--background: #259ed6;
--color: #ffffff;
}
.icon-cancel {
text-align: right;
margin-top: 15px;
margin-right: 15px;
}
.header {
text-align: center;
font-weight: bold;
margin-bottom: 50px;
}
.img-header {
max-height: 60px;
max-width: 100%;
}
.section {
background: #ffffff;
color: #2c2c2c;
border-radius: 10px;
margin: 50px 25px 75px;
padding: 10px;
}
.title {
text-align: center;
margin-bottom: 24px;
border-bottom: solid #00000055 1px
}
.forgot-link {
text-align: right;
color: rgba(0, 0, 0, 0.75);
margin-top: 30px
}
p {
text-align: center;
line-height: 1.4;
padding: 0px 5px;
}
```
---
Time: **15:22**
- Update on Dispenser API service for User App, add forgot password and reset password.
- Forgot password:
```typescript=
async userForgotPassword (email: string) {
let url = this.urlForgotPassword;
const postBody = {
"Email": email
};
return await this.http.post(url, postBody).toPromise()
.then((result) => {
if (result['code'] === 200) {
return 1;
} else {
console.error("Error while send reset password request: " + result['msg']);
return 0;
}
}, () => {
console.error("Promise rejected: unable to send reset password request!");
return 0;
})
.catch((e) => {
console.error("Function error: on userForgotPassword => " + e);
return -1;
});
}
```
- Using method POST to get the verification code from API.
- For using this function, it will return number value which identify the code of result
<br>
| Code | Meaning |
|---|---|
| 1 | Success generate verification code, check email address. |
| 0 | Invalid email address, please try again. |
| -1 | Unexpected error. |
- Reset password:
```typescript=
async userResetPassword (email: string, newPassword: string, reNewPassword: string, verifCode: string) {
let url = this.urlPasswordReset;
let token: string = "";
let returnValue = {
"RepsondNum": -1,
"Message": "Null message."
}
try {
token = await this.getToken();
} catch (e) {
console.error("Function error: on userResetPassword while getToken => " + e);
returnValue = {
"RepsondNum": -2,
"Message": "There is an error from server, please try again later!"
};
}
if (newPassword !== reNewPassword) {
console.error("Password not match!");
return 0;
} else {
const postBody = {
"Email": email,
"Password": newPassword,
"VerificationCode": verifCode
};
let httpOption = await {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': token
})
};
return await this.http.post(url, postBody, httpOption).toPromise()
.then((result) => {
if (result['code'] === 200) {
return 1;
} else {
console.error("Error while reset password: " + result['msg']);
return -1;
}
}, () => {
console.error("Promise rejected: unable to reset password!");
return -3;
})
.catch((e) => {
console.error("Function error: on userResetPassword => " + e);
return -4;
});
}
}
```
- Reset password use TOKEN from API.
- If token cannot be generate, it will return error code -2.
<br>
| Code | Meaning |
|---|---|
| 1 | Success reset password. |
| 0 | Password and re-type password not match. |
| -1 | Success from API but unexpected error, password not reset. |
| -2 | Generate token error. |
| -3 | The Email does not exist or Verification Code is not valid. |
| -4 | Unexpected error. |
- Forgot password page back end code (.ts):
```typescript=
import { Component, OnInit } from '@angular/core';
import { NavController, ToastController, LoadingController } from '@ionic/angular';
import { DispenserAPIService } from 'src/app/services/DispenserAPI/dispenser-api.service';
@Component({
selector: 'app-forgot-password',
templateUrl: './forgot-password.page.html',
styleUrls: ['./forgot-password.page.scss'],
})
export class ForgotPasswordPage implements OnInit {
// field variable to store input
email: string = "";
// loadCtrl var
makeLoading: any;
constructor(
private navCtrl: NavController,
private api: DispenserAPIService,
private toastCtrl: ToastController,
private loadCtrl: LoadingController
) { }
/**
* To going back, or route back, to the previous
* opened page.
*/
backFunc() {
this.navCtrl.back();
}
/**
* Create the loading controller
*/
async createLoadCtrl () {
// insert component of loading controller
this.makeLoading = await this.loadCtrl.create({
message: 'Loading data ...',
spinner: 'crescent',
duration: 10000
});
// display the loading controller
await this.makeLoading.present();
}
/**
* Dismiss the loading controller
*/
async dismissLoadCtrl () {
this.makeLoading.dismiss();
}
ngOnInit() {
}
async reset (hasEmail: boolean) {
if (!hasEmail) {
// if user click RESET button
this.navCtrl.navigateForward(['reset-password']);
} else {
// initial local variables
let myToast: any;
let myToastMessage: string = "";
// create loading screen
await this.createLoadCtrl();
if (this.email === "") {
myToastMessage = "Please fill in all the required form!"
} else {
// if user click CONTINUE button
const { email } = this;
let resultData = await this.api.userForgotPassword(email);
if (resultData === 1) {
myToastMessage = "Verification has been sent to your email address!";
this.navCtrl.navigateForward(['reset-password']);
} else if (resultData === 0) {
myToastMessage = "Email address is not found, please try again!";
} else {
myToastMessage = "There is an unexpected error, please try again later!";
}
}
// create Toast with myToastMessage as message display
myToast = await this.toastCtrl.create({
message: myToastMessage,
duration: 2000,
position: 'top',
showCloseButton: true,
closeButtonText: 'Close'
});
// display the Toast
await myToast.present();
// dismiss the loading screen
this.dismissLoadCtrl();
}
}
}
```
- Import 4 libraries:
- NavController, to route the user forward and back.
- DispenserAPIService, to access the function which accessing the API.
- ToastController, to create toast notification.
- LoadingController, to create loading screen.
- `reset()` function has two condition:
- `hasEmail` is true, when user press the CONTINUE button.
- `hasEmail` is false, when user press the RESET button
- Both CONTINUE and RESET button has already explained above on UI design.
- When user use the CONTINUE button, email address will be sent to API and check whether is valid or not.
- If email is present and valid then API will return success value and a verification code will be sent to user's mailbox.
- After generating verification code, user will be routed to Reset Password page to reset his account password.
- Reset password page back end code (.ts):
```typescript=
import { Component, OnInit } from '@angular/core';
import { NavController, ToastController, LoadingController } from '@ionic/angular';
import { DispenserAPIService } from 'src/app/services/DispenserAPI/dispenser-api.service';
@Component({
selector: 'app-reset-password',
templateUrl: './reset-password.page.html',
styleUrls: ['./reset-password.page.scss'],
})
export class ResetPasswordPage implements OnInit {
// field variable to store input
email = "";
password = "";
re_password = "";
verif_code = "";
// loadCtrl var
makeLoading: any;
constructor(
private navCtrl: NavController,
private api: DispenserAPIService,
private toastCtrl: ToastController,
private loadCtrl: LoadingController
) { }
/**
* To going back, or route back, to the previous
* opened page.
*/
backFunc() {
this.navCtrl.back();
}
/**
* Create the loading controller
*/
async createLoadCtrl () {
// insert component of loading controller
this.makeLoading = await this.loadCtrl.create({
message: 'Loading data ...',
spinner: 'crescent',
duration: 10000
});
// display the loading controller
await this.makeLoading.present();
}
/**
* Dismiss the loading controller
*/
async dismissLoadCtrl () {
this.makeLoading.dismiss();
}
ngOnInit() {
}
async reset () {
// initial local variables
let myToast: any;
let myToastMessage: string = "";
// create loading screen
await this.createLoadCtrl();
// if form is not completed
if (
this.email === "" ||
this.password === "" ||
this.re_password === "" ||
this.verif_code === ""
) {
myToastMessage = "Please fill in all the required form!";
} else {
const { email, password, re_password, verif_code } = this;
let resultData = await this.api.userResetPassword(email, password, re_password, verif_code);
if (resultData === 1) {
myToastMessage = "Your account password has successfully reset!";
this.navCtrl.back();
this.navCtrl.back();
} else if (resultData === 0) {
myToastMessage = "Password not match!";
} else if (resultData === -3) {
myToastMessage = "The Email does not exist or Verification Code is not valid";
} else {
myToastMessage = "There is an unexpected error, please try again later!";
}
}
// create Toast with myToastMessage as message display
myToast = await this.toastCtrl.create({
message: myToastMessage,
duration: 2000,
position: 'top',
showCloseButton: true,
closeButtonText: 'Close'
});
// display the Toast
await myToast.present();
// dismiss the loading screen
this.dismissLoadCtrl();
}
}
```
- Same as Forgot Password page, it implement same 4 libraries.
- There are 4 parameters which used in form: email, password, re-type password for verification, and verification code.
- If one of the form attributes is unfilled then it cannot send to API.
- From DispenserAPIService it will return number value which identify the return code.
- If user successful reset his account password, it will re-direct the user back to Login page.
---
### Changes on User App based on Ms. Annie request
Time: **17:05**
- In Nearby Dispenser page, the water temperature indicator must be located in the bottom of each item card.
- Item card is each dispenser in Nearby Dispenser page which contain information.
- Water temperature indicator shows if the dispenser has cold, warm, and hot water.
- The indicator become smaller so the card has more space than before.
- Mock up from Ms. Annie
<center>
<img src="https://raw.githubusercontent.com/aru1702/images/master/ntust-documentation/43-04.JPG" style="max-width: 250px" />
</center>
<br>
- In Report Problem page, pictures to be upload now has their own upload section instead uploading one by one.
- By having this user know that they can only upload up to 3 pictures.
- Mock up from Ms. Annie:
<center>
<img src="https://raw.githubusercontent.com/aru1702/images/master/ntust-documentation/43-05.JPG" style="max-width: 250px" />
</center>
<br>
---
## Conclusion
- User can use Forgot Password page to reset his account password, this page will generate verification code and send to user mailbox, also it will notify whether verification code is successful sent or not.
- Along with Reset Password page, user can use this to input email, new password, and the verification code from mailbox, also it will notify whether password reset is success or not.
---
Time: **18:00**
Event: Leaving the lab
###### tags: `on-intern`