From 91e2304dbe7cfd249c29f3b9b0a9eda96fafee26 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Tue, 3 Oct 2023 16:56:32 +0700 Subject: [PATCH] Refactor and optimized code --- typescript-practice/src/pages/index.html | 2 +- .../src/styles/pages/_index.scss | 2 + .../src/ts/constants/config.ts | 17 +- .../{messages/dialog.ts => messages.ts} | 14 ++ .../src/ts/constants/messages/form.ts | 13 -- .../src/ts/controllers/homeController.ts | 23 +-- typescript-practice/src/ts/global/types.ts | 58 ++++++- typescript-practice/src/ts/helpers/connect.ts | 2 +- .../{transform.ts => evDataTrigger.ts} | 17 +- typescript-practice/src/ts/helpers/url.ts | 4 +- .../src/ts/helpers/validatorForm.ts | 4 +- typescript-practice/src/ts/models/category.ts | 12 +- typescript-practice/src/ts/models/user.ts | 17 +- typescript-practice/src/ts/models/wallet.ts | 21 +-- .../src/ts/services/localStorageService.ts | 6 +- .../src/ts/services/transactionService.ts | 2 +- .../src/ts/views/authenticationView.ts | 21 +-- .../src/ts/views/commonView.ts | 30 ++-- .../src/ts/views/home/budgetView.ts | 76 ++++---- .../src/ts/views/home/categoryView.ts | 26 +-- .../src/ts/views/home/homeView.ts | 164 +++++++++--------- .../src/ts/views/home/summaryTabView.ts | 14 +- .../src/ts/views/home/transactionTabView.ts | 21 ++- .../src/ts/views/home/transactionView.ts | 84 ++++----- .../src/ts/views/home/walletView.ts | 74 ++++---- typescript-practice/src/ts/views/index.ts | 7 +- typescript-practice/src/ts/views/loginView.ts | 18 +- .../src/ts/views/registerView.ts | 58 ++++--- 28 files changed, 443 insertions(+), 364 deletions(-) rename typescript-practice/src/ts/constants/{messages/dialog.ts => messages.ts} (53%) delete mode 100644 typescript-practice/src/ts/constants/messages/form.ts rename typescript-practice/src/ts/helpers/{transform.ts => evDataTrigger.ts} (65%) diff --git a/typescript-practice/src/pages/index.html b/typescript-practice/src/pages/index.html index bd438bd..810069e 100644 --- a/typescript-practice/src/pages/index.html +++ b/typescript-practice/src/pages/index.html @@ -250,7 +250,7 @@
-
+
diff --git a/typescript-practice/src/styles/pages/_index.scss b/typescript-practice/src/styles/pages/_index.scss index 3e3b2f8..0ea8664 100644 --- a/typescript-practice/src/styles/pages/_index.scss +++ b/typescript-practice/src/styles/pages/_index.scss @@ -104,6 +104,8 @@ &__line { position: absolute; top: 66px; + left: 152px; + width: 116px; height: 2px; background-color: $primary-color; border-radius: 10px; diff --git a/typescript-practice/src/ts/constants/config.ts b/typescript-practice/src/ts/constants/config.ts index d631bcd..dce8da0 100644 --- a/typescript-practice/src/ts/constants/config.ts +++ b/typescript-practice/src/ts/constants/config.ts @@ -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: diff --git a/typescript-practice/src/ts/constants/messages/dialog.ts b/typescript-practice/src/ts/constants/messages.ts similarity index 53% rename from typescript-practice/src/ts/constants/messages/dialog.ts rename to typescript-practice/src/ts/constants/messages.ts index 5b5de7c..a3c69df 100644 --- a/typescript-practice/src/ts/constants/messages/dialog.ts +++ b/typescript-practice/src/ts/constants/messages.ts @@ -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!'; diff --git a/typescript-practice/src/ts/constants/messages/form.ts b/typescript-practice/src/ts/constants/messages/form.ts deleted file mode 100644 index 4491ead..0000000 --- a/typescript-practice/src/ts/constants/messages/form.ts +++ /dev/null @@ -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!`; diff --git a/typescript-practice/src/ts/controllers/homeController.ts b/typescript-practice/src/ts/controllers/homeController.ts index 8388e76..f6c6a65 100644 --- a/typescript-practice/src/ts/controllers/homeController.ts +++ b/typescript-practice/src/ts/controllers/homeController.ts @@ -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(); diff --git a/typescript-practice/src/ts/global/types.ts b/typescript-practice/src/ts/global/types.ts index 98350cb..e4ef3c3 100644 --- a/typescript-practice/src/ts/global/types.ts +++ b/typescript-practice/src/ts/global/types.ts @@ -19,11 +19,13 @@ export class DataObject { } } -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 | null; +export type PromiseVoid = () => Promise; +export type VoidFunc = () => void; +export type PromiseOrNull = () => Promise; + +export interface IHomeFunc { + getInfoUserLogin?: PromiseOrNull; + getWalletByIdUser?: (idUser: string) => Promise; + getAllCategory?: PromiseOrNull; + getAllTransactions?: (idUser: string) => Promise; + saveWallet?: (wallet: Wallet) => Promise; + saveTransaction?: (transaction: Transaction) => Promise; + deleteTransaction?: (idTransaction: string) => Promise; +} + +export interface IBudgetViewFunc { + showErrorToast: (error: TError) => void; + showSuccessToast: (title: string, message: string) => void; + toggleLoaderSpinner: VoidFunc; + saveTransaction: Nullable<(transaction: Transaction) => Promise>; + loadTransactionData: PromiseVoid; + updateAmountWallet: PromiseVoid; + loadData: PromiseVoid; +} + +export interface ITransactionViewFunc { + toggleLoaderSpinner: VoidFunc; + deleteTransaction: (idTransaction: string) => Promise; + loadTransactionData: PromiseVoid; + updateAmountWallet: PromiseVoid; + loadData: PromiseVoid; + showSuccessToast: (title: string, message: string) => void; + showErrorToast: (error: TError) => void; + saveTransaction: (transaction: Transaction) => Promise; +} + +export interface IWalletViewFunc { + toggleLoaderSpinner: () => void; + saveWallet: ((wallet: Wallet) => Promise) | null; + saveTransaction: ((transaction: Transaction) => Promise) | null; + loadTransactionData: () => Promise; + loadData: () => Promise; + loadEvent: () => void; + showSuccessToast: (title: string, message: string) => void; + showErrorToast: (error: TError) => void; +} diff --git a/typescript-practice/src/ts/helpers/connect.ts b/typescript-practice/src/ts/helpers/connect.ts index 39daafe..53d62e9 100644 --- a/typescript-practice/src/ts/helpers/connect.ts +++ b/typescript-practice/src/ts/helpers/connect.ts @@ -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'; diff --git a/typescript-practice/src/ts/helpers/transform.ts b/typescript-practice/src/ts/helpers/evDataTrigger.ts similarity index 65% rename from typescript-practice/src/ts/helpers/transform.ts rename to typescript-practice/src/ts/helpers/evDataTrigger.ts index cadc84c..00178f7 100644 --- a/typescript-practice/src/ts/helpers/transform.ts +++ b/typescript-practice/src/ts/helpers/evDataTrigger.ts @@ -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]; diff --git a/typescript-practice/src/ts/helpers/url.ts b/typescript-practice/src/ts/helpers/url.ts index bf01a04..40e8f06 100644 --- a/typescript-practice/src/ts/helpers/url.ts +++ b/typescript-practice/src/ts/helpers/url.ts @@ -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 diff --git a/typescript-practice/src/ts/helpers/validatorForm.ts b/typescript-practice/src/ts/helpers/validatorForm.ts index 199f524..9cf70a5 100644 --- a/typescript-practice/src/ts/helpers/validatorForm.ts +++ b/typescript-practice/src/ts/helpers/validatorForm.ts @@ -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 = `

${REQUIRED_MESSAGE(field)}

`; diff --git a/typescript-practice/src/ts/models/category.ts b/typescript-practice/src/ts/models/category.ts index 71988bb..c1c10cc 100644 --- a/typescript-practice/src/ts/models/category.ts +++ b/typescript-practice/src/ts/models/category.ts @@ -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; diff --git a/typescript-practice/src/ts/models/user.ts b/typescript-practice/src/ts/models/user.ts index 9b2fa4c..e71f324 100644 --- a/typescript-practice/src/ts/models/user.ts +++ b/typescript-practice/src/ts/models/user.ts @@ -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 || ''; diff --git a/typescript-practice/src/ts/models/wallet.ts b/typescript-practice/src/ts/models/wallet.ts index 7e0e1a9..548da74 100644 --- a/typescript-practice/src/ts/models/wallet.ts +++ b/typescript-practice/src/ts/models/wallet.ts @@ -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; diff --git a/typescript-practice/src/ts/services/localStorageService.ts b/typescript-practice/src/ts/services/localStorageService.ts index 5786cd5..5339fb3 100644 --- a/typescript-practice/src/ts/services/localStorageService.ts +++ b/typescript-practice/src/ts/services/localStorageService.ts @@ -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(); } } diff --git a/typescript-practice/src/ts/services/transactionService.ts b/typescript-practice/src/ts/services/transactionService.ts index bb53cf9..54d8550 100644 --- a/typescript-practice/src/ts/services/transactionService.ts +++ b/typescript-practice/src/ts/services/transactionService.ts @@ -28,7 +28,7 @@ export default class TransactionService extends CommonService { return results || null; } - async deleteTransaction(idTransaction: string) { + async deleteTransaction(idTransaction: string): Promise { await this.deleteData(idTransaction); } } diff --git a/typescript-practice/src/ts/views/authenticationView.ts b/typescript-practice/src/ts/views/authenticationView.ts index a045dcc..77089c7 100644 --- a/typescript-practice/src/ts/views/authenticationView.ts +++ b/typescript-practice/src/ts/views/authenticationView.ts @@ -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; - public emailEl: HTMLBodyElement | null; + public emailEl: Nullable; public messageDefault: string[]; - public inputPasswordEl: HTMLBodyElement | null; + public inputPasswordEl: Nullable; - public inputPasswordConfirmEl: HTMLBodyElement | null; + public inputPasswordConfirmEl: Nullable; 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) => `
  • ${message}
  • `) diff --git a/typescript-practice/src/ts/views/commonView.ts b/typescript-practice/src/ts/views/commonView.ts index f8ea0eb..32d2e71 100644 --- a/typescript-practice/src/ts/views/commonView.ts +++ b/typescript-practice/src/ts/views/commonView.ts @@ -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 = null; - public toastIcon: HTMLBodyElement | null = null; + public toastIcon: Nullable = null; - public toastBtn: HTMLBodyElement | null = null; + public toastBtn: Nullable = null; - public toastTitle: HTMLBodyElement | null = null; + public toastTitle: Nullable = null; - public toastContent: HTMLBodyElement | null = null; + public toastContent: Nullable = null; - public spinner: HTMLBodyElement | null = null; + public spinner: Nullable = 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 = `
    @@ -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(); diff --git a/typescript-practice/src/ts/views/home/budgetView.ts b/typescript-practice/src/ts/views/home/budgetView.ts index 425fca8..383fd7d 100644 --- a/typescript-practice/src/ts/views/home/budgetView.ts +++ b/typescript-practice/src/ts/views/home/budgetView.ts @@ -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 = null; - addBudgetBtn: HTMLElement | null = null; + addBudgetBtn: Nullable = null; - transform: Transform | null = null; + evDataTrigger: Nullable = null; - toggleLoaderSpinner: (() => void) | null = null; + toggleLoaderSpinner: Nullable = null; - saveTransaction: ((transaction: Transaction) => Promise) | null = null; + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; - loadTransactionData: (() => Promise) | null = null; + loadTransactionData: Nullable = null; - updateAmountWallet: (() => Promise) | null = null; + updateAmountWallet: Nullable = null; - loadData: (() => Promise) | null = null; + loadData: Nullable = 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 = null; - user: User | null = null; + user: Nullable = 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) | null, - loadTransactionData: () => Promise, - updateAmountWallet: () => Promise, - loadData: () => Promise, - 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 { try { const form = document.getElementById('formAddBudget') as HTMLFormElement; const formAddBudget = new FormData(form); @@ -149,11 +145,11 @@ export default class BudgetView { (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'); diff --git a/typescript-practice/src/ts/views/home/categoryView.ts b/typescript-practice/src/ts/views/home/categoryView.ts index 759428c..1124694 100644 --- a/typescript-practice/src/ts/views/home/categoryView.ts +++ b/typescript-practice/src/ts/views/home/categoryView.ts @@ -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 = null; - categoryField: HTMLElement | null = null; + categoryField: Nullable = null; - closeIcon: HTMLElement | null = null; + closeIcon: Nullable = null; - getAllCategory: (() => Promise) | null = null; + getAllCategory: Nullable> = null; - transform: Transform | null = null; + evDataTrigger: Nullable = null; - listCategory: Category[] | null = null; + listCategory: Nullable = null; categorySelected: string; @@ -32,17 +32,17 @@ export default class CategoryView { } initFunction( - getAllCategory: () => Promise, - transform: Transform, + getAllCategory: PromiseOrNull, + 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 { if (!this.listCategory) { this.listCategory = await this.getAllCategory!(); diff --git a/typescript-practice/src/ts/views/home/homeView.ts b/typescript-practice/src/ts/views/home/homeView.ts index 518a0fd..fea1d8f 100644 --- a/typescript-practice/src/ts/views/home/homeView.ts +++ b/typescript-practice/src/ts/views/home/homeView.ts @@ -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; - user: User | null = null; + user: Nullable = null; - wallet: Wallet | null = null; + wallet: Nullable = null; - listTransactions: Transaction[] | null = null; + listTransactions: Transaction[] = []; transactionDetails: TransactionDetail[] = []; - getInfoUserLogin: (() => Promise) | null = null; + getInfoUserLogin: Nullable> = null; - getWalletByIdUser: ((idUser: string) => Promise) | null = null; + getWalletByIdUser: Nullable<(idUser: string) => Promise> = + null; - getAllCategory: (() => Promise) | null = null; + getAllCategory: Nullable<() => Promise> = null; - getAllTransactions: - | ((idUser: string) => Promise) - | null = null; + getAllTransactions: Nullable< + (idUser: string) => Promise + > = null; - deleteTransaction: ((idTransaction: string) => Promise) | null = null; + deleteTransaction: Nullable<(idTransaction: string) => Promise> = null; - saveWallet: ((wallet: Wallet) => Promise) | null = null; + saveWallet: Nullable<(wallet: Wallet) => Promise> = null; - saveTransaction: ((transaction: Transaction) => Promise) | null = null; + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; - transform: Transform | null = null; + evDataTrigger: Nullable = null; constructor() { super(); @@ -89,25 +99,17 @@ export default class HomeView extends CommonView { this.handleEventToast(); } - initFunction( - getInfoUserLogin: () => Promise, - getWalletByIdUser: (idUser: string) => Promise, - getAllCategory: () => Promise, - getAllTransactions: (idUser: string) => Promise, - saveWallet: (wallet: Wallet) => Promise, - saveTransaction: (transaction: Transaction) => Promise, - deleteTransaction: (idTransaction: string) => Promise, - 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 { // 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 { 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 { 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 { + const data = await this.getAllTransactions!(this.wallet!.idUser); + + if (data) this.listTransactions = data; this.sendData(); } - async updateAmountWallet() { + async updateAmountWallet(): Promise { 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 diff --git a/typescript-practice/src/ts/views/home/summaryTabView.ts b/typescript-practice/src/ts/views/home/summaryTabView.ts index 75277e0..eae2560 100644 --- a/typescript-practice/src/ts/views/home/summaryTabView.ts +++ b/typescript-practice/src/ts/views/home/summaryTabView.ts @@ -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 = null; - wallet: Wallet | null = null; + wallet: Nullable = 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) { diff --git a/typescript-practice/src/ts/views/home/transactionTabView.ts b/typescript-practice/src/ts/views/home/transactionTabView.ts index b39e265..c365ea5 100644 --- a/typescript-practice/src/ts/views/home/transactionTabView.ts +++ b/typescript-practice/src/ts/views/home/transactionTabView.ts @@ -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 = null; - wallet: Wallet | null = null; + wallet: Nullable = 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 { // 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[] = []; diff --git a/typescript-practice/src/ts/views/home/transactionView.ts b/typescript-practice/src/ts/views/home/transactionView.ts index 81122b2..dd806eb 100644 --- a/typescript-practice/src/ts/views/home/transactionView.ts +++ b/typescript-practice/src/ts/views/home/transactionView.ts @@ -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 = null; listTransactions: Transaction[] = []; @@ -21,29 +28,29 @@ export default class TransactionView { categoryView: CategoryView; - addTransactionBtn: HTMLElement | null = null; + addTransactionBtn: Nullable = null; - transactionDialog: HTMLDialogElement | null = null; + transactionDialog: Nullable = null; - transactionForm: HTMLFormElement | null = null; + transactionForm: Nullable = null; - toggleLoaderSpinner: (() => void) | null = null; + toggleLoaderSpinner: Nullable = null; - deleteTransaction: ((idTransaction: string) => Promise) | null = null; + deleteTransaction: Nullable<(idTransaction: string) => Promise> = null; - loadTransactionData: (() => Promise) | null = null; + loadTransactionData: Nullable = null; - updateAmountWallet: (() => Promise) | null = null; + updateAmountWallet: Nullable = null; - loadData: (() => Promise) | null = null; + loadData: Nullable = 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) | null = null; + saveTransaction: Nullable<(transaction: Transaction) => Promise> = 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, - loadTransactionData: () => Promise, - updateAmountWallet: () => Promise, - loadData: () => Promise, - showSuccessToast: (title: string, message: string) => void, - showErrorToast: (error: string | TError) => void, - saveTransaction: (transaction: Transaction) => Promise, - 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 { try { const dateEl = ( 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'); diff --git a/typescript-practice/src/ts/views/home/walletView.ts b/typescript-practice/src/ts/views/home/walletView.ts index f5dd34e..d2ca12e 100644 --- a/typescript-practice/src/ts/views/home/walletView.ts +++ b/typescript-practice/src/ts/views/home/walletView.ts @@ -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 = null; - transform: Transform | null = null; + evDataTrigger: Nullable = null; - toggleLoaderSpinner: (() => void) | null = null; + toggleLoaderSpinner: Nullable = null; - saveWallet: ((wallet: Wallet) => Promise) | null = null; + saveWallet: Nullable<(wallet: Wallet) => Promise> = null; - saveTransaction: ((transaction: Transaction) => Promise) | null = null; + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; - loadTransactionData: (() => Promise) | null = null; + loadTransactionData: Nullable = null; - loadData: (() => Promise) | null = null; + loadData: Nullable = null; - loadEvent: (() => void) | null = null; + loadEvent: Nullable = 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) | null, - saveTransaction: ((transaction: Transaction) => Promise) | null, - loadTransactionData: () => Promise, - loadData: () => Promise, - 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 { 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'); diff --git a/typescript-practice/src/ts/views/index.ts b/typescript-practice/src/ts/views/index.ts index 8af6861..af1b6a4 100644 --- a/typescript-practice/src/ts/views/index.ts +++ b/typescript-practice/src/ts/views/index.ts @@ -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 = null; - public loginView: LoginView | null = null; + public loginView: Nullable = null; - public homeView: HomeView | null = null; + public homeView: Nullable = null; constructor() { switch (getSubdirectoryURL()) { diff --git a/typescript-practice/src/ts/views/loginView.ts b/typescript-practice/src/ts/views/loginView.ts index e05a001..984bcb7 100644 --- a/typescript-practice/src/ts/views/loginView.ts +++ b/typescript-practice/src/ts/views/loginView.ts @@ -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) { + async loadPage(getInfoUserLogin: PromiseOrNull) { 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 { 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); } } } diff --git a/typescript-practice/src/ts/views/registerView.ts b/typescript-practice/src/ts/views/registerView.ts index f60d587..055d522 100644 --- a/typescript-practice/src/ts/views/registerView.ts +++ b/typescript-practice/src/ts/views/registerView.ts @@ -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) { + async loadPage(getInfoUserLogin: PromiseOrNull) { 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 { 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, ) { 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, saveUser: (user: User) => Promise, - ) { + ): Promise { 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