Fix code according to the comments

This commit is contained in:
2023-09-05 17:33:53 +07:00
parent 51c84a7c82
commit 6f378dcdcf
11 changed files with 111 additions and 94 deletions
@@ -4,7 +4,16 @@ export const MESSAGE = {
'Password must at least one uppercase, one lowercase letter, one number and one special character!', 'Password must at least one uppercase, one lowercase letter, one number and one special character!',
ERROR_MESSAGE_DEFAULT: 'Something went wrong!', ERROR_MESSAGE_DEFAULT: 'Something went wrong!',
TIME_OUT_ERROR: 'Connection time out! Please try again!', 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 TYPE_POPUP = { success: 'success', error: 'error' };
export const MARK_ICON = { success: 'check', error: 'error' }; export const MARK_ICON = { success: 'check', error: 'error' };
@@ -4,20 +4,13 @@ export default class LoginController {
this.loginView = view.loginView; this.loginView = view.loginView;
} }
handlerGetUserByEmail(email) { handlerValidateUser(email, password) {
return this.service.userService.getUserByEmail(email); return this.service.userService.validateUser(email, password);
}
handlerCreateTokenUser(user) {
return this.service.userService.createTokenUser(user);
} }
init() { init() {
if (this.loginView.isLoginPage()) { if (this.loginView.isLoginPage()) {
this.loginView.addHandlerForm( this.loginView.addHandlerForm(this.handlerValidateUser.bind(this));
this.handlerGetUserByEmail.bind(this),
this.handlerCreateTokenUser.bind(this),
);
} }
} }
} }
@@ -50,3 +50,17 @@ export const createToken = () => {
} }
return token; 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;
};
@@ -1,5 +1,6 @@
export default class User { export default class User {
constructor({ email, password, walletName = '' }) { constructor({ email, password, walletName = '' }) {
this.id = User.createIdUser();
this.email = email; this.email = email;
this.password = password; this.password = password;
this.walletName = walletName; this.walletName = walletName;
@@ -1,4 +1,8 @@
import { timeOutConnect } from '../helpers/helpers'; import {
convertDataObjectToModel,
convertModelToDataObject,
timeOutConnect,
} from '../helpers/helpers';
import FirebaseService from './firebaseService'; import FirebaseService from './firebaseService';
export default class CommonService { export default class CommonService {
@@ -14,23 +18,20 @@ export default class CommonService {
this.firebaseService.reconnect(); this.firebaseService.reconnect();
} }
/** async getDataFromProp(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(); this.connectToDb();
const existUser = this.firebaseService.findIdByProperty( const existUser = this.firebaseService.getDataFromProp(
path, path,
property, property,
value, value,
); );
const result = await timeOutConnect(existUser); 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 {*} data The data wants to save on database
* @param {string} path The path of database * @param {string} path The path of database
*/ */
async save(data, path = this.defaultPath) { async save(model) {
this.connectToDb(); 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);
} }
/** /**
@@ -49,22 +49,24 @@ class FirebaseService {
* @param {value} value The value to compare in database * @param {value} value The value to compare in database
* @returns {Promise} Return the relsoves when find completed * @returns {Promise} Return the relsoves when find completed
*/ */
findIdByProperty(path, property, value) { getDataFromProp(path, property, value) {
return new Promise((resolve) => { return new Promise((resolve) => {
onValue( onValue(
ref(this.db, path), ref(this.db, path),
(snapshot) => { (snapshot) => {
let result; let id;
let data;
// snapshot is a type of data by Firebase define // snapshot is a type of data by Firebase define
snapshot.forEach((childSnapshot) => { snapshot.forEach((childSnapshot) => {
const data = childSnapshot.val(); const dataTemp = childSnapshot.val();
if (data[property] === value) { if (dataTemp[property] === value) {
result = childSnapshot.key; id = childSnapshot.key;
data = dataTemp;
} }
}); });
resolve(result); resolve({ id, data });
}, },
{ {
onlyOnce: true, onlyOnce: true,
@@ -1,5 +1,4 @@
import { createToken } from '../helpers/helpers'; import { createToken } from '../helpers/helpers';
import User from '../models/user';
import CommonService from './commonService'; import CommonService from './commonService';
export default class UserService extends 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 * @param {Object} user The user object need to be saved into databae
*/ */
saveUser(user) { saveUser(user) {
const pathData = this.defaultPath + User.createIdUser(); this.save(user);
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);
} }
/** /**
@@ -34,7 +22,7 @@ export default class UserService extends CommonService {
* @returns {boolean} Return true if find, otherwise return false * @returns {boolean} Return true if find, otherwise return false
*/ */
async checkUserExist(email) { async checkUserExist(email) {
const userExist = await this.getUserIdByEmail(email); const userExist = await this.getUserByEmail(email);
if (userExist) { if (userExist) {
return true; return true;
@@ -49,24 +37,37 @@ export default class UserService extends CommonService {
* @returns {Object || null} Return new User Object if find, otherwise return null. * @returns {Object || null} Return new User Object if find, otherwise return null.
*/ */
async getUserByEmail(email) { async getUserByEmail(email) {
const id = await this.getUserIdByEmail(email); const result = await this.getDataFromProp('email', email);
if (id) { if (result) {
const user = await this.getDataFromId(id); return result;
return new User(user);
} }
return null; return null;
} }
async createTokenUser(user) { async validateUser(email, password) {
const id = await this.getUserIdByEmail(user.email); 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 // Add token to user object
const newUserData = new User(user); const newUserData = user;
newUserData.accessToken = createToken(); newUserData.accessToken = createToken();
this.save(newUserData);
this.save(newUserData, this.defaultPath + id);
} }
} }
+18 -26
View File
@@ -1,21 +1,20 @@
import CommonLoginRegisterView from './commonLoginRegisterView'; 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 { export default class LoginView extends CommonLoginRegisterView {
constructor() { constructor() {
super(); super();
this.parentElement = document.querySelector('.form'); this.parentElement = document.querySelector('.form');
this.loginPage = document.getElementById('loginPage'); this.loginPage = document.URL.includes('/login');
} }
/** /**
* Get data from user input * Get data from user input
* @returns {Object || null} Return object or null * @returns {Object || null} Return object or null
*/ */
getDataFromForm() { getDataFromForm(event) {
const { loginForm } = document.forms; const formData = new FormData(event.target);
const formData = new FormData(loginForm);
const email = formData.get('email'); const email = formData.get('email');
const password = formData.get('password'); const password = formData.get('password');
@@ -28,12 +27,11 @@ export default class LoginView extends CommonLoginRegisterView {
* Implement error popup in site * Implement error popup in site
* @param {string} content The content will show in error popup * @param {string} content The content will show in error popup
*/ */
initErrorPopup(content) { initErrorPopup(error) {
const typePopup = CONSTANT.TYPE_POPUP.error; const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP;
const title = 'Error!'; const content = error.message ? error.message : error;
const btnContent = 'Got it!';
this.initPopupContent(typePopup, title, content, btnContent); this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.GOT_IT);
// Show popup // Show popup
this.tooglePopupForm(); this.tooglePopupForm();
@@ -41,42 +39,36 @@ export default class LoginView extends CommonLoginRegisterView {
/** /**
* Add event listener for form input * Add event listener for form input
* @param {Function} getUserByEmail The function need to be set event * @param {Function} validateUser The function need to be set event
* @param {Function} createTokenUser The function need to be set event
*/ */
addHandlerForm(getUserByEmail, createTokenUser) { addHandlerForm(validateUser) {
this.parentElement.addEventListener('submit', (e) => { this.parentElement.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.clearErrorMessage(); this.clearErrorMessage();
this.submitForm(getUserByEmail, createTokenUser); this.submitForm(validateUser, e);
}); });
} }
/** /**
* The action when submit form * The action when submit form
* @param {Function} getUserByEmail The function need to be set event * @param {Function} validateUser The function need to be set event
* @param {Function} createTokenUser The function need to be set event
*/ */
async submitForm(getUserByEmail, createTokenUser) { async submitForm(validateUser, event) {
try { try {
// Load spinner // Load spinner
this.toogleLoaderSpinner(); this.toogleLoaderSpinner();
// Get data from form // Get data from form
const userInput = this.getDataFromForm(); const userInput = this.getDataFromForm(event);
// Check user exist // Check user exist
const user = await getUserByEmail(userInput.email); const results = await validateUser(userInput.email, userInput.password);
if (user) { if (results) {
// If user exist, compare password
if (userInput.password === user.password) {
await createTokenUser(user);
window.location.replace('/'); window.location.replace('/');
return; return;
} }
} throw MESSAGE.ERROR_CREDENTIAL;
throw Error(CONSTANT.MESSAGE.ERROR_CREDENTIAL);
} catch (error) { } catch (error) {
// Show popup error // Show popup error
this.initErrorPopup(error); this.initErrorPopup(error);
@@ -86,6 +78,6 @@ export default class LoginView extends CommonLoginRegisterView {
} }
isLoginPage() { isLoginPage() {
return this.loginPage !== null; return this.loginPage;
} }
} }
@@ -1,4 +1,4 @@
import { TYPE_POPUP } from '../constants/constant'; import { TYPE_POPUP, MESSAGE, BTN_CONTENT } from '../constants/constant';
import CommonLoginRegisterView from './commonLoginRegisterView'; import CommonLoginRegisterView from './commonLoginRegisterView';
import User from '../models/user'; import User from '../models/user';
@@ -6,7 +6,7 @@ export default class RegisterView extends CommonLoginRegisterView {
constructor() { constructor() {
super(); 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 * Implement error popup in site
* @param {string} content The content will show in error popup * @param {string} content The content will show in error popup
*/ */
initErrorPopup(content) { initErrorPopup(error) {
const typePopup = TYPE_POPUP.error; const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP;
const title = 'Error'; const content = error.message ? error.message : error;
const btnContent = 'Got it!';
this.initPopupContent(typePopup, title, content, btnContent); this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.OK);
// Show popup // Show popup
this.tooglePopupForm(); this.tooglePopupForm();
@@ -86,7 +85,7 @@ export default class RegisterView extends CommonLoginRegisterView {
// Check user exist // Check user exist
const userExist = await checkExistUser(user.email); const userExist = await checkExistUser(user.email);
if (userExist) { if (userExist) {
throw Error('User is exists! Please try another email!'); throw Error(MESSAGE.USER_EXIST_ERROR);
} else { } else {
await saveUser(user); await saveUser(user);
// Show popup success // Show popup success
@@ -103,6 +102,6 @@ export default class RegisterView extends CommonLoginRegisterView {
} }
isRegisterPage() { isRegisterPage() {
return this.registerPage !== null; return this.registerPage;
} }
} }
+1 -1
View File
@@ -7,7 +7,7 @@
<title>Login - Money Lover</title> <title>Login - Money Lover</title>
</head> </head>
<body> <body>
<main id="loginPage"> <main>
<div class="background"> <div class="background">
<div class="wrapper"> <div class="wrapper">
<img <img
+1 -1
View File
@@ -7,7 +7,7 @@
<title>Register - Money Lover</title> <title>Register - Money Lover</title>
</head> </head>
<body> <body>
<main id="registerPage"> <main>
<div class="background"> <div class="background">
<div class="wrapper"> <div class="wrapper">
<img <img