mirror of
https://github.com/Nezumi-2711/javascript-training.git
synced 2026-09-22 20:01:31 +00:00
Implement category search method
This commit is contained in:
@@ -24,6 +24,10 @@ export default class HomeController {
|
|||||||
return this.service.transactionService.saveTransaction(transaction);
|
return this.service.transactionService.saveTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlerGetAllCategory() {
|
||||||
|
return this.service.categoryService.getAllCategory();
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (this.homeView) {
|
if (this.homeView) {
|
||||||
this.homeView.addHandlerInputChangeWalletForm();
|
this.homeView.addHandlerInputChangeWalletForm();
|
||||||
@@ -36,6 +40,7 @@ export default class HomeController {
|
|||||||
this.handlerGetInfoUserLogin.bind(this),
|
this.handlerGetInfoUserLogin.bind(this),
|
||||||
this.handlerCheckWalletValid.bind(this),
|
this.handlerCheckWalletValid.bind(this),
|
||||||
this.handlerGetWalletUser.bind(this),
|
this.handlerGetWalletUser.bind(this),
|
||||||
|
this.handlerGetAllCategory.bind(this),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.homeView.addHandlerSubmitBudgetForm(
|
this.homeView.addHandlerSubmitBudgetForm(
|
||||||
@@ -44,6 +49,8 @@ export default class HomeController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.homeView.addHandlerInputChangeBudgetForm();
|
this.homeView.addHandlerInputChangeBudgetForm();
|
||||||
|
|
||||||
|
this.homeView.handlerInputChangeCategoryDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export default class Category {
|
||||||
|
constructor({ id, url, name }) {
|
||||||
|
this.id = id;
|
||||||
|
this.url = url;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,4 +62,16 @@ export default class CommonService {
|
|||||||
|
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
export default new FirebaseService();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import CategoryService from './categoryService';
|
||||||
import TransactionService from './transactionService';
|
import TransactionService from './transactionService';
|
||||||
import UserService from './userService';
|
import UserService from './userService';
|
||||||
import WalletService from './walletService';
|
import WalletService from './walletService';
|
||||||
@@ -7,5 +8,6 @@ export default class Service {
|
|||||||
this.userService = new UserService();
|
this.userService = new UserService();
|
||||||
this.walletService = new WalletService();
|
this.walletService = new WalletService();
|
||||||
this.transactionService = new TransactionService();
|
this.transactionService = new TransactionService();
|
||||||
|
this.categoryService = new CategoryService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ export default class HomeView extends CommonView {
|
|||||||
this.walletDialog = document.getElementById('walletDialog');
|
this.walletDialog = document.getElementById('walletDialog');
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadPage(getInfoUserLogin, isValidWallet, getWalletByIdUser) {
|
async loadPage(
|
||||||
|
getInfoUserLogin,
|
||||||
|
isValidWallet,
|
||||||
|
getWalletByIdUser,
|
||||||
|
getAllCategory,
|
||||||
|
) {
|
||||||
this.getWalletByIdUser = getWalletByIdUser; // Init function
|
this.getWalletByIdUser = getWalletByIdUser; // Init function
|
||||||
this.toggleLoaderSpinner();
|
this.toggleLoaderSpinner();
|
||||||
const user = await getInfoUserLogin();
|
const user = await getInfoUserLogin();
|
||||||
@@ -47,15 +52,89 @@ export default class HomeView extends CommonView {
|
|||||||
this.loadEvent();
|
this.loadEvent();
|
||||||
|
|
||||||
// Init data
|
// Init data
|
||||||
this.loadData();
|
this.loadData(getAllCategory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleLoaderSpinner();
|
this.toggleLoaderSpinner();
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadData() {
|
async loadData(getAllCategory) {
|
||||||
const wallet = await this.getWalletByIdUser(this.user.id); // Get data wallet
|
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 = `
|
||||||
|
<div class="category-item" value="${category.name}">
|
||||||
|
<img
|
||||||
|
class="icon-category"
|
||||||
|
src="${category.url}"
|
||||||
|
alt="${category.name} Icon"
|
||||||
|
/>
|
||||||
|
<p class="name-category">${category.name}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
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 walletName = document.querySelector('.wallet__name');
|
||||||
const walletPrice = document.querySelector('.wallet__price');
|
const walletPrice = document.querySelector('.wallet__price');
|
||||||
const sign = wallet.amount >= 0 ? '+' : '-';
|
const sign = wallet.amount >= 0 ? '+' : '-';
|
||||||
|
|||||||
@@ -194,81 +194,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog__body">
|
<div class="dialog__body">
|
||||||
<div class="list-category">
|
<div class="list-category"></div>
|
||||||
<!-- Category item -->
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
<div class="category-item">
|
|
||||||
<img
|
|
||||||
class="icon-category"
|
|
||||||
src="../assets/images/ic_category_foodndrink.png.png"
|
|
||||||
alt="Food & Beverage Icon"
|
|
||||||
/>
|
|
||||||
<p class="name-category">Food & Beverage</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
@@ -412,5 +338,13 @@
|
|||||||
<!-- End app -->
|
<!-- End app -->
|
||||||
</div>
|
</div>
|
||||||
<script type="module" src="../js/main.js"></script>
|
<script type="module" src="../js/main.js"></script>
|
||||||
|
<script>
|
||||||
|
document
|
||||||
|
.querySelector('.list-category')
|
||||||
|
.addEventListener('click', (e) => {
|
||||||
|
const value = e.target.getAttribute('value');
|
||||||
|
alert(value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -605,6 +605,11 @@
|
|||||||
color: $dark-gray;
|
color: $dark-gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-category {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.list-category {
|
.list-category {
|
||||||
@extend %d-flex;
|
@extend %d-flex;
|
||||||
@include flex-layout($direction: column);
|
@include flex-layout($direction: column);
|
||||||
@@ -621,6 +626,13 @@
|
|||||||
margin-inline: 68px;
|
margin-inline: 68px;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
border-bottom: 1px solid $gray;
|
border-bottom: 1px solid $gray;
|
||||||
|
transition: 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.selected {
|
||||||
|
background-color: $hover-light-primary-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user