diff --git a/javascript-practice/src/js/app.js b/javascript-practice/src/js/app.js index 80e6a3e..5f951bf 100644 --- a/javascript-practice/src/js/app.js +++ b/javascript-practice/src/js/app.js @@ -1,6 +1,6 @@ -import Controller from './controllers/controller'; -import Service from './services/service'; -import View from './views/view'; +import Controller from './controllers/index'; +import Service from './services/index'; +import View from './views/index'; import 'regenerator-runtime/runtime'; import 'core-js/stable'; diff --git a/javascript-practice/src/js/constants/config.js b/javascript-practice/src/js/constants/config.js index 8a88e89..4950d70 100644 --- a/javascript-practice/src/js/constants/config.js +++ b/javascript-practice/src/js/constants/config.js @@ -1,5 +1,3 @@ export const DATABASE_URL = 'https://javascript-training-81f7a-default-rtdb.asia-southeast1.firebasedatabase.app'; export const TIME_OUT_SEC = 3; -export const REGEX_PASSWORD = - /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; diff --git a/javascript-practice/src/js/constants/constant.js b/javascript-practice/src/js/constants/constant.js deleted file mode 100644 index e9dbaac..0000000 --- a/javascript-practice/src/js/constants/constant.js +++ /dev/null @@ -1,36 +0,0 @@ -export const MESSAGE = { - PASSWORD_NOT_MATCH: 'Password not match! Please try again!', - PASSWORD_NOT_STRONG: - '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: { - 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!', - WELCOME: { - title: 'Login Successful!', - message: 'Welcome to Money Lover!', - }, -}; - -export const URL = { - LOGIN: 'login', - REGISTER: 'register', - HOME: '', -}; - -export const BTN_CONTENT = { - GOT_IT: 'Got it!', - OK: 'Ok', -}; - -export const LOCAL_STORAGE = { - ACCESS_TOKEN: 'accessToken', - IS_FIRST_LOGIN: 'isFirstLogin', -}; - -export const TYPE_POPUP = { success: 'success', error: 'error' }; -export const MARK_ICON = { success: 'check', error: 'error' }; diff --git a/javascript-practice/src/js/constants/message.js b/javascript-practice/src/js/constants/message.js new file mode 100644 index 0000000..b0e7995 --- /dev/null +++ b/javascript-practice/src/js/constants/message.js @@ -0,0 +1,17 @@ +export const PASSWORD_NOT_MATCH = 'Password not match! Please try again!'; + +export const PASSWORD_NOT_STRONG = + 'Password must at least one uppercase, one lowercase letter, one number and one special character!'; + +export const ERROR_MESSAGE_DEFAULT = 'Something went wrong!'; + +export const TIME_OUT_ERROR = 'Connection time out! Please try again!'; + +export const ERROR_CREDENTIAL = { + title: 'Error Credential', + message: 'Email or password not match! Please try again!', +}; + +export const DEFAULT_TITLE_ERROR_TOAST = 'Error'; + +export const USER_EXIST_ERROR = 'User is exists! Please try another email!'; diff --git a/javascript-practice/src/js/constants/variable.js b/javascript-practice/src/js/constants/variable.js new file mode 100644 index 0000000..423aaef --- /dev/null +++ b/javascript-practice/src/js/constants/variable.js @@ -0,0 +1,20 @@ +export const URL = { + LOGIN: 'login', + REGISTER: 'register', + HOME: '', +}; + +export const BTN_CONTENT = { + GOT_IT: 'Got it!', + OK: 'Ok', +}; + +export const LOCAL_STORAGE = { + ACCESS_TOKEN: 'accessToken', +}; + +export const TYPE_TOAST = { success: 'success', error: 'error' }; +export const MARK_ICON = { success: 'check', error: 'error' }; + +export const REGEX_PASSWORD = + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; diff --git a/javascript-practice/src/js/controllers/controller.js b/javascript-practice/src/js/controllers/index.js similarity index 100% rename from javascript-practice/src/js/controllers/controller.js rename to javascript-practice/src/js/controllers/index.js diff --git a/javascript-practice/src/js/controllers/loginController.js b/javascript-practice/src/js/controllers/loginController.js index 59b3d4c..12a1117 100644 --- a/javascript-practice/src/js/controllers/loginController.js +++ b/javascript-practice/src/js/controllers/loginController.js @@ -4,13 +4,13 @@ export default class LoginController { this.loginView = view.loginView; } - handlerValidateUser(email, password) { - return this.service.userService.validateUser(email, password); + handlerLoginUser(email, password) { + return this.service.userService.loginUser(email, password); } init() { if (this.loginView) { - this.loginView.addHandlerForm(this.handlerValidateUser.bind(this)); + this.loginView.addHandlerForm(this.handlerLoginUser.bind(this)); } } } diff --git a/javascript-practice/src/js/controllers/registerController.js b/javascript-practice/src/js/controllers/registerController.js index ea7ee41..0722299 100644 --- a/javascript-practice/src/js/controllers/registerController.js +++ b/javascript-practice/src/js/controllers/registerController.js @@ -4,7 +4,7 @@ export default class RegisterController { this.service = service; } - hanlderCheckUserExist(email) { + handlerCheckUserExist(email) { return this.service.userService.checkUserExist(email); } @@ -15,7 +15,7 @@ export default class RegisterController { init() { if (this.registerView) { this.registerView.addHandlerForm( - this.hanlderCheckUserExist.bind(this), + this.handlerCheckUserExist.bind(this), this.handlerSaveUser.bind(this), ); this.registerView.addHandlerInputFormChange(); diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js index c8a8a72..46c44fe 100644 --- a/javascript-practice/src/js/helpers/helpers.js +++ b/javascript-practice/src/js/helpers/helpers.js @@ -1,6 +1,7 @@ -import { MESSAGE } from '../constants/constant'; -import { REGEX_PASSWORD, TIME_OUT_SEC } from '../constants/config'; +import * as MESSAGE from '../constants/message'; +import { TIME_OUT_SEC } from '../constants/config'; import FirebaseService from '../services/firebaseService'; +import { REGEX_PASSWORD } from '../constants/variable'; /** * Validate password @@ -70,6 +71,7 @@ export const getSubdirectoryURL = () => { const subDirectory = parts[3]; // Get subdirectory url only + // Remove query behind subDirectory const index = subDirectory.indexOf('?'); if (index !== -1) { return subDirectory.substring(0, index); diff --git a/javascript-practice/src/js/services/service.js b/javascript-practice/src/js/services/index.js similarity index 100% rename from javascript-practice/src/js/services/service.js rename to javascript-practice/src/js/services/index.js diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index 6a07c1b..692fb76 100644 --- a/javascript-practice/src/js/services/userService.js +++ b/javascript-practice/src/js/services/userService.js @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE } from '../constants/constant'; +import { LOCAL_STORAGE } from '../constants/variable'; import { createToken } from '../helpers/helpers'; import CommonService from './commonService'; import LocalStorageService from './localStorageService'; @@ -54,7 +54,7 @@ export default class UserService extends CommonService { * @param {*} password The password user input * @returns {boolean} Return true if match info on database, otherwise return false */ - async validateUser(email, password) { + async loginUser(email, password) { const user = await this.getUserByEmail(email); // Check password diff --git a/javascript-practice/src/js/views/commonLoginRegisterView.js b/javascript-practice/src/js/views/commonLoginRegisterView.js index a58683b..5003978 100644 --- a/javascript-practice/src/js/views/commonLoginRegisterView.js +++ b/javascript-practice/src/js/views/commonLoginRegisterView.js @@ -1,15 +1,13 @@ import CommonView from './commonView'; -import * as CONSTANT from '../constants/constant'; +import * as MESSAGE from '../constants/message'; import { validatePassword } from '../helpers/helpers'; export default class CommonLoginRegisterView extends CommonView { constructor() { super(); - this.handleEventBtnPopupAndOverlay(); - this.parentElement = document.querySelector('.form'); - this.messageDefault = CONSTANT.MESSAGE.ERROR_MESSAGE_DEFAULT; + this.messageDefault = MESSAGE.ERROR_MESSAGE_DEFAULT; this.inputPassword = document.querySelector('input[name="password"]'); this.inputPasswordConfirm = document.querySelector( 'input[name="password_confirm"]', @@ -26,17 +24,17 @@ export default class CommonLoginRegisterView extends CommonView { if (validatePassword(account.passwordConfirm)) { return true; } - this.showError(CONSTANT.MESSAGE.PASSWORD_NOT_STRONG); + this.showError(MESSAGE.PASSWORD_NOT_STRONG); return false; } - this.showError(CONSTANT.MESSAGE.PASSWORD_NOT_MATCH); + this.showError(MESSAGE.PASSWORD_NOT_MATCH); return false; } /** * Show or hide style error input password */ - toogleErrorStyleInputPass() { + toggleErrorStyleInputPass() { this.inputPassword.classList.toggle('error-input'); this.inputPasswordConfirm.classList.toggle('error-input'); } @@ -51,7 +49,7 @@ export default class CommonLoginRegisterView extends CommonView { // If have error message on page, remove it with style error input password if (this.errorMessageEl) { this.errorMessageEl.remove(); - this.toogleErrorStyleInputPass(); + this.toggleErrorStyleInputPass(); } } @@ -70,7 +68,11 @@ export default class CommonLoginRegisterView extends CommonView { */ showError(message) { this.renderError(message); - this.toogleErrorStyleInputPass(); + this.toggleErrorStyleInputPass(); + } + + toggleDialog() { + this.dialog.classList.toggle('active'); } /** @@ -86,16 +88,4 @@ export default class CommonLoginRegisterView extends CommonView { .querySelector('.form__title') .insertAdjacentHTML('afterend', markup); } - - /** - * Add event listener for popup and overlay - */ - handleEventBtnPopupAndOverlay() { - this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this)); - this.overlay.addEventListener('click', this.toogleDialog.bind(this)); - } - - toogleDialog() { - this.dialog.classList.toggle('active'); - } } diff --git a/javascript-practice/src/js/views/commonView.js b/javascript-practice/src/js/views/commonView.js index d83153f..636c55c 100644 --- a/javascript-practice/src/js/views/commonView.js +++ b/javascript-practice/src/js/views/commonView.js @@ -1,93 +1,106 @@ -import { MARK_ICON, TYPE_POPUP } from '../constants/constant'; +import { MARK_ICON, TYPE_TOAST } from '../constants/variable'; export default class CommonView { constructor() { - this.overlayMarkup = '
'; - - this.initPopup(); - this.initElementPopup(); + this.initToast(); + this.initElementToast(); this.initLoader(); + this.handleEventToast(); } /** - * Implement popup in site + * Implement toast in site */ - initPopup() { + initToast() { this.rootElement = document.querySelector('body'); const markup = ` - ${this.overlayMarkup} - + +
+
+

+

+ +
+
`; this.rootElement.insertAdjacentHTML('afterbegin', markup); } /** - * Assgign element in popup to property + * Assign element in toast to property */ - initElementPopup() { - this.modalBox = document.querySelector('.modal-box'); - this.popupIcon = document.querySelector('.mark'); - this.popupBtn = document.querySelector('.modal-box__redirect-btn'); - this.popupTitle = document.querySelector('.modal-box__title'); - this.popupContent = document.querySelector('.modal-box__message'); - this.overlay = document.querySelector('.overlay'); + initElementToast() { + this.toastDialog = document.querySelector('.dialog'); + this.toast = document.querySelector('.toast'); + this.toastIcon = document.querySelector('.mark'); + this.toastBtn = document.querySelector('.toast__redirect-btn'); + this.toastTitle = document.querySelector('.toast__title'); + this.toastContent = document.querySelector('.toast__message'); } /** * Show or hide loader screen */ - toogleLoaderSpinner() { + toggleLoaderSpinner() { this.spinner.classList.toggle('hidden'); } /** - * Show or hide popup + * Add toast content + * @param {TYPE_TOAST} typeToast Type of the toast + * @param {string} title Title of toast + * @param {string} content Content of toast + * @param {string} btnContent Content of button */ - tooglePopupForm() { - this.overlay.classList.toggle('active'); - this.modalBox.classList.toggle('active'); + initToastContent(typeToast, title, content, btnContent) { + // Remove old typeToast class if haved + this.toast.classList.forEach((classItem) => + classItem === TYPE_TOAST.success || classItem === TYPE_TOAST.error + ? this.toast.classList.remove(classItem) + : '', + ); + + // Remove old icon toast if haved + this.toastIcon.classList.forEach((classItem) => + classItem === MARK_ICON.success || classItem === MARK_ICON.error + ? this.toastIcon.classList.remove(classItem) + : '', + ); + + // Init content toast + this.toast.classList.add( + typeToast === TYPE_TOAST.success ? TYPE_TOAST.success : TYPE_TOAST.error, + ); + this.toastIcon.classList.add( + typeToast === TYPE_TOAST.success ? MARK_ICON.success : MARK_ICON.error, + ); + this.toastTitle.textContent = title; + this.toastContent.textContent = content; + this.toastBtn.textContent = btnContent; } /** - * 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 + * Add event listener for toast */ - initPopupContent(typePopup, title, content, btnContent) { - // Remove old typePopup class if haved - this.modalBox.classList.forEach((classItem) => - classItem === TYPE_POPUP.success || classItem === TYPE_POPUP.error - ? this.modalBox.classList.remove(classItem) - : '', - ); + handleEventToast() { + this.toastBtn.addEventListener('click', () => { + this.toastDialog.close(); + }); - // Remove old icon popup if haved - this.popupIcon.classList.forEach((classItem) => - classItem === MARK_ICON.success || classItem === MARK_ICON.error - ? this.popupIcon.classList.remove(classItem) - : '', - ); - - // Init content popup - this.modalBox.classList.add( - typePopup === TYPE_POPUP.success ? TYPE_POPUP.success : TYPE_POPUP.error, - ); - this.popupIcon.classList.add( - typePopup === TYPE_POPUP.success ? MARK_ICON.success : MARK_ICON.error, - ); - this.popupTitle.textContent = title; - this.popupContent.textContent = content; - this.popupBtn.textContent = btnContent; + // Add event close dialog when click outside + this.toastDialog.addEventListener('click', (e) => { + const dialogDimensions = this.toastDialog.getBoundingClientRect(); + if ( + e.clientX < dialogDimensions.left || + e.clientX > dialogDimensions.right || + e.clientY < dialogDimensions.top || + e.clientY > dialogDimensions.bottom + ) { + this.toastDialog.close(); + } + }); } /** diff --git a/javascript-practice/src/js/views/homeView.js b/javascript-practice/src/js/views/homeView.js index f9b882f..e5c26bb 100644 --- a/javascript-practice/src/js/views/homeView.js +++ b/javascript-practice/src/js/views/homeView.js @@ -1,4 +1,5 @@ -import { TYPE_POPUP, MESSAGE, BTN_CONTENT } from '../constants/constant'; +import { TYPE_TOAST, BTN_CONTENT } from '../constants/variable'; +import * as MESSAGE from '../constants/message'; import CommonView from './commonView'; import Wallet from '../models/wallet'; @@ -10,19 +11,15 @@ export default class HomeView extends CommonView { this.allContent = document.querySelectorAll('.app__content-item'); this.addTransactionBtn = document.getElementById('addTransaction'); this.addBudgetBtn = document.getElementById('addBudget'); - this.overlay = document.querySelector('.overlay'); - this.darkOverlay = document.querySelector('.dark-overlay'); - this.dialog = document.querySelectorAll('.dialog'); this.saveBtn = document.querySelectorAll('.form__save-btn'); + this.dialogs = document.querySelectorAll('.dialog'); this.cancelBtn = document.querySelectorAll('.form__cancel-btn'); this.categoryField = document.getElementById('selectCategory'); this.closeIcon = document.querySelector('.close-icon'); - this.budgetForm = document.getElementById('budgetForm'); - this.transactionForm = document.getElementById('transactionForm'); - this.categoryForm = document.getElementById('categoryForm'); - this.walletForm = document.getElementById('walletForm'); - + this.budgetDialog = document.getElementById('budgetDialog'); + this.transactionDialog = document.getElementById('transactionDialog'); + this.categoryDialog = document.getElementById('categoryDialog'); this.walletDialog = document.getElementById('walletDialog'); } @@ -38,11 +35,7 @@ export default class HomeView extends CommonView { // Check user's wallet if have or not if (!walletExist) { // Show add wallet dialog - this.walletDialog.classList.add('active'); - // If overlay is not exist on page - if (!this.overlay.classList.contains('active')) { - this.toggleActiveOverlay(); - } + this.walletDialog.showModal(); } else { this.loadEvent(); } @@ -50,7 +43,7 @@ export default class HomeView extends CommonView { } addHandlerSubmitWalletForm(saveWallet) { - this.walletForm.addEventListener('submit', (e) => { + this.walletDialog.addEventListener('submit', (e) => { e.preventDefault(); this.submitWalletForm(saveWallet); @@ -68,16 +61,16 @@ export default class HomeView extends CommonView { await saveWallet(wallet); this.hideDialog(); - this.showSuccessPopup('Add wallet success', 'Click ok to continue!'); + this.showSuccessToast('Add wallet success', 'Click ok to continue!'); this.loadEvent(); } catch (error) { - // Show popup error - this.initErrorPopup(error); + // Show toast error + this.initErrorToast(error); } } addHandlerInputChangeWalletForm() { - this.walletForm.addEventListener('input', (e) => { + this.walletDialog.addEventListener('input', (e) => { const bodyDialog = e.target.closest('.dialog__body'); this.validateWalletForm(bodyDialog); }); @@ -95,28 +88,27 @@ export default class HomeView extends CommonView { } } - showSuccessPopup(title, message) { - const typePopup = TYPE_POPUP.success; + showSuccessToast(title, message) { + const typeToast = TYPE_TOAST.success; const btnContent = BTN_CONTENT.OK; - this.initPopupContent(typePopup, title, message, btnContent); + this.initToastContent(typeToast, title, message, btnContent); - // Show popup - this.tooglePopupForm(); + this.dialogToast.showModal(); } /** - * Implement error popup in site - * @param {string} content The content will show in error popup + * Implement error toast in site + * @param {string} content The content will show in error toast */ - initErrorPopup(error) { - const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP; + initErrorToast(error) { + const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_TOAST; const content = error.message ? error.message : error; - this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.GOT_IT); + this.initToastContent(TYPE_TOAST.error, title, content, BTN_CONTENT.GOT_IT); - // Show popup - this.tooglePopupForm(); + // Show toast + this.toggleToastForm(); } /* ------------------------------- HANDLER EVENT ------------------------------- */ @@ -149,66 +141,38 @@ export default class HomeView extends CommonView { } addCommonEventPage() { - this.addTransactionBtn.addEventListener('click', () => { - this.transactionForm.classList.add('active'); - this.toggleActiveOverlay(); - }); - - this.addBudgetBtn.addEventListener('click', () => { - this.budgetForm.classList.add('active'); - this.toggleActiveOverlay(); - }); - - this.cancelBtn.forEach((item) => { - item.addEventListener('click', () => { - this.hideDialog(); + // Add event close dialog when click outside + this.dialogs.forEach((dialog) => { + dialog.addEventListener('click', (e) => { + const dialogDimensions = dialog.getBoundingClientRect(); + if ( + e.clientX < dialogDimensions.left || + e.clientX > dialogDimensions.right || + e.clientY < dialogDimensions.top || + e.clientY > dialogDimensions.bottom + ) { + dialog.close(); + } }); }); - this.overlay.addEventListener('click', () => { - this.hideDialog(); + this.addTransactionBtn.addEventListener('click', () => { + this.transactionDialog.showModal(); }); - this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this)); + this.addBudgetBtn.addEventListener('click', () => { + this.budgetDialog.showModal(); + }); } addEventSelectCategoryDialog() { this.categoryField.addEventListener('click', () => { - this.categoryForm.classList.add('active'); - this.toggleDarkOverlayActive(); + this.categoryDialog.showModal(); }); - this.closeIcon.addEventListener( - 'click', - this.hideSelectCategoryForm.bind(this), - ); - - this.darkOverlay.addEventListener( - 'click', - this.hideSelectCategoryForm.bind(this), - ); - } - - hideSelectCategoryForm() { - this.categoryForm.classList.remove('active'); - this.toggleDarkOverlayActive(); - } - - toggleDarkOverlayActive() { - this.darkOverlay.classList.toggle('active'); - } - - hideDialog() { - this.dialog.forEach((item) => { - if (item.classList.contains('active')) { - item.classList.remove('active'); - } + this.closeIcon.addEventListener('click', () => { + this.categoryDialog.close(); }); - this.toggleActiveOverlay(); - } - - toggleActiveOverlay() { - this.overlay.classList.toggle('active'); } removeActiveTab() { @@ -216,4 +180,12 @@ export default class HomeView extends CommonView { tab.classList.remove('active'); }); } + + toggleDialog() { + this.dialog.forEach((item) => { + if (item.classList.contains('active')) { + item.classList.remove('active'); + } + }); + } } diff --git a/javascript-practice/src/js/views/view.js b/javascript-practice/src/js/views/index.js similarity index 92% rename from javascript-practice/src/js/views/view.js rename to javascript-practice/src/js/views/index.js index 684b193..a2f11d2 100644 --- a/javascript-practice/src/js/views/view.js +++ b/javascript-practice/src/js/views/index.js @@ -1,7 +1,7 @@ import RegisterView from './registerView'; import LoginView from './loginView'; import { getSubdirectoryURL } from '../helpers/helpers'; -import { URL } from '../constants/constant'; +import { URL } from '../constants/variable'; import HomeView from './homeView'; export default class View { diff --git a/javascript-practice/src/js/views/loginView.js b/javascript-practice/src/js/views/loginView.js index c325955..3fe4d49 100644 --- a/javascript-practice/src/js/views/loginView.js +++ b/javascript-practice/src/js/views/loginView.js @@ -1,12 +1,13 @@ import CommonLoginRegisterView from './commonLoginRegisterView'; -import { MESSAGE, TYPE_POPUP, BTN_CONTENT } from '../constants/constant'; +import { TYPE_TOAST, BTN_CONTENT } from '../constants/variable'; +import * as MESSAGE from '../constants/message'; export default class LoginView extends CommonLoginRegisterView { constructor() { super(); this.parentElement = document.querySelector('.form'); - this.dialog = document.querySelector('.modal-box'); + this.dialog = document.querySelector('.toast'); } /** @@ -24,17 +25,17 @@ export default class LoginView extends CommonLoginRegisterView { } /** - * Implement error popup in site - * @param {string} content The content will show in error popup + * Implement error toast in site + * @param {string} content The content will show in error toast */ - initErrorPopup(error) { - const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP; + initErrorToast(error) { + const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_TOAST; const content = error.message ? error.message : error; - this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.GOT_IT); + this.initToastContent(TYPE_TOAST.error, title, content, BTN_CONTENT.GOT_IT); - // Show popup - this.tooglePopupForm(); + // Show toast + this.toastDialog.showModal(); } /** @@ -51,17 +52,18 @@ export default class LoginView extends CommonLoginRegisterView { /** * The action when submit form - * @param {Function} validateUser The function need to be set event + * @param {Function} loginUser The function need to be set event + * * @param {event} event The event target */ - async submitForm(validateUser, event) { + async submitForm(loginUser, event) { try { // Load spinner - this.toogleLoaderSpinner(); + this.toggleLoaderSpinner(); // Get data from form const userInput = this.getDataFromForm(event); // Check user exist - const results = await validateUser(userInput.email, userInput.password); + const results = await loginUser(userInput.email, userInput.password); if (results) { window.location.replace('/'); @@ -70,10 +72,10 @@ export default class LoginView extends CommonLoginRegisterView { } throw MESSAGE.ERROR_CREDENTIAL; } catch (error) { - // Show popup error - this.initErrorPopup(error); + // Show toast error + this.initErrorToast(error); } // Close spinner - this.toogleLoaderSpinner(); + this.toggleLoaderSpinner(); } } diff --git a/javascript-practice/src/js/views/registerView.js b/javascript-practice/src/js/views/registerView.js index f7a4aed..cea6bcc 100644 --- a/javascript-practice/src/js/views/registerView.js +++ b/javascript-practice/src/js/views/registerView.js @@ -1,4 +1,5 @@ -import { TYPE_POPUP, MESSAGE, BTN_CONTENT } from '../constants/constant'; +import { TYPE_TOAST, BTN_CONTENT } from '../constants/variable'; +import * as MESSAGE from '../constants/message'; import CommonLoginRegisterView from './commonLoginRegisterView'; import User from '../models/user'; @@ -6,7 +7,7 @@ export default class RegisterView extends CommonLoginRegisterView { constructor() { super(); - this.dialog = document.querySelector('.modal-box'); + this.dialog = document.querySelector('.toast'); } /** @@ -32,32 +33,32 @@ export default class RegisterView extends CommonLoginRegisterView { } /** - * Implement register success popup in site + * Implement register success toast in site */ - showRegisterSuccessPopup() { - const typePopup = TYPE_POPUP.success; + showRegisterSuccessToast() { + const typeToast = TYPE_TOAST.success; const title = 'Register Commpleted'; const content = 'Please login to continue!'; const btnContent = 'OK'; - this.initPopupContent(typePopup, title, content, btnContent); + this.initToastContent(typeToast, title, content, btnContent); - // Show popup - this.tooglePopupForm(); + // Show toast + this.toastDialog.showModal(); } /** - * Implement error popup in site - * @param {string} content The content will show in error popup + * Implement error toast in site + * @param {string} content The content will show in error toast */ - initErrorPopup(error) { - const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP; + initErrorToast(error) { + const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_TOAST; const content = error.message ? error.message : error; - this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.OK); + this.initToastContent(TYPE_TOAST.error, title, content, BTN_CONTENT.OK); - // Show popup - this.tooglePopupForm(); + // Show toast + this.toastDialog.showModal(); } /** @@ -75,7 +76,7 @@ export default class RegisterView extends CommonLoginRegisterView { async submitForm(checkExistUser, saveUser) { try { // Load spinner - this.toogleLoaderSpinner(); + this.toggleLoaderSpinner(); // Get data from form const user = this.getDataFromForm(); @@ -88,16 +89,16 @@ export default class RegisterView extends CommonLoginRegisterView { throw Error(MESSAGE.USER_EXIST_ERROR); } else { await saveUser(user); - // Show popup success - this.showRegisterSuccessPopup(); + // Show toast success + this.showRegisterSuccessToast(); } } } catch (error) { - // Show popup error - this.initErrorPopup(error); + // Show toast error + this.initErrorToast(error); } // Close spinner - this.toogleLoaderSpinner(); + this.toggleLoaderSpinner(); } } diff --git a/javascript-practice/src/pages/index.html b/javascript-practice/src/pages/index.html index 492bb2f..c7183ac 100644 --- a/javascript-practice/src/pages/index.html +++ b/javascript-practice/src/pages/index.html @@ -8,16 +8,16 @@ Money Lover Web -
- + +
+
+

Login Success!

+

Welcome to Money Lover!

+ +
+
-
+
@@ -62,10 +62,10 @@
-
+ -
+
@@ -102,16 +102,18 @@ />
- +
- + -
+
@@ -160,20 +162,22 @@ />
- +
- + -
+
-
+
Select category
@@ -268,7 +272,7 @@
- +
@@ -410,89 +414,5 @@ - diff --git a/javascript-practice/src/pages/login.html b/javascript-practice/src/pages/login.html index fe79d78..e759d46 100644 --- a/javascript-practice/src/pages/login.html +++ b/javascript-practice/src/pages/login.html @@ -3,6 +3,7 @@ + Login - Money Lover diff --git a/javascript-practice/src/pages/register.html b/javascript-practice/src/pages/register.html index b0bc1ca..cc41c7f 100644 --- a/javascript-practice/src/pages/register.html +++ b/javascript-practice/src/pages/register.html @@ -3,6 +3,7 @@ + Register - Money Lover diff --git a/javascript-practice/src/styles/_main.scss b/javascript-practice/src/styles/_main.scss index c3a14c5..507659b 100644 --- a/javascript-practice/src/styles/_main.scss +++ b/javascript-practice/src/styles/_main.scss @@ -12,7 +12,7 @@ @import './components/dialog'; @import './components/icons'; @import './components/loader'; -@import './components/popup-form'; +@import './components/toast-form'; // Layouts @import './layouts/header'; diff --git a/javascript-practice/src/styles/components/_dialog.scss b/javascript-practice/src/styles/components/_dialog.scss index 5edd09e..fa741f0 100644 --- a/javascript-practice/src/styles/components/_dialog.scss +++ b/javascript-practice/src/styles/components/_dialog.scss @@ -1,14 +1,9 @@ .dialog { - @extend %d-absolute, %rounded-sm; + @extend %rounded-sm; - left: 50%; - top: 32%; - transform: translate(-50%, -50%) scale(1); + border: none; background-color: $white; - z-index: $zindex-lv-2; - - opacity: 0; - pointer-events: none; + padding: none; transition: all 0.3s ease; &__title { @@ -17,7 +12,17 @@ line-height: 20px; } - &.active { - @extend %active; + &::backdrop { + background-color: rgba($color: #000000, $alpha: 0.2); + } +} + +// Login page +.login-page, +.register-page { + .dialog { + @extend %rounded; + + padding: 0px; } } diff --git a/javascript-practice/src/styles/components/_popup-form.scss b/javascript-practice/src/styles/components/_toast-form.scss similarity index 52% rename from javascript-practice/src/styles/components/_popup-form.scss rename to javascript-practice/src/styles/components/_toast-form.scss index 0617043..60ff0dd 100644 --- a/javascript-practice/src/styles/components/_popup-form.scss +++ b/javascript-practice/src/styles/components/_toast-form.scss @@ -1,19 +1,8 @@ -.modal-box { +.toast { @extend %d-flex; - @extend %d-absolute; @include flex-layout($direction: column, $align: center, $gap: 30px); - left: 50%; - top: 50%; - transform: translate(-50%, -50%) scale(1); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); - z-index: $zindex-lv-2; padding: 40px 50px; - border-radius: 10px; - background-color: $white; - opacity: 0; - pointer-events: none; - transition: all 0.3s ease; &__title { font-size: $fs-2x-lg; @@ -32,17 +21,12 @@ padding: 15px 30px; cursor: pointer; } - - &.active { - opacity: 1; - pointer-events: auto; - } } -.success .modal-box__redirect-btn { +.success .toast__redirect-btn { background-color: $light-primary-color; } -.error .modal-box__redirect-btn { +.error .toast__redirect-btn { background-color: $dark-error-color; }