diff --git a/javascript-practice/src/js/controllers/homeController.js b/javascript-practice/src/js/controllers/homeController.js index 4facfd0..eedf192 100644 --- a/javascript-practice/src/js/controllers/homeController.js +++ b/javascript-practice/src/js/controllers/homeController.js @@ -24,6 +24,10 @@ export default class HomeController { return this.service.transactionService.saveTransaction(transaction); } + handlerGetAllCategory() { + return this.service.categoryService.getAllCategory(); + } + init() { if (this.homeView) { this.homeView.addHandlerInputChangeWalletForm(); @@ -36,6 +40,7 @@ export default class HomeController { this.handlerGetInfoUserLogin.bind(this), this.handlerCheckWalletValid.bind(this), this.handlerGetWalletUser.bind(this), + this.handlerGetAllCategory.bind(this), ); this.homeView.addHandlerSubmitBudgetForm( @@ -44,6 +49,8 @@ export default class HomeController { ); this.homeView.addHandlerInputChangeBudgetForm(); + + this.homeView.handlerInputChangeCategoryDialog(); } } } diff --git a/javascript-practice/src/js/models/category.js b/javascript-practice/src/js/models/category.js new file mode 100644 index 0000000..6acaf24 --- /dev/null +++ b/javascript-practice/src/js/models/category.js @@ -0,0 +1,7 @@ +export default class Category { + constructor({ id, url, name }) { + this.id = id; + this.url = url; + this.name = name; + } +} diff --git a/javascript-practice/src/js/services/categoryService.js b/javascript-practice/src/js/services/categoryService.js new file mode 100644 index 0000000..86b0db3 --- /dev/null +++ b/javascript-practice/src/js/services/categoryService.js @@ -0,0 +1,25 @@ +import CommonService from './commonService'; +import Category from '../models/category'; + +export default class CategoryService extends CommonService { + constructor() { + super(); + + this.defaultPath = 'categories/'; + } + + async getAllCategory() { + const data = await this.getAllDataFromPath(this.defaultPath); + const listCategory = []; + + if (data) { + data.forEach((category) => { + listCategory.unshift(new Category(category)); + }); + + return listCategory; + } + + return null; + } +} diff --git a/javascript-practice/src/js/services/commonService.js b/javascript-practice/src/js/services/commonService.js index ce4a698..ee96671 100644 --- a/javascript-practice/src/js/services/commonService.js +++ b/javascript-practice/src/js/services/commonService.js @@ -62,4 +62,16 @@ export default class CommonService { return null; } + + async getAllDataFromPath(path = this.defaultPath) { + this.connectToDb(); + + const result = await this.firebaseService.getAllDataFromPath(path); + + const data = await timeOutConnect(result); + + if (data) return data; + + return null; + } } diff --git a/javascript-practice/src/js/services/firebaseService.js b/javascript-practice/src/js/services/firebaseService.js index 3f31092..a5a40f7 100644 --- a/javascript-practice/src/js/services/firebaseService.js +++ b/javascript-practice/src/js/services/firebaseService.js @@ -94,6 +94,35 @@ class FirebaseService { ); }); } + + getAllDataFromPath(path) { + return new Promise((resolve) => { + onValue( + ref(this.db, path), + (snapshot) => { + const data = []; + + // snapshot is a type of data by Firebase define + snapshot.forEach((childSnapshot) => { + // const dataTemp = childSnapshot.val(); + + // if (dataTemp[property] === value) { + // id = childSnapshot.key; + // data = dataTemp; + // } + const id = childSnapshot.key; + const val = childSnapshot.val(); + + data.push({ id, ...val }); + }); + resolve(data); + }, + { + onlyOnce: true, + }, + ); + }); + } } export default new FirebaseService(); diff --git a/javascript-practice/src/js/services/index.js b/javascript-practice/src/js/services/index.js index b13be49..61597e8 100644 --- a/javascript-practice/src/js/services/index.js +++ b/javascript-practice/src/js/services/index.js @@ -1,3 +1,4 @@ +import CategoryService from './categoryService'; import TransactionService from './transactionService'; import UserService from './userService'; import WalletService from './walletService'; @@ -7,5 +8,6 @@ export default class Service { this.userService = new UserService(); this.walletService = new WalletService(); this.transactionService = new TransactionService(); + this.categoryService = new CategoryService(); } } diff --git a/javascript-practice/src/js/views/homeView.js b/javascript-practice/src/js/views/homeView.js index e1e0248..f815189 100644 --- a/javascript-practice/src/js/views/homeView.js +++ b/javascript-practice/src/js/views/homeView.js @@ -27,7 +27,12 @@ export default class HomeView extends CommonView { this.walletDialog = document.getElementById('walletDialog'); } - async loadPage(getInfoUserLogin, isValidWallet, getWalletByIdUser) { + async loadPage( + getInfoUserLogin, + isValidWallet, + getWalletByIdUser, + getAllCategory, + ) { this.getWalletByIdUser = getWalletByIdUser; // Init function this.toggleLoaderSpinner(); const user = await getInfoUserLogin(); @@ -47,15 +52,89 @@ export default class HomeView extends CommonView { this.loadEvent(); // Init data - this.loadData(); + this.loadData(getAllCategory); } } this.toggleLoaderSpinner(); } - async loadData() { - const wallet = await this.getWalletByIdUser(this.user.id); // Get data wallet + async loadData(getAllCategory) { + await this.loadWalletUser(); + await this.loadCategory(getAllCategory); + } + + // ---------------------SELECTED CATEGORY DIALOG---------------------// + /** + * Load category data + * @param {function} getAllCategory Get all category function + */ + async loadCategory(getAllCategory) { + this.listCategory = await getAllCategory(); + + if (this.listCategory) { + this.renderCategoryItem(this.listCategory); + } + } + + handlerInputChangeCategoryDialog() { + this.categoryDialog.addEventListener('input', () => { + setTimeout(() => { + this.searchCategory(); + }, 300); + }); + } + + searchCategory() { + const searchCategoryEl = + this.categoryDialog.querySelector("[name='category']"); + const searchValue = searchCategoryEl.value.trim().toLowerCase(); + let newListCategory = []; + + if (searchValue) { + this.listCategory.forEach((category) => { + const categoryName = category.name.trim().toLowerCase(); + + if (categoryName.includes(searchValue)) { + newListCategory.unshift(category); + } + }); + } else { + newListCategory = this.listCategory; + } + + // Render category item + this.renderCategoryItem(newListCategory); + } + + renderCategoryItem(listCategory) { + const listCategoryEl = document.querySelector('.list-category'); + + listCategoryEl.innerHTML = ''; // Remove old category item + + listCategory.forEach((category) => { + const markup = ` +
+ ${category.name} Icon +

${category.name}

+
+ `; + + listCategoryEl.insertAdjacentHTML('afterbegin', markup); + }); + } + + // ---------------------END DIALOG---------------------// + + /** + * Load wallet user + */ + async loadWalletUser() { + const wallet = await this.getWalletByIdUser(this.user.id); const walletName = document.querySelector('.wallet__name'); const walletPrice = document.querySelector('.wallet__price'); const sign = wallet.amount >= 0 ? '+' : '-'; diff --git a/javascript-practice/src/pages/index.html b/javascript-practice/src/pages/index.html index 18700ab..83f933f 100644 --- a/javascript-practice/src/pages/index.html +++ b/javascript-practice/src/pages/index.html @@ -194,81 +194,7 @@
-
- -
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
- Food & Beverage Icon -

Food & Beverage

-
-
+
@@ -412,5 +338,13 @@ + diff --git a/javascript-practice/src/styles/pages/_index.scss b/javascript-practice/src/styles/pages/_index.scss index 0605974..f2cbba7 100644 --- a/javascript-practice/src/styles/pages/_index.scss +++ b/javascript-practice/src/styles/pages/_index.scss @@ -605,6 +605,11 @@ color: $dark-gray; } + .icon-category { + width: 40px; + height: 40px; + } + .list-category { @extend %d-flex; @include flex-layout($direction: column); @@ -621,6 +626,13 @@ margin-inline: 68px; padding: 8px 0; border-bottom: 1px solid $gray; + transition: 0.3s; + cursor: pointer; + + &:hover, + &.selected { + background-color: $hover-light-primary-color; + } } }