From 2469b5c7b5f6efedbe7a880f6cf0b5ace49b06e5 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 12 Sep 2023 09:40:06 +0700 Subject: [PATCH 1/4] Refactor services, view project --- .../src/js/services/{service.js => index.js} | 0 .../src/js/services/userService.js | 4 +- .../src/js/views/commonLoginRegisterView.js | 18 +-- .../src/js/views/commonView.js | 118 +++++++++--------- javascript-practice/src/js/views/homeView.js | 90 +++++++++++++ javascript-practice/src/js/views/index.js | 22 ++++ javascript-practice/src/js/views/loginView.js | 38 +++--- .../src/js/views/registerView.js | 47 ++++--- javascript-practice/src/js/views/view.js | 9 -- 9 files changed, 226 insertions(+), 120 deletions(-) rename javascript-practice/src/js/services/{service.js => index.js} (100%) create mode 100644 javascript-practice/src/js/views/homeView.js create mode 100644 javascript-practice/src/js/views/index.js delete mode 100644 javascript-practice/src/js/views/view.js 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 9821641..511d7ba 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 1e5dcf3..5003978 100644 --- a/javascript-practice/src/js/views/commonLoginRegisterView.js +++ b/javascript-practice/src/js/views/commonLoginRegisterView.js @@ -1,5 +1,5 @@ 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 { @@ -7,7 +7,7 @@ export default class CommonLoginRegisterView extends CommonView { super(); 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"]', @@ -24,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'); } @@ -49,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(); } } @@ -68,7 +68,11 @@ export default class CommonLoginRegisterView extends CommonView { */ showError(message) { this.renderError(message); - this.toogleErrorStyleInputPass(); + this.toggleErrorStyleInputPass(); + } + + toggleDialog() { + this.dialog.classList.toggle('active'); } /** diff --git a/javascript-practice/src/js/views/commonView.js b/javascript-practice/src/js/views/commonView.js index 083f01f..636c55c 100644 --- a/javascript-practice/src/js/views/commonView.js +++ b/javascript-practice/src/js/views/commonView.js @@ -1,102 +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.handleEventBtnPopupAndOverlay(); + 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 - */ - tooglePopupForm() { - this.overlay.classList.toggle('active'); - this.modalBox.classList.toggle('active'); - } - - /** - * Add popup content - * @param {TYPE_POPUP} typePopup Type of the popup - * @param {string} title Title of popup - * @param {string} content Content of 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 */ - 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) + 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 popup if haved - this.popupIcon.classList.forEach((classItem) => + // Remove old icon toast if haved + this.toastIcon.classList.forEach((classItem) => classItem === MARK_ICON.success || classItem === MARK_ICON.error - ? this.popupIcon.classList.remove(classItem) + ? this.toastIcon.classList.remove(classItem) : '', ); - // Init content popup - this.modalBox.classList.add( - typePopup === TYPE_POPUP.success ? TYPE_POPUP.success : TYPE_POPUP.error, + // Init content toast + this.toast.classList.add( + typeToast === TYPE_TOAST.success ? TYPE_TOAST.success : TYPE_TOAST.error, ); - this.popupIcon.classList.add( - typePopup === TYPE_POPUP.success ? MARK_ICON.success : MARK_ICON.error, + this.toastIcon.classList.add( + typeToast === TYPE_TOAST.success ? MARK_ICON.success : MARK_ICON.error, ); - this.popupTitle.textContent = title; - this.popupContent.textContent = content; - this.popupBtn.textContent = btnContent; + this.toastTitle.textContent = title; + this.toastContent.textContent = content; + this.toastBtn.textContent = btnContent; } /** - * Add event listener for popup and overlay + * Add event listener for toast */ - handleEventBtnPopupAndOverlay() { - this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this)); - this.overlay.addEventListener('click', this.tooglePopupForm.bind(this)); + handleEventToast() { + this.toastBtn.addEventListener('click', () => { + this.toastDialog.close(); + }); + + // 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 new file mode 100644 index 0000000..08f7637 --- /dev/null +++ b/javascript-practice/src/js/views/homeView.js @@ -0,0 +1,90 @@ +import CommonView from './commonView'; + +export default class HomeView extends CommonView { + constructor() { + super(); + + this.tabs = document.querySelectorAll('.app__tab-item'); + this.allContent = document.querySelectorAll('.app__content-item'); + this.addTransactionBtn = document.getElementById('addTransaction'); + this.addBudgetBtn = document.getElementById('addBudget'); + this.dialogs = document.querySelectorAll('.dialog'); + this.cancelBtn = document.querySelectorAll('.form__cancel-btn'); + this.categoryField = document.getElementById('selectCategory'); + this.closeIcon = document.querySelector('.close-icon'); + + this.budgetDialog = document.getElementById('budgetDialog'); + this.transactionDialog = document.getElementById('transactionDialog'); + this.categoryDialog = document.getElementById('categoryDialog'); + } + + /** + * Handle event when click on tabs + */ + handlerTabsTransfer() { + this.tabs.forEach((tab, index) => { + tab.addEventListener('click', (e) => { + this.removeActiveTab(); + tab.classList.add('active'); + + const line = document.querySelector('.app__line'); + line.style.width = `${e.target.offsetWidth}px`; + line.style.left = `${e.target.offsetLeft}px`; + + this.allContent.forEach((content) => { + content.classList.remove('active'); + }); + this.allContent[index].classList.add('active'); + }); + }); + } + + addCommonEventPage() { + // 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.addTransactionBtn.addEventListener('click', () => { + this.transactionDialog.showModal(); + }); + + this.addBudgetBtn.addEventListener('click', () => { + this.budgetDialog.showModal(); + }); + } + + addEventSelectCategoryDialog() { + this.categoryField.addEventListener('click', () => { + this.categoryDialog.showModal(); + }); + + this.closeIcon.addEventListener('click', () => { + this.categoryDialog.close(); + }); + } + + removeActiveTab() { + this.tabs.forEach((tab) => { + 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/index.js b/javascript-practice/src/js/views/index.js new file mode 100644 index 0000000..a2f11d2 --- /dev/null +++ b/javascript-practice/src/js/views/index.js @@ -0,0 +1,22 @@ +import RegisterView from './registerView'; +import LoginView from './loginView'; +import { getSubdirectoryURL } from '../helpers/helpers'; +import { URL } from '../constants/variable'; +import HomeView from './homeView'; + +export default class View { + constructor() { + switch (getSubdirectoryURL()) { + case URL.LOGIN: + this.loginView = new LoginView(); + break; + case URL.REGISTER: + this.registerView = new RegisterView(); + break; + case URL.HOME: + this.homeView = new HomeView(); + break; + default: + } + } +} diff --git a/javascript-practice/src/js/views/loginView.js b/javascript-practice/src/js/views/loginView.js index 0733561..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.loginPage = document.URL.includes('/login'); + 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,14 +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(); - } - - isLoginPage() { - return this.loginPage; + this.toggleLoaderSpinner(); } } diff --git a/javascript-practice/src/js/views/registerView.js b/javascript-practice/src/js/views/registerView.js index 7470dd2..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.registerPage = document.URL.includes('/register'); + 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,20 +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(); - } - - isRegisterPage() { - return this.registerPage; + this.toggleLoaderSpinner(); } } diff --git a/javascript-practice/src/js/views/view.js b/javascript-practice/src/js/views/view.js deleted file mode 100644 index 333d0a7..0000000 --- a/javascript-practice/src/js/views/view.js +++ /dev/null @@ -1,9 +0,0 @@ -import RegisterView from './registerView'; -import LoginView from './loginView'; - -export default class View { - constructor() { - this.registerView = new RegisterView(); - this.loginView = new LoginView(); - } -} From df391452375070aa401075283be73d5728bfaafc Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 12 Sep 2023 11:30:50 +0700 Subject: [PATCH 2/4] Merge branch from feat/javascript-practice --- javascript-practice/src/js/helpers/helpers.js | 5 ++--- javascript-practice/src/js/services/userService.js | 2 +- javascript-practice/src/js/views/commonView.js | 2 +- javascript-practice/src/js/views/index.js | 2 +- javascript-practice/src/js/views/loginView.js | 2 +- javascript-practice/src/js/views/registerView.js | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js index 54b8fd5..97b5146 100644 --- a/javascript-practice/src/js/helpers/helpers.js +++ b/javascript-practice/src/js/helpers/helpers.js @@ -1,7 +1,6 @@ import * as MESSAGE from '../constants/message'; -import { TIME_OUT_SEC } from '../constants/config'; +import { TIME_OUT_SEC, REGEX } from '../constants/config'; import FirebaseService from '../services/firebaseService'; -import { REGEX_PASSWORD } from '../constants/variable'; /** * Validate password @@ -9,7 +8,7 @@ import { REGEX_PASSWORD } from '../constants/variable'; * @returns {boolean} Return true if validate password success, otherwise return false */ export const validatePassword = (password) => { - return REGEX_PASSWORD.test(password); + return REGEX.PASSWORD.test(password); }; /** diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js index 511d7ba..75698e1 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/variable'; +import { LOCAL_STORAGE } from '../constants/config'; import { createToken } from '../helpers/helpers'; import CommonService from './commonService'; import LocalStorageService from './localStorageService'; diff --git a/javascript-practice/src/js/views/commonView.js b/javascript-practice/src/js/views/commonView.js index 636c55c..02ceef2 100644 --- a/javascript-practice/src/js/views/commonView.js +++ b/javascript-practice/src/js/views/commonView.js @@ -1,4 +1,4 @@ -import { MARK_ICON, TYPE_TOAST } from '../constants/variable'; +import { MARK_ICON, TYPE_TOAST } from '../constants/config'; export default class CommonView { constructor() { diff --git a/javascript-practice/src/js/views/index.js b/javascript-practice/src/js/views/index.js index a2f11d2..b7a43f5 100644 --- a/javascript-practice/src/js/views/index.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/variable'; +import { URL } from '../constants/config'; 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 3fe4d49..fb2800f 100644 --- a/javascript-practice/src/js/views/loginView.js +++ b/javascript-practice/src/js/views/loginView.js @@ -1,5 +1,5 @@ import CommonLoginRegisterView from './commonLoginRegisterView'; -import { TYPE_TOAST, BTN_CONTENT } from '../constants/variable'; +import { TYPE_TOAST, BTN_CONTENT } from '../constants/config'; import * as MESSAGE from '../constants/message'; export default class LoginView extends CommonLoginRegisterView { diff --git a/javascript-practice/src/js/views/registerView.js b/javascript-practice/src/js/views/registerView.js index cea6bcc..327433d 100644 --- a/javascript-practice/src/js/views/registerView.js +++ b/javascript-practice/src/js/views/registerView.js @@ -1,4 +1,4 @@ -import { TYPE_TOAST, BTN_CONTENT } from '../constants/variable'; +import { TYPE_TOAST, BTN_CONTENT } from '../constants/config'; import * as MESSAGE from '../constants/message'; import CommonLoginRegisterView from './commonLoginRegisterView'; import User from '../models/user'; From 9760d369175e6c84164f3e48f9430f858fdda32d Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 12 Sep 2023 15:34:32 +0700 Subject: [PATCH 3/4] Optimized code --- .../src/js/views/commonView.js | 30 ++++++++++--------- javascript-practice/src/js/views/homeView.js | 15 ++++++++-- javascript-practice/src/pages/index.html | 2 +- .../src/styles/pages/_index.scss | 12 ++++++-- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/javascript-practice/src/js/views/commonView.js b/javascript-practice/src/js/views/commonView.js index 02ceef2..f329ae3 100644 --- a/javascript-practice/src/js/views/commonView.js +++ b/javascript-practice/src/js/views/commonView.js @@ -34,10 +34,10 @@ export default class CommonView { 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'); + this.toastIcon = this.toast.querySelector('.mark'); + this.toastBtn = this.toast.querySelector('.toast__redirect-btn'); + this.toastTitle = this.toast.querySelector('.toast__title'); + this.toastContent = this.toast.querySelector('.toast__message'); } /** @@ -56,18 +56,14 @@ export default class CommonView { */ 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) - : '', - ); + Object.keys(TYPE_TOAST).forEach((value) => { + CommonView.removeClassElement(value, this.toast); + }); // Remove old icon toast if haved - this.toastIcon.classList.forEach((classItem) => - classItem === MARK_ICON.success || classItem === MARK_ICON.error - ? this.toastIcon.classList.remove(classItem) - : '', - ); + Object.keys(MARK_ICON).forEach((value) => { + CommonView.removeClassElement(value, this.toastIcon); + }); // Init content toast this.toast.classList.add( @@ -81,6 +77,12 @@ export default class CommonView { this.toastBtn.textContent = btnContent; } + static removeClassElement(classEl, el) { + if (el.classList.contains(classEl)) { + el.classList.remove(classEl); + } + } + /** * Add event listener for toast */ diff --git a/javascript-practice/src/js/views/homeView.js b/javascript-practice/src/js/views/homeView.js index 08f7637..0e585de 100644 --- a/javascript-practice/src/js/views/homeView.js +++ b/javascript-practice/src/js/views/homeView.js @@ -23,13 +23,17 @@ export default class HomeView extends CommonView { */ handlerTabsTransfer() { this.tabs.forEach((tab, index) => { - tab.addEventListener('click', (e) => { + tab.addEventListener('click', () => { this.removeActiveTab(); tab.classList.add('active'); const line = document.querySelector('.app__line'); - line.style.width = `${e.target.offsetWidth}px`; - line.style.left = `${e.target.offsetLeft}px`; + + if (line.classList.contains('left')) { + HomeView.replaceClassElement('left', 'right', line); + } else { + HomeView.replaceClassElement('right', 'left', line); + } this.allContent.forEach((content) => { content.classList.remove('active'); @@ -39,6 +43,11 @@ export default class HomeView extends CommonView { }); } + static replaceClassElement(oldEl, newEl, el) { + el.classList.remove(oldEl); + el.classList.add(newEl); + } + addCommonEventPage() { // Add event close dialog when click outside this.dialogs.forEach((dialog) => { diff --git a/javascript-practice/src/pages/index.html b/javascript-practice/src/pages/index.html index 125e10f..840adc0 100644 --- a/javascript-practice/src/pages/index.html +++ b/javascript-practice/src/pages/index.html @@ -299,7 +299,7 @@
-
+
diff --git a/javascript-practice/src/styles/pages/_index.scss b/javascript-practice/src/styles/pages/_index.scss index 868a1ad..0605974 100644 --- a/javascript-practice/src/styles/pages/_index.scss +++ b/javascript-practice/src/styles/pages/_index.scss @@ -109,12 +109,20 @@ &__line { position: absolute; top: 66px; - left: 150px; - width: 115px; height: 2px; background-color: $primary-color; border-radius: 10px; transition: all 0.3s ease-in-out; + + &.left { + left: 152px; + width: 116px; + } + + &.right { + left: 272px; + width: 200px; + } } } From 0144cf404624a020adb5318106000e17b889d9d6 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 12 Sep 2023 16:34:08 +0700 Subject: [PATCH 4/4] Update code --- javascript-practice/src/js/views/homeView.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/javascript-practice/src/js/views/homeView.js b/javascript-practice/src/js/views/homeView.js index 0e585de..0496b0b 100644 --- a/javascript-practice/src/js/views/homeView.js +++ b/javascript-practice/src/js/views/homeView.js @@ -9,7 +9,6 @@ export default class HomeView extends CommonView { this.addTransactionBtn = document.getElementById('addTransaction'); this.addBudgetBtn = document.getElementById('addBudget'); this.dialogs = document.querySelectorAll('.dialog'); - this.cancelBtn = document.querySelectorAll('.form__cancel-btn'); this.categoryField = document.getElementById('selectCategory'); this.closeIcon = document.querySelector('.close-icon'); @@ -29,11 +28,8 @@ export default class HomeView extends CommonView { const line = document.querySelector('.app__line'); - if (line.classList.contains('left')) { - HomeView.replaceClassElement('left', 'right', line); - } else { - HomeView.replaceClassElement('right', 'left', line); - } + line.classList.toggle('right', line.classList.contains('left')); + line.classList.toggle('left', !line.classList.contains('right')); this.allContent.forEach((content) => { content.classList.remove('active'); @@ -43,11 +39,6 @@ export default class HomeView extends CommonView { }); } - static replaceClassElement(oldEl, newEl, el) { - el.classList.remove(oldEl); - el.classList.add(newEl); - } - addCommonEventPage() { // Add event close dialog when click outside this.dialogs.forEach((dialog) => {