mirror of
https://github.com/Nezumi-2711/javascript-training.git
synced 2026-09-22 20:01:31 +00:00
Add comments and rename folder view to views
This commit is contained in:
@@ -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 +0,0 @@
|
|||||||
console.log('Hello World!');
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
+31
-7
@@ -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>`;
|
||||||
|
|
||||||
+48
-7
@@ -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">${
|
||||||
Reference in New Issue
Block a user