diff --git a/javascript-practice/src/js/constants/config.js b/javascript-practice/src/js/constants/config.js
index 07b138e..f027b92 100644
--- a/javascript-practice/src/js/constants/config.js
+++ b/javascript-practice/src/js/constants/config.js
@@ -23,14 +23,16 @@ export const DEFAULT_CATEGORY = {
INCOME: 'Income',
};
+export const REMOVE_CATEGORY = ['Income'];
+
export const DAY = [
+ 'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
- 'Sunday',
];
export const MONTH = [
@@ -54,4 +56,6 @@ export const MARK_ICON = { success: 'check', error: 'error' };
export const REGEX = {
PASSWORD:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
+ EMAIL:
+ /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
};
diff --git a/javascript-practice/src/js/constants/message.js b/javascript-practice/src/js/constants/message.js
index 7902312..6a4bad3 100644
--- a/javascript-practice/src/js/constants/message.js
+++ b/javascript-practice/src/js/constants/message.js
@@ -1,9 +1,9 @@
-export const PASSWORD_NOT_MATCH = 'Password not match! Please try again!';
+export const PASSWORD_NOT_MATCH = 'Password not match!';
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 ERROR_MESSAGE_DEFAULT = ['Something went wrong!'];
export const TIME_OUT_ERROR = 'Connection time out! Please try again!';
@@ -21,3 +21,11 @@ export const ADD_WALLET_SUCCESS = 'Add wallet success!';
export const DEFAULT_MESSAGE = 'Press OK to continue!';
export const ADD_TRANSACTION_SUCCESS = 'Add success!';
+
+export const UPDATE_TRANSACTION_SUCCESS = 'Update success!';
+
+export const REGISTER_SUCCESS = 'Register Success';
+
+export const REQUIRED_MESSAGE = (field) => `The ${field} is required!`;
+
+export const INVALID_EMAIL_FORMAT = `The email is not correct!`;
diff --git a/javascript-practice/src/js/controllers/homeController.js b/javascript-practice/src/js/controllers/homeController.js
index a846768..e08905c 100644
--- a/javascript-practice/src/js/controllers/homeController.js
+++ b/javascript-practice/src/js/controllers/homeController.js
@@ -10,10 +10,6 @@ export default class HomeController {
return this.service.userService.getInfoUserLogin();
}
- handlerCheckWalletValid(idUser) {
- return this.service.walletService.isValidWallet(idUser);
- }
-
handlerGetWalletUser(idUser) {
return this.service.walletService.getWalletByIdUser(idUser);
}
@@ -46,7 +42,6 @@ export default class HomeController {
if (this.homeView) {
this.homeView.initFunction(
this.handlerGetInfoUserLogin.bind(this),
- this.handlerCheckWalletValid.bind(this),
this.handlerGetWalletUser.bind(this),
this.handlerGetAllCategory.bind(this),
this.handlerGetAllTransactions.bind(this),
diff --git a/javascript-practice/src/js/helpers/helpers.js b/javascript-practice/src/js/helpers/helpers.js
index 7b44388..7027169 100644
--- a/javascript-practice/src/js/helpers/helpers.js
+++ b/javascript-practice/src/js/helpers/helpers.js
@@ -7,10 +7,18 @@ import FirebaseService from '../services/firebaseService';
* @param {string} password Password input
* @returns {boolean} Return true if validate password success, otherwise return false
*/
-export const isValidatePassword = (password) => {
+export const isValidPassword = (password) => {
return REGEX.PASSWORD.test(password);
};
+export const isValidateEmail = (email) => {
+ return String(email).toLowerCase().match(REGEX.EMAIL);
+};
+
+export const compare2Password = (password, passwordConfirm) => {
+ return password === passwordConfirm;
+};
+
/**
* A waiting function with s second
* @param {number} s The time will be waiting
@@ -85,7 +93,7 @@ export const formatNumber = (number) => {
export const changeDateFormat = (oldFormatDate) => {
const tempDate = new Date(oldFormatDate);
- const day = DAY[tempDate.getDay() - 1];
+ const day = DAY[tempDate.getDay()];
const date = tempDate.getDate();
const month = MONTH[tempDate.getMonth()];
const year = tempDate.getFullYear();
@@ -105,9 +113,7 @@ export const createTransactionDetailObject = (category, transactions) => {
return amount;
};
const listTransaction = () => {
- const results = [];
-
- transactions.forEach((transaction) => {
+ const results = transactions.map((transaction) => {
const dateParts = changeDateFormat(transaction.date).split(','); // ['Monday', '14', 'September', '2023']
const day = dateParts[1];
const fullDateString = `${dateParts[0]}, ${dateParts[2]} ${dateParts[3]}`;
@@ -119,7 +125,7 @@ export const createTransactionDetailObject = (category, transactions) => {
amount: transaction.amount,
};
- results.push(tempData);
+ return tempData;
});
results.sort((a, b) => parseInt(b.id, 10) - parseInt(a.id, 10));
@@ -153,3 +159,15 @@ export const getAllTransactionByCategoryName = (categoryName, transactions) => {
return results;
};
+
+export const renderRequiredText = (field, element) => {
+ const markup = `
+
${MESSAGE.REQUIRED_MESSAGE(field)}
+ `;
+
+ element.insertAdjacentHTML('afterend', markup);
+};
+
+export const redirectToLoginPage = () => {
+ window.location.replace('/login');
+};
diff --git a/javascript-practice/src/js/services/categoryService.js b/javascript-practice/src/js/services/categoryService.js
index c0d48a3..a8c39ab 100644
--- a/javascript-practice/src/js/services/categoryService.js
+++ b/javascript-practice/src/js/services/categoryService.js
@@ -10,14 +10,11 @@ export default class CategoryService extends CommonService {
async getAllCategory() {
const data = await this.getAllDataFromPath(this.defaultPath);
- const listCategory = [];
if (data) {
- data.forEach((category) => {
- listCategory.unshift(new Category(category));
+ return data.reverse().map((category) => {
+ return new Category(category);
});
-
- return listCategory;
}
return null;
diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js
index e4cdf98..eb3d611 100644
--- a/javascript-practice/src/js/services/commonService.js
+++ b/javascript-practice/src/js/services/commonService.js
@@ -69,15 +69,12 @@ export default class CommonService {
const results = await timeOutConnect(
this.firebaseService.getAllDataFromPath(path),
);
- const listData = [];
if (results) {
// Convert format object
- results.forEach((data) => {
- listData.push(convertDataObjectToModel(data));
+ return results.map((data) => {
+ return convertDataObjectToModel(data);
});
-
- return listData;
}
return null;
@@ -89,15 +86,12 @@ export default class CommonService {
const results = await timeOutConnect(
this.firebaseService.getListDataFromProp(path, property, value),
);
- const listData = [];
-
if (results) {
// Convert format object
- results.forEach((data) => {
- listData.push(convertDataObjectToModel(data));
- });
- return listData;
+ return results.map((data) => {
+ return convertDataObjectToModel(data);
+ });
}
return null;
diff --git a/javascript-practice/src/js/services/transactionService.js b/javascript-practice/src/js/services/transactionService.js
index e923435..5fc7ab8 100644
--- a/javascript-practice/src/js/services/transactionService.js
+++ b/javascript-practice/src/js/services/transactionService.js
@@ -22,11 +22,7 @@ export default class TransactionService extends CommonService {
this.defaultPath,
);
- if (results) {
- return results;
- }
-
- return null;
+ return results || null;
}
async deleteTransaction(idTransaction) {
diff --git a/javascript-practice/src/js/services/userService.js b/javascript-practice/src/js/services/userService.js
index b31d63a..79ea404 100644
--- a/javascript-practice/src/js/services/userService.js
+++ b/javascript-practice/src/js/services/userService.js
@@ -26,11 +26,7 @@ export default class UserService extends CommonService {
async isValidUser(email) {
const userExist = await this.getUserByEmail(email);
- if (userExist) {
- return true;
- }
-
- return false;
+ return !!userExist;
}
/**
@@ -41,11 +37,7 @@ export default class UserService extends CommonService {
async getUserByEmail(email) {
const result = await this.getDataFromProp('email', email);
- if (result) {
- return result;
- }
-
- return null;
+ return result || null;
}
/**
@@ -117,11 +109,7 @@ export default class UserService extends CommonService {
async getUserByToken(accessToken) {
const result = await this.getDataFromProp('accessToken', accessToken);
- if (result) {
- return result;
- }
-
- return null;
+ return result || null;
}
static clearAccessToken() {
diff --git a/javascript-practice/src/js/services/walletService.js b/javascript-practice/src/js/services/walletService.js
index 614c42f..7092e11 100644
--- a/javascript-practice/src/js/services/walletService.js
+++ b/javascript-practice/src/js/services/walletService.js
@@ -23,11 +23,7 @@ export default class WalletService extends CommonService {
async isValidWallet(idUser) {
const wallet = await this.getWalletByIdUser(idUser);
- if (wallet) {
- return true;
- }
-
- return false;
+ return !!wallet;
}
/**
@@ -38,10 +34,6 @@ export default class WalletService extends CommonService {
async getWalletByIdUser(idUser) {
const result = await this.getDataFromProp('idUser', idUser);
- if (result) {
- return result;
- }
-
- return null;
+ return result || null;
}
}
diff --git a/javascript-practice/src/js/views/authenticationView.js b/javascript-practice/src/js/views/authenticationView.js
new file mode 100644
index 0000000..29a3fbc
--- /dev/null
+++ b/javascript-practice/src/js/views/authenticationView.js
@@ -0,0 +1,155 @@
+import CommonView from './commonView';
+import * as MESSAGE from '../constants/message';
+import {
+ compare2Password,
+ isValidPassword,
+ isValidateEmail,
+ renderRequiredText,
+} from '../helpers/helpers';
+
+export default class AuthenticationView extends CommonView {
+ constructor() {
+ super();
+
+ this.parentElement = document.querySelector('.form');
+ this.emailEl = document.querySelector("[name='email']");
+ this.messageDefault = MESSAGE.ERROR_MESSAGE_DEFAULT;
+ this.inputPasswordEl = document.querySelector('input[name="password"]');
+ this.inputPasswordConfirmEl = document.querySelector(
+ 'input[name="password_confirm"]',
+ );
+
+ this.listError = [];
+ }
+
+ /**
+ * 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
+ */
+ // isValidateAccount(account) {
+ // if (account.password === account.passwordConfirm) {
+ // if (isValidPassword(account.passwordConfirm)) {
+ // return true;
+ // }
+ // this.showError(MESSAGE.PASSWORD_NOT_STRONG);
+ // return false;
+ // }
+ // this.showError(MESSAGE.PASSWORD_NOT_MATCH);
+ // return false;
+ // }
+
+ // eslint-disable-next-line class-methods-use-this
+ validateEmail(email) {
+ if (email) {
+ if (!isValidateEmail(email)) {
+ this.listError.push(MESSAGE.INVALID_EMAIL_FORMAT);
+
+ return false;
+ }
+ return true;
+ }
+
+ renderRequiredText('email', this.emailEl);
+ return false;
+ }
+
+ validatePassword(password) {
+ if (password) {
+ if (!isValidPassword(password)) {
+ this.listError.push(MESSAGE.PASSWORD_NOT_STRONG);
+
+ return false;
+ }
+
+ return true;
+ }
+ renderRequiredText('password', this.inputPasswordEl);
+
+ return false;
+ }
+
+ validatePasswordConfirm(password, passwordConfirm) {
+ if (passwordConfirm) {
+ if (!compare2Password(password, passwordConfirm)) {
+ this.listError.push(MESSAGE.PASSWORD_NOT_MATCH);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ renderRequiredText('confirm password', this.inputPasswordConfirmEl);
+
+ return false;
+ }
+
+ /**
+ * Clear error message at form
+ */
+ clearErrorMessage() {
+ // Reassign again to check error message element haved on page or not
+ this.errorMessageEl = document.querySelector('.form__error-message');
+ this.errorTextEl = document.querySelectorAll('.error-text');
+
+ // If have error message on page, remove it with style error input password
+ if (this.errorMessageEl || this.errorTextEl.length > 0) {
+ if (this.errorMessageEl) this.errorMessageEl.remove();
+
+ if (this.errorTextEl) {
+ this.errorTextEl.forEach((item) => {
+ item.remove();
+ });
+ }
+ this.emailEl.classList.remove('error-input');
+ this.inputPasswordEl.classList.remove('error-input');
+
+ if (this.inputPasswordConfirmEl)
+ this.inputPasswordConfirmEl.classList.remove('error-input');
+ }
+ }
+
+ /**
+ * Add event listener for input field at form
+ */
+ addHandlerInputFormChange() {
+ this.parentElement.addEventListener('input', () => {
+ this.clearErrorMessage();
+ });
+ }
+
+ /**
+ * Show error message with error style input password.
+ * @param {string} message The error message you want show in form.
+ */
+ showError(message) {
+ this.renderError(message);
+ }
+
+ toggleDialog() {
+ this.dialog.classList.toggle('active');
+ }
+
+ /**
+ * Show error message in form
+ * @param {string} message The message will show in form
+ */
+ renderError(messages = this.messageDefault) {
+ if (messages.length > 0) {
+ const messageItemMarkup = messages
+ .map((message) => `${message}`)
+ .join('\n');
+
+ const markup = `
+
+ `;
+
+ document
+ .querySelector('.form__title')
+ .insertAdjacentHTML('afterend', markup);
+ }
+ }
+}
diff --git a/javascript-practice/src/js/views/commonLoginRegisterView.js b/javascript-practice/src/js/views/commonLoginRegisterView.js
deleted file mode 100644
index 5a598a6..0000000
--- a/javascript-practice/src/js/views/commonLoginRegisterView.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import CommonView from './commonView';
-import * as MESSAGE from '../constants/message';
-import { isValidatePassword } from '../helpers/helpers';
-
-export default class CommonLoginRegisterView extends CommonView {
- constructor() {
- super();
-
- this.parentElement = document.querySelector('.form');
- this.messageDefault = MESSAGE.ERROR_MESSAGE_DEFAULT;
- this.inputPassword = document.querySelector('input[name="password"]');
- this.inputPasswordConfirm = document.querySelector(
- 'input[name="password_confirm"]',
- );
- }
-
- /**
- * 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
- */
- isValidateAccount(account) {
- if (account.password === account.passwordConfirm) {
- if (isValidatePassword(account.passwordConfirm)) {
- return true;
- }
- this.showError(MESSAGE.PASSWORD_NOT_STRONG);
- return false;
- }
- this.showError(MESSAGE.PASSWORD_NOT_MATCH);
- return false;
- }
-
- /**
- * Show or hide style error input password
- */
- toggleErrorStyleInputPass() {
- this.inputPassword.classList.toggle('error-input');
- this.inputPasswordConfirm.classList.toggle('error-input');
- }
-
- /**
- * Clear error message at form
- */
- clearErrorMessage() {
- // Reassign again to check error message element haved on page or not
- this.errorMessageEl = document.querySelector('.form__error-message');
-
- // If have error message on page, remove it with style error input password
- if (this.errorMessageEl) {
- this.errorMessageEl.remove();
- this.toggleErrorStyleInputPass();
- }
- }
-
- /**
- * Add event listener for input field at form
- */
- addHandlerInputFormChange() {
- this.parentElement.addEventListener('input', () => {
- this.clearErrorMessage();
- });
- }
-
- /**
- * Show error message with error style input password.
- * @param {string} message The error message you want show in form.
- */
- showError(message) {
- this.renderError(message);
- this.toggleErrorStyleInputPass();
- }
-
- toggleDialog() {
- this.dialog.classList.toggle('active');
- }
-
- /**
- * Show error message in form
- * @param {string} message The message will show in form
- */
- renderError(message = this.messageDefault) {
- const markup = `
- ${message}
- `;
-
- document
- .querySelector('.form__title')
- .insertAdjacentHTML('afterend', markup);
- }
-}
diff --git a/javascript-practice/src/js/views/homeView.js b/javascript-practice/src/js/views/homeView.js
index bd2c6b6..ad8908e 100644
--- a/javascript-practice/src/js/views/homeView.js
+++ b/javascript-practice/src/js/views/homeView.js
@@ -4,6 +4,7 @@ import {
BTN_CONTENT,
DEFAULT_CATEGORY,
FIRST_ADD_WALLET_NOTE,
+ REMOVE_CATEGORY,
} from '../constants/config';
import * as MESSAGE from '../constants/message';
import CommonView from './commonView';
@@ -14,6 +15,7 @@ import {
formatNumber,
getAllCategoryNameInTransactions,
getAllTransactionByCategoryName,
+ renderRequiredText,
} from '../helpers/helpers';
import defaultCategoryIcon from '../../assets/images/question-icon.svg';
@@ -44,7 +46,6 @@ export default class HomeView extends CommonView {
initFunction(
getInfoUserLogin,
- isValidWallet,
getWalletByIdUser,
getAllCategory,
getAllTransactions,
@@ -54,7 +55,6 @@ export default class HomeView extends CommonView {
deleteTransaction,
) {
this.getInfoUserLogin = getInfoUserLogin;
- this.isValidWallet = isValidWallet;
this.getWalletByIdUser = getWalletByIdUser;
this.getAllCategory = getAllCategory;
this.getAllTransactions = getAllTransactions;
@@ -75,14 +75,15 @@ export default class HomeView extends CommonView {
window.location.replace('/login');
} else {
this.user = user;
- const wallet = await this.isValidWallet(user.id);
+ this.wallet = await this.getWalletByIdUser(user.id);
// Check user's wallet if have or not
- if (!wallet) {
+ if (!this.wallet) {
// Show add wallet dialog
this.walletDialog.showModal();
} else {
// Init data
+ await this.loadTransactionData();
await this.loadData();
// Load event page
@@ -95,7 +96,6 @@ export default class HomeView extends CommonView {
async loadData() {
await this.loadWalletUser();
- await this.loadTransactionData();
this.loadSummaryTab();
await this.loadTransactionTab();
}
@@ -126,17 +126,26 @@ export default class HomeView extends CommonView {
this.saveWallet(this.wallet);
}
- async updateAmountWallet(amount) {
- if (amount >= 0) {
- this.wallet.inflow += amount;
- } else {
- this.wallet.outflow += amount;
- }
+ async updateAmountWallet() {
+ let inflow = 0;
+ let outflow = 0;
+
+ // Init data first
+ this.transactionDetails = this.loadTransactionDetailsData();
+
+ this.transactionDetails.forEach((transaction) => {
+ if (transaction.totalAmount >= 0) {
+ inflow += transaction.totalAmount;
+ } else {
+ outflow -= transaction.totalAmount;
+ }
+ });
+
+ // Reassign value for wallet user;
+ this.wallet.inflow = inflow;
+ this.wallet.outflow = -outflow;
await this.saveWallet(this.wallet);
-
- // Reload data
- await this.loadData();
}
/**
@@ -144,10 +153,12 @@ export default class HomeView extends CommonView {
* @param {function} getAllCategory Get all category function
*/
async loadCategory() {
- this.listCategory = await this.getAllCategory();
+ if (!this.listCategory) {
+ this.listCategory = await this.getAllCategory();
+ }
if (this.listCategory) {
- this.renderCategoryItem();
+ this.renderCategoryList();
}
}
@@ -176,15 +187,16 @@ export default class HomeView extends CommonView {
await this.loadCategory();
// Init data first
- const transactionDetails = this.loadTransactionDetailsData();
+ this.transactionDetails = this.loadTransactionDetailsData();
+
const transactionEl = document.querySelector('.transaction');
const listTransactionDetailEl =
transactionEl.querySelector('.transaction__list');
const markup = [];
- if (transactionDetails) {
- transactionDetails.forEach((transactionDetail) => {
+ if (this.transactionDetails) {
+ this.transactionDetails.forEach((transactionDetail) => {
markup.push(this.transactionDetailMarkup(transactionDetail));
});
}
@@ -203,9 +215,7 @@ export default class HomeView extends CommonView {
);
// Create transactions details object
- const tempList = [];
-
- listCategoryInTransaction.forEach((categoryName) => {
+ const tempList = listCategoryInTransaction.map((categoryName) => {
// Get category object from list category has been loaded.
const category = this.listCategory.filter(
(item) => item.name === categoryName,
@@ -216,11 +226,9 @@ export default class HomeView extends CommonView {
this.listTransactions,
);
- tempList.push(
- createTransactionDetailObject(
- Object.assign({}, ...category),
- transactions,
- ),
+ return createTransactionDetailObject(
+ Object.assign({}, ...category),
+ transactions,
);
});
@@ -300,27 +308,35 @@ export default class HomeView extends CommonView {
handlerEventTransactionDialog() {
this.transactionDialog.addEventListener('submit', (e) => {
e.preventDefault();
+ this.clearErrorTransactionDialog();
this.submitTransactionDialog();
- this.transactionDialog.close();
});
this.transactionDialog.addEventListener('input', () => {
- const dateInput = this.transactionDialog.querySelector(
- "[name='selected_date']",
- ).value;
- const categoryName = this.transactionDialog.querySelector(
- "[name='category_name']",
- ).value;
- const amountInput =
- this.transactionDialog.querySelector("[name='amount']").value;
- const saveBtn = this.transactionDialog.querySelector('.form__save-btn');
-
- saveBtn.classList.toggle(
- 'active',
- dateInput && categoryName && amountInput >= 1,
- );
+ this.changeBtnStyleTransactionDialog();
+ this.clearErrorTransactionDialog();
});
+ // Add delete transaction event
+ this.deleteTransactionEvent();
+ }
+
+ clearErrorTransactionDialog() {
+ // Clear error style
+ const inputFieldEls =
+ this.transactionDialog.querySelectorAll('.form__input-field');
+ const errorTextEls = this.transactionDialog.querySelectorAll('.error-text');
+
+ inputFieldEls.forEach((item) => {
+ if (item.classList.contains('error-input'))
+ item.classList.remove('error-input');
+ });
+ errorTextEls.forEach((item) => {
+ if (item) item.remove();
+ });
+ }
+
+ deleteTransactionEvent() {
const deleteTransactionBtn =
this.transactionDialog.querySelector('.form__delete-btn');
@@ -336,9 +352,11 @@ export default class HomeView extends CommonView {
await this.deleteTransaction(idEl.value);
- this.showSuccessToast('Delete success!', MESSAGE.DEFAULT_MESSAGE);
-
+ // Reload data
+ await this.loadTransactionData();
await this.loadData();
+
+ this.showSuccessToast('Delete success!', MESSAGE.DEFAULT_MESSAGE);
} catch (error) {
this.showErrorToast(error);
}
@@ -347,6 +365,23 @@ export default class HomeView extends CommonView {
});
}
+ changeBtnStyleTransactionDialog() {
+ const dateInput = this.transactionDialog.querySelector(
+ "[name='selected_date']",
+ ).value;
+ const categoryName = this.transactionDialog.querySelector(
+ "[name='category_name']",
+ ).value;
+ const amountInput =
+ this.transactionDialog.querySelector("[name='amount']").value;
+ const saveBtn = this.transactionDialog.querySelector('.form__save-btn');
+
+ saveBtn.classList.toggle(
+ 'active',
+ dateInput && categoryName && amountInput >= 1,
+ );
+ }
+
initDataTransactionDialog(idTransaction) {
const transactionArr = this.listTransactions.filter(
(obj) => obj.id === idTransaction,
@@ -379,8 +414,6 @@ export default class HomeView extends CommonView {
}
async submitTransactionDialog() {
- this.toggleLoaderSpinner();
-
try {
const dateEl = this.transactionForm.querySelector(
"[name='selected_date']",
@@ -393,43 +426,87 @@ export default class HomeView extends CommonView {
const idEl = this.transactionForm.querySelector(
"[name='id_transaction']",
);
- const transaction = new Transaction({
- id: idEl.value,
- categoryName: categoryNameEl.value,
- date: dateEl.value,
- amount: -+amountEl.value,
- note: noteEl.value,
- idUser: this.wallet.idUser,
- });
+ const amount =
+ categoryNameEl.value === 'Income' ? +amountEl.value : -+amountEl.value; // Check if this is a income transaction, amount must plus
- await this.saveTransaction(transaction);
+ // Validate data user input
+ if (
+ this.validateTransactionForm(dateEl.value, categoryNameEl.value, amount)
+ ) {
+ this.toggleLoaderSpinner();
+ this.transactionDialog.close();
- // Reload data
- await this.loadData();
- this.updateAmountWallet(-+amountEl.value);
+ const transaction = new Transaction({
+ id: idEl.value,
+ categoryName: categoryNameEl.value,
+ date: dateEl.value,
+ amount,
+ note: noteEl.value,
+ idUser: this.wallet.idUser,
+ });
- this.showSuccessToast(
- MESSAGE.ADD_TRANSACTION_SUCCESS,
- MESSAGE.DEFAULT_MESSAGE,
- );
+ await this.saveTransaction(transaction);
- this.clearInputTransactionForm(this.transactionForm);
+ // Reload data
+ await this.loadTransactionData();
+ this.updateAmountWallet();
+ await this.loadData();
+
+ if (!idEl.value) {
+ // Add success
+ this.showSuccessToast(
+ MESSAGE.ADD_TRANSACTION_SUCCESS,
+ MESSAGE.DEFAULT_MESSAGE,
+ );
+ } else {
+ // Update success
+ this.showSuccessToast(
+ MESSAGE.UPDATE_TRANSACTION_SUCCESS,
+ MESSAGE.DEFAULT_MESSAGE,
+ );
+ }
+
+ this.toggleLoaderSpinner();
+ this.clearInputTransactionForm(this.transactionForm);
+ }
} catch (error) {
this.showErrorToast(error);
+ this.toggleLoaderSpinner();
+ }
+ }
+
+ validateTransactionForm(date, categoryName, amount) {
+ const inputFieldEls =
+ this.transactionDialog.querySelectorAll('.form__input-field');
+
+ if (!date || !categoryName || !amount) {
+ if (!date) {
+ renderRequiredText('date', inputFieldEls[0]);
+ inputFieldEls[0].classList.add('error-input');
+ }
+
+ if (!categoryName) {
+ renderRequiredText('category', inputFieldEls[1]);
+ inputFieldEls[1].classList.add('error-input');
+ }
+
+ if (!amount) {
+ renderRequiredText('amount', inputFieldEls[2]);
+ inputFieldEls[2].classList.add('error-input');
+ }
+
+ return false;
}
- this.toggleLoaderSpinner();
+ return true;
}
clearInputTransactionForm() {
const categoryIcon = this.transactionForm.querySelector('.category-icon');
categoryIcon.src = defaultCategoryIcon;
-
this.keySearchCategory = null; // Delete keyword search
-
- this.renderCategoryItem(this.keySearchCategory);
-
+ this.renderCategoryList(this.keySearchCategory);
this.transactionForm.reset();
}
// ---------------------END DIALOG---------------------//
@@ -462,15 +539,20 @@ export default class HomeView extends CommonView {
}
// Render category item
- this.renderCategoryItem(this.keySearchCategory, newListCategory);
+ this.renderCategoryList(this.keySearchCategory, newListCategory);
}
- renderCategoryItem(categorySelected, listCategory = this.listCategory) {
+ renderCategoryList(categorySelected, listCategory = this.listCategory) {
+ // Remove category name unnecessary
+ const newListCategory = listCategory.filter(
+ (item) => !REMOVE_CATEGORY.includes(item.name),
+ );
+
const listCategoryEl = document.querySelector('.list-category');
listCategoryEl.innerHTML = ''; // Remove old category item
- listCategory.forEach((category) => {
+ newListCategory.forEach((category) => {
const markup = `