diff options
Diffstat (limited to 'ufund-ui/src/app/components/cupboard')
3 files changed, 286 insertions, 49 deletions
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.html b/ufund-ui/src/app/components/cupboard/cupboard.component.html index 37954bb..bdc8a0e 100644 --- a/ufund-ui/src/app/components/cupboard/cupboard.component.html +++ b/ufund-ui/src/app/components/cupboard/cupboard.component.html @@ -3,36 +3,64 @@ <h1> Cupboard </h1> <button *ngIf="isManager()" class="button2" (click)="this.selectForm('create')"><span class="icon">add</span>Create Need</button> </div> - <app-need-list (currentNeed) = populateForm($event) #needList></app-need-list> -</div> -<ng-template [ngIf]="isManager()" > -<div> - <app-need-edit *ngIf="selectedForm === 'update'" [selectedNeed]="selectedNeed" (refreshNeedList)="needList.refresh()"></app-need-edit> - <div> - <div id="create-form" *ngIf="selectedForm === 'create'"> - <h1> Create Need </h1> - <form #cupboardForm="ngForm" (ngSubmit)="submit(cupboardForm.value)"> - <label>Name:</label><br> - <input type="text" name="name" ngModel><br> - <label>Image:</label><br> - <input type="text" name="image" ngModel><br> - <label>Location:</label><br> - <input type="text" name="location" ngModel><br> - <label>Max Goal:</label><br> - <input type="number" name="maxGoal" ngModel><br> - <label>Type</label><br> - <input type="radio" name="type" value="MONETARY" ngModel> - <label>Monetary</label><br> - <input type="radio" name="type" value="PHYSICAL" ngModel> - <label>Physical</label><br> - <input type="checkbox" name="urgent" value="false" ngModel> - <label>Urgent</label><br> - <label>Description</label><br> - <textarea name="description"></textarea><br> - <input type="submit" value="Submit"> - </form> - </div> + <div id="header2"> + <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)] = "currentSortAlgo" class="wide-input" (change)="search(searchForm.value)" [value]="currentSortAlgo"> + <option *ngFor="let algorithm of Object.values(SortingAlgoArrays)" value="{{algorithm}}"> + {{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" min="1" max="{{searchResults.length}}">--> + </div> + <!--<button (click)="close()">Close</button>--> </div> + <h2 *ngIf="(searchResults | async)?.length < needs.length && (searchResults | async)?.length != 0"> Search Results({{needs.length - (searchResults | async)?.length}} needs filtered): </h2> + <h2 *ngIf="(searchResults | async)?.length == needs.length"> All Needs </h2> + <h2 *ngIf="(searchResults | async)?.length == 0"> No Results Found </h2> + + <app-need-list [needs]="searchResults" #needList></app-need-list> </div> -</ng-template> + +<!--<ng-template [ngIf]="isManager()" >--> +<!--<div>--> +<!-- <app-need-edit *ngIf="selectedForm === 'update'" [selectedNeed]="selectedNeed" (refreshNeedList)="needList.refresh()"></app-need-edit>--> +<!-- <div>--> +<!-- <div id="create-form" *ngIf="selectedForm === 'create'">--> +<!-- <h1> Create Need </h1>--> +<!-- <form #cupboardForm="ngForm" (ngSubmit)="submit(cupboardForm.value)">--> +<!-- <label>Name:</label><br>--> +<!-- <input type="text" name="name" ngModel><br>--> +<!-- <label>Image:</label><br>--> +<!-- <input type="text" name="image" ngModel><br>--> +<!-- <label>Location:</label><br>--> +<!-- <input type="text" name="location" ngModel><br>--> +<!-- <label>Max Goal:</label><br>--> +<!-- <input type="number" name="maxGoal" ngModel><br>--> +<!-- <label>Type</label><br>--> +<!-- <input type="radio" name="type" value="MONETARY" ngModel>--> +<!-- <label>Monetary</label><br>--> +<!-- <input type="radio" name="type" value="PHYSICAL" ngModel>--> +<!-- <label>Physical</label><br>--> +<!-- <input type="checkbox" name="urgent" value="false" ngModel>--> +<!-- <label>Urgent</label><br>--> +<!-- <label>Description</label><br>--> +<!-- <textarea name="description"></textarea><br>--> +<!-- <input type="submit" value="Submit">--> + +<!-- </form>--> +<!-- </div>--> +<!-- </div>--> +<!--</div>--> +<!--</ng-template>--> diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.ts b/ufund-ui/src/app/components/cupboard/cupboard.component.ts index 2230cd3..95845e7 100644 --- a/ufund-ui/src/app/components/cupboard/cupboard.component.ts +++ b/ufund-ui/src/app/components/cupboard/cupboard.component.ts @@ -2,10 +2,12 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import { CupboardService } from '../../services/cupboard.service'; import { Need, GoalType } from '../../models/Need'; import { userType } from '../../models/User'; -import { catchError, of } from 'rxjs'; +import {BehaviorSubject, catchError, of} from 'rxjs'; import { NeedListComponent } from '../need-list/need-list.component'; import {AuthService} from '../../services/auth.service'; import {ToastsService, ToastType} from '../../services/toasts.service'; +import {UsersService} from '../../services/users.service'; +import {SortingAlgoArrays} from './sorting'; @Component({ selector: 'app-cupboard', @@ -13,17 +15,36 @@ import {ToastsService, ToastType} from '../../services/toasts.service'; templateUrl: './cupboard.component.html', styleUrl: './cupboard.component.css' }) - export class CupboardComponent implements OnInit { selectedForm?: string = undefined; - needs: any; + // needs: any; @ViewChild("needList") needList?: NeedListComponent + private searchDelay: any; + selectedNeed: Need | null = null; + needs: Need[] = []; + searchResults = new BehaviorSubject<Need[]>([]); + sortMode: 'Ascending' | 'Descending' = 'Ascending' + // selectedNeed: any = { + // name: '', + // location:'', + // id: null, + // maxGoal: null, + // type: '', + // urgent: false + // }; + selectedNeedId: number | null = null; + // searchResults: any[] = []; + + currentSortAlgo = SortingAlgoArrays.sortByPriority; + // sortSelection: string = 'sortByPriority'; + constructor( private cupboardService: CupboardService, private authService: AuthService, - private toastService: ToastsService + private toastService: ToastsService, + private usersService: UsersService ) {} ngOnInit(): void { @@ -35,21 +56,26 @@ export class CupboardComponent implements OnInit { } } - selectedNeed: any = { - name: '', - location:'', - id: null, - maxGoal: null, - type: '', - urgent: false - }; - selectedNeedId: number | null = null; - searchResults: any[] = []; + refresh() { + this.cupboardService.getNeeds().subscribe(n => { + if (this.sortMode == 'Ascending') { + this.needs = n.sort(this.currentSortAlgo.func); + } else { + this.needs = n.sort(this.currentSortAlgo.func).reverse(); + } + this.searchResults.next(this.needs); + // this.updateVisibleNeeds(); + }); + + const form = document.getElementById('search-form') as HTMLFormElement; + form.reset(); + this.search(null); + } selectForm(name: string) { //get search results from the need list if (this.needList) { - this.searchResults = this.needList.searchResults; + // this.searchResults = this.needList.searchResults; } console.log(this.searchResults) this.selectedForm = name; @@ -63,10 +89,72 @@ export class CupboardComponent implements OnInit { } } + 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 + // SortingAlgoArrays.forEach(algo => { + // if(algo.name === this.sortSelection) { + // this.currentSortAlgo = SortingAlgoArrays[this.sort]; + // 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.next(n.sort(this.currentSortAlgo.func)); + } else { + this.searchResults.next(n.sort(this.currentSortAlgo.func).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.next(this.needs); + } + } + + changeSortMode(form : any) { + if (this.sortMode == 'Ascending'){ + this.sortMode = 'Descending' + } else { + this.sortMode = 'Ascending' + } + this.search(form) + } + + + + 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; + } + } + async updateSearchResults() { if (this.needList) { while (this.selectedForm == 'update') { - this.searchResults = this.needList.searchResults + // this.searchResults = this.needList.searchResults await new Promise(resolve => setTimeout(resolve, 100)); } } @@ -82,6 +170,40 @@ export class CupboardComponent implements OnInit { return type === ("MANAGER" as unknown as userType); } + // -------------- DISPLAY FUNCTIONS -------------- // + + 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'; + } + } + submit(form: any) { const need: Need = { name: form.name, @@ -90,7 +212,7 @@ export class CupboardComponent implements OnInit { id: 0, maxGoal: form.maxGoal, type: form.type, - urgent: form.urgent ? true : false, + urgent: !!form.urgent, filterAttributes: [], current: 0, description: form.description @@ -112,7 +234,7 @@ export class CupboardComponent implements OnInit { (result) => { if (result) { console.log("need created successfully"); - this.needList?.refresh() + // this.needList?.refresh() } else { console.log("need creation failed"); } @@ -121,7 +243,36 @@ export class CupboardComponent implements OnInit { ); } - destroy() { + // -------------- CRUD OPERATIONS -------------- // + 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(); } + + 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.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!") + } + } + } + + protected readonly SortingAlgoArrays = SortingAlgoArrays; + protected readonly Object = Object; } diff --git a/ufund-ui/src/app/components/cupboard/sorting.ts b/ufund-ui/src/app/components/cupboard/sorting.ts new file mode 100644 index 0000000..a512f22 --- /dev/null +++ b/ufund-ui/src/app/components/cupboard/sorting.ts @@ -0,0 +1,58 @@ +import {Need} from '../../models/Need'; + +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; +} + +export const SortingAlgoArrays = { + sortByPriority: { func: sortByPriority, display: ["Highest Priority", "Lowest Priority" ] }, + sortByName: { func: sortByName, display: ["Name (A to Z)", "Name (Z to A)" ] }, + sortByLocation: { func: sortByLocation, display: ["Location (A to Z)", "Location (Z to A)" ] }, + sortByCompletion: { func: sortByCompletion, display: ["Most Completed", "Least Completed" ] }, + sortByGoal: { func: sortByGoal, display: ["Largest Maximum Goal", "Smallest Maximum Goal" ] }, +}; |