diff options
| author | sowgro <tpoke.ferrari@gmail.com> | 2025-04-03 14:55:55 -0400 | 
|---|---|---|
| committer | sowgro <tpoke.ferrari@gmail.com> | 2025-04-03 14:55:55 -0400 | 
| commit | 0652eb445728806d7fd6a50021a763051503ab36 (patch) | |
| tree | 6036fd6901529ce217ec89456e2ee9a46655483a /ufund-ui/src | |
| parent | 6b7c830eeefb6a6a28136a3faacf7713953a6138 (diff) | |
| download | JellySolutions-0652eb445728806d7fd6a50021a763051503ab36.tar.gz JellySolutions-0652eb445728806d7fd6a50021a763051503ab36.tar.bz2 JellySolutions-0652eb445728806d7fd6a50021a763051503ab36.zip  | |
get checkout abstraction kinda working
Diffstat (limited to '')
8 files changed, 367 insertions, 453 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..5d6c93a 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.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> + +    <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..5139738 100644 --- a/ufund-ui/src/app/components/cupboard/cupboard.component.ts +++ b/ufund-ui/src/app/components/cupboard/cupboard.component.ts @@ -6,6 +6,8 @@ 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';  @Component({      selector: 'app-cupboard', @@ -13,43 +15,54 @@ 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: Need[] = []; +    sortMode: 'Ascending' | 'Descending' = 'Ascending' + +    currentSortAlgo = SortingAlgoArrays.sortByPriority; +      constructor(          private cupboardService: CupboardService,          private authService: AuthService, -        private toastService: ToastsService +        private toastService: ToastsService, +        private usersService: UsersService      ) {}      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() +        });      } -    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 = 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 +76,65 @@ 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 = n.sort(this.currentSortAlgo.func); +                        } else { +                            this.searchResults = 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 = this.needs; +        } +    } + +    changeSortMode(form : any) { +        if (this.sortMode == 'Ascending'){ +            this.sortMode = 'Descending' +        } else { +            this.sortMode = 'Ascending' +        } +        this.search(form) +    } + +    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 +150,45 @@ export class CupboardComponent implements OnInit {          return type === ("MANAGER" as unknown as userType);      } +    isHelper() { +        const type = this.authService.getCurrentUser()?.type; +        return type === ("HELPER" 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 +197,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 +219,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 +228,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" ] }, +}; diff --git a/ufund-ui/src/app/components/funding-basket/funding-basket.component.html b/ufund-ui/src/app/components/funding-basket/funding-basket.component.html index 52b35c1..2b05d01 100644 --- a/ufund-ui/src/app/components/funding-basket/funding-basket.component.html +++ b/ufund-ui/src/app/components/funding-basket/funding-basket.component.html @@ -1,75 +1,7 @@ - -<!--<div id="needCount">--> -<!--    <label for="needCount">Needs in Basket:</label>--> -<!--    <span>{{ this.usersService.getBasket().getValue().length }}</span>--> -<!--</div>--> - -<!--<div *ngIf="this.usersService.getBasket().getValue().length == 0">--> -<!--    <h2>There are no needs in the basket</h2>--> -<!--</div>--> - -<!--<table class="needs" id="funding-basket" *ngIf="this.usersService.getBasket().getValue().length != 0">--> -<!--    <thead>--> -<!--        <tr>--> -<!--            <th class="need"></th>--> -<!--        </tr>--> -<!--    </thead>--> -<!--    <tbody>--> -<!--        <tr *ngFor="let need of usersService.getBasket().getValue()">--> -<!--            <td>--> -<!--                <a routerLink="/need/{{need.id}}">{{need.name}}</a>--> -<!--                <p>Goal: {{need.maxGoal}}</p>--> -<!--                <p>Current: {{(need.current).toFixed(2)}}</p>--> -<!--                <p>How much to Contribute: <input type="number" placeholder="insert value" min="1" id={{need.id}} class="contribution"></p>--> -<!--                <br>--> -<!--                <div>--> -<!--                    <button type="button" class="removeNeed" title="delete need"--> -<!--                    (click)="this.usersService.removeNeed(need.id)">Remove Need</button>--> -<!--                </div>--> -<!--            </td>--> -<!--        </tr>--> -<!--    </tbody>--> -<!--</table>--> -<!--<br>-->  <div id="box">      <h1>Funding Basket</h1> -    <ng-template [ngIf]="usersService.getBasket().getValue().length"> -        <div id="needList"> -            <div *ngFor="let need of usersService.getBasket().getValue()" class="needEntry"> -                <div [routerLink]="'/need/' + need.id" class="clickable"> -                    <div class="split"> -                        <div class="left"> -                            <span class="needName">{{need.name}}</span> -                            <span class="needType">{{need.type}}</span> -                        </div> - -                        <div class="right"> -                            <span *ngIf="need.urgent" class="urgent">URGENT</span> -                            <span *ngIf="need.location"><span class="icon">location_on</span>{{need.location}}</span> -                        </div> -                    </div> - -                    <br> - -                    <div class="prog"> -                        <span id="hover-status-label-{{need.id}}"> </span> -                        <span>{{need.current}}/{{need.maxGoal}} ({{((need.current / need.maxGoal) * 100).toFixed(0)}}%)</span> -                        <progress [value]="need.current" [max]="need.maxGoal"></progress> -                    </div> - -                    <!--            <div class="description">--> -                    <!--                {{need.description}}--> -                    <!--            </div>--> -                </div> - -                <div class="actionArea"> -                    <input type="number" placeholder="Quantity" min="1" id={{need.id}} class="contribution"> -                    <button class="removeNeed" title="delete need" (click)="this.usersService.removeNeed(need.id)"> -                        <span class="icon">delete</span> Remove from Basket -                    </button> -                </div> -            </div> -        </div> +    <ng-template [ngIf]="(usersService.getBasket() | async)?.length"> +        <app-need-list [needs]="(usersService.getBasket() | async)!"/>          <br>          <div id="footer">              <button class="button2" title="checkout" (click)="checkout()">Checkout</button> 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..582b832 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;  } 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 88317dd..b19c33d 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)="resetVisibleNeeds()" 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"> @@ -45,20 +19,25 @@                  <span>{{need.current}}/{{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> +<!--        <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>--> +<!--        <div class="actionArea">--> +<!--            <input type="number" placeholder="Quantity" min="1" id={{need.id}} class="contribution">--> +<!--            <button class="removeNeed" title="delete need" (click)="this.usersService.removeNeed(need.id)">--> +<!--                <span class="icon">delete</span> Remove from Basket--> +<!--            </button>--> +<!--        </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 06a612e..d027690 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,282 +1,63 @@ -import {Component, EventEmitter, Output} from '@angular/core'; +import {Component, Input, OnChanges, OnInit} from '@angular/core';  import {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; -} +import {Observable} from 'rxjs';  @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); - -  decrementPage() { -    this.currentPage--; -    this.updateVisibleNeeds(); -  } - -  incrementPage() { -    this.currentPage++; -    this.updateVisibleNeeds(); -  } - -  lastPage() { -      this.currentPage = this.totalPages - 1 -      this.updateVisibleNeeds() -  } +export class NeedListComponent implements OnChanges { -  firstPage() { -      this.currentPage = 0 -      this.updateVisibleNeeds() -  } +    @Input({required: true}) needs!: Need[] -  editNeedsPerPage(amount: number) { -    this.itemsPerPage = amount; -    this.updateVisibleNeeds(); -  } +    visibleNeeds: Need[] = []; +    currentPage: number = 0; +    itemsPerPage: number = 5; +    totalPages: number = 0; -  updateVisibleNeeds() { -    this.totalPages = Math.ceil(this.searchResults.length / this.itemsPerPage); -    this.visibleNeeds = this.searchResults.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage); -  } +    constructor( -  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); +    ngOnChanges() { +        this.updateVisibleNeeds()      } -  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); -  } +    lastPage() { +        this.currentPage = this.totalPages - 1 +        this.updateVisibleNeeds() +    } -  changeText(id : number, text : string) { -    const span = document.getElementById('hover-status-label-' + id); -    if (span) { -      span.innerHTML = ' ' + text; +    firstPage() { +        this.currentPage = 0 +        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.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!") -      } +    editNeedsPerPage(amount: number) { +        this.itemsPerPage = amount; +        this.updateVisibleNeeds();      } -  } -  back() { -    this.searchResults = this.needs; -  } +    updateVisibleNeeds() { +        this.totalPages = Math.ceil(this.needs.length / this.itemsPerPage); +        this.visibleNeeds = this.needs.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage); +    } -  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'; -      } +    resetVisibleNeeds() { +        this.currentPage = 0; +        this.updateVisibleNeeds();      } -      //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'; -      } -  }  }  | 
