aboutsummaryrefslogtreecommitdiff
path: root/ufund-ui/src/app/components/cupboard
diff options
context:
space:
mode:
Diffstat (limited to 'ufund-ui/src/app/components/cupboard')
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.css33
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.html74
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.ts191
-rw-r--r--ufund-ui/src/app/components/cupboard/sorting.ts69
4 files changed, 249 insertions, 118 deletions
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.css b/ufund-ui/src/app/components/cupboard/cupboard.component.css
index e45d929..9c37582 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.css
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.css
@@ -52,3 +52,36 @@
margin-top: 3px;
}
}
+
+#header2 {
+ display: flex;
+ flex-direction: column;
+ gap: 10px
+}
+
+#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;
+}
+
+select {
+ font-size: 14pt;
+ padding: 5px;
+}
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.html b/ufund-ui/src/app/components/cupboard/cupboard.component.html
index 37954bb..cd8fec2 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.html
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.html
@@ -1,38 +1,50 @@
<div id="box">
<div id="header">
<h1> Cupboard </h1>
- <button *ngIf="isManager()" class="button2" (click)="this.selectForm('create')"><span class="icon">add</span>Create Need</button>
+ <ng-template #create>
+ <app-need-edit [mode]="'Create'" (refreshNeedList)="refresh()"></app-need-edit>
+ </ng-template>
+ <button *ngIf="usersService.isManager()" class="button2" (click)="modalService.showModal(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.keys(SortingAlgorithms)" [value]="algorithm">
+ {{SortingAlgorithms[algorithm].display[sortMode === 'Ascending' ? 0 : 1]}}
+ </option>
+ </select>
+ <button (click)="toggleSortMode(searchForm.value)" [title]="sortMode">
+ <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>
</div>
+ <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>
+
+ <ng-template let-need #NLActions>
+ <button *ngIf="usersService.isHelper()" (click)="addToBasket(need)" [disabled]="usersService.inBasket(usersService.getBasket() | async, need)">
+ <span class="icon">{{usersService.inBasket(usersService.getBasket() | async, need)? "check": "add" }}</span>Add To Basket
+ </button>
+ <ng-template #edit>
+ <app-need-edit *ngIf="need" [mode]="'Edit'" [need]="need" (refreshNeedList)="refresh()"></app-need-edit>
+ </ng-template>
+ <button *ngIf="usersService.isManager()" (click)="modalService.showModal(edit)">
+ <span class="icon">edit</span>Edit Need
+ </button>
+ <button *ngIf="usersService.isManager()" (click)="deleteNeed(need.id)" >
+ <span class="icon">delete</span>Delete Need
+ </button>
+ </ng-template>
+ <app-need-list [actionArea]="NLActions" *ngIf="searchResults.length > 0" [needs]="searchResults" [itemsPerPage]="itemsPerPage" #needList/>
</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 a4706b3..b03b77e 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.ts
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.ts
@@ -1,11 +1,14 @@
import {Component, OnInit, ViewChild} from '@angular/core';
-import { CupboardService } from '../../services/cupboard.service';
-import { Need } from '../../models/Need';
-import { userType } from '../../models/User';
-import { catchError, of } from 'rxjs';
-import { NeedListComponent } from '../need-list/need-list.component';
+import {CupboardService} from '../../services/cupboard.service';
+import {Need} from '../../models/Need';
+import {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';
+import {Router} from '@angular/router';
+import {ModalService} from '../../services/modal.service';
@Component({
selector: 'app-cupboard',
@@ -13,111 +16,125 @@ 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;
+ // selectedForm?: string = undefined;
+ // needs: any;
@ViewChild("needList") needList?: NeedListComponent
+ private searchDelay: any;
+ needs: Need[] = [];
+ searchResults: Need[] = [];
+ sortMode: 'Ascending' | 'Descending' = 'Ascending'
+ itemsPerPage = 5;
+ currentSortAlgo = 'sortByPriority';
+
constructor(
private cupboardService: CupboardService,
private authService: AuthService,
- private toastService: ToastsService
+ private toastService: ToastsService,
+ protected usersService: UsersService,
+ private router: Router,
+ protected modalService: ModalService
) {}
ngOnInit(): void {
- this.cupboardService.getNeeds().subscribe(n => this.needs = n);
- if (this.isManager()) {
- console.log("Admin view of Cupboard");
- } else {
- console.log("Limited helper view of Cupboard");
- }
+ this.cupboardService.getNeeds().subscribe(n => {
+ this.needs = n;
+ // this.refresh()
+ this.search(null)
+ });
+ this.authService.getCurrentUserSubject().subscribe(
+ () => this.usersService.refreshBasket())
+ }
+
+ refresh() {
+ this.cupboardService.getNeeds().subscribe(n => {
+ if (this.sortMode == 'Ascending') {
+ this.needs = n.sort(SortingAlgoArrays[this.currentSortAlgo].func);
+ } else {
+ this.needs = n.sort(SortingAlgoArrays[this.currentSortAlgo].func).reverse();
+ }
+ this.searchResults = this.needs;
+ // this.updateVisibleNeeds();
+ });
+
+ const form = document.getElementById('search-form') as HTMLFormElement;
+ form.reset();
+ this.search(null);
}
- selectedNeed: any = {
- name: '',
- location:'',
- id: null,
- maxGoal: null,
- type: '',
- urgent: false
- };
- selectedNeedId: number | null = null;
- searchResults: any[] = [];
+ async search(form: any) {
+ console.log(this.currentSortAlgo)
+ //wait .25 seconds before searching but cancel if another search is made during the wait to prevent too many api calls
- selectForm(name: string) {
- //get search results from the need list
- if (this.needList) {
- this.searchResults = this.needList.searchResults;
+ //remove previous search if it exists
+ if (this.searchDelay) {
+ clearTimeout(this.searchDelay);
}
- console.log(this.searchResults)
- this.selectedForm = name;
- if (name == 'update') {
- if (this.searchResults) {
- this.searchResults.forEach((element: any) => {
- console.log(element)
- });
- }
+ if (form) {
+ this.searchDelay = setTimeout(() => {
+
+ if (form) {
+ const currentSearchValue = form.search; //latest value of the search
+ this.cupboardService.searchNeeds(currentSearchValue).subscribe((n) => {
+ if (this.sortMode == 'Ascending') {
+ this.searchResults = n.sort(SortingAlgoArrays[this.currentSortAlgo].func);
+ } else {
+ this.searchResults = n.sort(SortingAlgoArrays[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 = this.needs;
}
}
- async updateSearchResults() {
- if (this.needList) {
- while (this.selectedForm == 'update') {
- this.searchResults = this.needList.searchResults
- await new Promise(resolve => setTimeout(resolve, 100));
- }
+ toggleSortMode(form : any) {
+ if (this.sortMode == 'Ascending'){
+ this.sortMode = 'Descending'
+ } else {
+ this.sortMode = 'Ascending'
}
+ this.search(form)
}
- populateForm(need: any): void {
- this.selectForm('update');
- this.selectedNeed = { ...need };
+ deleteNeed(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);
+ addToBasket(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(() => {
+ let action = {label: "View Basket", onAction: () => this.router.navigate(['/basket'])}
+ this.toastService.sendToast(ToastType.INFO, `"${need.name}" Added to basket`, action)
+ this.usersService.refreshBasket();
+ });
+ } else {
+ this.toastService.sendToast(ToastType.ERROR, "This need is already in your basket!")
+ }
+ }
}
- submit(form: any) {
- const need: Need = {
- name: form.name,
- image: form.image,
- location: form.location,
- id: 0,
- maxGoal: form.maxGoal,
- type: form.type,
- urgent: !!form.urgent,
- filterAttributes: [],
- current: 0,
- description: form.description
- };
- console.log("need:", need);
- console.log("form submitted. creating need: ", need);
- this.cupboardService.createNeed(need)
- .pipe(catchError((ex, _) => {
- if (ex.status == 500) {
- this.toastService.sendToast(ToastType.ERROR, "Fields cannot be blank");
- } else if (ex.status == 400) {
- this.toastService.sendToast(ToastType.ERROR, ex.error);
- } else {
- this.toastService.sendToast(ToastType.ERROR, "Error on creating need");
- }
- return of()
- }))
- .subscribe(
- (result) => {
- if (result) {
- console.log("need created successfully");
- this.needList?.refresh()
- } else {
- console.log("need creation failed");
- }
- }
-
- );
- }
+ protected readonly SortingAlgorithms = 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..5c37019
--- /dev/null
+++ b/ufund-ui/src/app/components/cupboard/sorting.ts
@@ -0,0 +1,69 @@
+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;
+}
+
+const sortByType: sortAlgo = (a:Need, b:Need): number => {
+ if(a.type == b.type) {
+ return sortByName(a,b);
+ }
+ else if(a.type > b.type) {
+ return -1;
+ }
+ return 1;
+}
+
+export const SortingAlgoArrays: {[key: string]: { func: sortAlgo, display: [string, string]}} = {
+ 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" ] },
+ sortByType: { func: sortByType, display: ["Type (Physical first)", "Type (Monetary first)" ] },
+};