import {Component, EventEmitter, Output} from '@angular/core'; import {GoalType, Need} from '../../models/Need'; import {CupboardService} from '../../services/cupboard.service'; import {UsersService} from '../../services/users.service'; import {userType} from '../../models/User'; import {AuthService} from '../../services/auth.service'; import {catchError, of} from 'rxjs'; import {ToastsService, ToastType} from '../../services/toasts.service'; interface sortAlgo { (a: Need,b: Need): number; } // sort functions const sortByName: sortAlgo = (a: Need, b: Need): number => { if(a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { return -1; } return 1; } const sortByGoal: sortAlgo = (a: Need, b: Need): number => { if(a.maxGoal == b.maxGoal) { return sortByName(a,b); } else if(a.maxGoal > b.maxGoal) { return -1; } return 1; } const sortByCompletion: sortAlgo = (a: Need, b: Need): number => { if(a.current == b.current) { return sortByGoal(a,b); } else if(a.current > b.current) { return -1; } return 1; } const sortByPriority: sortAlgo = (a: Need, b: Need): number => { if(a.urgent == b.urgent) { return sortByGoal(a,b); } else if(a.urgent && !b.urgent) { return -1; } return 1; } const sortByLocation: sortAlgo = (a: Need, b: Need): number => { if(a.location.toLocaleLowerCase() < b.location.toLocaleLowerCase()) { return -1; } return 1; } @Component({ selector: 'app-need-list', standalone: false, templateUrl: './need-list.component.html', styleUrl: './need-list.component.css' }) export class NeedListComponent { selectedNeed: Need | null = null; needs: Need[] = []; searchResults: Need[] = []; visibleNeeds: Need[] = []; sortMode: 'Ascending' | 'Descending' = 'Ascending' currentPage: number = localStorage.getItem('currentPage') ? parseInt(localStorage.getItem('currentPage')!) : 0; itemsPerPage: number = localStorage.getItem('itemsPerPage') ? parseInt(localStorage.getItem('itemsPerPage')!) : 5; totalPages: number = Math.ceil(this.needs.length / this.itemsPerPage); getPrefix(need: Need) { return (need.type === GoalType.MONETARY) ? "$" : ""; } //increment/decrement decrementPage() { this.currentPage--; localStorage.setItem('currentPage', this.currentPage.toString()); this.updateVisibleNeeds(); } incrementPage() { this.currentPage++; localStorage.setItem('currentPage', this.currentPage.toString()); this.updateVisibleNeeds(); } //skipping pages lastPage() { this.currentPage = this.totalPages - 1 localStorage.setItem('currentPage', this.currentPage.toString()); this.updateVisibleNeeds() } firstPage() { this.currentPage = 0 localStorage.setItem('currentPage', this.currentPage.toString()); this.updateVisibleNeeds() } //user editing needs per page editNeedsPerPage() { if (this.itemsPerPage > this.searchResults.length) { this.itemsPerPage = this.searchResults.length; } if (this.itemsPerPage < 1) { this.itemsPerPage = 1; } localStorage.setItem('itemsPerPage', this.itemsPerPage.toString()); this.resetVisibleNeeds(); } //refresing visible needs updateVisibleNeeds() { this.totalPages = Math.ceil(this.searchResults.length / this.itemsPerPage); this.visibleNeeds = this.searchResults.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage); } //reset back to first page and refresh needs resetVisibleNeeds() { this.currentPage = 0; localStorage.setItem('currentPage', this.currentPage.toString()); this.updateVisibleNeeds(); } currentSortAlgo: sortAlgo = sortByPriority; sortSelection: string = 'sortByPriority'; SortingAlgoArrays: {func:sortAlgo,name:string, display:string[]}[] = [ {func:sortByPriority,name:"sortByPriority", display:["Highest Priority", "Lowest Priority"]}, {func:sortByName,name:"sortByName", display:["Name (A to Z)", "Name (Z to A)"]}, {func:sortByLocation,name:"sortByLocation", display:["Location (A to Z)", "Location (Z to A)"]}, {func:sortByCompletion,name:"sortByCompletion", display:["Most Completed", "Least Completed"]}, {func:sortByGoal,name:"sortByGoal", display:["Largest Maximum Goal", "Smallest Maximum Goal"]}, ]; @Output() currentNeed = new EventEmitter(); constructor( private cupboardService: CupboardService, private usersService: UsersService, private authService: AuthService, private toastService: ToastsService ) {} refresh() { this.cupboardService.getNeeds().subscribe(n => { if (this.sortMode == 'Ascending') { this.needs = n.sort(this.currentSortAlgo); } else { this.needs = n.sort(this.currentSortAlgo).reverse(); } this.searchResults = this.needs; this.updateVisibleNeeds(); }); const form = document.getElementById('search-form') as HTMLFormElement; form.reset(); this.search(null); } ngOnInit(): void { this.refresh() } changeSortMode(form : any) { if (this.sortMode == 'Ascending'){ this.sortMode = 'Descending' } else { this.sortMode = 'Ascending' } this.search(form) } private searchDelay: any; async search(form: any) { //wait .25 seconds before searching but cancel if another search is made during the wait to prevent too many api calls //remove previous search if it exists if (this.searchDelay) { clearTimeout(this.searchDelay); } if (form) { this.searchDelay = setTimeout(() => { if (form) { //sorting based on algo selected this.SortingAlgoArrays.forEach(algo => { if(algo.name === this.sortSelection) { this.currentSortAlgo = algo.func; console.log("changed sorting algorithm to: ", algo.name + this.sortMode) return } }); const currentSearchValue = form.search; //latest value of the search this.cupboardService.searchNeeds(currentSearchValue).subscribe((n) => { if (this.sortMode == 'Ascending') { this.searchResults = n.sort(this.currentSortAlgo); } else { this.searchResults = n.sort(this.currentSortAlgo).reverse(); } this.updateVisibleNeeds(); }); } }, 250); } else { //user has cleared the search bar, we can skip the timeout for a 1/4 second faster response //clear timeout to stop pending search clearTimeout(this.searchDelay); this.searchResults = this.needs; } } delete(id : number) { this.cupboardService.deleteNeed(id).subscribe(() => { this.toastService.sendToast(ToastType.INFO, "Need deleted.") this.needs = this.needs.filter(n => n.id !== id) }) this.refresh(); } isManager() { const type = this.authService.getCurrentUser()?.type; return type === ("MANAGER" as unknown as userType); } isHelper() { const type = this.authService.getCurrentUser()?.type; return type === ("HELPER" as unknown as userType); } changeText(id : number, text : string) { const span = document.getElementById('hover-status-label-' + id); if (span) { span.innerHTML = ' ' + text; } } add(need: Need) { const currentUser = this.authService.getCurrentUser(); //console.log("get current user in angular:", currentUser) if (currentUser) { if (!currentUser.basket.includes(need.id)) { currentUser.basket.push(need.id); this.toastService.sendToast(ToastType.INFO, "Need added to your basket!") this.usersService.updateUser(currentUser) .pipe(catchError((err, _) => { console.error(err); return of(); })) .subscribe(() => { this.usersService.refreshBasket(); }); } else { this.toastService.sendToast(ToastType.ERROR, "This need is already in your basket!") } } } back() { this.searchResults = this.needs; } select(need : Need) { //emit value this.currentNeed.emit(need); if (this.selectedNeed) { //revert already selected need to previous style console.log(need.id); let button = document.getElementById('need-button-' + this.selectedNeed.id); if (button) { console.log(button) button.style.background = 'lightgray'; button.style.marginLeft = '0%'; button.style.width = '98%'; } button = document.getElementById('need-edit-button-' + this.selectedNeed.id); if (button) { button.style.visibility = 'visible'; } } //change selected need to selected style this.selectedNeed = need; let button = document.getElementById('need-button-' + need.id); if (button) { button.style.background = 'white'; button.style.marginLeft = '4%'; button.style.width = '100%'; } button = document.getElementById('need-edit-button-' + need.id); if (button) { button.style.visibility = 'hidden'; } } protected readonly GoalType = GoalType; }