mirror of
https://github.com/Nezumi-2711/javascript-training.git
synced 2026-09-22 13:38:43 +00:00
Add wallet method
This commit is contained in:
@@ -10,6 +10,10 @@ export const MESSAGE = {
|
||||
},
|
||||
DEFAULT_TITLE_ERROR_POPUP: 'Error',
|
||||
USER_EXIST_ERROR: 'User is exists! Please try another email!',
|
||||
WELCOME: {
|
||||
title: 'Login Successful!',
|
||||
message: 'Welcome to Money Lover!',
|
||||
},
|
||||
};
|
||||
|
||||
export const URL = {
|
||||
@@ -25,6 +29,7 @@ export const BTN_CONTENT = {
|
||||
|
||||
export const LOCAL_STORAGE = {
|
||||
ACCESS_TOKEN: 'accessToken',
|
||||
IS_FIRST_LOGIN: 'isFirstLogin',
|
||||
};
|
||||
|
||||
export const TYPE_POPUP = { success: 'success', error: 'error' };
|
||||
|
||||
@@ -4,11 +4,28 @@ export default class HomeController {
|
||||
this.homeView = view.homeView;
|
||||
}
|
||||
|
||||
handlerGetInfoUserLogin() {
|
||||
return this.service.userService.getInfoUserLogin();
|
||||
}
|
||||
|
||||
handlerCheckWalletExist(idUser) {
|
||||
return this.service.walletService.checkWalletExist(idUser);
|
||||
}
|
||||
|
||||
handlerSaveWallet(wallet) {
|
||||
return this.service.walletService.saveWallet(wallet);
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.homeView) {
|
||||
this.homeView.handlerTabsTransfer();
|
||||
this.homeView.addCommonEventPage();
|
||||
this.homeView.addEventSelectCategoryDialog();
|
||||
this.homeView.addHandlerInputChangeWalletForm();
|
||||
this.homeView.addHandlerSubmitWalletForm(
|
||||
this.handlerSaveWallet.bind(this),
|
||||
);
|
||||
this.homeView.loadPage(
|
||||
this.handlerGetInfoUserLogin.bind(this),
|
||||
this.handlerCheckWalletExist.bind(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,5 +70,10 @@ export const getSubdirectoryURL = () => {
|
||||
|
||||
const subDirectory = parts[3]; // Get subdirectory url only
|
||||
|
||||
const index = subDirectory.indexOf('?');
|
||||
if (index !== -1) {
|
||||
return subDirectory.substring(0, index);
|
||||
}
|
||||
|
||||
return subDirectory;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
export default class User {
|
||||
constructor({ email, password, walletName = '', accessToken = '' }) {
|
||||
constructor({ email, password, accessToken = '' }) {
|
||||
this.id = User.createIdUser();
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.walletName = walletName;
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export default class Wallet {
|
||||
constructor({
|
||||
walletName = '',
|
||||
amount = '',
|
||||
inflow = 0,
|
||||
outflow = 0,
|
||||
idUser,
|
||||
}) {
|
||||
this.id = Wallet.createIdWallet();
|
||||
this.walletName = walletName;
|
||||
this.amout = amount;
|
||||
this.inflow = inflow;
|
||||
this.outflow = outflow;
|
||||
this.idUser = idUser;
|
||||
}
|
||||
|
||||
static createIdWallet() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ export default class CommonService {
|
||||
|
||||
async getDataFromProp(property, value, path = this.defaultPath) {
|
||||
this.connectToDb();
|
||||
const existUser = this.firebaseService.getDataFromProp(
|
||||
const dataExists = this.firebaseService.getDataFromProp(
|
||||
path,
|
||||
property,
|
||||
value,
|
||||
);
|
||||
const result = await timeOutConnect(existUser);
|
||||
const result = await timeOutConnect(dataExists);
|
||||
|
||||
if (result.id && result.data) {
|
||||
return convertDataObjectToModel(result);
|
||||
|
||||
@@ -8,7 +8,7 @@ class LocalStorageService {
|
||||
}
|
||||
|
||||
get(key) {
|
||||
this.localStorage.getItem(key);
|
||||
return this.localStorage.getItem(key);
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import UserService from './userService';
|
||||
import WalletService from './walletService';
|
||||
|
||||
export default class Service {
|
||||
constructor() {
|
||||
this.userService = new UserService();
|
||||
this.walletService = new WalletService();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,5 +86,41 @@ export default class UserService extends CommonService {
|
||||
LOCAL_STORAGE.ACCESS_TOKEN,
|
||||
newUserData.accessToken,
|
||||
);
|
||||
|
||||
LocalStorageService.add(LOCAL_STORAGE.IS_FIRST_LOGIN, true);
|
||||
}
|
||||
|
||||
async getInfoUserLogin() {
|
||||
// Find access token
|
||||
const accessToken = LocalStorageService.get(LOCAL_STORAGE.ACCESS_TOKEN);
|
||||
|
||||
if (accessToken) {
|
||||
const user = await this.getUserByToken(accessToken);
|
||||
|
||||
if (LocalStorageService.get(LOCAL_STORAGE.IS_FIRST_LOGIN)) {
|
||||
user.isFirstLogin = true;
|
||||
|
||||
LocalStorageService.remove(LOCAL_STORAGE.IS_FIRST_LOGIN);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user data from token access
|
||||
* @param {string} accessToken Access token user
|
||||
* @returns {Object || null} Return new User Object if find, otherwise return null.
|
||||
*/
|
||||
async getUserByToken(accessToken) {
|
||||
const result = await this.getDataFromProp('accessToken', accessToken);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import CommonService from './commonService';
|
||||
|
||||
export default class WalletService extends CommonService {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.defaultPath = 'wallets/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Save wallet into database
|
||||
* @param {Object} wallet The wallet object need to be saved into databae
|
||||
*/
|
||||
async saveWallet(wallet) {
|
||||
await this.save(wallet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check wallet exist in database
|
||||
* @param {string} idUser The id user to find user's wallet
|
||||
* @returns {boolean} Return true if find, otherwise return false
|
||||
*/
|
||||
async checkWalletExist(idUser) {
|
||||
const walletExist = await this.getWalletByIdUser(idUser);
|
||||
|
||||
if (walletExist) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wallet data from idUser
|
||||
* @param {string} email The id user to find user's wallet
|
||||
* @returns {Object || null} Return new Wallet Object if find, otherwise return null.
|
||||
*/
|
||||
async getWalletByIdUser(idUser) {
|
||||
const result = await this.getDataFromProp('idUser', idUser);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export default class CommonLoginRegisterView extends CommonView {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.handleEventBtnPopupAndOverlay();
|
||||
|
||||
this.parentElement = document.querySelector('.form');
|
||||
this.messageDefault = CONSTANT.MESSAGE.ERROR_MESSAGE_DEFAULT;
|
||||
this.inputPassword = document.querySelector('input[name="password"]');
|
||||
@@ -84,4 +86,16 @@ export default class CommonLoginRegisterView extends CommonView {
|
||||
.querySelector('.form__title')
|
||||
.insertAdjacentHTML('afterend', markup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event listener for popup and overlay
|
||||
*/
|
||||
handleEventBtnPopupAndOverlay() {
|
||||
this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this));
|
||||
this.overlay.addEventListener('click', this.toogleDialog.bind(this));
|
||||
}
|
||||
|
||||
toogleDialog() {
|
||||
this.dialog.classList.toggle('active');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ export default class CommonView {
|
||||
this.initPopup();
|
||||
this.initElementPopup();
|
||||
this.initLoader();
|
||||
this.handleEventBtnPopupAndOverlay();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,28 +90,6 @@ export default class CommonView {
|
||||
this.popupBtn.textContent = btnContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event listener for popup and overlay
|
||||
*/
|
||||
handleEventBtnPopupAndOverlay() {
|
||||
this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this));
|
||||
this.overlay.addEventListener('click', this.toogleDialog.bind(this));
|
||||
}
|
||||
|
||||
toogleDialog() {
|
||||
this.overlay.classList.toggle('active');
|
||||
if (this.dialog.length) {
|
||||
// If it have more dialog
|
||||
this.dialog.forEach((item) => {
|
||||
if (item.classList.contains('active')) {
|
||||
item.classList.remove('active');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.dialog.classList.toggle('active');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement loader screen
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { TYPE_POPUP, MESSAGE, BTN_CONTENT } from '../constants/constant';
|
||||
import CommonView from './commonView';
|
||||
import Wallet from '../models/wallet';
|
||||
|
||||
export default class HomeView extends CommonView {
|
||||
constructor() {
|
||||
@@ -11,6 +13,7 @@ export default class HomeView extends CommonView {
|
||||
this.overlay = document.querySelector('.overlay');
|
||||
this.darkOverlay = document.querySelector('.dark-overlay');
|
||||
this.dialog = document.querySelectorAll('.dialog');
|
||||
this.saveBtn = document.querySelectorAll('.form__save-btn');
|
||||
this.cancelBtn = document.querySelectorAll('.form__cancel-btn');
|
||||
this.categoryField = document.getElementById('selectCategory');
|
||||
this.closeIcon = document.querySelector('.close-icon');
|
||||
@@ -18,6 +21,110 @@ export default class HomeView extends CommonView {
|
||||
this.budgetForm = document.getElementById('budgetForm');
|
||||
this.transactionForm = document.getElementById('transactionForm');
|
||||
this.categoryForm = document.getElementById('categoryForm');
|
||||
this.walletForm = document.getElementById('walletForm');
|
||||
|
||||
this.walletDialog = document.getElementById('walletDialog');
|
||||
}
|
||||
|
||||
async loadPage(getInfoUserLogin, checkWalletExist) {
|
||||
const user = await getInfoUserLogin();
|
||||
|
||||
if (!user) {
|
||||
window.location.replace('/login');
|
||||
} else {
|
||||
this.user = user;
|
||||
const walletExist = await checkWalletExist(user.id);
|
||||
|
||||
// Check user's wallet if have or not
|
||||
if (!walletExist) {
|
||||
// Show add wallet dialog
|
||||
this.walletDialog.classList.add('active');
|
||||
// If overlay is not exist on page
|
||||
if (!this.overlay.classList.contains('active')) {
|
||||
this.toggleActiveOverlay();
|
||||
}
|
||||
} else {
|
||||
this.loadEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addHandlerSubmitWalletForm(saveWallet) {
|
||||
this.walletForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
this.submitWalletForm(saveWallet);
|
||||
});
|
||||
}
|
||||
|
||||
async submitWalletForm(saveWallet) {
|
||||
try {
|
||||
const wallet = new Wallet({
|
||||
walletName: this.walletName,
|
||||
amount: this.amount,
|
||||
idUser: this.user.id,
|
||||
});
|
||||
|
||||
await saveWallet(wallet);
|
||||
|
||||
this.hideDialog();
|
||||
this.showSuccessPopup('Add wallet success', 'Click ok to continue!');
|
||||
this.loadEvent();
|
||||
} catch (error) {
|
||||
// Show popup error
|
||||
this.initErrorPopup(error);
|
||||
}
|
||||
}
|
||||
|
||||
addHandlerInputChangeWalletForm() {
|
||||
this.walletForm.addEventListener('input', (e) => {
|
||||
const bodyDialog = e.target.closest('.dialog__body');
|
||||
this.validateWalletForm(bodyDialog);
|
||||
});
|
||||
}
|
||||
|
||||
validateWalletForm(bodyDialog) {
|
||||
this.walletName = bodyDialog.querySelector('.form__input-text').value;
|
||||
this.amount = bodyDialog.querySelector('.form__input-balance').value;
|
||||
const saveBtn = bodyDialog.querySelector('.form__save-btn');
|
||||
|
||||
if (this.walletName.length >= 3 && this.amount.length >= 1) {
|
||||
saveBtn.classList.add('active');
|
||||
} else {
|
||||
saveBtn.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
showSuccessPopup(title, message) {
|
||||
const typePopup = TYPE_POPUP.success;
|
||||
const btnContent = BTN_CONTENT.OK;
|
||||
|
||||
this.initPopupContent(typePopup, title, message, btnContent);
|
||||
|
||||
// Show popup
|
||||
this.tooglePopupForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement error popup in site
|
||||
* @param {string} content The content will show in error popup
|
||||
*/
|
||||
initErrorPopup(error) {
|
||||
const title = error.title ? error.title : MESSAGE.DEFAULT_TITLE_ERROR_POPUP;
|
||||
const content = error.message ? error.message : error;
|
||||
|
||||
this.initPopupContent(TYPE_POPUP.error, title, content, BTN_CONTENT.GOT_IT);
|
||||
|
||||
// Show popup
|
||||
this.tooglePopupForm();
|
||||
}
|
||||
|
||||
/* ------------------------------- HANDLER EVENT ------------------------------- */
|
||||
|
||||
loadEvent() {
|
||||
this.addCommonEventPage();
|
||||
this.handlerTabsTransfer();
|
||||
this.addEventSelectCategoryDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,13 +162,14 @@ export default class HomeView extends CommonView {
|
||||
this.cancelBtn.forEach((item) => {
|
||||
item.addEventListener('click', () => {
|
||||
this.hideDialog();
|
||||
this.toggleActiveOverlay();
|
||||
});
|
||||
});
|
||||
|
||||
this.overlay.addEventListener('click', () => {
|
||||
this.hideDialog();
|
||||
});
|
||||
|
||||
this.popupBtn.addEventListener('click', this.tooglePopupForm.bind(this));
|
||||
}
|
||||
|
||||
addEventSelectCategoryDialog() {
|
||||
@@ -96,6 +204,7 @@ export default class HomeView extends CommonView {
|
||||
item.classList.remove('active');
|
||||
}
|
||||
});
|
||||
this.toggleActiveOverlay();
|
||||
}
|
||||
|
||||
toggleActiveOverlay() {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<button class="modal-box__redirect-btn">OK</button>
|
||||
</div> -->
|
||||
<!-- Add a wallet form -->
|
||||
<div class="dialog" id="walletForm">
|
||||
<div class="dialog" id="walletDialog">
|
||||
<div class="dialog__add-wallet">
|
||||
<!-- Dialog header -->
|
||||
<div class="dialog__header">
|
||||
@@ -25,14 +25,16 @@
|
||||
</div>
|
||||
<!-- Dialog body -->
|
||||
<div class="dialog__body">
|
||||
<form class="form">
|
||||
<form class="form" id="walletForm">
|
||||
<div class="form__input-field">
|
||||
<p class="form__label">Wallet name</p>
|
||||
<input
|
||||
type="text"
|
||||
class="form__input-text"
|
||||
placeholder="Your wallet name?"
|
||||
name="wallet-name"
|
||||
name="walletName"
|
||||
required
|
||||
minlength="3"
|
||||
/>
|
||||
</div>
|
||||
<div class="form__currency-balance">
|
||||
@@ -48,7 +50,12 @@
|
||||
</div>
|
||||
<div class="form__input-field">
|
||||
<p class="form__label">Initial Balance</p>
|
||||
<input type="number" class="form__input-balance" value="0" />
|
||||
<input
|
||||
type="number"
|
||||
class="form__input-balance"
|
||||
name="amount"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="form__save-btn">SAVE</button>
|
||||
|
||||
Reference in New Issue
Block a user