Change validator style

This commit is contained in:
2023-09-17 19:19:07 +07:00
parent 312a009d00
commit 8b0078d1a1
22 changed files with 746 additions and 428 deletions
@@ -23,14 +23,16 @@ export const DEFAULT_CATEGORY = {
INCOME: 'Income', INCOME: 'Income',
}; };
export const REMOVE_CATEGORY = ['Income'];
export const DAY = [ export const DAY = [
'Sunday',
'Monday', 'Monday',
'Tuesday', 'Tuesday',
'Wednesday', 'Wednesday',
'Thursday', 'Thursday',
'Friday', 'Friday',
'Saturday', 'Saturday',
'Sunday',
]; ];
export const MONTH = [ export const MONTH = [
@@ -54,4 +56,6 @@ export const MARK_ICON = { success: 'check', error: 'error' };
export const REGEX = { export const REGEX = {
PASSWORD: PASSWORD:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, /^(?=.*[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,}))$/,
}; };
@@ -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 = export const 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!';
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!'; 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 DEFAULT_MESSAGE = 'Press OK to continue!';
export const ADD_TRANSACTION_SUCCESS = 'Add success!'; 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!`;
@@ -10,10 +10,6 @@ export default class HomeController {
return this.service.userService.getInfoUserLogin(); return this.service.userService.getInfoUserLogin();
} }
handlerCheckWalletValid(idUser) {
return this.service.walletService.isValidWallet(idUser);
}
handlerGetWalletUser(idUser) { handlerGetWalletUser(idUser) {
return this.service.walletService.getWalletByIdUser(idUser); return this.service.walletService.getWalletByIdUser(idUser);
} }
@@ -46,7 +42,6 @@ export default class HomeController {
if (this.homeView) { if (this.homeView) {
this.homeView.initFunction( this.homeView.initFunction(
this.handlerGetInfoUserLogin.bind(this), this.handlerGetInfoUserLogin.bind(this),
this.handlerCheckWalletValid.bind(this),
this.handlerGetWalletUser.bind(this), this.handlerGetWalletUser.bind(this),
this.handlerGetAllCategory.bind(this), this.handlerGetAllCategory.bind(this),
this.handlerGetAllTransactions.bind(this), this.handlerGetAllTransactions.bind(this),
+24 -6
View File
@@ -7,10 +7,18 @@ import FirebaseService from '../services/firebaseService';
* @param {string} password Password input * @param {string} password Password input
* @returns {boolean} Return true if validate password success, otherwise return false * @returns {boolean} Return true if validate password success, otherwise return false
*/ */
export const isValidatePassword = (password) => { export const isValidPassword = (password) => {
return REGEX.PASSWORD.test(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 * A waiting function with s second
* @param {number} s The time will be waiting * @param {number} s The time will be waiting
@@ -85,7 +93,7 @@ export const formatNumber = (number) => {
export const changeDateFormat = (oldFormatDate) => { export const changeDateFormat = (oldFormatDate) => {
const tempDate = new Date(oldFormatDate); const tempDate = new Date(oldFormatDate);
const day = DAY[tempDate.getDay() - 1]; const day = DAY[tempDate.getDay()];
const date = tempDate.getDate(); const date = tempDate.getDate();
const month = MONTH[tempDate.getMonth()]; const month = MONTH[tempDate.getMonth()];
const year = tempDate.getFullYear(); const year = tempDate.getFullYear();
@@ -105,9 +113,7 @@ export const createTransactionDetailObject = (category, transactions) => {
return amount; return amount;
}; };
const listTransaction = () => { const listTransaction = () => {
const results = []; const results = transactions.map((transaction) => {
transactions.forEach((transaction) => {
const dateParts = changeDateFormat(transaction.date).split(','); // ['Monday', '14', 'September', '2023'] const dateParts = changeDateFormat(transaction.date).split(','); // ['Monday', '14', 'September', '2023']
const day = dateParts[1]; const day = dateParts[1];
const fullDateString = `${dateParts[0]}, ${dateParts[2]} ${dateParts[3]}`; const fullDateString = `${dateParts[0]}, ${dateParts[2]} ${dateParts[3]}`;
@@ -119,7 +125,7 @@ export const createTransactionDetailObject = (category, transactions) => {
amount: transaction.amount, amount: transaction.amount,
}; };
results.push(tempData); return tempData;
}); });
results.sort((a, b) => parseInt(b.id, 10) - parseInt(a.id, 10)); results.sort((a, b) => parseInt(b.id, 10) - parseInt(a.id, 10));
@@ -153,3 +159,15 @@ export const getAllTransactionByCategoryName = (categoryName, transactions) => {
return results; return results;
}; };
export const renderRequiredText = (field, element) => {
const markup = `
<p class="error-text">${MESSAGE.REQUIRED_MESSAGE(field)}</p>
`;
element.insertAdjacentHTML('afterend', markup);
};
export const redirectToLoginPage = () => {
window.location.replace('/login');
};
@@ -10,14 +10,11 @@ export default class CategoryService extends CommonService {
async getAllCategory() { async getAllCategory() {
const data = await this.getAllDataFromPath(this.defaultPath); const data = await this.getAllDataFromPath(this.defaultPath);
const listCategory = [];
if (data) { if (data) {
data.forEach((category) => { return data.reverse().map((category) => {
listCategory.unshift(new Category(category)); return new Category(category);
}); });
return listCategory;
} }
return null; return null;
@@ -69,15 +69,12 @@ export default class CommonService {
const results = await timeOutConnect( const results = await timeOutConnect(
this.firebaseService.getAllDataFromPath(path), this.firebaseService.getAllDataFromPath(path),
); );
const listData = [];
if (results) { if (results) {
// Convert format object // Convert format object
results.forEach((data) => { return results.map((data) => {
listData.push(convertDataObjectToModel(data)); return convertDataObjectToModel(data);
}); });
return listData;
} }
return null; return null;
@@ -89,15 +86,12 @@ export default class CommonService {
const results = await timeOutConnect( const results = await timeOutConnect(
this.firebaseService.getListDataFromProp(path, property, value), this.firebaseService.getListDataFromProp(path, property, value),
); );
const listData = [];
if (results) { if (results) {
// Convert format object // Convert format object
results.forEach((data) => {
listData.push(convertDataObjectToModel(data));
});
return listData; return results.map((data) => {
return convertDataObjectToModel(data);
});
} }
return null; return null;
@@ -22,11 +22,7 @@ export default class TransactionService extends CommonService {
this.defaultPath, this.defaultPath,
); );
if (results) { return results || null;
return results;
}
return null;
} }
async deleteTransaction(idTransaction) { async deleteTransaction(idTransaction) {
@@ -26,11 +26,7 @@ export default class UserService extends CommonService {
async isValidUser(email) { async isValidUser(email) {
const userExist = await this.getUserByEmail(email); const userExist = await this.getUserByEmail(email);
if (userExist) { return !!userExist;
return true;
}
return false;
} }
/** /**
@@ -41,11 +37,7 @@ export default class UserService extends CommonService {
async getUserByEmail(email) { async getUserByEmail(email) {
const result = await this.getDataFromProp('email', email); const result = await this.getDataFromProp('email', email);
if (result) { return result || null;
return result;
}
return null;
} }
/** /**
@@ -117,11 +109,7 @@ export default class UserService extends CommonService {
async getUserByToken(accessToken) { async getUserByToken(accessToken) {
const result = await this.getDataFromProp('accessToken', accessToken); const result = await this.getDataFromProp('accessToken', accessToken);
if (result) { return result || null;
return result;
}
return null;
} }
static clearAccessToken() { static clearAccessToken() {
@@ -23,11 +23,7 @@ export default class WalletService extends CommonService {
async isValidWallet(idUser) { async isValidWallet(idUser) {
const wallet = await this.getWalletByIdUser(idUser); const wallet = await this.getWalletByIdUser(idUser);
if (wallet) { return !!wallet;
return true;
}
return false;
} }
/** /**
@@ -38,10 +34,6 @@ export default class WalletService extends CommonService {
async getWalletByIdUser(idUser) { async getWalletByIdUser(idUser) {
const result = await this.getDataFromProp('idUser', idUser); const result = await this.getDataFromProp('idUser', idUser);
if (result) { return result || null;
return result;
}
return null;
} }
} }
@@ -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) => `<li>${message}</li>`)
.join('\n');
const markup = `
<ul class="form__error-message">
${messageItemMarkup}
</ul>
`;
document
.querySelector('.form__title')
.insertAdjacentHTML('afterend', markup);
}
}
}
@@ -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 = `
<p class="form__error-message">${message}</p>
`;
document
.querySelector('.form__title')
.insertAdjacentHTML('afterend', markup);
}
}
+264 -78
View File
@@ -4,6 +4,7 @@ import {
BTN_CONTENT, BTN_CONTENT,
DEFAULT_CATEGORY, DEFAULT_CATEGORY,
FIRST_ADD_WALLET_NOTE, FIRST_ADD_WALLET_NOTE,
REMOVE_CATEGORY,
} from '../constants/config'; } from '../constants/config';
import * as MESSAGE from '../constants/message'; import * as MESSAGE from '../constants/message';
import CommonView from './commonView'; import CommonView from './commonView';
@@ -14,6 +15,7 @@ import {
formatNumber, formatNumber,
getAllCategoryNameInTransactions, getAllCategoryNameInTransactions,
getAllTransactionByCategoryName, getAllTransactionByCategoryName,
renderRequiredText,
} from '../helpers/helpers'; } from '../helpers/helpers';
import defaultCategoryIcon from '../../assets/images/question-icon.svg'; import defaultCategoryIcon from '../../assets/images/question-icon.svg';
@@ -44,7 +46,6 @@ export default class HomeView extends CommonView {
initFunction( initFunction(
getInfoUserLogin, getInfoUserLogin,
isValidWallet,
getWalletByIdUser, getWalletByIdUser,
getAllCategory, getAllCategory,
getAllTransactions, getAllTransactions,
@@ -54,7 +55,6 @@ export default class HomeView extends CommonView {
deleteTransaction, deleteTransaction,
) { ) {
this.getInfoUserLogin = getInfoUserLogin; this.getInfoUserLogin = getInfoUserLogin;
this.isValidWallet = isValidWallet;
this.getWalletByIdUser = getWalletByIdUser; this.getWalletByIdUser = getWalletByIdUser;
this.getAllCategory = getAllCategory; this.getAllCategory = getAllCategory;
this.getAllTransactions = getAllTransactions; this.getAllTransactions = getAllTransactions;
@@ -75,14 +75,15 @@ export default class HomeView extends CommonView {
window.location.replace('/login'); window.location.replace('/login');
} else { } else {
this.user = user; 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 // Check user's wallet if have or not
if (!wallet) { if (!this.wallet) {
// Show add wallet dialog // Show add wallet dialog
this.walletDialog.showModal(); this.walletDialog.showModal();
} else { } else {
// Init data // Init data
await this.loadTransactionData();
await this.loadData(); await this.loadData();
// Load event page // Load event page
@@ -95,7 +96,6 @@ export default class HomeView extends CommonView {
async loadData() { async loadData() {
await this.loadWalletUser(); await this.loadWalletUser();
await this.loadTransactionData();
this.loadSummaryTab(); this.loadSummaryTab();
await this.loadTransactionTab(); await this.loadTransactionTab();
} }
@@ -126,17 +126,26 @@ export default class HomeView extends CommonView {
this.saveWallet(this.wallet); this.saveWallet(this.wallet);
} }
async updateAmountWallet(amount) { async updateAmountWallet() {
if (amount >= 0) { let inflow = 0;
this.wallet.inflow += amount; let outflow = 0;
// Init data first
this.transactionDetails = this.loadTransactionDetailsData();
this.transactionDetails.forEach((transaction) => {
if (transaction.totalAmount >= 0) {
inflow += transaction.totalAmount;
} else { } else {
this.wallet.outflow += amount; outflow -= transaction.totalAmount;
} }
});
// Reassign value for wallet user;
this.wallet.inflow = inflow;
this.wallet.outflow = -outflow;
await this.saveWallet(this.wallet); 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 * @param {function} getAllCategory Get all category function
*/ */
async loadCategory() { async loadCategory() {
if (!this.listCategory) {
this.listCategory = await this.getAllCategory(); this.listCategory = await this.getAllCategory();
}
if (this.listCategory) { if (this.listCategory) {
this.renderCategoryItem(); this.renderCategoryList();
} }
} }
@@ -176,15 +187,16 @@ export default class HomeView extends CommonView {
await this.loadCategory(); await this.loadCategory();
// Init data first // Init data first
const transactionDetails = this.loadTransactionDetailsData(); this.transactionDetails = this.loadTransactionDetailsData();
const transactionEl = document.querySelector('.transaction'); const transactionEl = document.querySelector('.transaction');
const listTransactionDetailEl = const listTransactionDetailEl =
transactionEl.querySelector('.transaction__list'); transactionEl.querySelector('.transaction__list');
const markup = []; const markup = [];
if (transactionDetails) { if (this.transactionDetails) {
transactionDetails.forEach((transactionDetail) => { this.transactionDetails.forEach((transactionDetail) => {
markup.push(this.transactionDetailMarkup(transactionDetail)); markup.push(this.transactionDetailMarkup(transactionDetail));
}); });
} }
@@ -203,9 +215,7 @@ export default class HomeView extends CommonView {
); );
// Create transactions details object // Create transactions details object
const tempList = []; const tempList = listCategoryInTransaction.map((categoryName) => {
listCategoryInTransaction.forEach((categoryName) => {
// Get category object from list category has been loaded. // Get category object from list category has been loaded.
const category = this.listCategory.filter( const category = this.listCategory.filter(
(item) => item.name === categoryName, (item) => item.name === categoryName,
@@ -216,11 +226,9 @@ export default class HomeView extends CommonView {
this.listTransactions, this.listTransactions,
); );
tempList.push( return createTransactionDetailObject(
createTransactionDetailObject(
Object.assign({}, ...category), Object.assign({}, ...category),
transactions, transactions,
),
); );
}); });
@@ -300,27 +308,35 @@ export default class HomeView extends CommonView {
handlerEventTransactionDialog() { handlerEventTransactionDialog() {
this.transactionDialog.addEventListener('submit', (e) => { this.transactionDialog.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.clearErrorTransactionDialog();
this.submitTransactionDialog(); this.submitTransactionDialog();
this.transactionDialog.close();
}); });
this.transactionDialog.addEventListener('input', () => { this.transactionDialog.addEventListener('input', () => {
const dateInput = this.transactionDialog.querySelector( this.changeBtnStyleTransactionDialog();
"[name='selected_date']", this.clearErrorTransactionDialog();
).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,
);
}); });
// 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 = const deleteTransactionBtn =
this.transactionDialog.querySelector('.form__delete-btn'); this.transactionDialog.querySelector('.form__delete-btn');
@@ -336,9 +352,11 @@ export default class HomeView extends CommonView {
await this.deleteTransaction(idEl.value); await this.deleteTransaction(idEl.value);
this.showSuccessToast('Delete success!', MESSAGE.DEFAULT_MESSAGE); // Reload data
await this.loadTransactionData();
await this.loadData(); await this.loadData();
this.showSuccessToast('Delete success!', MESSAGE.DEFAULT_MESSAGE);
} catch (error) { } catch (error) {
this.showErrorToast(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) { initDataTransactionDialog(idTransaction) {
const transactionArr = this.listTransactions.filter( const transactionArr = this.listTransactions.filter(
(obj) => obj.id === idTransaction, (obj) => obj.id === idTransaction,
@@ -379,8 +414,6 @@ export default class HomeView extends CommonView {
} }
async submitTransactionDialog() { async submitTransactionDialog() {
this.toggleLoaderSpinner();
try { try {
const dateEl = this.transactionForm.querySelector( const dateEl = this.transactionForm.querySelector(
"[name='selected_date']", "[name='selected_date']",
@@ -393,11 +426,21 @@ export default class HomeView extends CommonView {
const idEl = this.transactionForm.querySelector( const idEl = this.transactionForm.querySelector(
"[name='id_transaction']", "[name='id_transaction']",
); );
const amount =
categoryNameEl.value === 'Income' ? +amountEl.value : -+amountEl.value; // Check if this is a income transaction, amount must plus
// Validate data user input
if (
this.validateTransactionForm(dateEl.value, categoryNameEl.value, amount)
) {
this.toggleLoaderSpinner();
this.transactionDialog.close();
const transaction = new Transaction({ const transaction = new Transaction({
id: idEl.value, id: idEl.value,
categoryName: categoryNameEl.value, categoryName: categoryNameEl.value,
date: dateEl.value, date: dateEl.value,
amount: -+amountEl.value, amount,
note: noteEl.value, note: noteEl.value,
idUser: this.wallet.idUser, idUser: this.wallet.idUser,
}); });
@@ -405,31 +448,65 @@ export default class HomeView extends CommonView {
await this.saveTransaction(transaction); await this.saveTransaction(transaction);
// Reload data // Reload data
await this.loadTransactionData();
this.updateAmountWallet();
await this.loadData(); await this.loadData();
this.updateAmountWallet(-+amountEl.value);
if (!idEl.value) {
// Add success
this.showSuccessToast( this.showSuccessToast(
MESSAGE.ADD_TRANSACTION_SUCCESS, MESSAGE.ADD_TRANSACTION_SUCCESS,
MESSAGE.DEFAULT_MESSAGE, MESSAGE.DEFAULT_MESSAGE,
); );
} else {
this.clearInputTransactionForm(this.transactionForm); // Update success
} catch (error) { this.showSuccessToast(
this.showErrorToast(error); MESSAGE.UPDATE_TRANSACTION_SUCCESS,
MESSAGE.DEFAULT_MESSAGE,
);
} }
this.toggleLoaderSpinner(); 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;
}
return true;
} }
clearInputTransactionForm() { clearInputTransactionForm() {
const categoryIcon = this.transactionForm.querySelector('.category-icon'); const categoryIcon = this.transactionForm.querySelector('.category-icon');
categoryIcon.src = defaultCategoryIcon; categoryIcon.src = defaultCategoryIcon;
this.keySearchCategory = null; // Delete keyword search this.keySearchCategory = null; // Delete keyword search
this.renderCategoryList(this.keySearchCategory);
this.renderCategoryItem(this.keySearchCategory);
this.transactionForm.reset(); this.transactionForm.reset();
} }
// ---------------------END DIALOG---------------------// // ---------------------END DIALOG---------------------//
@@ -462,15 +539,20 @@ export default class HomeView extends CommonView {
} }
// Render category item // 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'); const listCategoryEl = document.querySelector('.list-category');
listCategoryEl.innerHTML = ''; // Remove old category item listCategoryEl.innerHTML = ''; // Remove old category item
listCategory.forEach((category) => { newListCategory.forEach((category) => {
const markup = ` const markup = `
<div class="category-item ${ <div class="category-item ${
category.name === categorySelected ? 'selected' : '' category.name === categorySelected ? 'selected' : ''
@@ -495,26 +577,48 @@ export default class HomeView extends CommonView {
this.budgetDialog.addEventListener('submit', (e) => { this.budgetDialog.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.clearErrorStyleBudgetForm();
this.submitBudgetForm(); this.submitBudgetForm();
}); });
this.budgetDialog.addEventListener('input', (e) => { this.budgetDialog.addEventListener('input', (e) => {
const bodyDialog = e.target.closest('.dialog__body'); const bodyDialog = e.target.closest('.dialog__body');
this.validateBudgetForm(bodyDialog);
this.changeBtnStyle(bodyDialog);
this.clearErrorStyleBudgetForm();
});
}
clearErrorStyleBudgetForm() {
// Clear error style
const inputFieldEls =
this.budgetDialog.querySelectorAll('.form__input-field');
const errorTexts = this.budgetDialog.querySelectorAll('.error-text');
inputFieldEls.forEach((item) => {
if (item.classList.contains('error-input'))
item.classList.remove('error-input');
});
errorTexts.forEach((item) => {
if (item) item.remove();
}); });
} }
async submitBudgetForm() { async submitBudgetForm() {
try { try {
this.toggleLoaderSpinner(); // Enable loader spinner
this.budgetDialog.close(); // Close dialog
const { formAddBudget } = document.forms; const { formAddBudget } = document.forms;
const form = new FormData(formAddBudget); const form = new FormData(formAddBudget);
const date = form.get('date'); const date = form.get('selected_date');
const amount = form.get('amount'); const amount = form.get('amount');
const note = form.get('note'); const note = form.get('note');
// Validate data user input
if (this.validateBudgetForm(date, amount)) {
this.toggleLoaderSpinner(); // Enable loader spinner
this.budgetDialog.close(); // Close dialog
const transaction = new Transaction({ const transaction = new Transaction({
categoryName: DEFAULT_CATEGORY.INCOME, categoryName: DEFAULT_CATEGORY.INCOME,
date, date,
@@ -526,8 +630,9 @@ export default class HomeView extends CommonView {
await this.saveTransaction(transaction); await this.saveTransaction(transaction);
// Reload data // Reload data
await this.loadTransactionData();
await this.updateAmountWallet();
await this.loadData(); await this.loadData();
await this.updateAmountWallet(+amount); // Update wallet
// Hide loader spinner // Hide loader spinner
this.toggleLoaderSpinner(); this.toggleLoaderSpinner();
@@ -539,12 +644,34 @@ export default class HomeView extends CommonView {
); );
document.getElementById('formAddBudget').reset(); document.getElementById('formAddBudget').reset();
}
} catch (error) { } catch (error) {
this.showErrorToast(error); this.showErrorToast(error);
} }
} }
validateBudgetForm(bodyDialog) { validateBudgetForm(date, amount) {
const inputFieldEl =
this.budgetDialog.querySelectorAll('.form__input-field');
if (!date || !amount) {
if (!date) {
renderRequiredText('date', inputFieldEl[0]);
inputFieldEl[0].classList.add('error-input');
}
if (!amount) {
renderRequiredText('amount', inputFieldEl[1]);
inputFieldEl[1].classList.add('error-input');
}
return false;
}
return true;
}
changeBtnStyle(bodyDialog) {
const date = bodyDialog.querySelector('.input-date').value; const date = bodyDialog.querySelector('.input-date').value;
const amount = +bodyDialog.querySelector('.form__input-balance').value; const amount = +bodyDialog.querySelector('.form__input-balance').value;
const saveBtn = bodyDialog.querySelector('.form__save-btn'); const saveBtn = bodyDialog.querySelector('.form__save-btn');
@@ -562,19 +689,34 @@ export default class HomeView extends CommonView {
this.walletDialog.addEventListener('submit', (e) => { this.walletDialog.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
this.clearErrorStyleWalletDialog();
this.submitWalletForm(); this.submitWalletForm();
}); });
this.walletDialog.addEventListener('input', (e) => { this.walletDialog.addEventListener('input', (e) => {
const bodyDialog = e.target.closest('.dialog__body'); const bodyDialog = e.target.closest('.dialog__body');
this.validateWalletForm(bodyDialog);
this.changeBtnStyleWalletDialog(bodyDialog);
this.clearErrorStyleWalletDialog();
});
}
clearErrorStyleWalletDialog() {
const inputFieldEls =
this.walletDialog.querySelectorAll('.form__input-field');
const errorTextEls = this.walletDialog.querySelectorAll('.error-text');
inputFieldEls.forEach((item) => {
if (item.classList.contains('error-input'))
item.classList.remove('error-input');
});
errorTextEls.forEach((item) => {
if (item) item.remove();
}); });
} }
async submitWalletForm() { async submitWalletForm() {
this.walletDialog.close();
this.toggleLoaderSpinner();
try { try {
// Wallet info // Wallet info
const { walletForm } = document.forms; const { walletForm } = document.forms;
@@ -582,19 +724,23 @@ export default class HomeView extends CommonView {
const walletName = form.get('walletName'); const walletName = form.get('walletName');
const amount = form.get('amount'); const amount = form.get('amount');
const wallet = new Wallet({ if (this.validateWalletDialog(walletName, amount)) {
this.walletDialog.close();
this.toggleLoaderSpinner();
this.wallet = new Wallet({
walletName, walletName,
amount: +amount, amount: +amount,
idUser: this.user.id, idUser: this.user.id,
inflow: +amount, inflow: +amount,
}); });
await this.saveWallet(wallet); await this.saveWallet(this.wallet);
// Transaction info // Transaction info
const transaction = new Transaction({ const transaction = new Transaction({
categoryName: 'Income', categoryName: 'Income',
date: new Date().toLocaleDateString('en-US'), date: new Date().toISOString().slice(0, 10),
note: FIRST_ADD_WALLET_NOTE, note: FIRST_ADD_WALLET_NOTE,
amount: +amount, amount: +amount,
idUser: this.user.id, idUser: this.user.id,
@@ -603,6 +749,7 @@ export default class HomeView extends CommonView {
await this.saveTransaction(transaction); await this.saveTransaction(transaction);
// Load data and event // Load data and event
await this.loadTransactionData();
await this.loadData(); await this.loadData();
this.loadEvent(); this.loadEvent();
@@ -612,15 +759,38 @@ export default class HomeView extends CommonView {
); );
await this.loadData(); // Load data from database into page await this.loadData(); // Load data from database into page
} catch (error) {
// Show toast error
this.showErrorToast(error);
}
this.toggleLoaderSpinner(); this.toggleLoaderSpinner();
} }
} catch (error) {
// Show toast error
this.showErrorToast(error);
this.toggleLoaderSpinner();
}
}
validateWalletForm(bodyDialog) { validateWalletDialog(walletName, amount) {
const inputFieldEls =
this.walletDialog.querySelectorAll('.form__input-field');
if (!walletName || !amount) {
if (!walletName) {
renderRequiredText('wallet name', inputFieldEls[0]);
inputFieldEls[0].classList.add('error-input');
}
if (!amount) {
renderRequiredText('amount', inputFieldEls[2]);
inputFieldEls[2].classList.add('error-input');
}
return false;
}
return true;
}
changeBtnStyleWalletDialog(bodyDialog) {
const walletName = bodyDialog.querySelector('.form__input-text').value; const walletName = bodyDialog.querySelector('.form__input-text').value;
const amount = bodyDialog.querySelector('.form__input-balance').value; const amount = bodyDialog.querySelector('.form__input-balance').value;
const saveBtn = bodyDialog.querySelector('.form__save-btn'); const saveBtn = bodyDialog.querySelector('.form__save-btn');
@@ -671,14 +841,14 @@ export default class HomeView extends CommonView {
*/ */
handlerTabsTransfer() { handlerTabsTransfer() {
this.tabs.forEach((tab, index) => { this.tabs.forEach((tab, index) => {
tab.addEventListener('click', () => { tab.addEventListener('click', (e) => {
this.removeActiveTab(); this.removeActiveTab();
tab.classList.add('active'); tab.classList.add('active');
const line = document.querySelector('.app__line'); const line = document.querySelector('.app__line');
line.classList.toggle('right', line.classList.contains('left')); line.style.width = `${e.target.offsetWidth}px`;
line.classList.toggle('left', !line.classList.contains('right')); line.style.left = `${e.target.offsetLeft}px`;
this.allContent.forEach((content) => { this.allContent.forEach((content) => {
content.classList.remove('active'); content.classList.remove('active');
@@ -709,6 +879,10 @@ export default class HomeView extends CommonView {
}); });
this.addBudgetBtn.addEventListener('click', () => { this.addBudgetBtn.addEventListener('click', () => {
// Set default value for date input
this.budgetDialog.querySelector("[name='selected_date']").valueAsDate =
new Date();
this.budgetDialog.showModal(); this.budgetDialog.showModal();
}); });
@@ -743,11 +917,20 @@ export default class HomeView extends CommonView {
showTransactionDialog(idTransaction = null) { showTransactionDialog(idTransaction = null) {
this.clearInputTransactionForm(); this.clearInputTransactionForm();
// Show delete button only if it is a edit form
const deleteBtn = this.transactionDialog.querySelector('.form__delete-btn'); const deleteBtn = this.transactionDialog.querySelector('.form__delete-btn');
deleteBtn.classList.toggle('hide', !idTransaction); deleteBtn.classList.toggle('hide', !idTransaction);
if (idTransaction) this.initDataTransactionDialog(idTransaction); if (idTransaction) {
// Init data transaction to dialog
this.initDataTransactionDialog(idTransaction);
} else
this.transactionDialog.querySelector(
"[name='selected_date']",
).valueAsDate = new Date(); // Set default value for date input
// Change style submit btn
this.changeBtnStyleTransactionDialog();
this.transactionDialog.showModal(); this.transactionDialog.showModal();
} }
@@ -785,6 +968,9 @@ export default class HomeView extends CommonView {
// Close select category dialog // Close select category dialog
this.categoryDialog.close(); this.categoryDialog.close();
// Clear error style for transaction dialog
this.clearErrorTransactionDialog();
} }
}); });
@@ -794,7 +980,7 @@ export default class HomeView extends CommonView {
// Make the keyword search category name into global // Make the keyword search category name into global
this.keySearchCategory = categoryNameEl.value; this.keySearchCategory = categoryNameEl.value;
this.renderCategoryItem(this.keySearchCategory); this.renderCategoryList(this.keySearchCategory);
} }
this.categoryDialog.showModal(); this.categoryDialog.showModal();
}); });
+21 -4
View File
@@ -1,8 +1,8 @@
import CommonLoginRegisterView from './commonLoginRegisterView'; import AuthenticationView from './authenticationView';
import { TYPE_TOAST, BTN_CONTENT } from '../constants/config'; import { TYPE_TOAST, BTN_CONTENT } from '../constants/config';
import * as MESSAGE from '../constants/message'; import * as MESSAGE from '../constants/message';
export default class LoginView extends CommonLoginRegisterView { export default class LoginView extends AuthenticationView {
constructor() { constructor() {
super(); super();
@@ -26,16 +26,31 @@ export default class LoginView extends CommonLoginRegisterView {
* Get data from user input * Get data from user input
* @returns {Object || null} Return object or null * @returns {Object || null} Return object or null
*/ */
getDataFromForm(event) { validateForm(event) {
const formData = new FormData(event.target); const formData = new FormData(event.target);
const email = formData.get('email'); const email = formData.get('email');
const password = formData.get('password'); const password = formData.get('password');
// Validate user input
this.listError = []; // Reset list error
const emailValid = this.validateEmail(email);
const passwordValid = this.validatePassword(password);
// Show error style
this.emailEl.classList.toggle('error-input', !emailValid);
this.inputPasswordEl.classList.toggle('error-input', !passwordValid);
if (emailValid && passwordValid) {
this.account = { email, password }; this.account = { email, password };
return this.account; return this.account;
} }
this.showError(this.listError);
return null;
}
/** /**
* Implement error toast in site * Implement error toast in site
* @param {string} content The content will show in error toast * @param {string} content The content will show in error toast
@@ -73,7 +88,8 @@ export default class LoginView extends CommonLoginRegisterView {
this.toggleLoaderSpinner(); this.toggleLoaderSpinner();
// Get data from form // Get data from form
const userInput = this.getDataFromForm(event); const userInput = this.validateForm(event);
if (userInput) {
// Check user exist // Check user exist
const results = await loginUser(userInput.email, userInput.password); const results = await loginUser(userInput.email, userInput.password);
@@ -83,6 +99,7 @@ export default class LoginView extends CommonLoginRegisterView {
return; return;
} }
throw MESSAGE.ERROR_CREDENTIAL; throw MESSAGE.ERROR_CREDENTIAL;
}
} catch (error) { } catch (error) {
// Show toast error // Show toast error
this.initErrorToast(error); this.initErrorToast(error);
@@ -1,13 +1,15 @@
import { TYPE_TOAST, BTN_CONTENT } from '../constants/config'; import { TYPE_TOAST, BTN_CONTENT } from '../constants/config';
import * as MESSAGE from '../constants/message'; import * as MESSAGE from '../constants/message';
import CommonLoginRegisterView from './commonLoginRegisterView'; import AuthenticationView from './authenticationView';
import User from '../models/user'; import User from '../models/user';
import { redirectToLoginPage } from '../helpers/helpers';
export default class RegisterView extends CommonLoginRegisterView { export default class RegisterView extends AuthenticationView {
constructor() { constructor() {
super(); super();
this.dialog = document.querySelector('.toast'); this.dialog = document.querySelector('.toast');
this.toastBtn = document.querySelector('.toast__redirect-btn');
} }
async loadPage(getInfoUserLogin) { async loadPage(getInfoUserLogin) {
@@ -26,21 +28,38 @@ export default class RegisterView extends CommonLoginRegisterView {
* Get data from user input * Get data from user input
* @returns {Object || null} Return object or null * @returns {Object || null} Return object or null
*/ */
getDataFromForm() { validateForm() {
const { registerForm } = document.forms; const { registerForm } = document.forms;
const formData = new FormData(registerForm); const formData = new FormData(registerForm);
const email = formData.get('email'); const email = formData.get('email');
const password = formData.get('password'); const password = formData.get('password');
const passwordConfirm = formData.get('password_confirm'); const passwordConfirm = formData.get('password_confirm');
const account = { email, password, passwordConfirm }; // Validate user input
this.listError = []; // Reset list error
const emailValid = this.validateEmail(email);
const passwordValid = this.validatePassword(password);
const passwordConfirmValid = this.validatePasswordConfirm(
password,
passwordConfirm,
);
if (this.isValidateAccount(account)) { // Show error style
const user = new User(account); this.emailEl.classList.toggle('error-input', !emailValid);
this.inputPasswordEl.classList.toggle('error-input', !passwordValid);
this.inputPasswordConfirmEl.classList.toggle(
'error-input',
!passwordConfirmValid,
);
if (emailValid && passwordValid && passwordConfirmValid) {
const user = new User({ email, password, passwordConfirm });
return user; return user;
} }
this.showError(this.listError);
return null; return null;
} }
@@ -49,14 +68,17 @@ export default class RegisterView extends CommonLoginRegisterView {
*/ */
showRegisterSuccessToast() { showRegisterSuccessToast() {
const typeToast = TYPE_TOAST.success; const typeToast = TYPE_TOAST.success;
const title = 'Register Commpleted'; const title = MESSAGE.REGISTER_SUCCESS;
const content = 'Please login to continue!'; const content = MESSAGE.DEFAULT_MESSAGE;
const btnContent = 'OK'; const btnContent = BTN_CONTENT.OK;
this.initToastContent(typeToast, title, content, btnContent); this.initToastContent(typeToast, title, content, btnContent);
// Show toast // Show toast
this.toastDialog.showModal(); this.toastDialog.showModal();
// Add event for toast button
this.toastBtn.addEventListener('click', redirectToLoginPage);
} }
/** /**
@@ -71,6 +93,9 @@ export default class RegisterView extends CommonLoginRegisterView {
// Show toast // Show toast
this.toastDialog.showModal(); this.toastDialog.showModal();
// Remove event for toast button
this.toastBtn.removeEventListener('click', redirectToLoginPage);
} }
/** /**
@@ -90,8 +115,8 @@ export default class RegisterView extends CommonLoginRegisterView {
// Load spinner // Load spinner
this.toggleLoaderSpinner(); this.toggleLoaderSpinner();
// Get data from form // Get validate form
const user = this.getDataFromForm(); const user = this.validateForm();
// Save user // Save user
if (user) { if (user) {
@@ -103,6 +128,9 @@ export default class RegisterView extends CommonLoginRegisterView {
await saveUser(user); await saveUser(user);
// Show toast success // Show toast success
this.showRegisterSuccessToast(); this.showRegisterSuccessToast();
// Clear form
document.getElementById('registerForm').reset();
} }
} }
} catch (error) { } catch (error) {
+19 -7
View File
@@ -18,6 +18,7 @@
<!-- Dialog body --> <!-- Dialog body -->
<div class="dialog__body"> <div class="dialog__body">
<form class="form" id="walletForm"> <form class="form" id="walletForm">
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Wallet name</p> <p class="form__label">Wallet name</p>
<input <input
@@ -25,10 +26,10 @@
class="form__input-text" class="form__input-text"
placeholder="Your wallet name?" placeholder="Your wallet name?"
name="walletName" name="walletName"
required
minlength="3" minlength="3"
/> />
</div> </div>
</div>
<div class="form__currency-balance"> <div class="form__currency-balance">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Currency</p> <p class="form__label">Currency</p>
@@ -40,16 +41,17 @@
<p class="form__text-currency">United States Dollar</p> <p class="form__text-currency">United States Dollar</p>
</div> </div>
</div> </div>
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Initial Balance</p> <p class="form__label">Initial Balance</p>
<input <input
type="number" type="number"
class="form__input-balance" class="form__input-balance"
name="amount" name="amount"
required
/> />
</div> </div>
</div> </div>
</div>
<button type="submit" class="form__save-btn">SAVE</button> <button type="submit" class="form__save-btn">SAVE</button>
</form> </form>
</div> </div>
@@ -67,13 +69,20 @@
<div class="dialog__body"> <div class="dialog__body">
<form class="form" id="formAddBudget"> <form class="form" id="formAddBudget">
<div class="form__date-amount-input"> <div class="form__date-amount-input">
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Date</p> <p class="form__label">Date</p>
<div class="date-input-container"> <div class="date-input-container">
<input class="input-date" type="date" name="date" required /> <input
class="input-date"
type="date"
name="selected_date"
/>
<div class="icon-btn"></div> <div class="icon-btn"></div>
</div> </div>
</div> </div>
</div>
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Amount</p> <p class="form__label">Amount</p>
<input <input
@@ -81,10 +90,10 @@
type="number" type="number"
min="1" min="1"
name="amount" name="amount"
required
/> />
</div> </div>
</div> </div>
</div>
<div class="form__note-input"> <div class="form__note-input">
<p class="form__label">Note</p> <p class="form__label">Note</p>
<input <input
@@ -116,6 +125,7 @@
<form class="form" id="formAddTransaction"> <form class="form" id="formAddTransaction">
<input type="text" name="id_transaction" hidden /> <input type="text" name="id_transaction" hidden />
<div class="form__date-category-amount-input"> <div class="form__date-category-amount-input">
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Date</p> <p class="form__label">Date</p>
<div class="date-input-container"> <div class="date-input-container">
@@ -123,11 +133,12 @@
class="input-date" class="input-date"
type="date" type="date"
name="selected_date" name="selected_date"
required
/> />
<span class="icon-btn"></span> <span class="icon-btn"></span>
</div> </div>
</div> </div>
</div>
<div class="form__input-container">
<div class="form__input-field" id="selectCategory"> <div class="form__input-field" id="selectCategory">
<p class="form__label">Category</p> <p class="form__label">Category</p>
<div class="category-input-container"> <div class="category-input-container">
@@ -141,11 +152,12 @@
name="category_name" name="category_name"
class="category-name" class="category-name"
placeholder="Select Category" placeholder="Select Category"
required
/> />
<div class="icon-btn"></div> <div class="icon-btn"></div>
</div> </div>
</div> </div>
</div>
<div class="form__input-container">
<div class="form__input-field"> <div class="form__input-field">
<p class="form__label">Amount</p> <p class="form__label">Amount</p>
<input <input
@@ -153,10 +165,10 @@
type="number" type="number"
name="amount" name="amount"
value="0" value="0"
required
/> />
</div> </div>
</div> </div>
</div>
<div class="form__note-input"> <div class="form__note-input">
<p class="form__label">Note</p> <p class="form__label">Note</p>
<input <input
+1 -3
View File
@@ -22,18 +22,16 @@
<h1 class="form__title">Log In</h1> <h1 class="form__title">Log In</h1>
<p class="form__description">Using Money Lover account</p> <p class="form__description">Using Money Lover account</p>
<input <input
type="email" type="text"
class="form__input" class="form__input"
placeholder="Email" placeholder="Email"
name="email" name="email"
required
/> />
<input <input
type="password" type="password"
name="password" name="password"
class="form__input" class="form__input"
placeholder="Password" placeholder="Password"
required
/> />
<button type="submit" class="form__submit-btn">Login</button> <button type="submit" class="form__submit-btn">Login</button>
<p class="form__redirect-signup-text"> <p class="form__redirect-signup-text">
+8 -4
View File
@@ -21,27 +21,31 @@
<div class="form__container"> <div class="form__container">
<h1 class="form__title">Register</h1> <h1 class="form__title">Register</h1>
<p class="form__description">Using Money Lover account</p> <p class="form__description">Using Money Lover account</p>
<div class="form__input-container">
<input <input
type="email" type="text"
class="form__input" class="form__input"
placeholder="Email" placeholder="Email"
name="email" name="email"
required
/> />
</div>
<div class="form__input-container">
<input <input
type="password" type="password"
name="password" name="password"
class="form__input" class="form__input"
placeholder="Password" placeholder="Password"
required
/> />
</div>
<div class="form__input-container">
<input <input
type="password" type="password"
name="password_confirm" name="password_confirm"
class="form__input" class="form__input"
placeholder="Confirm Password" placeholder="Confirm Password"
required
/> />
</div>
<button type="submit" class="form__submit-btn">Register</button> <button type="submit" class="form__submit-btn">Register</button>
<p class="form__redirect-signup-text"> <p class="form__redirect-signup-text">
Have you an account? Have you an account?
@@ -3,7 +3,6 @@
@import './abstracts/variables'; @import './abstracts/variables';
// Bases // Bases
@import './bases/base';
@import './bases/placeholder'; @import './bases/placeholder';
@import './bases/reset'; @import './bases/reset';
@import './bases/typography'; @import './bases/typography';
@@ -1,14 +0,0 @@
.overlay {
@extend %d-absolute;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: $zindex-lv-1;
opacity: 0;
pointer-events: none;
&.active {
@extend %active;
}
}
@@ -51,3 +51,9 @@
padding: 8 0px; padding: 8 0px;
} }
%error-text {
align-self: flex-start;
padding-left: 5px;
color: $dark-error-color;
}
@@ -143,16 +143,6 @@
background-color: $primary-color; background-color: $primary-color;
border-radius: 10px; border-radius: 10px;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
&.left {
left: 152px;
width: 116px;
}
&.right {
left: 272px;
width: 200px;
}
} }
} }
@@ -344,6 +334,10 @@
font-size: $fs-md; font-size: $fs-md;
line-height: 24px; line-height: 24px;
} }
&__input-field {
height: fit-content;
}
} }
} }
@@ -364,11 +358,11 @@
@extend %d-flex; @extend %d-flex;
@include flex-layout($gap: 32px); @include flex-layout($gap: 32px);
& .form__input-field:first-child { & .form__input-container:first-child .form__input-field {
width: 208px; width: 208px;
} }
& .form__input-field:last-child { & .form__input-container:last-child .form__input-field {
width: 240px; width: 240px;
} }
} }
@@ -504,7 +498,7 @@
&__input-field { &__input-field {
@extend %rounded; @extend %rounded;
padding: 6px 16px 13.5px 16px; padding: 6px 16px 12px;
border: 1px solid $gray; border: 1px solid $gray;
} }
@@ -519,6 +513,7 @@
font-size: $fs-lg; font-size: $fs-lg;
width: 100%; width: 100%;
border: none; border: none;
background-color: transparent;
&:focus { &:focus {
outline: none; outline: none;
@@ -530,11 +525,12 @@
} }
&__input-balance { &__input-balance {
font-size: $fs-md; font-size: $fs-lg;
line-height: 20px; line-height: 20px;
margin-top: 6px; height: 28px;
border: none; border: none;
width: 100%; width: 100%;
background-color: transparent;
&:focus { &:focus {
outline: none; outline: none;
@@ -599,6 +595,7 @@
width: 100%; width: 100%;
border: none; border: none;
font-size: $fs-lg; font-size: $fs-lg;
background-color: transparent;
&:focus { &:focus {
outline: none; outline: none;
@@ -614,7 +611,7 @@
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 5px; right: 5px;
background-color: $white; background-color: transparent;
border-top: 3px solid $dark-gray; border-top: 3px solid $dark-gray;
border-right: 3px solid $dark-gray; border-right: 3px solid $dark-gray;
border-bottom: none; border-bottom: none;
@@ -644,6 +641,7 @@
color: $black; color: $black;
border: none; border: none;
caret-color: transparent; caret-color: transparent;
background-color: transparent;
cursor: pointer; cursor: pointer;
&:focus { &:focus {
@@ -689,6 +687,24 @@
color: $primary-color; color: $primary-color;
} }
} }
.error-input {
background-color: $light-error-color;
border-color: $dark-error-color;
& .form__input-text::placeholder {
color: $white;
}
}
.error-text {
@extend %error-text;
}
.form__input-container {
@extend %d-flex;
@include flex-layout($direction: column, $gap: 7px);
}
} }
.close-icon { .close-icon {
@@ -52,6 +52,7 @@
padding: 15px 15px; padding: 15px 15px;
border-radius: 10px; border-radius: 10px;
line-height: 22px; line-height: 22px;
list-style: inside;
} }
&__description { &__description {
@@ -69,6 +70,11 @@
border: 2px solid $background-input-color; border: 2px solid $background-input-color;
background-color: $background-input-color; background-color: $background-input-color;
padding-inline: 14px; padding-inline: 14px;
&-container {
@extend %d-flex;
@include flex-layout($direction: column, $gap: 7px);
}
} }
&__submit-btn { &__submit-btn {
@@ -87,4 +93,8 @@
border: 2px solid $dark-error-color; border: 2px solid $dark-error-color;
background-color: $light-error-color; background-color: $light-error-color;
} }
.error-text {
@extend %error-text;
}
} }