Add transaction, budget, category view

This commit is contained in:
2023-10-02 17:46:22 +07:00
parent daf7bea3b6
commit 9313353b30
20 changed files with 1425 additions and 176 deletions
+1
View File
@@ -0,0 +1 @@
declare module '*.svg';
@@ -32,3 +32,34 @@ export const URL = {
REGISTER: 'register',
HOME: '',
};
export const DEFAULT_CATEGORY = {
INCOME: 'Income',
};
export const REMOVE_CATEGORY = ['Income'];
export const DAY = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
];
export const MONTH = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
@@ -4,6 +4,7 @@ import Service from 'services';
import View from 'views';
import Wallet from 'models/wallet';
import Transaction from 'models/transaction';
import Category from 'models/category';
export default class HomeController {
public homeView: HomeView | null = null;
@@ -20,25 +21,40 @@ export default class HomeController {
return this.service.userService.getInfoUserLogin();
}
handlerGetWalletByIdUser(idUser: number) {
handlerGetWalletByIdUser(idUser: number): Promise<Wallet | null> {
return this.service.walletService.getWalletByIdUser(idUser);
}
handlerSaveWallet(wallet: Wallet) {
handlerSaveWallet(wallet: Wallet): Promise<void> {
return this.service.walletService.saveWallet(wallet);
}
handlerSaveTransaction(transaction: Transaction) {
handlerSaveTransaction(transaction: Transaction): Promise<void> {
return this.service.transactionService.saveTransaction(transaction);
}
handlerGetAllCategory(): Promise<Category[] | null> {
return this.service.categoryService.getAllCategory();
}
handlerGetAllTransactions(idUser: number): Promise<Transaction[] | null> {
return this.service.transactionService.getListTransactionByIdUser(idUser);
}
handlerDeleteTransaction(idTransaction: number): Promise<void> {
return this.service.transactionService.deleteTransaction(idTransaction);
}
init() {
if (this.homeView) {
this.homeView.initFunction(
this.handlerGetInfoUserLogin.bind(this),
this.handlerGetWalletByIdUser.bind(this),
this.handlerGetAllCategory.bind(this),
this.handlerGetAllTransactions.bind(this),
this.handlerSaveWallet.bind(this),
this.handlerSaveTransaction.bind(this),
this.handlerDeleteTransaction.bind(this),
new Transform(),
);
+15 -3
View File
@@ -1,3 +1,5 @@
import Category from 'models/category';
import Transaction from 'models/transaction';
import User from 'models/user';
import Wallet from 'models/wallet';
@@ -13,7 +15,7 @@ export class DataObject<T> {
constructor(dataObject: IDataObject<T>) {
this.id = dataObject?.id ?? null;
this.data = dataObject.data as T;
this.data = <T>dataObject.data;
}
}
@@ -39,6 +41,16 @@ export type TSignal = {
};
export interface Data {
wallet: Wallet;
user: User;
wallet?: Wallet;
listTransactions?: Transaction[];
listCategories?: Category[];
user?: User;
}
export interface ItemTransaction {
id: number;
day: string;
fullDateString: string;
note: string;
amount: number;
}
+83 -2
View File
@@ -1,6 +1,9 @@
import localStorageService from 'services/localStorageService';
import { DataObject, IDataObject } from '../global/types';
import { LOCAL_STORAGE } from 'constants/config';
import { DataObject, IDataObject, ItemTransaction } from '../global/types';
import { DAY, LOCAL_STORAGE, MONTH } from 'constants/config';
import Transaction from 'models/transaction';
import TransactionDetail from 'models/transactionDetail';
import Category from 'models/category';
export const generateId = (): number => {
return new Date().getTime();
@@ -39,6 +42,84 @@ export const formatNumber = (number: number): string => {
});
};
export const changeDateFormat = (oldFormatDate: string) => {
const tempDate = new Date(oldFormatDate);
const day = DAY[tempDate.getDay()];
const date = tempDate.getDate();
const month = MONTH[tempDate.getMonth()];
const year = tempDate.getFullYear();
return `${day}, ${date}, ${month}, ${year}`;
};
export const clearAccessToken = (): void => {
localStorageService.remove(LOCAL_STORAGE.ACCESS_TOKEN);
};
export const getAllCategoryNameInTransactions = (
transactions: Transaction[],
): string[] => {
const categoryName = new Set();
transactions.forEach((transaction) =>
categoryName.add(transaction.categoryName),
);
return Array.from(categoryName) as string[];
};
export const getAllTransactionByCategoryName = (
categoryName: string,
transactions: Transaction[],
) => {
const results = transactions.filter((transaction) => {
return transaction.categoryName === categoryName;
});
return results;
};
export const createTransactionDetailObject = (
category: Category,
transactions: Transaction[],
): TransactionDetail => {
const totalTransaction = transactions.length;
const totalAmount = () => {
let amount = 0;
transactions.forEach((transaction) => {
amount += transaction.amount;
});
return amount;
};
const listTransaction = (): ItemTransaction[] => {
const results: ItemTransaction[] = 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]}`;
const tempData: ItemTransaction = {
id: transaction.id,
day,
fullDateString,
note: transaction.note,
amount: transaction.amount,
};
return tempData;
});
results.sort((a, b) => b.id - a.id);
return results;
};
return new TransactionDetail(
category.name,
category.url,
totalTransaction,
totalAmount(),
listTransaction(),
);
};
@@ -0,0 +1,25 @@
export default class Category {
private readonly _id: number;
private _url: string;
private _name: string;
constructor(id: number, url: string, name: string) {
this._id = id;
this._url = url;
this._name = name;
}
get id() {
return this._id;
}
get url() {
return this._url;
}
get name() {
return this._name;
}
}
@@ -1,65 +1,19 @@
import { generateId } from 'helpers/data';
export default class Transaction {
private readonly _id: number;
private _categoryName: string;
private _date: string;
private _note: string;
private _amount: number;
private _idUser: number;
constructor(
categoryName: string,
date: string,
note: string,
amount: number,
idUser: number,
public id: number,
public categoryName: string,
public date: string,
public note: string,
public amount: number,
public idUser: number,
) {
this._id = generateId();
this._categoryName = categoryName;
this._date = date;
this._note = note;
this._amount = amount;
this._idUser = idUser;
}
get id() {
return this._id;
}
get categoryName() {
return this._categoryName;
}
get date() {
return this._date;
}
get note() {
return this._note;
}
get amount() {
return this._amount;
}
get idUser() {
return this._idUser;
}
get toObject() {
return {
id: this._id,
categoryName: this._categoryName,
date: this._date,
note: this._note,
amount: this._amount,
idUser: this._idUser,
} as Transaction;
this.id = id !== 0 ? id : generateId();
this.categoryName = categoryName;
this.date = date;
this.note = note;
this.amount = amount;
this.idUser = idUser;
}
}
@@ -0,0 +1,17 @@
import { ItemTransaction } from 'global/types';
export default class TransactionDetail {
constructor(
public categoryName: string,
public url: string,
public totalTransaction: number,
public totalAmount: number,
public transactions: ItemTransaction[],
) {
this.categoryName = categoryName;
this.url = url;
this.totalTransaction = totalTransaction;
this.totalAmount = totalAmount;
this.transactions = transactions;
}
}
+10 -44
View File
@@ -1,15 +1,15 @@
import { generateId } from '../helpers/data';
export default class Wallet {
private readonly _id: number;
id: number;
private _walletName: string;
walletName: string;
private _inflow: number;
inflow: number;
private _outflow: number;
outflow: number;
private _idUser: number;
idUser: number;
constructor(
walletName: string,
@@ -17,44 +17,10 @@ export default class Wallet {
outflow: number,
idUser: number,
) {
this._id = generateId();
this._walletName = walletName;
this._inflow = inflow;
this._outflow = outflow;
this._idUser = idUser;
}
get id() {
return this._id;
}
get walletName() {
return this._walletName;
}
get inflow() {
return this._inflow;
}
get outflow() {
return this._outflow;
}
get idUser() {
return this._idUser;
}
get amountWallet() {
return this._inflow + this._outflow;
}
get toObject() {
return {
id: this._id,
walletName: this._walletName,
inflow: this._inflow,
outflow: this._outflow,
idUser: this._idUser,
};
this.id = generateId();
this.walletName = walletName;
this.inflow = inflow;
this.outflow = outflow;
this.idUser = idUser;
}
}
@@ -0,0 +1,32 @@
import CommonService from './commonService';
import Category from '../models/category';
export default class CategoryService extends CommonService<Category> {
constructor() {
super();
this.defaultPath = 'categories/';
}
async getAllCategory() {
const data = await this.getAllDataFromPath(this.defaultPath);
if (data) {
return data.reverse().map((category): Category => category);
}
return null;
}
async getCategoryByName(nameCategory: string) {
const data = await this.getDataFromProp(
'name',
nameCategory,
this.defaultPath,
);
if (data) return data;
return null;
}
}
@@ -77,7 +77,7 @@ export default class CommonService<T> {
return null;
}
async getAllDataFromPath(path = this.defaultPath): Promise<T | null> {
async getAllDataFromPath(path = this.defaultPath): Promise<T[] | null> {
this.connectToDb();
const results = await timeOutConnect(
@@ -90,7 +90,7 @@ export default class CommonService<T> {
const tempData = data as DataObject<T>;
return convertDataObjectToModel(tempData);
}) as T;
}) as T[];
}
return null;
@@ -100,7 +100,7 @@ export default class CommonService<T> {
property: string,
value: string,
path: string = this.defaultPath,
): Promise<T | null> {
): Promise<T[] | null> {
this.connectToDb();
const results = await timeOutConnect(
@@ -114,7 +114,7 @@ export default class CommonService<T> {
const tempData = data as DataObject<T>;
return convertDataObjectToModel(tempData);
}) as T;
}) as T[];
}
return null;
@@ -1,3 +1,4 @@
import CategoryService from './categoryService';
import TransactionService from './transactionService';
import UserService from './userService';
import WalletService from './walletService';
@@ -9,9 +10,12 @@ export default class Service {
public transactionService: TransactionService;
public categoryService: CategoryService;
constructor() {
this.userService = new UserService();
this.walletService = new WalletService();
this.transactionService = new TransactionService();
this.categoryService = new CategoryService();
}
}
@@ -18,7 +18,7 @@ export default class TransactionService extends CommonService<Transaction> {
async getListTransactionByIdUser(
idUser: number,
): Promise<Transaction | null> {
): Promise<Transaction[] | null> {
const results = this.getListDataFromProp(
'idUser',
idUser.toString(),
@@ -0,0 +1,205 @@
import Transaction from '../../models/transaction';
import { renderRequiredText } from '../../helpers/validatorForm';
import { Data, TError } from 'global/types';
import Transform from 'helpers/transform';
import Wallet from 'models/wallet';
import User from 'models/user';
import { DEFAULT_CATEGORY } from 'constants/config';
import {
ADD_TRANSACTION_SUCCESS,
DEFAULT_MESSAGE,
} from 'constants/messages/dialog';
export default class BudgetView {
budgetDialog: HTMLDialogElement | null = null;
addBudgetBtn: HTMLElement | null = null;
transform: Transform | null = null;
toggleLoaderSpinner: (() => void) | null = null;
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
loadTransactionData: (() => Promise<void>) | null = null;
updateAmountWallet: (() => Promise<void>) | null = null;
loadData: (() => Promise<void>) | null = null;
showSuccessToast: ((title: string, message: string) => void) | null = null;
showErrorToast: ((error: string | TError) => void) | null = null;
wallet: Wallet | null = null;
user: User | null = null;
constructor() {
this.budgetDialog = document.getElementById(
'budgetDialog',
) as HTMLDialogElement;
this.addBudgetBtn = document.getElementById('addBudget');
this.handlerEventBudgetView();
}
initFunction(
showErrorToast: (error: string | TError) => void,
showSuccessToast: (title: string, message: string) => void,
toggleLoaderSpinner: () => void,
saveTransaction: ((transaction: Transaction) => Promise<void>) | null,
loadTransactionData: () => Promise<void>,
updateAmountWallet: () => Promise<void>,
loadData: () => Promise<void>,
transform: Transform | null,
) {
this.showErrorToast = showErrorToast;
this.showSuccessToast = showSuccessToast;
this.toggleLoaderSpinner = toggleLoaderSpinner;
this.saveTransaction = saveTransaction;
this.loadTransactionData = loadTransactionData;
this.updateAmountWallet = updateAmountWallet;
this.loadData = loadData;
this.transform = transform;
}
subscribe() {
this.transform!.create('budgetView', this.updateData.bind(this));
}
sendData() {
const data = { wallet: this.wallet! };
this.transform!.onSendSignal('budgetView', data);
}
updateData(data: Data) {
if (data.wallet) this.wallet = data.wallet;
if (data.user) this.user = data.user;
}
addHandlerEventBudgetForm() {
this.budgetDialog!.addEventListener('submit', (e) => {
e.preventDefault();
this.clearErrorStyleBudgetForm();
this.submitBudgetForm();
});
this.budgetDialog!.addEventListener('input', () => {
this.changeBtnStyle();
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() {
try {
const form = document.getElementById('formAddBudget') as HTMLFormElement;
const formAddBudget = new FormData(form);
const date = formAddBudget.get('selected_date') as string;
const amount = formAddBudget.get('amount') as string;
const note = formAddBudget.get('note') as string;
// Validate data user input
if (this.validateBudgetForm(date, +amount)) {
this.toggleLoaderSpinner!(); // Enable loader spinner
this.budgetDialog!.close(); // Close dialog
const transaction = new Transaction(
0,
DEFAULT_CATEGORY.INCOME,
date,
note,
+amount,
+this.wallet!.idUser,
);
await this.saveTransaction!(transaction);
// Reload data
await this.loadTransactionData!();
await this.updateAmountWallet!();
await this.loadData!();
// Hide loader spinner
this.toggleLoaderSpinner!();
// Show success message
this.showSuccessToast!(ADD_TRANSACTION_SUCCESS, DEFAULT_MESSAGE);
(<HTMLFormElement>document.getElementById('formAddBudget')!).reset();
}
} catch (error) {
this.showErrorToast!(error as string | TError);
}
}
validateBudgetForm(date: string, amount: number) {
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() {
const date = (<HTMLDataElement>(
this.budgetDialog!.querySelector('.input-date')!
)).value;
const amount = +(<HTMLDataElement>(
this.budgetDialog!.querySelector('.form__input-balance')!
)).value;
const saveBtn = this.budgetDialog!.querySelector('.form__save-btn')!;
if (date.trim() && amount >= 1) {
saveBtn.classList.add('active');
} else {
saveBtn.classList.remove('active');
}
}
handlerEventBudgetView() {
this.addBudgetBtn!.addEventListener('click', () => {
// Set default value for date input
(<HTMLInputElement>(
this.budgetDialog!.querySelector("[name='selected_date']")
))!.valueAsDate = new Date();
this.budgetDialog!.showModal();
});
this.addHandlerEventBudgetForm();
}
}
@@ -0,0 +1,167 @@
import Transform from 'helpers/transform';
import { REMOVE_CATEGORY } from '../../constants/config';
import Category from 'models/category';
import { Data } from 'global/types';
export default class CategoryView {
categoryDialog: HTMLDialogElement | null = null;
categoryField: HTMLElement | null = null;
closeIcon: HTMLElement | null = null;
getAllCategory: (() => Promise<Category[] | null>) | null = null;
transform: Transform | null = null;
listCategory: Category[] | null = null;
categorySelected: string;
constructor() {
this.categorySelected = '';
this.categoryDialog = document.getElementById(
'categoryDialog',
) as HTMLDialogElement;
this.categoryField = document.getElementById('selectCategory');
this.closeIcon = document.querySelector('.close-icon') as HTMLElement;
this.handlerEventCategoryDialog();
this.addEventSelectCategoryDialog();
}
initFunction(
getAllCategory: () => Promise<Category[] | null>,
transform: Transform,
) {
this.getAllCategory = getAllCategory;
this.transform = transform;
}
sendData() {
const data: Data = { listCategories: this.listCategory! };
this.transform!.onSendSignal('categoryView', data);
}
handlerEventCategoryDialog() {
this.categoryDialog!.addEventListener('input', () => {
setTimeout(() => {
this.searchCategory();
}, 300);
});
}
/**
* Load category data
* @param {function} getAllCategory Get all category function
*/
async loadCategory() {
if (!this.listCategory) {
this.listCategory = await this.getAllCategory!();
this.sendData();
}
if (this.listCategory) {
this.renderCategoryList();
}
}
searchCategory() {
const searchCategoryEl: HTMLDataElement =
this.categoryDialog!.querySelector("[name='category']")!;
const searchValue = searchCategoryEl.value.trim().toLowerCase();
let newListCategory: Category[] = [];
if (searchValue) {
this.listCategory!.forEach((category) => {
const categoryName = category.name.trim().toLowerCase();
if (categoryName.includes(searchValue)) {
newListCategory.unshift(category);
}
});
} else {
newListCategory = this.listCategory!;
}
// Render category item
this.renderCategoryList(this.categorySelected, newListCategory);
}
renderCategoryList(
categorySelected?: string,
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
newListCategory.forEach((category) => {
const markup = `
<div class="category-item ${
category.name === categorySelected ? 'selected' : ''
}" data-value='${category.name}' data-url='${category.url}'>
<img
class="icon-category"
src="${category.url}"
alt="${category.name} Icon"
/>
<p class="name-category">${category.name}</p>
</div>
`;
listCategoryEl!.insertAdjacentHTML('afterbegin', markup);
});
}
addEventSelectCategoryDialog() {
const categoryListEl = document.querySelector('.list-category');
const categoryIconEl = this.categoryField!.querySelector(
'.category-icon',
) as HTMLImageElement;
const categoryNameEl = this.categoryField!.querySelector(
'.category-name',
) as HTMLDataElement;
categoryListEl!.addEventListener('click', (e) => {
const categoryItem = (<Element>e.target).closest(
'.category-item',
) as HTMLElement;
if (categoryItem) {
const { url } = categoryItem.dataset;
const { value } = categoryItem.dataset;
// Set url and value into category field in transaction dialog
categoryIconEl.src = url!;
categoryNameEl.value = value!;
// Close select category dialog
this.categoryDialog!.close();
}
});
// Pass value selected to category dialog
categoryNameEl.addEventListener('click', () => {
if (categoryNameEl.value) {
// Make the keyword search category name into global
this.categorySelected = categoryNameEl.value;
this.renderCategoryList(this.categorySelected);
}
this.categoryDialog!.showModal();
});
this.closeIcon!.addEventListener('click', () => {
this.categoryDialog!.close();
});
}
}
+179 -58
View File
@@ -10,49 +10,79 @@ import User from 'models/user';
import { Data, TError } from 'global/types';
import { DEFAULT_TITLE_ERROR_TOAST } from 'constants/messages/dialog';
import { redirectToLoginPage } from 'helpers/url';
import Category from 'models/category';
import CategoryView from './categoryView';
import BudgetView from './budgetView';
import TransactionView from './transactionView';
import SummaryTabView from './summaryTabView';
import TransactionDetail from 'models/transactionDetail';
import TransactionTabView from './transactionTabView';
export default class HomeView extends CommonView {
private _tabs: NodeListOf<Element>;
walletView: WalletView;
private _allContent: NodeListOf<Element>;
categoryView: CategoryView;
private _cancelBtns: NodeListOf<Element>;
budgetView: BudgetView;
private _dialogs: NodeListOf<Element>;
transactionView: TransactionView;
private _amountInputs: NodeListOf<Element>;
summaryTabView: SummaryTabView;
private _walletView: WalletView;
transactionTabView: TransactionTabView;
private _user: User | null = null;
tabs: NodeListOf<Element>;
private _wallet: Wallet | null = null;
allContent: NodeListOf<Element>;
private _getInfoUserLogin: (() => Promise<User | null>) | null = null;
cancelBtns: NodeListOf<Element>;
private _getWalletByIdUser:
| ((idUser: number) => Promise<Wallet | null>)
dialogs: NodeListOf<Element>;
amountInputs: NodeListOf<Element>;
user: User | null = null;
wallet: Wallet | null = null;
listTransactions: Transaction[] | null = null;
transactionDetails: TransactionDetail[] = [];
getInfoUserLogin: (() => Promise<User | null>) | null = null;
getWalletByIdUser: ((idUser: number) => Promise<Wallet | null>) | null = null;
getAllCategory: (() => Promise<Category[] | null>) | null = null;
getAllTransactions:
| ((idUser: number) => Promise<Transaction[] | null>)
| null = null;
private _saveWallet: ((wallet: Wallet) => Promise<void>) | null = null;
deleteTransaction: ((idTransaction: number) => Promise<void>) | null = null;
private _saveTransaction:
| ((transaction: Transaction) => Promise<void>)
| null = null;
saveWallet: ((wallet: Wallet) => Promise<void>) | null = null;
private _transform: Transform | null = null;
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
transform: Transform | null = null;
constructor() {
super();
this._tabs = document.querySelectorAll('.app__tab-item');
this._allContent = document.querySelectorAll('.app__content-item');
this._cancelBtns = document.querySelectorAll('.form__cancel-btn');
this._dialogs = document.querySelectorAll('.dialog');
this.tabs = document.querySelectorAll('.app__tab-item');
this.allContent = document.querySelectorAll('.app__content-item');
this.cancelBtns = document.querySelectorAll('.form__cancel-btn');
this.dialogs = document.querySelectorAll('.dialog');
this._amountInputs = document.querySelectorAll('.form__input-balance');
this.amountInputs = document.querySelectorAll('.form__input-balance');
this._walletView = new WalletView();
this.walletView = new WalletView();
this.categoryView = new CategoryView();
this.budgetView = new BudgetView();
this.transactionView = new TransactionView(this.categoryView);
this.summaryTabView = new SummaryTabView();
this.transactionTabView = new TransactionTabView(this.transactionView);
this.initToast();
this.initLoader();
@@ -62,27 +92,78 @@ export default class HomeView extends CommonView {
initFunction(
getInfoUserLogin: () => Promise<User | null>,
getWalletByIdUser: (idUser: number) => Promise<Wallet | null>,
getAllCategory: () => Promise<Category[] | null>,
getAllTransactions: (idUser: number) => Promise<Transaction[] | null>,
saveWallet: (wallet: Wallet) => Promise<void>,
saveTransaction: (transaction: Transaction) => Promise<void>,
deleteTransaction: (idTransaction: number) => Promise<void>,
transform: Transform,
) {
this._getInfoUserLogin = getInfoUserLogin;
this._getWalletByIdUser = getWalletByIdUser;
this._saveWallet = saveWallet;
this._saveTransaction = saveTransaction;
this.getInfoUserLogin = getInfoUserLogin;
this.getWalletByIdUser = getWalletByIdUser;
this.getAllCategory = getAllCategory;
this.getAllTransactions = getAllTransactions;
this.saveWallet = saveWallet;
this.saveTransaction = saveTransaction;
this.deleteTransaction = deleteTransaction;
this._transform = transform;
this.transform = transform;
// Init function for child view
this.initWalletViewFunction();
this.initBudgetViewFunction();
this.initTransactionViewFunction();
this.initCategoryViewFunction();
this.initSummaryTabViewFunction();
this.initTransactionTabViewFunction();
}
initTransactionViewFunction() {
this.transactionView.initFunction(
this.toggleLoaderSpinner.bind(this),
this.deleteTransaction!,
this.loadTransactionData.bind(this),
this.updateAmountWallet.bind(this),
this.loadData.bind(this),
this.showSuccessToast.bind(this),
this.showErrorToast.bind(this),
this.saveTransaction!,
this.transform,
);
}
initBudgetViewFunction() {
this.budgetView.initFunction(
this.showErrorToast.bind(this),
this.showSuccessToast.bind(this),
this.toggleLoaderSpinner.bind(this),
this.saveTransaction!.bind(this),
this.loadTransactionData.bind(this),
this.updateAmountWallet.bind(this),
this.loadData.bind(this),
this.transform,
);
}
initCategoryViewFunction() {
this.categoryView.initFunction(this.getAllCategory!, this.transform!);
}
initSummaryTabViewFunction() {
this.summaryTabView.initFunction(this.transform!);
}
initTransactionTabViewFunction() {
this.transactionTabView.initFunction(this.transform!);
}
initWalletViewFunction() {
this._walletView.initFunction(
this._transform,
this.walletView.initFunction(
this.transform,
this.toggleLoaderSpinner.bind(this),
this._saveWallet,
this._saveTransaction,
this.saveWallet,
this.saveTransaction,
this.loadTransactionData.bind(this),
this.loadData.bind(this),
this.loadEvent.bind(this),
this.showSuccessToast.bind(this),
@@ -92,19 +173,29 @@ export default class HomeView extends CommonView {
subscribeListenerData() {
this.subscribe();
this._walletView.subscribe();
this.transactionView.subscribe();
this.budgetView.subscribe();
this.summaryTabView.subscribe();
this.transactionTabView.subscribe();
this.walletView.subscribe();
}
async loadData() {
// Send data to other class
this.sendData();
await this.categoryView.loadCategory();
await this.loadWalletUser();
this.summaryTabView.load();
this.transactionTabView.loadTransactionTab();
}
async loadPage() {
this.toggleLoaderSpinner();
const user = await this._getInfoUserLogin!();
const user = await this.getInfoUserLogin!();
if (!user) {
// If user not login yet
@@ -112,16 +203,17 @@ export default class HomeView extends CommonView {
window.location.replace('/login');
} else {
// If user already login
this._user = user;
this._wallet = await this._getWalletByIdUser!(user.id);
this.user = user;
this.wallet = await this.getWalletByIdUser!(user.id);
this.sendData();
// Check user's wallet if have or not
if (!this._wallet) {
if (!this.wallet) {
// Show add wallet dialog
this._walletView.showDialog();
this.walletView.showDialog();
} else {
// Init data
await this.loadTransactionData();
await this.loadData();
// Load event page
@@ -135,31 +227,32 @@ export default class HomeView extends CommonView {
// ---------------------LOAD DATA---------------------//
subscribe() {
this._transform!.create('homeView', this.updateData.bind(this));
this.transform!.create('homeView', this.updateData.bind(this));
}
sendData() {
const data: Data = {
wallet: this._wallet!,
user: this._user!,
wallet: this.wallet!,
listTransactions: this.listTransactions!,
user: this.user!,
};
this._transform!.onSendSignal('homeView', data);
this.transform!.onSendSignal('homeView', data);
}
updateData(data: Data) {
if (data.wallet) this._wallet = data.wallet;
if (data.wallet) this.wallet = data.wallet;
if (data.user) this._user = data.user;
if (data.user) this.user = data.user;
}
/**
* Load wallet user
*/
async loadWalletUser() {
const wallet = this._wallet
? this._wallet
: await this._getWalletByIdUser!(this._user!.id);
const wallet = this.wallet
? this.wallet
: await this.getWalletByIdUser!(this.user!.id);
const walletName = document.querySelector('.wallet__name');
const walletPrice = document.querySelector('.wallet__price');
const walletNameValue = wallet!.walletName;
@@ -167,7 +260,7 @@ export default class HomeView extends CommonView {
const sign = walletAmountValue >= 0 ? '+' : '-';
this._wallet = wallet; // Make wallet into global variable
this.wallet = wallet; // Make wallet into global variable
walletName!.textContent = walletNameValue;
walletPrice!.textContent = `${sign}$ ${formatNumber(
@@ -175,11 +268,38 @@ export default class HomeView extends CommonView {
)}`; // Math.abs(walletAmountValue) to keep the value always > 0
// Update amount wallet into database
this._saveWallet!(this._wallet!);
this.saveWallet!(this.wallet!);
}
// ---------------------END---------------------//
async loadTransactionData() {
this.listTransactions = await this.getAllTransactions!(this.wallet!.idUser);
this.sendData();
}
async updateAmountWallet() {
let inflow = 0;
let outflow = 0;
// Init data first
this.transactionDetails =
this.transactionTabView!.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!);
}
// ---------------------END--------------------- //
// ---------------------TOAST--------------------- //
showSuccessToast(title: string, message: string) {
const typeToast = TypeToast.success;
const btnContent = BTN_CONTENT.OK;
@@ -214,8 +334,9 @@ export default class HomeView extends CommonView {
this.toastBtn.removeEventListener('click', redirectToLoginPage);
}
}
// ---------------------END--------------------- //
// ------------------------------- HANDLER EVENT ------------------------------- //
// --------------------- HANDLER EVENT --------------------- //
loadEvent() {
this.addCommonEventPage();
@@ -226,7 +347,7 @@ export default class HomeView extends CommonView {
* Handle event when click on tabs
*/
handlerTabsTransfer() {
this._tabs.forEach((tab, index) => {
this.tabs.forEach((tab, index) => {
tab.addEventListener('click', (e: Event) => {
this.removeActiveTab();
tab.classList.add('active');
@@ -240,17 +361,17 @@ export default class HomeView extends CommonView {
line.style.width = `${eventTarget.offsetWidth}px`;
line.style.left = `${eventTarget.offsetLeft}px`;
this._allContent.forEach((content) => {
this.allContent.forEach((content) => {
content.classList.remove('active');
});
this._allContent[index].classList.add('active');
this.allContent[index].classList.add('active');
});
});
}
addCommonEventPage() {
// Add event close dialog when click outside
this._dialogs.forEach((dialog) => {
this.dialogs.forEach((dialog) => {
dialog.addEventListener('click', (e) => {
const dialogDimensions = dialog.getBoundingClientRect();
const mouseEvent = e as MouseEvent;
@@ -265,14 +386,14 @@ export default class HomeView extends CommonView {
});
});
this._cancelBtns.forEach((btn) => {
this.cancelBtns.forEach((btn) => {
btn.addEventListener('click', () => {
this.closeAllDialog();
});
});
// Prevent input =,-,e into amount input
this._amountInputs.forEach((item) => {
this.amountInputs.forEach((item) => {
item.addEventListener(
'keypress',
(e) =>
@@ -298,13 +419,13 @@ export default class HomeView extends CommonView {
}
closeAllDialog() {
this._dialogs.forEach((dialog) => {
this.dialogs.forEach((dialog) => {
(<HTMLDialogElement>dialog).close();
});
}
removeActiveTab() {
this._tabs.forEach((tab) => {
this.tabs.forEach((tab) => {
tab.classList.remove('active');
});
}
@@ -0,0 +1,48 @@
import Transform from 'helpers/transform';
import { formatNumber } from '../../helpers/data';
import { Data } from 'global/types';
import Wallet from 'models/wallet';
import Transaction from 'models/transaction';
import Category from 'models/category';
export default class SummaryTabView {
transform: Transform | null = null;
wallet: Wallet | null = null;
listTransactions: Transaction[] = [];
listCategories: Category[] = [];
initFunction(transform: Transform) {
this.transform = transform;
}
subscribe() {
this.transform!.create('summaryTabView', this.updateData.bind(this));
}
updateData(data: Data) {
if (data.wallet) this.wallet = data.wallet;
if (data.listTransactions) this.listTransactions = data.listTransactions;
if (data.listCategories) this.listCategories = data.listCategories;
}
load() {
const inflowValue = document.querySelector('.inflow__text--income')!;
const outflowValue = document.querySelector('.outflow__text--outcome')!;
const totalValue = document.querySelector('.summary__total')!;
const { inflow } = this.wallet!;
const { outflow } = this.wallet!;
const total = inflow + outflow;
inflowValue.textContent = `+$ ${formatNumber(inflow)}`;
outflowValue.textContent = `-$ ${formatNumber(Math.abs(outflow))}`;
totalValue.textContent = `${total >= 0 ? '+' : '-'}$ ${formatNumber(
Math.abs(total),
)}`;
}
}
@@ -0,0 +1,192 @@
import Transform from 'helpers/transform';
import {
createTransactionDetailObject,
getAllCategoryNameInTransactions,
getAllTransactionByCategoryName,
} from '../../helpers/data';
import { formatNumber } from '../../helpers/data';
import TransactionView from './transactionView';
import { Data } from 'global/types';
import Wallet from 'models/wallet';
import Transaction from 'models/transaction';
import Category from 'models/category';
import TransactionDetail from 'models/transactionDetail';
export default class TransactionTabView {
transactionView: TransactionView;
transform: Transform | null = null;
wallet: Wallet | null = null;
listTransactions: Transaction[] = [];
listCategories: Category[] = [];
transactionDetails: TransactionDetail[] = [];
constructor(transactionView: TransactionView) {
this.transactionView = transactionView;
this.addEventTransactionItem();
}
initFunction(transform: Transform) {
this.transform = transform;
}
subscribe() {
this.transform!.create('transactionTabView', this.updateData.bind(this));
}
updateData(data: Data) {
if (data.wallet) this.wallet = data.wallet;
if (data.listTransactions) this.listTransactions = data.listTransactions;
if (data.listCategories) this.listCategories = data.listCategories;
}
async loadTransactionTab() {
// Load category
// Init data first
this.transactionDetails = this.loadTransactionDetailsData();
const transactionEl = document.querySelector('.transaction')!;
const listTransactionDetailEl =
transactionEl.querySelector('.transaction__list')!;
const markup: string[] = [];
if (this.transactionDetails) {
this.transactionDetails.forEach((transactionDetail) => {
markup.push(this.transactionDetailMarkup(transactionDetail));
});
}
listTransactionDetailEl.innerHTML = '';
listTransactionDetailEl.insertAdjacentHTML('afterbegin', markup.join('\n'));
// Load event
this.addEventTransactionItem();
}
loadTransactionDetailsData(): TransactionDetail[] {
// Get all category user have in transactions
const listCategoryInTransaction = getAllCategoryNameInTransactions(
this.listTransactions,
);
// Create transactions details object
const tempList: TransactionDetail[] = listCategoryInTransaction.map(
(categoryName) => {
// Get category object from list category has been loaded.
const category = this.listCategories.filter(
(item) => item.name === categoryName,
);
const transactions = getAllTransactionByCategoryName(
<string>categoryName,
this.listTransactions,
);
return createTransactionDetailObject(
Object.assign({}, ...category),
transactions,
);
},
);
tempList.sort((a, b) => b.transactions[0].id - a.transactions[0].id);
return tempList;
}
// eslint-disable-next-line class-methods-use-this
transactionDetailMarkup(transactionDetail: TransactionDetail) {
const itemTransaction = () => {
const listMarkup: string[] = [];
transactionDetail.transactions.forEach((transaction) => {
const markup = `
<div class="transaction__time" data-id=${transaction.id}>
<div class="transaction__details">
<p class="transaction__day">${transaction.day}</p>
<div class="transaction__time-details">
<p class="transaction__date-time">
${transaction.fullDateString}
</p>
<p class="transaction__note">${
transaction.note === '' ? 'None' : transaction.note
}</p>
</div>
</div>
<p class="transaction__${
transaction.amount >= 0 ? 'income' : 'outcome'
}">${transaction.amount >= 0 ? '+' : '-'}$ ${formatNumber(
Math.abs(transaction.amount),
)}</p>
</div>
`;
listMarkup.push(markup);
});
return listMarkup.join('\n');
};
return `
<div class="transaction__item">
<div class="transaction__category">
<div class="transaction__category-infor">
<div class="transaction__category-icon-container">
<img
class="icon-category"
src="${transactionDetail.url}"
alt="Transportation icon category"
/>
</div>
<div class="transaction__category-content">
<p class="transaction__category-name">
${transactionDetail.categoryName}
</p>
<p class="transaction__total">${
transactionDetail.totalTransaction
} Transactions</p>
</div>
</div>
<p class="transaction__category-total">${
transactionDetail.totalAmount >= 0 ? '+' : '-'
}$ ${formatNumber(Math.abs(transactionDetail.totalAmount))}</p>
</div>
<div class="transaction__line"></div>
<!-- Transaction time item -->
${itemTransaction()}
</div>
`;
}
// eslint-disable-next-line class-methods-use-this
addEventTransactionItem() {
const transactionItemEl = document.querySelectorAll('.transaction__item');
if (transactionItemEl) {
transactionItemEl.forEach((item) => {
item.addEventListener('click', (e) => {
const transactionTime = (<Element>e.target).closest(
'.transaction__time',
);
const categoryNameEl: HTMLInputElement = item.querySelector(
'.transaction__category-name',
)!;
if (transactionTime) {
const idTransaction = +(<HTMLElement>transactionTime).dataset.id!;
// If it is income transaction, don't show dialog
if (
categoryNameEl.textContent &&
categoryNameEl.textContent.trim() !== 'Income'
)
this.transactionView.showTransactionDialog(idTransaction);
}
});
});
}
}
}
@@ -0,0 +1,371 @@
import Transaction from 'models/transaction';
import defaultCategoryIcon from '../../../assets/images/question-icon.svg';
import CategoryView from './categoryView';
import Transform from 'helpers/transform';
import { Data, TError } from 'global/types';
import Wallet from 'models/wallet';
import Category from 'models/category';
import {
ADD_TRANSACTION_SUCCESS,
DEFAULT_MESSAGE,
UPDATE_TRANSACTION_SUCCESS,
} from 'constants/messages/dialog';
import { renderRequiredText } from 'helpers/validatorForm';
export default class TransactionView {
wallet: Wallet | null = null;
listTransactions: Transaction[] = [];
listCategories: Category[] = [];
categoryView: CategoryView;
addTransactionBtn: HTMLElement | null = null;
transactionDialog: HTMLDialogElement | null = null;
transactionForm: HTMLFormElement | null = null;
toggleLoaderSpinner: (() => void) | null = null;
deleteTransaction: ((idTransaction: number) => Promise<void>) | null = null;
loadTransactionData: (() => Promise<void>) | null = null;
updateAmountWallet: (() => Promise<void>) | null = null;
loadData: (() => Promise<void>) | null = null;
showSuccessToast: ((title: string, message: string) => void) | null = null;
showErrorToast: ((error: string | TError) => void) | null = null;
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
transform: Transform | null = null;
constructor(categoryView: CategoryView) {
this.addTransactionBtn = document.getElementById('addTransaction');
this.transactionDialog = document.getElementById(
'transactionDialog',
) as HTMLDialogElement;
this.transactionForm = <HTMLFormElement>(
document.getElementById('formAddTransaction')
);
this.handlerEventTransactionDialog();
this.categoryView = categoryView;
}
initFunction(
toggleLoaderSpinner: () => void,
deleteTransaction: (idTransaction: number) => Promise<void>,
loadTransactionData: () => Promise<void>,
updateAmountWallet: () => Promise<void>,
loadData: () => Promise<void>,
showSuccessToast: (title: string, message: string) => void,
showErrorToast: (error: string | TError) => void,
saveTransaction: (transaction: Transaction) => Promise<void>,
transform: Transform | null,
) {
this.toggleLoaderSpinner = toggleLoaderSpinner;
this.deleteTransaction = deleteTransaction;
this.loadTransactionData = loadTransactionData;
this.updateAmountWallet = updateAmountWallet;
this.loadData = loadData;
this.showSuccessToast = showSuccessToast;
this.showErrorToast = showErrorToast;
this.saveTransaction = saveTransaction;
this.transform = transform;
}
subscribe() {
this.transform!.create('transactionView', this.updateData.bind(this));
}
sendData() {
const data: Data = {
wallet: this.wallet!,
listTransactions: this.listTransactions!,
};
this.transform!.onSendSignal('transactionView', data);
}
updateData(data: Data) {
if (data.wallet) this.wallet = data.wallet;
if (data.listTransactions) this.listTransactions = data.listTransactions;
if (data.listCategories) this.listCategories = data.listCategories;
}
handlerEventTransactionDialog() {
this.transactionDialog!.addEventListener('submit', (e) => {
e.preventDefault();
this.clearErrorTransactionDialog();
this.submitTransactionDialog();
});
this.transactionDialog!.addEventListener('input', () => {
this.changeBtnStyleTransactionDialog();
this.clearErrorTransactionDialog();
});
// Add delete transaction event
this.deleteTransactionEvent();
this.addTransactionBtn!.addEventListener('click', () => {
this.showTransactionDialog();
});
this.handlerCategoryFieldEvent();
}
handlerCategoryFieldEvent() {
const categoryField = this.transactionForm!.querySelector(
"[name='category_name']",
);
categoryField!.addEventListener('click', () => {
this.clearErrorTransactionDialog();
});
}
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',
) as Element;
deleteTransactionBtn.addEventListener('click', async () => {
const idEl = this.transactionDialog!.querySelector(
"[name='id_transaction']",
) as HTMLDataElement;
if (idEl.value) {
try {
this.transactionDialog!.close();
this.toggleLoaderSpinner!();
await this.deleteTransaction!(+idEl.value);
// Reload data
await this.loadTransactionData!();
await this.updateAmountWallet!();
await this.loadData!();
this.showSuccessToast!('Delete success!', DEFAULT_MESSAGE);
} catch (error) {
this.showErrorToast!(error as string | TError);
}
this.toggleLoaderSpinner!();
}
});
}
changeBtnStyleTransactionDialog() {
const dateInput = (<HTMLDataElement>(
this.transactionDialog!.querySelector("[name='selected_date']")
)).value;
const categoryName = (<HTMLDataElement>(
this.transactionDialog!.querySelector("[name='category_name']")
)).value;
const amountInput = +(<HTMLDataElement>(
this.transactionDialog!.querySelector("[name='amount']")
)).value;
const saveBtn = this.transactionDialog!.querySelector('.form__save-btn')!;
saveBtn.classList.toggle(
'active',
<boolean>(dateInput && categoryName && amountInput >= 1),
);
}
initValueTransactionDialog(idTransaction: number | null) {
let categoryName: string;
if (idTransaction) {
// Get transaction object
const transactionArr = this.listTransactions.filter(
(obj) => obj.id === idTransaction,
);
const transaction = Object.assign({}, ...transactionArr);
// Get category object
const categoryArr = this.listCategories.filter(
(obj) => obj.name === transaction.categoryName,
);
const category = Object.assign({}, ...categoryArr);
const idEl = <HTMLDataElement>(
this.transactionDialog!.querySelector("[name='id_transaction']")
);
const dateEl = <HTMLDataElement>(
this.transactionDialog!.querySelector("[name='selected_date']"!)
);
const categoryEl = <HTMLDataElement>(
this.transactionDialog!.querySelector("[name='category_name']")
);
const amountEl = <HTMLDataElement>(
this.transactionDialog!.querySelector("[name='amount']")
);
const noteEl = <HTMLDataElement>(
this.transactionDialog!.querySelector("[name='note']")
);
const iconEl = <HTMLImageElement>(
this.transactionDialog!.querySelector('.category-icon')
);
idEl.value = transaction.id;
dateEl.value = transaction.date;
categoryEl.value = transaction.categoryName;
amountEl.value = Math.abs(transaction.amount).toString();
noteEl.value = transaction.note;
iconEl.src = category.url;
categoryName = categoryEl.value;
}
// Show delete button only if it is a edit form and not a income transaction
const deleteBtn =
this.transactionDialog!.querySelector('.form__delete-btn')!;
const showDeleteBtn = () => {
return idTransaction && categoryName !== 'Income';
};
deleteBtn.classList.toggle('hide', !showDeleteBtn());
}
async submitTransactionDialog() {
try {
const dateEl = <HTMLDataElement>(
this.transactionForm!.querySelector("[name='selected_date']")
);
const categoryNameEl = <HTMLDataElement>(
this.transactionForm!.querySelector("[name='category_name']")
);
const amountEl = <HTMLDataElement>(
this.transactionForm!.querySelector("[name='amount']")
);
const noteEl = <HTMLDataElement>(
this.transactionForm!.querySelector("[name='note']")
);
const idEl = <HTMLDataElement>(
this.transactionForm!.querySelector("[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(
+idEl.value,
categoryNameEl.value,
dateEl.value,
noteEl.value,
+amount,
+this.wallet!.idUser,
);
await this.saveTransaction!(transaction);
// Reload data
await this.loadTransactionData!();
await this.updateAmountWallet!();
await this.loadData!();
if (!idEl.value) {
// Add success
this.showSuccessToast!(ADD_TRANSACTION_SUCCESS, DEFAULT_MESSAGE);
} else {
// Update success
this.showSuccessToast!(UPDATE_TRANSACTION_SUCCESS, DEFAULT_MESSAGE);
}
this.toggleLoaderSpinner!();
this.clearInputTransactionForm();
}
} catch (error) {
this.showErrorToast!(error as string | TError);
this.toggleLoaderSpinner!();
}
}
validateTransactionForm(date: string, categoryName: string, amount: number) {
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() {
const categoryIcon = <HTMLImageElement>(
this.transactionForm!.querySelector('.category-icon')
);
categoryIcon.src = defaultCategoryIcon;
const keySearchCategory: string = ''; // Delete keyword search
this.categoryView.renderCategoryList(
keySearchCategory,
this.listCategories,
);
this.transactionForm!.reset();
}
showTransactionDialog(idTransaction: number | null = null) {
this.clearInputTransactionForm();
// Init data transaction to dialog
this.initValueTransactionDialog(idTransaction);
if (!idTransaction)
(<HTMLInputElement>(
this.transactionDialog!.querySelector("[name='selected_date']")
)).valueAsDate = new Date(); // Set default value for date input
// Change style submit btn
this.changeBtnStyleTransactionDialog();
this.transactionDialog!.showModal();
}
}
@@ -20,6 +20,8 @@ export default class WalletView {
| ((transaction: Transaction) => Promise<void>)
| null = null;
private _loadTransactionData: (() => Promise<void>) | null = null;
private _loadData: (() => Promise<void>) | null = null;
private _loadEvent: (() => void) | null = null;
@@ -46,6 +48,7 @@ export default class WalletView {
toggleLoaderSpinner: () => void,
saveWallet: ((wallet: Wallet) => Promise<void>) | null,
saveTransaction: ((transaction: Transaction) => Promise<void>) | null,
loadTransactionData: () => Promise<void>,
loadData: () => Promise<void>,
loadEvent: () => void,
showSuccessToast: (title: string, message: string) => void,
@@ -55,6 +58,7 @@ export default class WalletView {
this._toggleLoaderSpinner = toggleLoaderSpinner;
this._saveWallet = saveWallet;
this._saveTransaction = saveTransaction;
this._loadTransactionData = loadTransactionData;
this._loadData = loadData;
this._loadEvent = loadEvent;
this._showSuccessToast = showSuccessToast;
@@ -127,8 +131,7 @@ export default class WalletView {
this._walletDialog!.close();
this._toggleLoaderSpinner!();
const wallet = new Wallet(walletName, +amount, 0, this._user!.id)
.toObject as Wallet;
const wallet = new Wallet(walletName, +amount, 0, this._user!.id);
this._wallet = wallet;
this.sendData();
@@ -136,17 +139,20 @@ export default class WalletView {
await this._saveWallet!(wallet);
// Transaction info
const transaction = new Transaction(
0,
'Income',
new Date().toISOString().slice(0, 10),
FIRST_ADD_WALLET_NOTE,
+amount,
this._user!.id,
).toObject;
);
await this._saveTransaction!(transaction);
// Load data and event
await this._loadTransactionData!();
await this._loadData!();
this._loadEvent!();
this._showSuccessToast!(ADD_WALLET_SUCCESS, DEFAULT_MESSAGE);
this._toggleLoaderSpinner!();