mirror of
https://github.com/Nezumi-2711/typescript-training.git
synced 2026-09-22 13:48:29 +00:00
Refactor and optimized code
This commit is contained in:
@@ -250,7 +250,7 @@
|
||||
<div class="app__tabs">
|
||||
<button class="app__tab-item active">SUMMARY</button>
|
||||
<button class="app__tab-item">TRANSACTION DETAILS</button>
|
||||
<div class="app__line left"></div>
|
||||
<div class="app__line"></div>
|
||||
</div>
|
||||
<!-- Start content app -->
|
||||
<div class="app__contents">
|
||||
|
||||
@@ -104,6 +104,8 @@
|
||||
&__line {
|
||||
position: absolute;
|
||||
top: 66px;
|
||||
left: 152px;
|
||||
width: 116px;
|
||||
height: 2px;
|
||||
background-color: $primary-color;
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -11,14 +11,15 @@ export const LOCAL_STORAGE = {
|
||||
ACCESS_TOKEN: 'accessToken',
|
||||
};
|
||||
|
||||
export enum TypeToast {
|
||||
success = 'success',
|
||||
error = 'error',
|
||||
}
|
||||
export enum MarkIcon {
|
||||
success = 'success',
|
||||
error = 'error',
|
||||
}
|
||||
export const TypeToast = {
|
||||
success: 'success',
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
export const MarkIcon = {
|
||||
success: 'success',
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
export const REGEX = {
|
||||
PASSWORD:
|
||||
|
||||
+14
@@ -1,3 +1,17 @@
|
||||
export const PASSWORD_NOT_MATCH = 'Password not match!';
|
||||
|
||||
export const PASSWORD_NOT_STRONG =
|
||||
'Password must at least one uppercase, one lowercase letter, one number and one special character!';
|
||||
|
||||
export const ERROR_CREDENTIAL = {
|
||||
title: 'Error Credential',
|
||||
message: 'Email or password not match! Please try again!',
|
||||
};
|
||||
|
||||
export const INVALID_EMAIL_FORMAT = `The email is not correct!`;
|
||||
|
||||
export const REQUIRED_MESSAGE = (field: string) => `The ${field} is required!`;
|
||||
|
||||
export const ERROR_MESSAGE_DEFAULT = ['Something went wrong!'];
|
||||
|
||||
export const TIME_OUT_ERROR = 'Connection time out! Please try again!';
|
||||
@@ -1,13 +0,0 @@
|
||||
export const PASSWORD_NOT_MATCH = 'Password not match!';
|
||||
|
||||
export const PASSWORD_NOT_STRONG =
|
||||
'Password must at least one uppercase, one lowercase letter, one number and one special character!';
|
||||
|
||||
export const ERROR_CREDENTIAL = {
|
||||
title: 'Error Credential',
|
||||
message: 'Email or password not match! Please try again!',
|
||||
};
|
||||
|
||||
export const INVALID_EMAIL_FORMAT = `The email is not correct!`;
|
||||
|
||||
export const REQUIRED_MESSAGE = (field: string) => `The ${field} is required!`;
|
||||
@@ -1,10 +1,10 @@
|
||||
import HomeView from 'views/home/homeView';
|
||||
import Transform from '../helpers/transform';
|
||||
import Service from 'services';
|
||||
import View from 'views';
|
||||
import Wallet from 'models/wallet';
|
||||
import Transaction from 'models/transaction';
|
||||
import Category from 'models/category';
|
||||
import { IHomeFunc } from 'global/types';
|
||||
|
||||
export default class HomeController {
|
||||
public homeView: HomeView | null = null;
|
||||
@@ -47,16 +47,17 @@ export default class HomeController {
|
||||
|
||||
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(),
|
||||
);
|
||||
const func: IHomeFunc = {
|
||||
getInfoUserLogin: this.handlerGetInfoUserLogin.bind(this),
|
||||
getWalletByIdUser: this.handlerGetWalletByIdUser.bind(this),
|
||||
getAllCategory: this.handlerGetAllCategory.bind(this),
|
||||
getAllTransactions: this.handlerGetAllTransactions.bind(this),
|
||||
saveWallet: this.handlerSaveWallet.bind(this),
|
||||
saveTransaction: this.handlerSaveTransaction.bind(this),
|
||||
deleteTransaction: this.handlerDeleteTransaction.bind(this),
|
||||
};
|
||||
|
||||
this.homeView.initFunction(func);
|
||||
|
||||
this.homeView.loadPage();
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@ export class DataObject<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export interface TError {
|
||||
export interface IError {
|
||||
title: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type TError = string | IError;
|
||||
|
||||
export class CustomError extends Error {
|
||||
constructor(
|
||||
public title: string,
|
||||
@@ -33,13 +35,6 @@ export class CustomError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export type TSignal = {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
handler: (value: Data) => void;
|
||||
};
|
||||
};
|
||||
|
||||
export interface Data {
|
||||
wallet?: Wallet;
|
||||
listTransactions?: Transaction[];
|
||||
@@ -54,3 +49,50 @@ export interface ItemTransaction {
|
||||
note: string;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export type Nullable<T> = T | null;
|
||||
export type PromiseVoid = () => Promise<void>;
|
||||
export type VoidFunc = () => void;
|
||||
export type PromiseOrNull<T> = () => Promise<T | null>;
|
||||
|
||||
export interface IHomeFunc {
|
||||
getInfoUserLogin?: PromiseOrNull<User>;
|
||||
getWalletByIdUser?: (idUser: string) => Promise<Wallet | null>;
|
||||
getAllCategory?: PromiseOrNull<Category[]>;
|
||||
getAllTransactions?: (idUser: string) => Promise<Transaction[] | null>;
|
||||
saveWallet?: (wallet: Wallet) => Promise<void>;
|
||||
saveTransaction?: (transaction: Transaction) => Promise<void>;
|
||||
deleteTransaction?: (idTransaction: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface IBudgetViewFunc {
|
||||
showErrorToast: (error: TError) => void;
|
||||
showSuccessToast: (title: string, message: string) => void;
|
||||
toggleLoaderSpinner: VoidFunc;
|
||||
saveTransaction: Nullable<(transaction: Transaction) => Promise<void>>;
|
||||
loadTransactionData: PromiseVoid;
|
||||
updateAmountWallet: PromiseVoid;
|
||||
loadData: PromiseVoid;
|
||||
}
|
||||
|
||||
export interface ITransactionViewFunc {
|
||||
toggleLoaderSpinner: VoidFunc;
|
||||
deleteTransaction: (idTransaction: string) => Promise<void>;
|
||||
loadTransactionData: PromiseVoid;
|
||||
updateAmountWallet: PromiseVoid;
|
||||
loadData: PromiseVoid;
|
||||
showSuccessToast: (title: string, message: string) => void;
|
||||
showErrorToast: (error: TError) => void;
|
||||
saveTransaction: (transaction: Transaction) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface IWalletViewFunc {
|
||||
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;
|
||||
showErrorToast: (error: TError) => void;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TIME_OUT_ERROR } from '../constants/messages/dialog';
|
||||
import { TIME_OUT_ERROR } from '../constants/messages';
|
||||
import { TIME_OUT_SEC } from '../constants/config';
|
||||
import FirebaseService from '../services/firebaseService';
|
||||
|
||||
|
||||
+15
-2
@@ -1,12 +1,25 @@
|
||||
import { TSignal, Data } from 'global/types';
|
||||
import { Data } from 'global/types';
|
||||
|
||||
type TSignal = {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
handler: (value: Data) => void;
|
||||
};
|
||||
};
|
||||
|
||||
export default class EventDataTrigger {
|
||||
private static _instance: EventDataTrigger;
|
||||
|
||||
export default class Transform {
|
||||
public signal: TSignal;
|
||||
|
||||
constructor() {
|
||||
this.signal = {};
|
||||
}
|
||||
|
||||
public static get Instance() {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
onSendSignal(fromClass: string, value: Data) {
|
||||
Object.keys(this.signal).forEach((key) => {
|
||||
const item = this.signal[key as keyof TSignal];
|
||||
@@ -1,8 +1,8 @@
|
||||
export const redirectToLoginPage = (): void => {
|
||||
export const redirectToLoginPage = () => {
|
||||
window.location.replace('/login');
|
||||
};
|
||||
|
||||
export const getSubdirectoryURL = () => {
|
||||
export const getSubdirectoryURL = (): string => {
|
||||
const url = window.location.href;
|
||||
const parts = url.split('/'); // Results: ['http:', '', 'example.com', '']
|
||||
const subDirectory = parts[3]; // Get subdirectory url only
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { REGEX } from '../constants/config';
|
||||
import { REQUIRED_MESSAGE } from '../constants/messages/form';
|
||||
import { REQUIRED_MESSAGE } from '../constants/messages';
|
||||
|
||||
/**
|
||||
* Validate password
|
||||
@@ -21,7 +21,7 @@ export const compare2Password = (
|
||||
return password === passwordConfirm;
|
||||
};
|
||||
|
||||
export const renderRequiredText = (field: string, element: Element): void => {
|
||||
export const renderRequiredText = (field: string, element: Element) => {
|
||||
const markup: string = `
|
||||
<p class="error-text">${REQUIRED_MESSAGE(field)}</p>
|
||||
`;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
export default class Category {
|
||||
readonly id: string;
|
||||
|
||||
url: string;
|
||||
|
||||
name: string;
|
||||
|
||||
constructor(id: string, url: string, name: string) {
|
||||
constructor(
|
||||
public id: string,
|
||||
public url: string,
|
||||
public name: string,
|
||||
) {
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.name = name;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { generateId } from '../helpers/data';
|
||||
|
||||
export default class User {
|
||||
id: string;
|
||||
|
||||
email: string;
|
||||
|
||||
password: string;
|
||||
|
||||
accessToken: string;
|
||||
|
||||
constructor(email: string, password: string, accessToken?: string) {
|
||||
this.id = generateId();
|
||||
constructor(
|
||||
public id: string,
|
||||
public email: string,
|
||||
public password: string,
|
||||
public accessToken?: string,
|
||||
) {
|
||||
this.id = id ? id : generateId();
|
||||
this.email = email;
|
||||
this.password = password || '';
|
||||
this.accessToken = accessToken || '';
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import { generateId } from '../helpers/data';
|
||||
|
||||
export default class Wallet {
|
||||
id: string;
|
||||
|
||||
walletName: string;
|
||||
|
||||
inflow: number;
|
||||
|
||||
outflow: number;
|
||||
|
||||
idUser: string;
|
||||
|
||||
constructor(
|
||||
walletName: string,
|
||||
inflow: number,
|
||||
outflow: number,
|
||||
idUser: string,
|
||||
public id: string,
|
||||
public walletName: string,
|
||||
public inflow: number,
|
||||
public outflow: number,
|
||||
public idUser: string,
|
||||
) {
|
||||
this.id = generateId();
|
||||
this.id = id ? id : generateId();
|
||||
this.walletName = walletName;
|
||||
this.inflow = inflow;
|
||||
this.outflow = outflow;
|
||||
|
||||
@@ -5,7 +5,7 @@ class LocalStorageService {
|
||||
this.localStorage = localStorage;
|
||||
}
|
||||
|
||||
add(key: string, value: string): void {
|
||||
add(key: string, value: string) {
|
||||
this.localStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ class LocalStorageService {
|
||||
return this.localStorage.getItem(key);
|
||||
}
|
||||
|
||||
remove(key: string): void {
|
||||
remove(key: string) {
|
||||
this.localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
clear() {
|
||||
this.localStorage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export default class TransactionService extends CommonService<Transaction> {
|
||||
return results || null;
|
||||
}
|
||||
|
||||
async deleteTransaction(idTransaction: string) {
|
||||
async deleteTransaction(idTransaction: string): Promise<void> {
|
||||
await this.deleteData(idTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import CommonView from './commonView';
|
||||
import { ERROR_MESSAGE_DEFAULT } from '../constants/messages/dialog';
|
||||
import {
|
||||
INVALID_EMAIL_FORMAT,
|
||||
PASSWORD_NOT_MATCH,
|
||||
PASSWORD_NOT_STRONG,
|
||||
} from 'constants/messages/form';
|
||||
ERROR_MESSAGE_DEFAULT,
|
||||
} from 'constants/messages';
|
||||
import {
|
||||
compare2Password,
|
||||
isValidPassword,
|
||||
isValidateEmail,
|
||||
renderRequiredText,
|
||||
} from '../helpers/validatorForm';
|
||||
import { Nullable } from 'global/types';
|
||||
|
||||
export default class AuthenticationView extends CommonView {
|
||||
public formEl: HTMLBodyElement | null;
|
||||
public formEl: Nullable<HTMLBodyElement>;
|
||||
|
||||
public emailEl: HTMLBodyElement | null;
|
||||
public emailEl: Nullable<HTMLBodyElement>;
|
||||
|
||||
public messageDefault: string[];
|
||||
|
||||
public inputPasswordEl: HTMLBodyElement | null;
|
||||
public inputPasswordEl: Nullable<HTMLBodyElement>;
|
||||
|
||||
public inputPasswordConfirmEl: HTMLBodyElement | null;
|
||||
public inputPasswordConfirmEl: Nullable<HTMLBodyElement>;
|
||||
|
||||
public listError: string[];
|
||||
|
||||
@@ -70,7 +71,7 @@ export default class AuthenticationView extends CommonView {
|
||||
return false;
|
||||
}
|
||||
|
||||
validatePasswordConfirm(password: string, passwordConfirm: string) {
|
||||
validatePasswordConfirm(password: string, passwordConfirm: string): boolean {
|
||||
if (passwordConfirm) {
|
||||
if (!compare2Password(password, passwordConfirm)) {
|
||||
this.listError.push(PASSWORD_NOT_MATCH);
|
||||
@@ -120,7 +121,7 @@ export default class AuthenticationView extends CommonView {
|
||||
/**
|
||||
* Add event listener for input field at form
|
||||
*/
|
||||
addHandlerInputFormChange(): void {
|
||||
addHandlerInputFormChange() {
|
||||
if (this.formEl)
|
||||
this.formEl.addEventListener('input', () => {
|
||||
this.clearErrorMessage();
|
||||
@@ -131,7 +132,7 @@ export default class AuthenticationView extends CommonView {
|
||||
* Show error message with error style input password.
|
||||
* @param {string} message The error message you want show in form.
|
||||
*/
|
||||
showError(message: string[]): void {
|
||||
showError(message: string[]) {
|
||||
this.renderError(message);
|
||||
}
|
||||
|
||||
@@ -139,7 +140,7 @@ export default class AuthenticationView extends CommonView {
|
||||
* Show error message in form
|
||||
* @param {string} message The message will show in form
|
||||
*/
|
||||
renderError(messages = this.messageDefault): void {
|
||||
renderError(messages = this.messageDefault) {
|
||||
if (messages.length > 0) {
|
||||
const messageItemMarkup = messages
|
||||
.map((message) => `<li>${message}</li>`)
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { Nullable } from 'global/types';
|
||||
import { MarkIcon, TypeToast } from '../constants/config';
|
||||
|
||||
export default class CommonView {
|
||||
public toastDialog: HTMLDialogElement | null = null;
|
||||
public toastDialog: Nullable<HTMLDialogElement> = null;
|
||||
|
||||
public toastIcon: HTMLBodyElement | null = null;
|
||||
public toastIcon: Nullable<HTMLBodyElement> = null;
|
||||
|
||||
public toastBtn: HTMLBodyElement | null = null;
|
||||
public toastBtn: Nullable<HTMLBodyElement> = null;
|
||||
|
||||
public toastTitle: HTMLBodyElement | null = null;
|
||||
public toastTitle: Nullable<HTMLBodyElement> = null;
|
||||
|
||||
public toastContent: HTMLBodyElement | null = null;
|
||||
public toastContent: Nullable<HTMLBodyElement> = null;
|
||||
|
||||
public spinner: HTMLBodyElement | null = null;
|
||||
public spinner: Nullable<HTMLBodyElement> = null;
|
||||
|
||||
constructor() {
|
||||
this.toastDialog = document.querySelector('.dialog .toast');
|
||||
@@ -22,7 +23,7 @@ export default class CommonView {
|
||||
/**
|
||||
* Implement toast in site
|
||||
*/
|
||||
initToast(): void {
|
||||
initToast() {
|
||||
const markup = `
|
||||
<dialog class="dialog">
|
||||
<div class="toast">
|
||||
@@ -61,7 +62,7 @@ export default class CommonView {
|
||||
/**
|
||||
* Show or hide loader screen
|
||||
*/
|
||||
toggleLoaderSpinner(): void {
|
||||
toggleLoaderSpinner() {
|
||||
if (this.spinner) this.spinner.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
@@ -77,18 +78,21 @@ export default class CommonView {
|
||||
title: string,
|
||||
content: string,
|
||||
btnContent: string,
|
||||
): void {
|
||||
) {
|
||||
// Remove old typeToast class if haved
|
||||
Object.keys(TypeToast).forEach((key) => {
|
||||
CommonView.removeClassElement(
|
||||
TypeToast[key as TypeToast],
|
||||
TypeToast[key as keyof typeof TypeToast],
|
||||
this.toastDialog as HTMLBodyElement | null,
|
||||
);
|
||||
});
|
||||
|
||||
// Remove old icon toast if haved
|
||||
Object.keys(MarkIcon).forEach((key) => {
|
||||
CommonView.removeClassElement(MarkIcon[key as MarkIcon], this.toastIcon);
|
||||
CommonView.removeClassElement(
|
||||
MarkIcon[key as keyof typeof MarkIcon],
|
||||
this.toastIcon,
|
||||
);
|
||||
});
|
||||
|
||||
// Init content toast
|
||||
@@ -111,7 +115,7 @@ export default class CommonView {
|
||||
}
|
||||
}
|
||||
|
||||
static removeClassElement(classEl: string, el: HTMLBodyElement | null): void {
|
||||
static removeClassElement(classEl: string, el: HTMLBodyElement | null) {
|
||||
if (el && el.classList.contains(classEl)) {
|
||||
el.classList.remove(classEl);
|
||||
}
|
||||
@@ -120,7 +124,7 @@ export default class CommonView {
|
||||
/**
|
||||
* Add event listener for toast
|
||||
*/
|
||||
handleEventToast(): void {
|
||||
handleEventToast() {
|
||||
if (this.toastBtn) {
|
||||
this.toastBtn.addEventListener('click', () => {
|
||||
if (this.toastDialog) this.toastDialog.close();
|
||||
|
||||
@@ -1,39 +1,43 @@
|
||||
import Transaction from '../../models/transaction';
|
||||
import { renderRequiredText } from '../../helpers/validatorForm';
|
||||
import { Data, TError } from 'global/types';
|
||||
import Transform from 'helpers/transform';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
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';
|
||||
import {
|
||||
ADD_TRANSACTION_SUCCESS,
|
||||
DEFAULT_MESSAGE,
|
||||
} from 'constants/messages/dialog';
|
||||
IBudgetViewFunc,
|
||||
Data,
|
||||
Nullable,
|
||||
PromiseVoid,
|
||||
TError,
|
||||
VoidFunc,
|
||||
} from 'global/types';
|
||||
|
||||
export default class BudgetView {
|
||||
budgetDialog: HTMLDialogElement | null = null;
|
||||
budgetDialog: Nullable<HTMLDialogElement> = null;
|
||||
|
||||
addBudgetBtn: HTMLElement | null = null;
|
||||
addBudgetBtn: Nullable<HTMLElement> = null;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
toggleLoaderSpinner: (() => void) | null = null;
|
||||
toggleLoaderSpinner: Nullable<VoidFunc> = null;
|
||||
|
||||
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
|
||||
saveTransaction: Nullable<(transaction: Transaction) => Promise<void>> = null;
|
||||
|
||||
loadTransactionData: (() => Promise<void>) | null = null;
|
||||
loadTransactionData: Nullable<PromiseVoid> = null;
|
||||
|
||||
updateAmountWallet: (() => Promise<void>) | null = null;
|
||||
updateAmountWallet: Nullable<PromiseVoid> = null;
|
||||
|
||||
loadData: (() => Promise<void>) | null = null;
|
||||
loadData: Nullable<PromiseVoid> = null;
|
||||
|
||||
showSuccessToast: ((title: string, message: string) => void) | null = null;
|
||||
showSuccessToast: Nullable<(title: string, message: string) => void> = null;
|
||||
|
||||
showErrorToast: ((error: string | TError) => void) | null = null;
|
||||
showErrorToast: Nullable<(error: TError) => void> = null;
|
||||
|
||||
wallet: Wallet | null = null;
|
||||
wallet: Nullable<Wallet> = null;
|
||||
|
||||
user: User | null = null;
|
||||
user: Nullable<User> = null;
|
||||
|
||||
constructor() {
|
||||
this.budgetDialog = document.getElementById(
|
||||
@@ -44,34 +48,26 @@ export default class BudgetView {
|
||||
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;
|
||||
initFunction(func: IBudgetViewFunc) {
|
||||
this.showErrorToast = func.showErrorToast;
|
||||
this.showSuccessToast = func.showSuccessToast;
|
||||
this.toggleLoaderSpinner = func.toggleLoaderSpinner;
|
||||
this.saveTransaction = func.saveTransaction;
|
||||
this.loadTransactionData = func.loadTransactionData;
|
||||
this.updateAmountWallet = func.updateAmountWallet;
|
||||
this.loadData = func.loadData;
|
||||
|
||||
this.evDataTrigger = EventDataTrigger.Instance;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('budgetView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create('budgetView', this.updateData.bind(this));
|
||||
}
|
||||
|
||||
sendData() {
|
||||
const data = { wallet: this.wallet! };
|
||||
|
||||
this.transform!.onSendSignal('budgetView', data);
|
||||
this.evDataTrigger!.onSendSignal('budgetView', data);
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
@@ -110,7 +106,7 @@ export default class BudgetView {
|
||||
});
|
||||
}
|
||||
|
||||
async submitBudgetForm() {
|
||||
async submitBudgetForm(): Promise<void> {
|
||||
try {
|
||||
const form = document.getElementById('formAddBudget') as HTMLFormElement;
|
||||
const formAddBudget = new FormData(form);
|
||||
@@ -149,11 +145,11 @@ export default class BudgetView {
|
||||
(<HTMLFormElement>document.getElementById('formAddBudget')!).reset();
|
||||
}
|
||||
} catch (error) {
|
||||
this.showErrorToast!(error as string | TError);
|
||||
this.showErrorToast!(error as TError);
|
||||
}
|
||||
}
|
||||
|
||||
validateBudgetForm(date: string, amount: number) {
|
||||
validateBudgetForm(date: string, amount: number): boolean {
|
||||
const inputFieldEl =
|
||||
this.budgetDialog!.querySelectorAll('.form__input-field');
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import Transform from 'helpers/transform';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import { REMOVE_CATEGORY } from '../../constants/config';
|
||||
import Category from 'models/category';
|
||||
import { Data } from 'global/types';
|
||||
import { Data, Nullable, PromiseOrNull } from 'global/types';
|
||||
|
||||
export default class CategoryView {
|
||||
categoryDialog: HTMLDialogElement | null = null;
|
||||
categoryDialog: Nullable<HTMLDialogElement> = null;
|
||||
|
||||
categoryField: HTMLElement | null = null;
|
||||
categoryField: Nullable<HTMLElement> = null;
|
||||
|
||||
closeIcon: HTMLElement | null = null;
|
||||
closeIcon: Nullable<HTMLElement> = null;
|
||||
|
||||
getAllCategory: (() => Promise<Category[] | null>) | null = null;
|
||||
getAllCategory: Nullable<PromiseOrNull<Category[]>> = null;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
listCategory: Category[] | null = null;
|
||||
listCategory: Nullable<Category[]> = null;
|
||||
|
||||
categorySelected: string;
|
||||
|
||||
@@ -32,17 +32,17 @@ export default class CategoryView {
|
||||
}
|
||||
|
||||
initFunction(
|
||||
getAllCategory: () => Promise<Category[] | null>,
|
||||
transform: Transform,
|
||||
getAllCategory: PromiseOrNull<Category[]>,
|
||||
evDataTrigger: EventDataTrigger,
|
||||
) {
|
||||
this.getAllCategory = getAllCategory;
|
||||
this.transform = transform;
|
||||
this.evDataTrigger = evDataTrigger;
|
||||
}
|
||||
|
||||
sendData() {
|
||||
const data: Data = { listCategories: this.listCategory! };
|
||||
|
||||
this.transform!.onSendSignal('categoryView', data);
|
||||
this.evDataTrigger!.onSendSignal('categoryView', data);
|
||||
}
|
||||
|
||||
handlerEventCategoryDialog() {
|
||||
@@ -57,7 +57,7 @@ export default class CategoryView {
|
||||
* Load category data
|
||||
* @param {function} getAllCategory Get all category function
|
||||
*/
|
||||
async loadCategory() {
|
||||
async loadCategory(): Promise<void> {
|
||||
if (!this.listCategory) {
|
||||
this.listCategory = await this.getAllCategory!();
|
||||
|
||||
|
||||
@@ -4,11 +4,20 @@ import { clearAccessToken, formatNumber } from '../../helpers/data';
|
||||
|
||||
import WalletView from './walletView';
|
||||
import Wallet from 'models/wallet';
|
||||
import Transform from 'helpers/transform';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import Transaction from 'models/transaction';
|
||||
import User from 'models/user';
|
||||
import { Data, TError } from 'global/types';
|
||||
import { DEFAULT_TITLE_ERROR_TOAST } from 'constants/messages/dialog';
|
||||
import {
|
||||
Data,
|
||||
IBudgetViewFunc,
|
||||
IHomeFunc,
|
||||
ITransactionViewFunc,
|
||||
IWalletViewFunc,
|
||||
Nullable,
|
||||
PromiseOrNull,
|
||||
TError,
|
||||
} from 'global/types';
|
||||
import { DEFAULT_TITLE_ERROR_TOAST } from 'constants/messages';
|
||||
import { redirectToLoginPage } from 'helpers/url';
|
||||
import Category from 'models/category';
|
||||
import CategoryView from './categoryView';
|
||||
@@ -41,31 +50,32 @@ export default class HomeView extends CommonView {
|
||||
|
||||
amountInputs: NodeListOf<Element>;
|
||||
|
||||
user: User | null = null;
|
||||
user: Nullable<User> = null;
|
||||
|
||||
wallet: Wallet | null = null;
|
||||
wallet: Nullable<Wallet> = null;
|
||||
|
||||
listTransactions: Transaction[] | null = null;
|
||||
listTransactions: Transaction[] = [];
|
||||
|
||||
transactionDetails: TransactionDetail[] = [];
|
||||
|
||||
getInfoUserLogin: (() => Promise<User | null>) | null = null;
|
||||
getInfoUserLogin: Nullable<PromiseOrNull<User>> = null;
|
||||
|
||||
getWalletByIdUser: ((idUser: string) => Promise<Wallet | null>) | null = null;
|
||||
getWalletByIdUser: Nullable<(idUser: string) => Promise<Wallet | null>> =
|
||||
null;
|
||||
|
||||
getAllCategory: (() => Promise<Category[] | null>) | null = null;
|
||||
getAllCategory: Nullable<() => Promise<Category[] | null>> = null;
|
||||
|
||||
getAllTransactions:
|
||||
| ((idUser: string) => Promise<Transaction[] | null>)
|
||||
| null = null;
|
||||
getAllTransactions: Nullable<
|
||||
(idUser: string) => Promise<Transaction[] | null>
|
||||
> = null;
|
||||
|
||||
deleteTransaction: ((idTransaction: string) => Promise<void>) | null = null;
|
||||
deleteTransaction: Nullable<(idTransaction: string) => Promise<void>> = null;
|
||||
|
||||
saveWallet: ((wallet: Wallet) => Promise<void>) | null = null;
|
||||
saveWallet: Nullable<(wallet: Wallet) => Promise<void>> = null;
|
||||
|
||||
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
|
||||
saveTransaction: Nullable<(transaction: Transaction) => Promise<void>> = null;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -89,25 +99,17 @@ export default class HomeView extends CommonView {
|
||||
this.handleEventToast();
|
||||
}
|
||||
|
||||
initFunction(
|
||||
getInfoUserLogin: () => Promise<User | null>,
|
||||
getWalletByIdUser: (idUser: string) => Promise<Wallet | null>,
|
||||
getAllCategory: () => Promise<Category[] | null>,
|
||||
getAllTransactions: (idUser: string) => Promise<Transaction[] | null>,
|
||||
saveWallet: (wallet: Wallet) => Promise<void>,
|
||||
saveTransaction: (transaction: Transaction) => Promise<void>,
|
||||
deleteTransaction: (idTransaction: string) => Promise<void>,
|
||||
transform: Transform,
|
||||
) {
|
||||
this.getInfoUserLogin = getInfoUserLogin;
|
||||
this.getWalletByIdUser = getWalletByIdUser;
|
||||
this.getAllCategory = getAllCategory;
|
||||
this.getAllTransactions = getAllTransactions;
|
||||
this.saveWallet = saveWallet;
|
||||
this.saveTransaction = saveTransaction;
|
||||
this.deleteTransaction = deleteTransaction;
|
||||
// ----------------------- Init function ----------------------- //
|
||||
initFunction(func: IHomeFunc) {
|
||||
this.getInfoUserLogin = func.getInfoUserLogin || null;
|
||||
this.getWalletByIdUser = func.getWalletByIdUser || null;
|
||||
this.getAllCategory = func.getAllCategory || null;
|
||||
this.getAllTransactions = func.getAllTransactions || null;
|
||||
this.saveWallet = func.saveWallet || null;
|
||||
this.saveTransaction = func.saveTransaction || null;
|
||||
this.deleteTransaction = func.deleteTransaction || null;
|
||||
|
||||
this.transform = transform;
|
||||
this.evDataTrigger = EventDataTrigger.Instance;
|
||||
|
||||
// Init function for child view
|
||||
this.initWalletViewFunction();
|
||||
@@ -119,57 +121,61 @@ export default class HomeView extends CommonView {
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
const func: ITransactionViewFunc = {
|
||||
toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this),
|
||||
deleteTransaction: this.deleteTransaction!,
|
||||
loadTransactionData: this.loadTransactionData.bind(this),
|
||||
updateAmountWallet: this.updateAmountWallet.bind(this),
|
||||
loadData: this.loadData.bind(this),
|
||||
showSuccessToast: this.showSuccessToast.bind(this),
|
||||
showErrorToast: this.showErrorToast.bind(this),
|
||||
saveTransaction: this.saveTransaction!,
|
||||
};
|
||||
|
||||
this.transactionView.initFunction(func);
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
const func: IBudgetViewFunc = {
|
||||
showErrorToast: this.showErrorToast.bind(this),
|
||||
showSuccessToast: this.showSuccessToast.bind(this),
|
||||
toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this),
|
||||
saveTransaction: this.saveTransaction!.bind(this),
|
||||
loadTransactionData: this.loadTransactionData.bind(this),
|
||||
updateAmountWallet: this.updateAmountWallet.bind(this),
|
||||
loadData: this.loadData.bind(this),
|
||||
};
|
||||
|
||||
this.budgetView.initFunction(func);
|
||||
}
|
||||
|
||||
initCategoryViewFunction() {
|
||||
this.categoryView.initFunction(this.getAllCategory!, this.transform!);
|
||||
this.categoryView.initFunction(this.getAllCategory!, this.evDataTrigger!);
|
||||
}
|
||||
|
||||
initSummaryTabViewFunction() {
|
||||
this.summaryTabView.initFunction(this.transform!);
|
||||
this.summaryTabView.initFunction(this.evDataTrigger!);
|
||||
}
|
||||
|
||||
initTransactionTabViewFunction() {
|
||||
this.transactionTabView.initFunction(this.transform!);
|
||||
this.transactionTabView.initFunction(this.evDataTrigger!);
|
||||
}
|
||||
|
||||
initWalletViewFunction() {
|
||||
this.walletView.initFunction(
|
||||
this.transform,
|
||||
this.toggleLoaderSpinner.bind(this),
|
||||
this.saveWallet,
|
||||
this.saveTransaction,
|
||||
this.loadTransactionData.bind(this),
|
||||
this.loadData.bind(this),
|
||||
this.loadEvent.bind(this),
|
||||
this.showSuccessToast.bind(this),
|
||||
this.showErrorToast.bind(this),
|
||||
);
|
||||
const func: IWalletViewFunc = {
|
||||
toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this),
|
||||
saveWallet: this.saveWallet,
|
||||
saveTransaction: this.saveTransaction,
|
||||
loadTransactionData: this.loadTransactionData.bind(this),
|
||||
loadData: this.loadData.bind(this),
|
||||
loadEvent: this.loadEvent.bind(this),
|
||||
showSuccessToast: this.showSuccessToast.bind(this),
|
||||
showErrorToast: this.showErrorToast.bind(this),
|
||||
};
|
||||
|
||||
this.walletView.initFunction(func);
|
||||
}
|
||||
// ----------------------- End ----------------------- //
|
||||
|
||||
subscribeListenerData() {
|
||||
this.subscribe();
|
||||
@@ -180,7 +186,7 @@ export default class HomeView extends CommonView {
|
||||
this.walletView.subscribe();
|
||||
}
|
||||
|
||||
async loadData() {
|
||||
async loadData(): Promise<void> {
|
||||
// Send data to other class
|
||||
this.sendData();
|
||||
|
||||
@@ -195,7 +201,7 @@ export default class HomeView extends CommonView {
|
||||
await this.updateAmountWallet();
|
||||
}
|
||||
|
||||
async loadPage() {
|
||||
async loadPage(): Promise<void> {
|
||||
this.toggleLoaderSpinner();
|
||||
const user = await this.getInfoUserLogin!();
|
||||
|
||||
@@ -229,7 +235,7 @@ export default class HomeView extends CommonView {
|
||||
// ---------------------LOAD DATA---------------------//
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('homeView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create('homeView', this.updateData.bind(this));
|
||||
}
|
||||
|
||||
sendData() {
|
||||
@@ -239,7 +245,7 @@ export default class HomeView extends CommonView {
|
||||
user: this.user!,
|
||||
};
|
||||
|
||||
this.transform!.onSendSignal('homeView', data);
|
||||
this.evDataTrigger!.onSendSignal('homeView', data);
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
@@ -251,7 +257,7 @@ export default class HomeView extends CommonView {
|
||||
/**
|
||||
* Load wallet user
|
||||
*/
|
||||
async loadWalletUser() {
|
||||
async loadWalletUser(): Promise<void> {
|
||||
const wallet = this.wallet
|
||||
? this.wallet
|
||||
: await this.getWalletByIdUser!(this.user!.id);
|
||||
@@ -273,13 +279,15 @@ export default class HomeView extends CommonView {
|
||||
this.saveWallet!(this.wallet!);
|
||||
}
|
||||
|
||||
async loadTransactionData() {
|
||||
this.listTransactions = await this.getAllTransactions!(this.wallet!.idUser);
|
||||
async loadTransactionData(): Promise<void> {
|
||||
const data = await this.getAllTransactions!(this.wallet!.idUser);
|
||||
|
||||
if (data) this.listTransactions = data;
|
||||
|
||||
this.sendData();
|
||||
}
|
||||
|
||||
async updateAmountWallet() {
|
||||
async updateAmountWallet(): Promise<void> {
|
||||
let inflow = 0;
|
||||
let outflow = 0;
|
||||
// Init data first
|
||||
@@ -315,7 +323,7 @@ export default class HomeView extends CommonView {
|
||||
* Implement error toast in site
|
||||
* @param {string} content The content will show in error toast
|
||||
*/
|
||||
showErrorToast(error: TError | string): void {
|
||||
showErrorToast(error: TError) {
|
||||
const title =
|
||||
typeof error === 'object' && error.title
|
||||
? error.title
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import Transform from 'helpers/transform';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import { formatNumber } from '../../helpers/data';
|
||||
import { Data } from 'global/types';
|
||||
import { Data, Nullable } 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;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
wallet: Wallet | null = null;
|
||||
wallet: Nullable<Wallet> = null;
|
||||
|
||||
listTransactions: Transaction[] = [];
|
||||
|
||||
listCategories: Category[] = [];
|
||||
|
||||
initFunction(transform: Transform) {
|
||||
this.transform = transform;
|
||||
initFunction(evDataTrigger: EventDataTrigger) {
|
||||
this.evDataTrigger = evDataTrigger;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('summaryTabView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create('summaryTabView', this.updateData.bind(this));
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Transform from 'helpers/transform';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import {
|
||||
createTransactionDetailObject,
|
||||
getAllCategoryNameInTransactions,
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '../../helpers/data';
|
||||
import { formatNumber } from '../../helpers/data';
|
||||
import TransactionView from './transactionView';
|
||||
import { Data } from 'global/types';
|
||||
import { Data, Nullable } from 'global/types';
|
||||
import Wallet from 'models/wallet';
|
||||
import Transaction from 'models/transaction';
|
||||
import Category from 'models/category';
|
||||
@@ -15,9 +15,9 @@ import TransactionDetail from 'models/transactionDetail';
|
||||
export default class TransactionTabView {
|
||||
transactionView: TransactionView;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
wallet: Wallet | null = null;
|
||||
wallet: Nullable<Wallet> = null;
|
||||
|
||||
listTransactions: Transaction[] = [];
|
||||
|
||||
@@ -30,12 +30,15 @@ export default class TransactionTabView {
|
||||
this.addEventTransactionItem();
|
||||
}
|
||||
|
||||
initFunction(transform: Transform) {
|
||||
this.transform = transform;
|
||||
initFunction(evDataTrigger: EventDataTrigger) {
|
||||
this.evDataTrigger = evDataTrigger;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('transactionTabView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create(
|
||||
'transactionTabView',
|
||||
this.updateData.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
@@ -46,7 +49,7 @@ export default class TransactionTabView {
|
||||
if (data.listCategories) this.listCategories = data.listCategories;
|
||||
}
|
||||
|
||||
async loadTransactionTab() {
|
||||
async loadTransactionTab(): Promise<void> {
|
||||
// Load category
|
||||
// Init data first
|
||||
this.transactionDetails = this.loadTransactionDetailsData();
|
||||
@@ -100,7 +103,7 @@ export default class TransactionTabView {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
transactionDetailMarkup(transactionDetail: TransactionDetail) {
|
||||
transactionDetailMarkup(transactionDetail: TransactionDetail): string {
|
||||
const itemTransaction = () => {
|
||||
const listMarkup: string[] = [];
|
||||
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
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 EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import {
|
||||
Data,
|
||||
ITransactionViewFunc,
|
||||
Nullable,
|
||||
PromiseVoid,
|
||||
TError,
|
||||
VoidFunc,
|
||||
} 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';
|
||||
} from 'constants/messages';
|
||||
import { renderRequiredText } from 'helpers/validatorForm';
|
||||
|
||||
export default class TransactionView {
|
||||
wallet: Wallet | null = null;
|
||||
wallet: Nullable<Wallet> = null;
|
||||
|
||||
listTransactions: Transaction[] = [];
|
||||
|
||||
@@ -21,29 +28,29 @@ export default class TransactionView {
|
||||
|
||||
categoryView: CategoryView;
|
||||
|
||||
addTransactionBtn: HTMLElement | null = null;
|
||||
addTransactionBtn: Nullable<HTMLElement> = null;
|
||||
|
||||
transactionDialog: HTMLDialogElement | null = null;
|
||||
transactionDialog: Nullable<HTMLDialogElement> = null;
|
||||
|
||||
transactionForm: HTMLFormElement | null = null;
|
||||
transactionForm: Nullable<HTMLFormElement> = null;
|
||||
|
||||
toggleLoaderSpinner: (() => void) | null = null;
|
||||
toggleLoaderSpinner: Nullable<VoidFunc> = null;
|
||||
|
||||
deleteTransaction: ((idTransaction: string) => Promise<void>) | null = null;
|
||||
deleteTransaction: Nullable<(idTransaction: string) => Promise<void>> = null;
|
||||
|
||||
loadTransactionData: (() => Promise<void>) | null = null;
|
||||
loadTransactionData: Nullable<PromiseVoid> = null;
|
||||
|
||||
updateAmountWallet: (() => Promise<void>) | null = null;
|
||||
updateAmountWallet: Nullable<PromiseVoid> = null;
|
||||
|
||||
loadData: (() => Promise<void>) | null = null;
|
||||
loadData: Nullable<PromiseVoid> = null;
|
||||
|
||||
showSuccessToast: ((title: string, message: string) => void) | null = null;
|
||||
|
||||
showErrorToast: ((error: string | TError) => void) | null = null;
|
||||
showErrorToast: ((error: TError) => void) | null = null;
|
||||
|
||||
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
|
||||
saveTransaction: Nullable<(transaction: Transaction) => Promise<void>> = null;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: EventDataTrigger | null = null;
|
||||
|
||||
constructor(categoryView: CategoryView) {
|
||||
this.addTransactionBtn = document.getElementById('addTransaction');
|
||||
@@ -59,30 +66,21 @@ export default class TransactionView {
|
||||
this.categoryView = categoryView;
|
||||
}
|
||||
|
||||
initFunction(
|
||||
toggleLoaderSpinner: () => void,
|
||||
deleteTransaction: (idTransaction: string) => 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;
|
||||
initFunction(func: ITransactionViewFunc) {
|
||||
this.toggleLoaderSpinner = func.toggleLoaderSpinner;
|
||||
this.deleteTransaction = func.deleteTransaction;
|
||||
this.loadTransactionData = func.loadTransactionData;
|
||||
this.updateAmountWallet = func.updateAmountWallet;
|
||||
this.loadData = func.loadData;
|
||||
this.showSuccessToast = func.showSuccessToast;
|
||||
this.showErrorToast = func.showErrorToast;
|
||||
this.saveTransaction = func.saveTransaction;
|
||||
|
||||
this.evDataTrigger = EventDataTrigger.Instance;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('transactionView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create('transactionView', this.updateData.bind(this));
|
||||
}
|
||||
|
||||
sendData() {
|
||||
@@ -91,7 +89,7 @@ export default class TransactionView {
|
||||
listTransactions: this.listTransactions!,
|
||||
};
|
||||
|
||||
this.transform!.onSendSignal('transactionView', data);
|
||||
this.evDataTrigger!.onSendSignal('transactionView', data);
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
@@ -174,7 +172,7 @@ export default class TransactionView {
|
||||
|
||||
this.showSuccessToast!('Delete success!', DEFAULT_MESSAGE);
|
||||
} catch (error) {
|
||||
this.showErrorToast!(error as string | TError);
|
||||
this.showErrorToast!(error as TError);
|
||||
}
|
||||
this.toggleLoaderSpinner!();
|
||||
}
|
||||
@@ -253,7 +251,7 @@ export default class TransactionView {
|
||||
deleteBtn.classList.toggle('hide', !showDeleteBtn());
|
||||
}
|
||||
|
||||
async submitTransactionDialog() {
|
||||
async submitTransactionDialog(): Promise<void> {
|
||||
try {
|
||||
const dateEl = <HTMLDataElement>(
|
||||
this.transactionForm!.querySelector("[name='selected_date']")
|
||||
@@ -308,12 +306,16 @@ export default class TransactionView {
|
||||
this.clearInputTransactionForm();
|
||||
}
|
||||
} catch (error) {
|
||||
this.showErrorToast!(error as string | TError);
|
||||
this.showErrorToast!(error as TError);
|
||||
this.toggleLoaderSpinner!();
|
||||
}
|
||||
}
|
||||
|
||||
validateTransactionForm(date: string, categoryName: string, amount: number) {
|
||||
validateTransactionForm(
|
||||
date: string,
|
||||
categoryName: string,
|
||||
amount: number,
|
||||
): boolean {
|
||||
const inputFieldEls =
|
||||
this.transactionDialog!.querySelectorAll('.form__input-field');
|
||||
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
import Transaction from '../../models/transaction';
|
||||
import Wallet from '../../models/wallet';
|
||||
import { renderRequiredText } from '../../helpers/validatorForm';
|
||||
import Transform from 'helpers/transform';
|
||||
import { Data, TError } from 'global/types';
|
||||
import EventDataTrigger from 'helpers/evDataTrigger';
|
||||
import {
|
||||
Data,
|
||||
IWalletViewFunc,
|
||||
Nullable,
|
||||
PromiseVoid,
|
||||
TError,
|
||||
VoidFunc,
|
||||
} from 'global/types';
|
||||
import User from 'models/user';
|
||||
import { FIRST_ADD_WALLET_NOTE } from 'constants/defaultVariable';
|
||||
import { ADD_WALLET_SUCCESS, DEFAULT_MESSAGE } from 'constants/messages/dialog';
|
||||
import { ADD_WALLET_SUCCESS, DEFAULT_MESSAGE } from 'constants/messages';
|
||||
|
||||
export default class WalletView {
|
||||
walletDialog: HTMLDialogElement | null = null;
|
||||
walletDialog: Nullable<HTMLDialogElement> = null;
|
||||
|
||||
transform: Transform | null = null;
|
||||
evDataTrigger: Nullable<EventDataTrigger> = null;
|
||||
|
||||
toggleLoaderSpinner: (() => void) | null = null;
|
||||
toggleLoaderSpinner: Nullable<VoidFunc> = null;
|
||||
|
||||
saveWallet: ((wallet: Wallet) => Promise<void>) | null = null;
|
||||
saveWallet: Nullable<(wallet: Wallet) => Promise<void>> = null;
|
||||
|
||||
saveTransaction: ((transaction: Transaction) => Promise<void>) | null = null;
|
||||
saveTransaction: Nullable<(transaction: Transaction) => Promise<void>> = null;
|
||||
|
||||
loadTransactionData: (() => Promise<void>) | null = null;
|
||||
loadTransactionData: Nullable<PromiseVoid> = null;
|
||||
|
||||
loadData: (() => Promise<void>) | null = null;
|
||||
loadData: Nullable<PromiseVoid> = null;
|
||||
|
||||
loadEvent: (() => void) | null = null;
|
||||
loadEvent: Nullable<VoidFunc> = null;
|
||||
|
||||
showSuccessToast: ((title: string, message: string) => void) | null = null;
|
||||
|
||||
showErrorToast: ((error: string | TError) => void) | null = null;
|
||||
showErrorToast: ((error: TError) => void) | null = null;
|
||||
|
||||
user: User | null = null;
|
||||
|
||||
@@ -40,30 +47,21 @@ export default class WalletView {
|
||||
this.addHandlerEventWalletForm();
|
||||
}
|
||||
|
||||
initFunction(
|
||||
transform: Transform | null,
|
||||
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,
|
||||
showErrorToast: (error: string | TError) => void,
|
||||
) {
|
||||
this.transform = transform;
|
||||
this.toggleLoaderSpinner = toggleLoaderSpinner;
|
||||
this.saveWallet = saveWallet;
|
||||
this.saveTransaction = saveTransaction;
|
||||
this.loadTransactionData = loadTransactionData;
|
||||
this.loadData = loadData;
|
||||
this.loadEvent = loadEvent;
|
||||
this.showSuccessToast = showSuccessToast;
|
||||
this.showErrorToast = showErrorToast;
|
||||
initFunction(func: IWalletViewFunc) {
|
||||
this.toggleLoaderSpinner = func.toggleLoaderSpinner;
|
||||
this.saveWallet = func.saveWallet;
|
||||
this.saveTransaction = func.saveTransaction;
|
||||
this.loadTransactionData = func.loadTransactionData;
|
||||
this.loadData = func.loadData;
|
||||
this.loadEvent = func.loadEvent;
|
||||
this.showSuccessToast = func.showSuccessToast;
|
||||
this.showErrorToast = func.showErrorToast;
|
||||
|
||||
this.evDataTrigger = EventDataTrigger.Instance;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.transform!.create('walletView', this.updateData.bind(this));
|
||||
this.evDataTrigger!.create('walletView', this.updateData.bind(this));
|
||||
}
|
||||
|
||||
sendData() {
|
||||
@@ -72,7 +70,7 @@ export default class WalletView {
|
||||
user: this.user!,
|
||||
};
|
||||
|
||||
this.transform!.onSendSignal('walletView', data);
|
||||
this.evDataTrigger!.onSendSignal('walletView', data);
|
||||
}
|
||||
|
||||
updateData(data: Data) {
|
||||
@@ -116,7 +114,7 @@ export default class WalletView {
|
||||
});
|
||||
}
|
||||
|
||||
async submitWalletForm() {
|
||||
async submitWalletForm(): Promise<void> {
|
||||
try {
|
||||
// Wallet info
|
||||
const form = document.getElementById('walletForm') as HTMLFormElement;
|
||||
@@ -128,7 +126,7 @@ export default class WalletView {
|
||||
this.walletDialog!.close();
|
||||
this.toggleLoaderSpinner!();
|
||||
|
||||
const wallet = new Wallet(walletName, +amount, 0, this.user!.id);
|
||||
const wallet = new Wallet('', walletName, +amount, 0, this.user!.id);
|
||||
this.wallet = wallet;
|
||||
|
||||
this.sendData();
|
||||
@@ -156,12 +154,12 @@ export default class WalletView {
|
||||
}
|
||||
} catch (error) {
|
||||
// Show toast error
|
||||
this.showErrorToast!(error as string | TError);
|
||||
this.showErrorToast!(error as TError);
|
||||
this.toggleLoaderSpinner!();
|
||||
}
|
||||
}
|
||||
|
||||
validateWalletDialog(walletName: string, amount: number) {
|
||||
validateWalletDialog(walletName: string, amount: number): boolean {
|
||||
const inputFieldEls =
|
||||
this.walletDialog!.querySelectorAll('.form__input-field');
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ import LoginView from './loginView';
|
||||
import RegisterView from './registerView';
|
||||
import { URL } from 'constants/config';
|
||||
import HomeView from './home/homeView';
|
||||
import { Nullable } from 'global/types';
|
||||
|
||||
export default class View {
|
||||
public registerView: RegisterView | null = null;
|
||||
public registerView: Nullable<RegisterView> = null;
|
||||
|
||||
public loginView: LoginView | null = null;
|
||||
public loginView: Nullable<LoginView> = null;
|
||||
|
||||
public homeView: HomeView | null = null;
|
||||
public homeView: Nullable<HomeView> = null;
|
||||
|
||||
constructor() {
|
||||
switch (getSubdirectoryURL()) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import AuthenticationView from './authenticationView';
|
||||
import { TypeToast, BTN_CONTENT } from '../constants/config';
|
||||
import User from 'models/user';
|
||||
import { DEFAULT_TITLE_ERROR_TOAST } from 'constants/messages/dialog';
|
||||
import { CustomError, TError } from 'global/types';
|
||||
import {
|
||||
DEFAULT_TITLE_ERROR_TOAST,
|
||||
ERROR_CREDENTIAL,
|
||||
} from 'constants/messages';
|
||||
import { CustomError, Nullable, PromiseOrNull, TError } from 'global/types';
|
||||
import { redirectToLoginPage } from 'helpers/url';
|
||||
import { ERROR_CREDENTIAL } from 'constants/messages/form';
|
||||
|
||||
export default class LoginView extends AuthenticationView {
|
||||
constructor() {
|
||||
@@ -15,7 +17,7 @@ export default class LoginView extends AuthenticationView {
|
||||
this.handleEventToast();
|
||||
}
|
||||
|
||||
async loadPage(getInfoUserLogin: () => Promise<User | null>) {
|
||||
async loadPage(getInfoUserLogin: PromiseOrNull<User>) {
|
||||
this.toggleLoaderSpinner();
|
||||
const user = await getInfoUserLogin();
|
||||
if (user) {
|
||||
@@ -28,7 +30,7 @@ export default class LoginView extends AuthenticationView {
|
||||
* Implement error toast in site
|
||||
* @param {string} content The content will show in error toast
|
||||
*/
|
||||
initErrorToast(error: TError | string): void {
|
||||
initErrorToast(error: TError) {
|
||||
const title =
|
||||
typeof error === 'object' && error.title
|
||||
? error.title
|
||||
@@ -90,7 +92,7 @@ export default class LoginView extends AuthenticationView {
|
||||
}
|
||||
} catch (error) {
|
||||
// Show toast error
|
||||
this.initErrorToast(error as string | TError);
|
||||
this.initErrorToast(error as TError);
|
||||
}
|
||||
// Close spinner
|
||||
this.toggleLoaderSpinner();
|
||||
@@ -100,7 +102,7 @@ export default class LoginView extends AuthenticationView {
|
||||
* Get data from user input
|
||||
* @returns {Object || null} Return object or null
|
||||
*/
|
||||
validateForm(event: Event): User | null {
|
||||
validateForm(event: Event): Nullable<User> {
|
||||
if (event.target) {
|
||||
const formData = new FormData(event.target as HTMLFormElement);
|
||||
const email = formData.get('email') as string;
|
||||
@@ -116,7 +118,7 @@ export default class LoginView extends AuthenticationView {
|
||||
this.emailEl.classList.toggle('error-input', !emailValid);
|
||||
this.inputPasswordEl.classList.toggle('error-input', !passwordValid);
|
||||
if (emailValid && passwordValid) {
|
||||
return new User(email, password);
|
||||
return new User('', email, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,14 @@ import {
|
||||
DEFAULT_TITLE_ERROR_TOAST,
|
||||
REGISTER_SUCCESS,
|
||||
USER_EXIST_ERROR,
|
||||
} from 'constants/messages/dialog';
|
||||
import { TError } from 'global/types';
|
||||
} from 'constants/messages';
|
||||
import { Nullable, PromiseOrNull, TError } from 'global/types';
|
||||
|
||||
interface UserInput {
|
||||
email: string;
|
||||
password: string;
|
||||
passwordConfirm: string;
|
||||
}
|
||||
|
||||
export default class RegisterView extends AuthenticationView {
|
||||
constructor() {
|
||||
@@ -21,7 +27,7 @@ export default class RegisterView extends AuthenticationView {
|
||||
this.toastBtn = document.querySelector('.toast__redirect-btn');
|
||||
}
|
||||
|
||||
async loadPage(getInfoUserLogin: () => Promise<User | null>) {
|
||||
async loadPage(getInfoUserLogin: PromiseOrNull<User>) {
|
||||
this.toggleLoaderSpinner();
|
||||
|
||||
const user = await getInfoUserLogin();
|
||||
@@ -37,20 +43,36 @@ export default class RegisterView extends AuthenticationView {
|
||||
* Get data from user input
|
||||
* @returns {Object || null} Return object or null
|
||||
*/
|
||||
validateForm(): User | null {
|
||||
getUserFromForm(): Nullable<User> {
|
||||
const form = document.getElementById('registerForm') as HTMLFormElement;
|
||||
const formData = new FormData(form);
|
||||
const email = formData.get('email') as string;
|
||||
const password = formData.get('password') as string;
|
||||
const passwordConfirm = formData.get('password_confirm') as string;
|
||||
|
||||
// Validate user input
|
||||
this.listError = []; // Reset list error
|
||||
const emailValid = this.validateEmail(email);
|
||||
const passwordValid = this.validatePassword(password);
|
||||
const passwordConfirmValid = this.validatePasswordConfirm(
|
||||
const userInput: UserInput = {
|
||||
email,
|
||||
password,
|
||||
passwordConfirm,
|
||||
};
|
||||
|
||||
const result = this.validateForm(userInput);
|
||||
|
||||
if (result) {
|
||||
return new User('', email, password);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
validateForm(userInput: UserInput): boolean {
|
||||
// Validate user input
|
||||
this.listError = []; // Reset list error
|
||||
const emailValid = this.validateEmail(userInput.email);
|
||||
const passwordValid = this.validatePassword(userInput.password);
|
||||
const passwordConfirmValid = this.validatePasswordConfirm(
|
||||
userInput.password,
|
||||
userInput.passwordConfirm,
|
||||
);
|
||||
|
||||
// Show error style
|
||||
@@ -63,13 +85,9 @@ export default class RegisterView extends AuthenticationView {
|
||||
);
|
||||
}
|
||||
|
||||
if (emailValid && passwordValid && passwordConfirmValid) {
|
||||
return new User(email, password);
|
||||
}
|
||||
|
||||
this.showError(this.listError);
|
||||
|
||||
return null;
|
||||
return emailValid && passwordValid && passwordConfirmValid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +113,7 @@ export default class RegisterView extends AuthenticationView {
|
||||
* Implement error toast in site
|
||||
* @param {string} content The content will show in error toast
|
||||
*/
|
||||
initErrorToast(error: TError | string): void {
|
||||
initErrorToast(error: TError) {
|
||||
const title =
|
||||
typeof error === 'object' && error.title
|
||||
? error.title
|
||||
@@ -126,10 +144,10 @@ export default class RegisterView extends AuthenticationView {
|
||||
saveUser: (user: User) => Promise<void>,
|
||||
) {
|
||||
if (this.formEl) {
|
||||
this.formEl.addEventListener('submit', (e) => {
|
||||
this.formEl.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
this.clearErrorMessage();
|
||||
this.submitForm(checkExistUser, saveUser);
|
||||
await this.submitForm(checkExistUser, saveUser);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -137,13 +155,13 @@ export default class RegisterView extends AuthenticationView {
|
||||
async submitForm(
|
||||
checkExistUser: (email: string) => Promise<boolean>,
|
||||
saveUser: (user: User) => Promise<void>,
|
||||
) {
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Load spinner
|
||||
this.toggleLoaderSpinner();
|
||||
|
||||
// Get validate form
|
||||
const user = this.validateForm();
|
||||
const user = this.getUserFromForm();
|
||||
|
||||
// Save user
|
||||
if (user) {
|
||||
@@ -166,7 +184,7 @@ export default class RegisterView extends AuthenticationView {
|
||||
}
|
||||
} catch (error) {
|
||||
// Show toast error
|
||||
this.initErrorToast(error as string | TError);
|
||||
this.initErrorToast(error as TError);
|
||||
}
|
||||
|
||||
// Close spinner
|
||||
|
||||
Reference in New Issue
Block a user