diff options
Diffstat (limited to 'ufund-ui/src/app/components/need-list')
3 files changed, 39 insertions, 339 deletions
diff --git a/ufund-ui/src/app/components/need-list/need-list.component.css b/ufund-ui/src/app/components/need-list/need-list.component.css index e17609b..622b64a 100644 --- a/ufund-ui/src/app/components/need-list/need-list.component.css +++ b/ufund-ui/src/app/components/need-list/need-list.component.css @@ -1,9 +1,3 @@ -#header { - display: flex; - flex-direction: column; - gap: 10px -} - .needEntry { background-color: #2e2e2e; display: flex; @@ -17,33 +11,6 @@ gap: 15px } -select { - font-size: 14pt; - padding: 5px; -} - -#searchArea { - display: flex; - - form { - display: flex; - width: 100%; - gap: 10px; - } - - input[type=text] { - display: flex; - width: 100%; - } -} - -#sortArea { - display: flex; - flex-direction: row; - gap: 10px; - align-items: center; -} - .needName { font-weight: bold; } @@ -105,6 +72,10 @@ select { gap: 5px; } +.actionArea:empty { + padding: 0; +} + #page-selector { display: flex; align-items: center; diff --git a/ufund-ui/src/app/components/need-list/need-list.component.html b/ufund-ui/src/app/components/need-list/need-list.component.html index 84f80dc..406bfa0 100644 --- a/ufund-ui/src/app/components/need-list/need-list.component.html +++ b/ufund-ui/src/app/components/need-list/need-list.component.html @@ -1,30 +1,4 @@ -<div id="header"> - <div id="searchArea"> - <form id="search-form" #searchForm="ngForm"> - <input type="text" name="search" class="wide-input" placeholder="Search in {{needs.length}} needs..." (input)="search(searchForm.value)" ngModel> - <input type="reset" value="Clear" (click)="search(null)"> <br> - </form> - </div> - <div id="sortArea"> - <label for="sort">Sort by: </label> - <select id='sort' [(ngModel)] = "sortSelection" class="wide-input" (change)="search(searchForm.value)" [value]="sortSelection"> - <option *ngFor="let algorithm of SortingAlgoArrays" value="{{algorithm.name}}"> - {{algorithm.display[sortMode === 'Ascending' ? 0 : 1]}} - </option> - </select> - <button (click)="changeSortMode(searchForm.value)"> - <span class="icon">{{sortMode === 'Ascending' ? 'arrow_upward': 'arrow_downward'}}</span> - </button> - <label>Needs per page: </label> - <input type ="number" [(ngModel)]="itemsPerPage" (change)="editNeedsPerPage()" min="1" max="{{searchResults.length}}"> - </div> - <!--<button (click)="close()">Close</button>--> -</div> - <!-- display for when results are present and filtered--> -<h2 *ngIf="searchResults.length < needs.length && searchResults.length != 0"> Search Results({{needs.length - searchResults.length}} needs filtered): </h2> -<h2 *ngIf="searchResults.length == needs.length"> All Needs </h2> -<h2 *ngIf="searchResults.length == 0"> No Results Found </h2> <div id="needList"> <div *ngFor="let need of visibleNeeds" class="needEntry"> <div [routerLink]="'/need/' + need.id" class="clickable"> @@ -46,19 +20,9 @@ <span>{{need.type.toString() == 'MONETARY' ? '$' : ''}}{{need.current}}/{{need.type.toString() == 'MONETARY' ? '$' : ''}}{{need.maxGoal}} ({{((need.current / need.maxGoal) * 100).toFixed(0)}}%)</span> <progress [value]="need.current" [max]="need.maxGoal"></progress> </div> - </div> - - <div class="actionArea"> - <button *ngIf="isHelper()" (click)="add(need)"> - <span class="icon">add</span>Add To Basket - </button> - <button *ngIf="isManager()" (click)="select(need)"> - <span class="icon">edit</span>Edit Need - </button> - <button *ngIf="isManager()" (click)="delete(need.id)" > - <span class="icon">delete</span>Delete Need - </button> + <div *ngIf="actionArea" class="actionArea"> + <ng-container [ngTemplateOutlet]="actionArea" [ngTemplateOutletContext]="{$implicit: need}"/> </div> </div> </div> diff --git a/ufund-ui/src/app/components/need-list/need-list.component.ts b/ufund-ui/src/app/components/need-list/need-list.component.ts index ae6bc99..40af9f5 100644 --- a/ufund-ui/src/app/components/need-list/need-list.component.ts +++ b/ufund-ui/src/app/components/need-list/need-list.component.ts @@ -1,293 +1,58 @@ -import {Component, EventEmitter, Output} from '@angular/core'; +import {Component, Input, OnChanges, TemplateRef} 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' + 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 = 0; - itemsPerPage: number = 5; - totalPages: number = Math.ceil(this.needs.length / this.itemsPerPage); +export class NeedListComponent implements OnChanges { - getPrefix(need: Need) { - return (need.type === GoalType.MONETARY) ? "$" : ""; - } + @Input({required: true}) needs!: Need[] + @Input() itemsPerPage: number = 5; + @Input() actionArea: TemplateRef<any> | null = null - decrementPage() { - this.currentPage--; - this.updateVisibleNeeds(); - } + visibleNeeds: Need[] = []; + currentPage: number = 0; + totalPages: number = 0; - incrementPage() { - this.currentPage++; - this.updateVisibleNeeds(); - } + constructor( - lastPage() { - this.currentPage = this.totalPages - 1 - this.updateVisibleNeeds() - } + ) {} - firstPage() { - this.currentPage = 0 - this.updateVisibleNeeds() - } - - editNeedsPerPage() { - if (this.itemsPerPage > this.searchResults.length) { - this.itemsPerPage = this.searchResults.length; - } - if (this.itemsPerPage < 1) { - this.itemsPerPage = 1; + ngOnChanges() { + this.updateVisibleNeeds() } - this.resetVisibleNeeds(); - } - - updateVisibleNeeds() { - this.totalPages = Math.ceil(this.searchResults.length / this.itemsPerPage); - this.visibleNeeds = this.searchResults.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage); - } - - resetVisibleNeeds() { - this.currentPage = 0; - 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<Need>(); - - 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); + getPrefix(need: Need) { + return (need.type === GoalType.MONETARY) ? "$" : ""; } - ngOnInit(): void { - this.refresh() - - } - - changeSortMode(form : any) { - if (this.sortMode == 'Ascending'){ - this.sortMode = 'Descending' - } else { - this.sortMode = 'Ascending' + decrementPage() { + this.currentPage--; + this.updateVisibleNeeds(); } - 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); + incrementPage() { + this.currentPage++; + this.updateVisibleNeeds(); } - 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; + lastPage() { + this.currentPage = this.totalPages - 1 + this.updateVisibleNeeds() } - } - 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!") - } + firstPage() { + this.currentPage = 0 + this.updateVisibleNeeds() } - } - - 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'; - } + updateVisibleNeeds() { + this.totalPages = Math.ceil(this.needs.length / this.itemsPerPage); + this.visibleNeeds = this.needs.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage); } - //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; } |