From b5c94bb35b6ef8f0864ec59f9147dd73022fcd15 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Mon, 4 Sep 2023 17:00:57 +0700 Subject: [PATCH 1/6] Implement login method --- javascript-practice/src/js/app.js | 1 + .../src/js/constants/constant.js | 1 + .../src/js/controllers/controller.js | 2 + .../src/js/controllers/loginController.js | 23 +++++ javascript-practice/src/js/helpers/helpers.js | 15 ++++ .../src/js/services/commonService.js | 4 +- .../src/js/services/userService.js | 11 +++ javascript-practice/src/js/views/loginView.js | 84 +++++++++++++++++++ javascript-practice/src/js/views/view.js | 2 + javascript-practice/src/pages/login.html | 3 +- 10 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 javascript-practice/src/js/controllers/loginController.js create mode 100644 javascript-practice/src/js/views/loginView.js diff --git a/javascript-practice/src/js/app.js b/javascript-practice/src/js/app.js index 6c68c70..c3f6fc3 100644 --- a/javascript-practice/src/js/app.js +++ b/javascript-practice/src/js/app.js @@ -11,5 +11,6 @@ export default class App { start() { this.controller.registerController.init(); + this.controller.loginController.init(); } } diff --git a/javascript-practice/src/js/constants/constant.js b/javascript-practice/src/js/constants/constant.js index 397a4ef..e6a63f2 100644 --- a/javascript-practice/src/js/constants/constant.js +++ b/javascript-practice/src/js/constants/constant.js @@ -4,6 +4,7 @@ export const MESSAGE = { 'Password must at least one uppercase, one lowercase letter, one number and one special character!', ERROR_MESSAGE_DEFAULT: 'Something went wrong!', TIME_OUT_ERROR: 'Connection time out! Please try again!', + ERROR_CREDENTIAL: 'Email or password not match! Please try again!', }; export const TYPE_POPUP = { success: 'success', error: 'error' }; export const MARK_ICON = { success: 'check', error: 'error' }; diff --git a/javascript-practice/src/js/controllers/controller.js b/javascript-practice/src/js/controllers/controller.js index e360b3c..1434739 100644 --- a/javascript-practice/src/js/controllers/controller.js +++ b/javascript-practice/src/js/controllers/controller.js @@ -1,7 +1,9 @@ +import LoginController from './loginController'; import RegisterController from './registerController'; export default class Controller { constructor(service, view) { this.registerController = new RegisterController(service, view); + this.loginController = new LoginController(service, view); } } diff --git a/javascript-practice/src/js/controllers/loginController.js b/javascript-practice/src/js/controllers/loginController.js new file mode 100644 index 0000000..a2ae10d --- /dev/null +++ b/javascript-practice/src/js/controllers/loginController.js @@ -0,0 +1,23 @@ +export default class LoginController { + constructor(service, view) { + this.service = service; + this.loginView = view.loginView; + } + + handlerGetUserByEmail(email) { + return this.service.userService.getUserByEmail(email); + } + + handlerCreateTokenUser(user) { + return this.service.userService.createTokenUser(user); + } + + init() { + if (this.loginView.isLoginPage()) { + this.loginView.addHandlerForm( + this.handlerGetUserByEmail.bind(this), + this.handlerCreateTokenUser.bind(this), + ); + } + } +} diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js index c6adaf1..f577ee1 100644 --- a/javascript-practice/src/js/helpers/helpers.js +++ b/javascript-practice/src/js/helpers/helpers.js @@ -35,3 +35,18 @@ export const timeOutConnect = async (action) => { return result; }; + +/** + * A function create token for user + * @returns {string} Return token string + */ +export const createToken = () => { + const lengthToken = 36; + const chars = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + let token = ''; + for (let i = 0; i < lengthToken; i += 1) { + token += chars[Math.floor(Math.random() * chars.length)]; + } + return token; +}; diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js index 569a6d3..f967a7e 100644 --- a/javascript-practice/src/js/services/commonService.js +++ b/javascript-practice/src/js/services/commonService.js @@ -22,13 +22,13 @@ export default class CommonService { return result; } - async save(data, path = this.path) { + async save(data, path = this.defaultPath) { this.connectToDb(); const saveUser = this.firebaseService.save(data, path); await timeOutConnect(saveUser); } - async getDataFromId(id, path = this.path) { + async getDataFromId(id, path = this.defaultPath) { this.connectToDb(); const data = await this.firebaseService.getDataFromId(id, path); if (data) return data; diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index d096ec2..556fe54 100644 --- a/javascript-practice/src/js/services/userService.js +++ b/javascript-practice/src/js/services/userService.js @@ -1,3 +1,4 @@ +import { createToken } from '../helpers/helpers'; import User from '../models/user'; import CommonService from './commonService'; @@ -52,4 +53,14 @@ export default class UserService extends CommonService { } return null; } + + async createTokenUser(user) { + const id = await this.getUserIdByEmail(user.email); + + // Add token to user object + const newUserData = new User(user); + newUserData.accessToken = createToken(); + + this.save(newUserData, this.defaultPath + id); + } } diff --git a/javascript-practice/src/js/views/loginView.js b/javascript-practice/src/js/views/loginView.js new file mode 100644 index 0000000..2ac412e --- /dev/null +++ b/javascript-practice/src/js/views/loginView.js @@ -0,0 +1,84 @@ +import CommonLoginRegisterView from './commonLoginRegisterView'; +import * as CONSTANT from '../constants/constant'; + +export default class LoginView extends CommonLoginRegisterView { + constructor() { + super(); + + this.parentElement = document.querySelector('.form'); + this.loginPage = document.getElementById('loginPage'); + } + + /** + * Get data from user input + * @returns {Object || null} Return object or null + */ + getDataFromForm() { + const { loginForm } = document.forms; + const formData = new FormData(loginForm); + const email = formData.get('email'); + const password = formData.get('password'); + + this.account = { email, password }; + + return this.account; + } + + /** + * Implement error popup in site + * @param {string} content The content will show in error popup + */ + initErrorPopup(content) { + const typePopup = CONSTANT.TYPE_POPUP.error; + const title = 'Error Credential!'; + const btnContent = 'Got it!'; + + this.initPopupContent(typePopup, title, content, btnContent); + + // Show popup + this.tooglePopupForm(); + } + + /** + * Add event listener for form input + * @param {Function} handler The function need to be set event + */ + addHandlerForm(getUserByEmail, createTokenUser) { + this.parentElement.addEventListener('submit', (e) => { + e.preventDefault(); + this.clearErrorMessage(); + this.submitForm(getUserByEmail, createTokenUser); + }); + } + + async submitForm(getUserByEmail, createTokenUser) { + try { + // Load spinner + this.toogleLoaderSpinner(); + + // Get data from form + const userInput = this.getDataFromForm(); + // Check user exist + const user = await getUserByEmail(userInput.email); + + if (user) { + // If user exist, compare password + if (userInput.password === user.password) { + await createTokenUser(user); + window.location.replace('/'); + return; + } + } + throw Error(CONSTANT.MESSAGE.ERROR_CREDENTIAL); + } catch (error) { + // Show popup error + this.initErrorPopup(error); + } + // Close spinner + this.toogleLoaderSpinner(); + } + + isLoginPage() { + return this.loginPage !== null; + } +} diff --git a/javascript-practice/src/js/views/view.js b/javascript-practice/src/js/views/view.js index a2a1675..333d0a7 100644 --- a/javascript-practice/src/js/views/view.js +++ b/javascript-practice/src/js/views/view.js @@ -1,7 +1,9 @@ import RegisterView from './registerView'; +import LoginView from './loginView'; export default class View { constructor() { this.registerView = new RegisterView(); + this.loginView = new LoginView(); } } diff --git a/javascript-practice/src/pages/login.html b/javascript-practice/src/pages/login.html index 4c19064..c502e11 100644 --- a/javascript-practice/src/pages/login.html +++ b/javascript-practice/src/pages/login.html @@ -16,7 +16,7 @@ alt="Logo web" /> -
+

Log In

Using Money Lover account

@@ -45,5 +45,6 @@
+ From 95b1c8cb3d6e3a20ef347f73c1551b2cea545363 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Mon, 4 Sep 2023 17:28:48 +0700 Subject: [PATCH 2/6] Add time out connect for getDataFromId function --- javascript-practice/src/js/services/commonService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js index f967a7e..55c2415 100644 --- a/javascript-practice/src/js/services/commonService.js +++ b/javascript-practice/src/js/services/commonService.js @@ -30,7 +30,8 @@ export default class CommonService { async getDataFromId(id, path = this.defaultPath) { this.connectToDb(); - const data = await this.firebaseService.getDataFromId(id, path); + const result = await this.firebaseService.getDataFromId(id, path); + const data = await timeOutConnect(result); if (data) return data; return null; } From 51c84a7c825df6450eab871b03145f03ea0f4971 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 5 Sep 2023 10:15:00 +0700 Subject: [PATCH 3/6] Format code, add comments and fix typo --- .../src/js/services/commonService.js | 27 ++++++++++++++++--- .../src/js/services/firebaseService.js | 10 +++++-- .../src/js/services/userService.js | 2 +- javascript-practice/src/js/views/loginView.js | 11 ++++++-- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js index 934e78c..ed37218 100644 --- a/javascript-practice/src/js/services/commonService.js +++ b/javascript-practice/src/js/services/commonService.js @@ -7,13 +7,23 @@ export default class CommonService { this.firebaseService = FirebaseService; } + /** + * Connect to Firebase Databse + */ connectToDb() { this.firebaseService.reconnect(); } - async findKeyByProperty(property, value, path = this.defaultPath) { + /** + * Find the id of data on database + * @param {string} property The property want to get value + * @param {string} value The value of property + * @param {path} path The path of datbase + * @returns {string} The id of data object + */ + async findIdByProperty(property, value, path = this.defaultPath) { this.connectToDb(); - const existUser = this.firebaseService.findKeyByPropery( + const existUser = this.firebaseService.findIdByProperty( path, property, value, @@ -23,6 +33,11 @@ export default class CommonService { return result; } + /** + * Save data on database + * @param {*} data The data wants to save on database + * @param {string} path The path of database + */ async save(data, path = this.defaultPath) { this.connectToDb(); const saveUser = this.firebaseService.save(data, path); @@ -30,11 +45,17 @@ export default class CommonService { await timeOutConnect(saveUser); } + /** + * + * @param {string} id The string of data object + * @param {string} path The path of database + * @returns {Object || null} Return the object if has, otherwise return null + */ async getDataFromId(id, path = this.defaultPath) { this.connectToDb(); const result = await this.firebaseService.getDataFromId(id, path); const data = await timeOutConnect(result); - + if (data) return data; return null; diff --git a/javascript-practice/src/js/services/firebaseService.js b/javascript-practice/src/js/services/firebaseService.js index d65b544..9cb2b09 100644 --- a/javascript-practice/src/js/services/firebaseService.js +++ b/javascript-practice/src/js/services/firebaseService.js @@ -43,13 +43,13 @@ class FirebaseService { } /** - * Find the key of value by property in database + * Find id of value by property in database * @param {string} path The path of database to be found * @param {string} property The property of the value need to be found * @param {value} value The value to compare in database * @returns {Promise} Return the relsoves when find completed */ - findKeyByPropery(path, property, value) { + findIdByProperty(path, property, value) { return new Promise((resolve) => { onValue( ref(this.db, path), @@ -73,6 +73,12 @@ class FirebaseService { }); } + /** + * Get data object from Id + * @param {string} id The id of data object + * @param {string} path The path of data save in database + * @returns {Promise} Return new Promise + */ getDataFromId(id, path) { return new Promise((resolve) => { onValue( diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index fa4147f..8ebd00e 100644 --- a/javascript-practice/src/js/services/userService.js +++ b/javascript-practice/src/js/services/userService.js @@ -25,7 +25,7 @@ export default class UserService extends CommonService { * @returns {Promise || number} Return id user when exist, otherwise will undefined */ getUserIdByEmail(email) { - return this.findKeyByProperty('email', email); + return this.findIdByProperty('email', email); } /** diff --git a/javascript-practice/src/js/views/loginView.js b/javascript-practice/src/js/views/loginView.js index 2ac412e..ab97fce 100644 --- a/javascript-practice/src/js/views/loginView.js +++ b/javascript-practice/src/js/views/loginView.js @@ -30,7 +30,7 @@ export default class LoginView extends CommonLoginRegisterView { */ initErrorPopup(content) { const typePopup = CONSTANT.TYPE_POPUP.error; - const title = 'Error Credential!'; + const title = 'Error!'; const btnContent = 'Got it!'; this.initPopupContent(typePopup, title, content, btnContent); @@ -41,7 +41,8 @@ export default class LoginView extends CommonLoginRegisterView { /** * Add event listener for form input - * @param {Function} handler The function need to be set event + * @param {Function} getUserByEmail The function need to be set event + * @param {Function} createTokenUser The function need to be set event */ addHandlerForm(getUserByEmail, createTokenUser) { this.parentElement.addEventListener('submit', (e) => { @@ -51,6 +52,11 @@ export default class LoginView extends CommonLoginRegisterView { }); } + /** + * The action when submit form + * @param {Function} getUserByEmail The function need to be set event + * @param {Function} createTokenUser The function need to be set event + */ async submitForm(getUserByEmail, createTokenUser) { try { // Load spinner @@ -66,6 +72,7 @@ export default class LoginView extends CommonLoginRegisterView { if (userInput.password === user.password) { await createTokenUser(user); window.location.replace('/'); + return; } } From 6f378dcdcfd6ee1f40937c0270040df2b95849d5 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 5 Sep 2023 17:33:53 +0700 Subject: [PATCH 4/6] Fix code according to the comments --- .../src/js/constants/constant.js | 11 ++++- .../src/js/controllers/loginController.js | 13 ++--- javascript-practice/src/js/helpers/helpers.js | 14 ++++++ javascript-practice/src/js/models/user.js | 1 + .../src/js/services/commonService.js | 34 +++++++------ .../src/js/services/firebaseService.js | 14 +++--- .../src/js/services/userService.js | 49 ++++++++++--------- javascript-practice/src/js/views/loginView.js | 48 ++++++++---------- .../src/js/views/registerView.js | 17 +++---- javascript-practice/src/pages/login.html | 2 +- javascript-practice/src/pages/register.html | 2 +- 11 files changed, 111 insertions(+), 94 deletions(-) diff --git a/javascript-practice/src/js/constants/constant.js b/javascript-practice/src/js/constants/constant.js index e6a63f2..9a05204 100644 --- a/javascript-practice/src/js/constants/constant.js +++ b/javascript-practice/src/js/constants/constant.js @@ -4,7 +4,16 @@ export const MESSAGE = { 'Password must at least one uppercase, one lowercase letter, one number and one special character!', ERROR_MESSAGE_DEFAULT: 'Something went wrong!', TIME_OUT_ERROR: 'Connection time out! Please try again!', - ERROR_CREDENTIAL: 'Email or password not match! Please try again!', + ERROR_CREDENTIAL: { + title: 'Error Credential', + message: 'Email or password not match! Please try again!', + }, + DEFAULT_TITLE_ERROR_POPUP: 'Error', + USER_EXIST_ERROR: 'User is exists! Please try another email!', +}; +export const BTN_CONTENT = { + GOT_IT: 'Got it!', + OK: 'Ok', }; export const TYPE_POPUP = { success: 'success', error: 'error' }; export const MARK_ICON = { success: 'check', error: 'error' }; diff --git a/javascript-practice/src/js/controllers/loginController.js b/javascript-practice/src/js/controllers/loginController.js index a2ae10d..322b537 100644 --- a/javascript-practice/src/js/controllers/loginController.js +++ b/javascript-practice/src/js/controllers/loginController.js @@ -4,20 +4,13 @@ export default class LoginController { this.loginView = view.loginView; } - handlerGetUserByEmail(email) { - return this.service.userService.getUserByEmail(email); - } - - handlerCreateTokenUser(user) { - return this.service.userService.createTokenUser(user); + handlerValidateUser(email, password) { + return this.service.userService.validateUser(email, password); } init() { if (this.loginView.isLoginPage()) { - this.loginView.addHandlerForm( - this.handlerGetUserByEmail.bind(this), - this.handlerCreateTokenUser.bind(this), - ); + this.loginView.addHandlerForm(this.handlerValidateUser.bind(this)); } } } diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js index f577ee1..c4300e9 100644 --- a/javascript-practice/src/js/helpers/helpers.js +++ b/javascript-practice/src/js/helpers/helpers.js @@ -50,3 +50,17 @@ export const createToken = () => { } return token; }; + +export const convertModelToDataObject = (model) => { + const { id, ...data } = model; + + return { id, data }; +}; + +export const convertDataObjectToModel = (data) => { + const model = data.data; + + model.id = data.id; + + return model; +}; diff --git a/javascript-practice/src/js/models/user.js b/javascript-practice/src/js/models/user.js index 3e6ab49..68e3962 100644 --- a/javascript-practice/src/js/models/user.js +++ b/javascript-practice/src/js/models/user.js @@ -1,5 +1,6 @@ export default class User { constructor({ email, password, walletName = '' }) { + this.id = User.createIdUser(); this.email = email; this.password = password; this.walletName = walletName; diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js index ed37218..717d424 100644 --- a/javascript-practice/src/js/services/commonService.js +++ b/javascript-practice/src/js/services/commonService.js @@ -1,4 +1,8 @@ -import { timeOutConnect } from '../helpers/helpers'; +import { + convertDataObjectToModel, + convertModelToDataObject, + timeOutConnect, +} from '../helpers/helpers'; import FirebaseService from './firebaseService'; export default class CommonService { @@ -14,23 +18,20 @@ export default class CommonService { this.firebaseService.reconnect(); } - /** - * Find the id of data on database - * @param {string} property The property want to get value - * @param {string} value The value of property - * @param {path} path The path of datbase - * @returns {string} The id of data object - */ - async findIdByProperty(property, value, path = this.defaultPath) { + async getDataFromProp(property, value, path = this.defaultPath) { this.connectToDb(); - const existUser = this.firebaseService.findIdByProperty( + const existUser = this.firebaseService.getDataFromProp( path, property, value, ); const result = await timeOutConnect(existUser); - return result; + if (result.id && result.data) { + return convertDataObjectToModel(result); + } + + return null; } /** @@ -38,11 +39,16 @@ export default class CommonService { * @param {*} data The data wants to save on database * @param {string} path The path of database */ - async save(data, path = this.defaultPath) { + async save(model) { this.connectToDb(); - const saveUser = this.firebaseService.save(data, path); + const results = convertModelToDataObject(model); - await timeOutConnect(saveUser); + const saveData = this.firebaseService.save( + results.data, + this.defaultPath + results.id, + ); + + await timeOutConnect(saveData); } /** diff --git a/javascript-practice/src/js/services/firebaseService.js b/javascript-practice/src/js/services/firebaseService.js index 9cb2b09..80d2036 100644 --- a/javascript-practice/src/js/services/firebaseService.js +++ b/javascript-practice/src/js/services/firebaseService.js @@ -49,22 +49,24 @@ class FirebaseService { * @param {value} value The value to compare in database * @returns {Promise} Return the relsoves when find completed */ - findIdByProperty(path, property, value) { + getDataFromProp(path, property, value) { return new Promise((resolve) => { onValue( ref(this.db, path), (snapshot) => { - let result; + let id; + let data; // snapshot is a type of data by Firebase define snapshot.forEach((childSnapshot) => { - const data = childSnapshot.val(); + const dataTemp = childSnapshot.val(); - if (data[property] === value) { - result = childSnapshot.key; + if (dataTemp[property] === value) { + id = childSnapshot.key; + data = dataTemp; } }); - resolve(result); + resolve({ id, data }); }, { onlyOnce: true, diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index 8ebd00e..216bf9f 100644 --- a/javascript-practice/src/js/services/userService.js +++ b/javascript-practice/src/js/services/userService.js @@ -1,5 +1,4 @@ import { createToken } from '../helpers/helpers'; -import User from '../models/user'; import CommonService from './commonService'; export default class UserService extends CommonService { @@ -14,18 +13,7 @@ export default class UserService extends CommonService { * @param {Object} user The user object need to be saved into databae */ saveUser(user) { - const pathData = this.defaultPath + User.createIdUser(); - - this.save(user, pathData); - } - - /** - * Get user id by email - * @param {string} email Email need to be check - * @returns {Promise || number} Return id user when exist, otherwise will undefined - */ - getUserIdByEmail(email) { - return this.findIdByProperty('email', email); + this.save(user); } /** @@ -34,7 +22,7 @@ export default class UserService extends CommonService { * @returns {boolean} Return true if find, otherwise return false */ async checkUserExist(email) { - const userExist = await this.getUserIdByEmail(email); + const userExist = await this.getUserByEmail(email); if (userExist) { return true; @@ -49,24 +37,37 @@ export default class UserService extends CommonService { * @returns {Object || null} Return new User Object if find, otherwise return null. */ async getUserByEmail(email) { - const id = await this.getUserIdByEmail(email); + const result = await this.getDataFromProp('email', email); - if (id) { - const user = await this.getDataFromId(id); - - return new User(user); + if (result) { + return result; } return null; } - async createTokenUser(user) { - const id = await this.getUserIdByEmail(user.email); + async validateUser(email, password) { + const user = await this.getUserByEmail(email); + + if (user) { + // Check password + if (user.password === password) { + // Create token for user + await this.createTokenUser(email); + + return true; + } + return false; + } + return false; + } + + async createTokenUser(email) { + const user = await this.getUserByEmail(email); // Add token to user object - const newUserData = new User(user); + const newUserData = user; newUserData.accessToken = createToken(); - - this.save(newUserData, this.defaultPath + id); + this.save(newUserData); } } diff --git a/javascript-practice/src/js/views/loginView.js b/javascript-practice/src/js/views/loginView.js index ab97fce..0733561 100644 --- a/javascript-practice/src/js/views/loginView.js +++ b/javascript-practice/src/js/views/loginView.js @@ -1,21 +1,20 @@ import CommonLoginRegisterView from './commonLoginRegisterView'; -import * as CONSTANT from '../constants/constant'; +import { MESSAGE, TYPE_POPUP, BTN_CONTENT } from '../constants/constant'; export default class LoginView extends CommonLoginRegisterView { constructor() { super(); this.parentElement = document.querySelector('.form'); - this.loginPage = document.getElementById('loginPage'); + this.loginPage = document.URL.includes('/login'); } /** * Get data from user input * @returns {Object || null} Return object or null */ - getDataFromForm() { - const { loginForm } = document.forms; - const formData = new FormData(loginForm); + getDataFromForm(event) { + const formData = new FormData(event.target); const email = formData.get('email'); const password = formData.get('password'); @@ -28,12 +27,11 @@ export default class LoginView extends CommonLoginRegisterView { * Implement error popup in site * @param {string} content The content will show in error popup */ - initErrorPopup(content) { - const typePopup = CONSTANT.TYPE_POPUP.error; - const title = 'Error!'; - const btnContent = 'Got it!'; + initErrorPopup(error) { + const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP; + const content = error.message ? error.message : error; - this.initPopupContent(typePopup, title, content, btnContent); + this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.GOT_IT); // Show popup this.tooglePopupForm(); @@ -41,42 +39,36 @@ export default class LoginView extends CommonLoginRegisterView { /** * Add event listener for form input - * @param {Function} getUserByEmail The function need to be set event - * @param {Function} createTokenUser The function need to be set event + * @param {Function} validateUser The function need to be set event */ - addHandlerForm(getUserByEmail, createTokenUser) { + addHandlerForm(validateUser) { this.parentElement.addEventListener('submit', (e) => { e.preventDefault(); this.clearErrorMessage(); - this.submitForm(getUserByEmail, createTokenUser); + this.submitForm(validateUser, e); }); } /** * The action when submit form - * @param {Function} getUserByEmail The function need to be set event - * @param {Function} createTokenUser The function need to be set event + * @param {Function} validateUser The function need to be set event */ - async submitForm(getUserByEmail, createTokenUser) { + async submitForm(validateUser, event) { try { // Load spinner this.toogleLoaderSpinner(); // Get data from form - const userInput = this.getDataFromForm(); + const userInput = this.getDataFromForm(event); // Check user exist - const user = await getUserByEmail(userInput.email); + const results = await validateUser(userInput.email, userInput.password); - if (user) { - // If user exist, compare password - if (userInput.password === user.password) { - await createTokenUser(user); - window.location.replace('/'); + if (results) { + window.location.replace('/'); - return; - } + return; } - throw Error(CONSTANT.MESSAGE.ERROR_CREDENTIAL); + throw MESSAGE.ERROR_CREDENTIAL; } catch (error) { // Show popup error this.initErrorPopup(error); @@ -86,6 +78,6 @@ export default class LoginView extends CommonLoginRegisterView { } isLoginPage() { - return this.loginPage !== null; + return this.loginPage; } } diff --git a/javascript-practice/src/js/views/registerView.js b/javascript-practice/src/js/views/registerView.js index b0fb0c0..7470dd2 100644 --- a/javascript-practice/src/js/views/registerView.js +++ b/javascript-practice/src/js/views/registerView.js @@ -1,4 +1,4 @@ -import { TYPE_POPUP } from '../constants/constant'; +import { TYPE_POPUP, MESSAGE, BTN_CONTENT } from '../constants/constant'; import CommonLoginRegisterView from './commonLoginRegisterView'; import User from '../models/user'; @@ -6,7 +6,7 @@ export default class RegisterView extends CommonLoginRegisterView { constructor() { super(); - this.registerPage = document.getElementById('registerPage'); + this.registerPage = document.URL.includes('/register'); } /** @@ -50,12 +50,11 @@ export default class RegisterView extends CommonLoginRegisterView { * Implement error popup in site * @param {string} content The content will show in error popup */ - initErrorPopup(content) { - const typePopup = TYPE_POPUP.error; - const title = 'Error'; - const btnContent = 'Got it!'; + initErrorPopup(error) { + const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP; + const content = error.message ? error.message : error; - this.initPopupContent(typePopup, title, content, btnContent); + this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.OK); // Show popup this.tooglePopupForm(); @@ -86,7 +85,7 @@ export default class RegisterView extends CommonLoginRegisterView { // Check user exist const userExist = await checkExistUser(user.email); if (userExist) { - throw Error('User is exists! Please try another email!'); + throw Error(MESSAGE.USER_EXIST_ERROR); } else { await saveUser(user); // Show popup success @@ -103,6 +102,6 @@ export default class RegisterView extends CommonLoginRegisterView { } isRegisterPage() { - return this.registerPage !== null; + return this.registerPage; } } diff --git a/javascript-practice/src/pages/login.html b/javascript-practice/src/pages/login.html index c502e11..bef7925 100644 --- a/javascript-practice/src/pages/login.html +++ b/javascript-practice/src/pages/login.html @@ -7,7 +7,7 @@ Login - Money Lover -
+
Register - Money Lover -
+
Date: Wed, 6 Sep 2023 09:00:56 +0700 Subject: [PATCH 5/6] Change method code --- javascript-practice/src/js/helpers/helpers.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js index c4300e9..7bb705a 100644 --- a/javascript-practice/src/js/helpers/helpers.js +++ b/javascript-practice/src/js/helpers/helpers.js @@ -58,9 +58,7 @@ export const convertModelToDataObject = (model) => { }; export const convertDataObjectToModel = (data) => { - const model = data.data; + const { id, ...object } = data; - model.id = data.id; - - return model; + return { id, ...object.data }; }; From 2978ace46e870ea409c9b5c796ff139092064783 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Wed, 6 Sep 2023 09:22:02 +0700 Subject: [PATCH 6/6] Refactor, format code and add comments on function --- .../src/js/services/userService.js | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index 216bf9f..86bf3fc 100644 --- a/javascript-practice/src/js/services/userService.js +++ b/javascript-practice/src/js/services/userService.js @@ -46,27 +46,35 @@ export default class UserService extends CommonService { return null; } + /** + * Validate user info + * @param {string} email The email user input + * @param {*} password The password user input + * @returns {boolean} Return true if match info on database, otherwise return false + */ async validateUser(email, password) { const user = await this.getUserByEmail(email); - if (user) { - // Check password - if (user.password === password) { - // Create token for user - await this.createTokenUser(email); + // Check password + if (user && user.password === password) { + // Create token for user + await this.createTokenUser(email); - return true; - } - return false; + return true; } + return false; } + /** + * Create token for user on database + * @param {string} email The email user need to be create token + */ async createTokenUser(email) { const user = await this.getUserByEmail(email); + const newUserData = user; // Add token to user object - const newUserData = user; newUserData.accessToken = createToken(); this.save(newUserData); }