Add comments and rename folder view to views

This commit is contained in:
2023-08-30 13:52:36 +07:00
parent 5c76ed4217
commit f7de0d4351
8 changed files with 129 additions and 29 deletions
@@ -3,10 +3,7 @@ export const MESSAGE = {
PASSWORD_NOT_STRONG: PASSWORD_NOT_STRONG:
'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!',
}; };
export const TIME_OUT_ERROR = { export const TYPE_POPUP = { success: 'success', error: 'error' };
status: 408,
message: 'Connection time out! Please try again!',
};
export const TYPE_FORM = { success: 'success', error: 'error' };
export const MARK_ICON = { success: 'check', error: 'error' }; export const MARK_ICON = { success: 'check', error: 'error' };
-1
View File
@@ -1 +0,0 @@
console.log('Hello World!');
+19 -8
View File
@@ -1,26 +1,37 @@
import { TIME_OUT_ERROR } from '../constants/constant'; import { MESSAGE } from '../constants/constant';
import { REGEX_PASSWORD, TIME_OUT_SEC } from '../constants/config'; import { REGEX_PASSWORD, TIME_OUT_SEC } from '../constants/config';
import FirebaseService from '../services/firebaseService'; import FirebaseService from '../services/firebaseService';
/**
* Validate password
* @param {string} password Password input
* @returns {boolean} Return true if validate password success, otherwise return false
*/
export const validatePassword = (password) => { export const validatePassword = (password) => {
return REGEX_PASSWORD.test(password); return REGEX_PASSWORD.test(password);
}; };
/**
* A waiting function with s second
* @param {number} s The time will be waiting
* @returns {Promise} A Promise will be only reject after s second
*/
export const timeout = (s) => { export const timeout = (s) => {
return new Promise((reject) => { return new Promise((_, reject) => {
setTimeout(() => { setTimeout(() => {
reject(TIME_OUT_ERROR); FirebaseService.disconnect();
reject(MESSAGE.TIME_OUT_ERROR);
}, s * 1000); }, s * 1000);
}); });
}; };
/**
* A function waiting the action need to be perform and throw error after s second.
* @param {Function} action The action need to be perform.
* @returns { Object || Error } Return the any object from Firebase or Error
*/
export const timeOutConnect = async (action) => { export const timeOutConnect = async (action) => {
const result = await Promise.race([action, timeout(TIME_OUT_SEC)]); const result = await Promise.race([action, timeout(TIME_OUT_SEC)]);
if (result && result.status === TIME_OUT_ERROR.status) {
FirebaseService.disconnect();
throw new Error(`${result.message}`);
}
return result; return result;
}; };
@@ -12,24 +12,43 @@ import { DATABASE_URL } from '../constants/config';
class FirebaseService { class FirebaseService {
constructor() { constructor() {
const firebaseConfig = { const firebaseConfig = {
databaseUrl: DATABASE_URL, databaseURL: DATABASE_URL,
}; };
this.app = initializeApp(firebaseConfig); this.app = initializeApp(firebaseConfig);
this.db = getDatabase(this.app); this.db = getDatabase(this.app);
} }
/**
* Save data in database
* @param {Object} data The object need to save into database
* @param {string} path The path of database need to be save
* @returns {Promise} Return the relsoves when write to database completed
*/
save(data, path) { save(data, path) {
return set(ref(this.db, path), data); return set(ref(this.db, path), data);
} }
/**
* Disconnect to database
*/
disconnect() { disconnect() {
goOffline(this.db); goOffline(this.db);
} }
/**
* Reconnect to database
*/
reconnect() { reconnect() {
goOnline(this.db); goOnline(this.db);
} }
/**
* Find the key 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) { findKeyByPropery(path, property, value) {
return new Promise((resolve) => { return new Promise((resolve) => {
onValue( onValue(
@@ -7,6 +7,10 @@ export default class UserService {
this.path = 'users/'; this.path = 'users/';
} }
/**
* Save user into database
* @param {Object} user The user object need to be saved into databae
*/
async saveUser(user) { async saveUser(user) {
FirebaseService.reconnect(); FirebaseService.reconnect();
const saveUser = FirebaseService.save( const saveUser = FirebaseService.save(
@@ -16,6 +20,11 @@ export default class UserService {
await timeOutConnect(saveUser); await timeOutConnect(saveUser);
} }
/**
* Check user exist in database by email
* @param {string} email Email need to be check
* @returns {boolean} Return true if email exist and otherwise is false
*/
async checkExistUserByEmail(email) { async checkExistUserByEmail(email) {
FirebaseService.reconnect(); FirebaseService.reconnect();
const existUser = FirebaseService.findKeyByPropery( const existUser = FirebaseService.findKeyByPropery(
@@ -1,4 +1,4 @@
import { MARK_ICON, TYPE_FORM } from '../constants/constant'; import { MARK_ICON, TYPE_POPUP } from '../constants/constant';
export default class CommonView { export default class CommonView {
constructor() { constructor() {
@@ -10,6 +10,9 @@ export default class CommonView {
this.handleEventBtnPopupAndOverlay(); this.handleEventBtnPopupAndOverlay();
} }
/**
* Implement popup in site
*/
initPopup() { initPopup() {
this.rootElement = document.querySelector('body'); this.rootElement = document.querySelector('body');
@@ -27,8 +30,10 @@ export default class CommonView {
this.rootElement.insertAdjacentHTML('afterbegin', markup); this.rootElement.insertAdjacentHTML('afterbegin', markup);
} }
/**
* Assgign element in popup to property
*/
initElementPopup() { initElementPopup() {
// Init element
this.modalBox = document.querySelector('.modal-box'); this.modalBox = document.querySelector('.modal-box');
this.popupIcon = document.querySelector('.mark'); this.popupIcon = document.querySelector('.mark');
this.popupBtn = document.querySelector('.modal-box__redirect-btn'); this.popupBtn = document.querySelector('.modal-box__redirect-btn');
@@ -37,19 +42,32 @@ export default class CommonView {
this.overlay = document.querySelector('.overlay'); this.overlay = document.querySelector('.overlay');
} }
/**
* Show or hide loader screen
*/
toogleLoaderSpinner() { toogleLoaderSpinner() {
this.spinner.classList.toggle('hidden'); this.spinner.classList.toggle('hidden');
} }
/**
* Show or hide popup
*/
tooglePopupForm() { tooglePopupForm() {
this.overlay.classList.toggle('active'); this.overlay.classList.toggle('active');
this.modalBox.classList.toggle('active'); this.modalBox.classList.toggle('active');
} }
initPopupContent(typeForm, title, content, btnContent) { /**
// Remove old typeForm class if haved * Add popup content
* @param {TYPE_POPUP} typePopup Type of the popup
* @param {string} title Title of popup
* @param {string} content Content of popup
* @param {string} btnContent Content of button
*/
initPopupContent(typePopup, title, content, btnContent) {
// Remove old typePopup class if haved
this.modalBox.classList.forEach((classItem) => this.modalBox.classList.forEach((classItem) =>
classItem === TYPE_FORM.success || classItem === TYPE_FORM.error classItem === TYPE_POPUP.success || classItem === TYPE_POPUP.error
? this.modalBox.classList.remove(classItem) ? this.modalBox.classList.remove(classItem)
: '', : '',
); );
@@ -63,21 +81,27 @@ export default class CommonView {
// Init content popup // Init content popup
this.modalBox.classList.add( this.modalBox.classList.add(
typeForm === TYPE_FORM.success ? TYPE_FORM.success : TYPE_FORM.error, typePopup === TYPE_POPUP.success ? TYPE_POPUP.success : TYPE_POPUP.error,
); );
this.popupIcon.classList.add( this.popupIcon.classList.add(
typeForm === TYPE_FORM.success ? MARK_ICON.success : MARK_ICON.error, typePopup === TYPE_POPUP.success ? MARK_ICON.success : MARK_ICON.error,
); );
this.popupTitle.textContent = title; this.popupTitle.textContent = title;
this.popupContent.textContent = content; this.popupContent.textContent = content;
this.popupBtn.textContent = btnContent; this.popupBtn.textContent = btnContent;
} }
/**
* Add event listener for popup and overlay
*/
handleEventBtnPopupAndOverlay() { handleEventBtnPopupAndOverlay() {
this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this)); this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this));
this.overlay.addEventListener('click', this.tooglePopupForm.bind(this)); this.overlay.addEventListener('click', this.tooglePopupForm.bind(this));
} }
/**
* Implement loader screen
*/
initLoader() { initLoader() {
const markup = `<div class="loader hidden"></div>`; const markup = `<div class="loader hidden"></div>`;
@@ -13,7 +13,10 @@ export default class RegisterView extends CommonView {
this.messageDefault = CONSTANT.MESSAGE.ERROR_MESSAGE_DEFAULT; this.messageDefault = CONSTANT.MESSAGE.ERROR_MESSAGE_DEFAULT;
} }
// Function get data from form /**
* Get data from user input
* @returns {Object || null} Return user object or null
*/
getDataFromForm() { getDataFromForm() {
const { registerForm } = document.forms; const { registerForm } = document.forms;
const formData = new FormData(registerForm); const formData = new FormData(registerForm);
@@ -30,6 +33,11 @@ export default class RegisterView extends CommonView {
return null; return null;
} }
/**
* Validate user input data
* @param {Object} account The account object with email, password, passwordConfirm field
* @returns {boolean} Return true if validate success and return false if validate not success
*/
validateForm(account) { validateForm(account) {
if (account.password === account.passwordConfirm) { if (account.password === account.passwordConfirm) {
if (validatePassword(account.passwordConfirm)) { if (validatePassword(account.passwordConfirm)) {
@@ -42,7 +50,10 @@ export default class RegisterView extends CommonView {
return false; return false;
} }
// Handler event submit form /**
* Add event listener for form input
* @param {Function} handler The function need to be set event
*/
addHandlerForm(handler) { addHandlerForm(handler) {
this.parentElement.addEventListener('submit', (e) => { this.parentElement.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
@@ -51,13 +62,20 @@ export default class RegisterView extends CommonView {
}); });
} }
/**
* Show error style input password
*/
changeToStyleErrorInputPassword() { changeToStyleErrorInputPassword() {
// Index = 1 because it should skip email input field
for (let index = 1; index < this.inputField.length; index += 1) { for (let index = 1; index < this.inputField.length; index += 1) {
this.inputField[index].style.background = '#ffc3c3'; this.inputField[index].style.background = '#ffc3c3';
this.inputField[index].style.borderColor = '#ce1414'; this.inputField[index].style.borderColor = '#ce1414';
} }
} }
/**
* Clear error style input password
*/
clearStyleErrorInputPassword() { clearStyleErrorInputPassword() {
for (let index = 1; index < this.inputField.length; index += 1) { for (let index = 1; index < this.inputField.length; index += 1) {
this.inputField[index].style.background = '#f5f5f5'; this.inputField[index].style.background = '#f5f5f5';
@@ -65,11 +83,16 @@ export default class RegisterView extends CommonView {
} }
} }
// Reassign again to check error message element haved on page or not /**
* Reassign again to check error message element haved on page or not
*/
reassignVariableErrorMessage() { reassignVariableErrorMessage() {
this.errorMessage = document.querySelector('.form__error-message'); this.errorMessage = document.querySelector('.form__error-message');
} }
/**
* Clear error message at form
*/
clearErrorMessage() { clearErrorMessage() {
this.reassignVariableErrorMessage(); this.reassignVariableErrorMessage();
@@ -80,34 +103,52 @@ export default class RegisterView extends CommonView {
} }
} }
/**
* Add event listener for input field at form
*/
addHandlerInputFormChange() { addHandlerInputFormChange() {
this.parentElement.addEventListener('input', () => { this.parentElement.addEventListener('input', () => {
this.clearErrorMessage(); this.clearErrorMessage();
}); });
} }
/**
* Show error message with error style input password.
* @param {string} message The error message you want show in form.
*/
showError(message) { showError(message) {
this.renderError(message); this.renderError(message);
this.changeToStyleErrorInputPassword(); this.changeToStyleErrorInputPassword();
} }
/**
* Implement register success popup in site
*/
initRegisterSuccessPopup() { initRegisterSuccessPopup() {
const typeForm = CONSTANT.TYPE_FORM.success; const typePopup = CONSTANT.TYPE_POPUP.success;
const title = 'Register Commpleted'; const title = 'Register Commpleted';
const content = 'Please login to continue!'; const content = 'Please login to continue!';
const btnContent = 'OK'; const btnContent = 'OK';
this.initPopupContent(typeForm, title, content, btnContent); this.initPopupContent(typePopup, title, content, btnContent);
} }
/**
* Implement error popup in site
* @param {string} content The content will show in error popup
*/
initErrorPopup(content) { initErrorPopup(content) {
const typeForm = CONSTANT.TYPE_FORM.error; const typePopup = CONSTANT.TYPE_POPUP.error;
const title = 'Error'; const title = 'Error';
const btnContent = 'Got it!'; const btnContent = 'Got it!';
this.initPopupContent(typeForm, title, content, btnContent); this.initPopupContent(typePopup, title, content, btnContent);
} }
/**
* Show error message in form
* @param {*} message The message will show in form
*/
renderError(message) { renderError(message) {
const markup = ` const markup = `
<p class="form__error-message">${ <p class="form__error-message">${