diff options
Diffstat (limited to 'ufund-ui/src')
| -rw-r--r-- | ufund-ui/src/app/app.component.css | 47 | ||||
| -rw-r--r-- | ufund-ui/src/app/app.component.html | 12 | ||||
| -rw-r--r-- | ufund-ui/src/app/app.component.ts | 42 | ||||
| -rw-r--r-- | ufund-ui/src/app/app.module.ts | 2 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/dashboard/dashboard.component.ts | 6 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/funding-basket/funding-basket.component.ts | 21 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/login/login.component.html | 1 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/login/login.component.ts | 2 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/need-list/need-list.component.html | 2 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/toast/toast.component.css | 57 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/toast/toast.component.html | 7 | ||||
| -rw-r--r-- | ufund-ui/src/app/components/toast/toast.component.ts | 37 | ||||
| -rw-r--r-- | ufund-ui/src/app/services/auth.service.ts | 14 | ||||
| -rw-r--r-- | ufund-ui/src/app/services/toasts.service.ts | 12 | ||||
| -rw-r--r-- | ufund-ui/src/styles.css | 2 | 
15 files changed, 195 insertions, 69 deletions
diff --git a/ufund-ui/src/app/app.component.css b/ufund-ui/src/app/app.component.css index 5af3958..0bcd658 100644 --- a/ufund-ui/src/app/app.component.css +++ b/ufund-ui/src/app/app.component.css @@ -38,36 +38,29 @@          text-decoration: none;      } -    a:hover { -        /*color: light-dark(black, white)*/ -        text-decoration: underline; +    a { +        display: block; +        position: relative; +        padding: 0.1em 0;      } -} -.toast { -    transform: translateY(-90px); -    transition: transform .5s; -    align-self: center; -    z-index: 3; -    position: absolute; -    top: 15px; -    display: flex; -    flex-direction: row; -    padding: 3px 15px; -    background-color: #3a3a3a; -    border-radius: 100000px; -    gap: 10px; -    align-items: center; +    a::after { +        content: ''; +        position: absolute; +        bottom: 4px; +        left: 0; +        width: 100%; +        height: 0.03em; +        background-color: white; +        opacity: 0; +        transition: opacity 300ms, transform 300ms; +    } -    button { -        aspect-ratio: 1/1; -        margin-right: -11px; -        padding: 8px; -        display: flex; -        align-items: center; +    a:hover::after, +    a:focus::after { +        opacity: 1; +        transform: translate3d(0, 0.2em, 0);      } -} -.toast.active { -    transform: translateY(0); +  } diff --git a/ufund-ui/src/app/app.component.html b/ufund-ui/src/app/app.component.html index b41a225..959eada 100644 --- a/ufund-ui/src/app/app.component.html +++ b/ufund-ui/src/app/app.component.html @@ -1,11 +1,3 @@ -<div class="toast" #toastdiv> -<!--    <span{{(toast | async).message}}</span>--> -<!--    <a *ngIf="toast.action" (click)="toast.action.onAction()">{{toast.action.label}}</a>--> -<!--    <button (click)="toastdiv.classList.remove('active')">--> -<!--        <span class="icon">close</span>--> -<!--    </button>--> -</div> -  <div id="header">      <div>          <a routerLink="/"> @@ -17,8 +9,8 @@          <a routerLink="/cupboard">Cupboard</a>          <a routerLink="/basket">Basket</a>  <!--        <span>{{currentUser$ | async}}</span>--> -        <button *ngIf="currentUser$.value != 'Logged out.'" onclick="location.href='/';"> Log Out</button> -        <button *ngIf="currentUser$.value == 'Logged out.'" routerLink="/login"> Log In</button> +        <button *ngIf="currentUser | async" (click)="logout()"> Log Out</button> +        <button *ngIf="!(currentUser | async)" (click)="login()"> Log In</button>      </div>  </div> diff --git a/ufund-ui/src/app/app.component.ts b/ufund-ui/src/app/app.component.ts index 7d9afcd..2f98334 100644 --- a/ufund-ui/src/app/app.component.ts +++ b/ufund-ui/src/app/app.component.ts @@ -1,12 +1,10 @@ -import {Component, OnInit, Inject, ViewChild} from '@angular/core'; -import {BehaviorSubject, Observable} from 'rxjs'; +import {Component, OnInit, Inject, ViewContainerRef} from '@angular/core'; +import {BehaviorSubject} from 'rxjs';  import { DOCUMENT } from '@angular/common';  import {AuthService} from './services/auth.service'; -import {ToastType} from './services/toasts.service'; - -interface ToastProps { -    type: ToastType, message: string, action?: {label: string, onAction: () => void} -} +import {ToastsService} from './services/toasts.service'; +import {User} from './models/User'; +import {ActivatedRoute, Router} from '@angular/router';  @Component({    selector: 'app-root', @@ -16,12 +14,14 @@ interface ToastProps {  })  export class AppComponent implements OnInit {      // title = 'ufund-ui'; -    currentUser$: BehaviorSubject<string> = new BehaviorSubject<string>("Logged out."); -    toast = new BehaviorSubject<ToastProps>({type: ToastType.INFO, message: "testToast"}) - +    currentUser?: BehaviorSubject<User | null>;      constructor(          private authService: AuthService, +        private router: Router, +        private route: ActivatedRoute, +        protected toastService: ToastsService, +        private viewContainerRef: ViewContainerRef,          @Inject(DOCUMENT) private document: Document      ) {} @@ -30,14 +30,22 @@ export class AppComponent implements OnInit {      }      ngOnInit() { -        this.authService.getCurrentUserSubject().subscribe(r => { -            this.currentUser$?.next(r -                ? "Logged in as " + r.username -                : "Logged out." -            ) -        }) +        this.toastService.setRootViewContainerRef(this.viewContainerRef) +        this.currentUser = this.authService.getCurrentUserSubject() +        let data = localStorage.getItem("credential"); +        if (data) { +            let dataParsed = JSON.parse(data) +            this.authService.restoreLogin(dataParsed.username, dataParsed.key) +            console.log("Key found", dataParsed.key) +        }      } +    login() { +        this.router.navigate(['/login'], {queryParams: {redir: this.router.url}}); +    } - +    logout() { +        localStorage.removeItem("credential") +        location.reload() +    }  } diff --git a/ufund-ui/src/app/app.module.ts b/ufund-ui/src/app/app.module.ts index ea7e6ad..c91256e 100644 --- a/ufund-ui/src/app/app.module.ts +++ b/ufund-ui/src/app/app.module.ts @@ -16,6 +16,7 @@ import {CommonModule} from '@angular/common';  import {LoginComponent} from './components/login/login.component';  import { MiniNeedListComponent } from './components/mini-need-list/mini-need-list.component';  import { SignupComponent } from './components/signup/signup.component'; +import { ToastComponent } from './components/toast/toast.component';  @NgModule({      declarations: [ @@ -29,6 +30,7 @@ import { SignupComponent } from './components/signup/signup.component';          LoginComponent,          SignupComponent,          MiniNeedListComponent, +        ToastComponent,      ],      imports: [          BrowserModule, diff --git a/ufund-ui/src/app/components/dashboard/dashboard.component.ts b/ufund-ui/src/app/components/dashboard/dashboard.component.ts index 165c7ba..645893f 100644 --- a/ufund-ui/src/app/components/dashboard/dashboard.component.ts +++ b/ufund-ui/src/app/components/dashboard/dashboard.component.ts @@ -1,10 +1,8 @@  import {Component, OnInit} from '@angular/core'; -import {userType} from '../../models/User';  import {AuthService} from '../../services/auth.service';  import {Router} from '@angular/router';  import {Need} from '../../models/Need';  import {CupboardService} from '../../services/cupboard.service'; -import {UsersService} from '../../services/users.service';  import {firstValueFrom} from 'rxjs';  @Component({ @@ -27,7 +25,7 @@ export class DashboardComponent implements OnInit{      ngOnInit() {          let user = this.authService.getCurrentUser() -        if(!user) { +        if(!localStorage.getItem("credential") && !user) {              this.router.navigate(['/login'])              return          } @@ -35,7 +33,7 @@ export class DashboardComponent implements OnInit{          firstValueFrom(this.cupboardService.getNeeds()).then(r => {              this.topNeeds = r.sort((a, b) => b.current - a.current)              this.almostThere = r.sort((a, b) => a.current/a.maxGoal - b.current/b.maxGoal) -            this.inBasket = r.filter(n => n.id in user?.basket) +            this.inBasket = r.filter(n => n.id in user!.basket)          })      } diff --git a/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts b/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts index faa7e0b..24e2c0b 100644 --- a/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts +++ b/ufund-ui/src/app/components/funding-basket/funding-basket.component.ts @@ -4,6 +4,7 @@ import {Router} from '@angular/router';  import {CupboardService} from '../../services/cupboard.service';  import {catchError, firstValueFrom, Observable} from 'rxjs';  import {AuthService} from '../../services/auth.service'; +import {ToastsService, ToastType} from '../../services/toasts.service';  @Component({      selector: 'app-funding-basket', @@ -18,7 +19,8 @@ export class FundingBasketComponent implements OnInit {          private router: Router,          protected cupboardService: CupboardService,          protected usersService: UsersService, -        private authService: AuthService +        private authService: AuthService, +        private toastService: ToastsService      ) {}      @ViewChild("contribution") contribution?: Input; @@ -42,9 +44,20 @@ export class FundingBasketComponent implements OnInit {              contribution.setAttribute("style", "");              if (contribution.value == '' || contribution.valueAsNumber <= 0) {                  this.isValid = false; +                  contribution.setAttribute("style", "color: #ff0000"); +                this.toastService.sendToast(ToastType.WARNING, "Invalid input in funding basket!")              }          } +        // if (this.usersService.getBasket().value != await firstValueFrom(this.usersService.getUser(1)) +        // for (let c of this.usersService.getBasket().value) { +        //     if (c == null) { +        //         this.isValid = false; +        //         this.statusText.next("One or more needs have been deleted") +        //     } else { +        //         this.statusText.next("test") +        //     } +        // }          if (this.isValid) {              for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {                  let contribution = c as HTMLInputElement; @@ -54,11 +67,11 @@ export class FundingBasketComponent implements OnInit {                  this.cupboardService.checkoutNeed(need.id, +contribution.value)                      .pipe(catchError((ex, _) => {                          if (ex.status == 500) { -                            this.statusText.next('Fields cannot be blank'); +                            this.toastService.sendToast(ToastType.INFO, 'Fields cannot be blank');                          } else if (ex.status == 400) { -                            this.statusText.next('Goal must be greater than 0'); +                            this.toastService.sendToast(ToastType.INFO, 'Goal must be greater than 0');                          } else { -                            this.statusText.next('Error on creating need'); +                            this.toastService.sendToast(ToastType.INFO, 'Error on creating need');                          }                          return new Observable<string>();                      })) diff --git a/ufund-ui/src/app/components/login/login.component.html b/ufund-ui/src/app/components/login/login.component.html index 743b1b3..e1c3e2a 100644 --- a/ufund-ui/src/app/components/login/login.component.html +++ b/ufund-ui/src/app/components/login/login.component.html @@ -1,5 +1,4 @@  <div id="box"> -    <span *ngIf="next" style="color: red">You must be logged in to view this page</span>      <h1>Login</h1>      <input placeholder="Username" type="text" #username>      <input placeholder="Password" type="password" #password> diff --git a/ufund-ui/src/app/components/login/login.component.ts b/ufund-ui/src/app/components/login/login.component.ts index f6a2996..4dcaedd 100644 --- a/ufund-ui/src/app/components/login/login.component.ts +++ b/ufund-ui/src/app/components/login/login.component.ts @@ -35,6 +35,8 @@ export class LoginComponent implements OnInit {          this.authService.login(username, password).then(() => {              this.router.navigate([next]); +            let key = this.authService.getApiKey() +            localStorage.setItem("credential", JSON.stringify({username: username, key: key}))          }).catch(ex => {              this.statusText.next("Unable to login: " + friendlyHttpStatus[ex.status])              console.log(ex) 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 d35f2ed..c325320 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 @@ -41,7 +41,7 @@              <div class="prog">                  <span id="hover-status-label-{{need.id}}"> </span> -                <span>{{need.current}}/{{need.maxGoal}} ({{(need.current / need.maxGoal) * 100}}%)</span> +                <span>{{need.current}}/{{need.maxGoal}} ({{((need.current / need.maxGoal) * 100).toFixed(0)}}%)</span>                  <progress [value]="need.current" [max]="need.maxGoal"></progress>              </div> diff --git a/ufund-ui/src/app/components/toast/toast.component.css b/ufund-ui/src/app/components/toast/toast.component.css new file mode 100644 index 0000000..4cd81fe --- /dev/null +++ b/ufund-ui/src/app/components/toast/toast.component.css @@ -0,0 +1,57 @@ +:host { +    display: flex; +    align-items: center; +    justify-content: center; +} + +@keyframes slideDown { +    from {transform: translateY(-90px);} +    to {transform: translateY(0);} +} + +.toast { +    /*transform: translateY(-90px);*/ +    animation: slideDown .5s ease-in-out; +    transition: transform .5s; +    align-self: center; +    z-index: 3; +    position: absolute; +    top: 15px; +    display: flex; +    flex-direction: row; +    padding: 3px 15px; +    background-color: #3a3a3a; +    border-radius: 100000px; +    gap: 10px; +    align-items: center; + +    button { +        aspect-ratio: 1/1; +        margin-right: -11px; +        padding: 8px; +        display: flex; +        align-items: center; +        background-color: transparent; +    } + +    button:hover { +        background-color: rgba(255, 255, 255, 0.1); +    } +} + +.toast.hide { +    transform: translateY(-90px); +} + +.toast.warning { +    background-color: #ffc500; +    color: black; + +    button { +        color: black; +    } +} + +.toast.error { +    background-color: #d81a1a; +} diff --git a/ufund-ui/src/app/components/toast/toast.component.html b/ufund-ui/src/app/components/toast/toast.component.html new file mode 100644 index 0000000..dccf869 --- /dev/null +++ b/ufund-ui/src/app/components/toast/toast.component.html @@ -0,0 +1,7 @@ +<div class="toast" [ngClass]="ToastType[type].toLowerCase()" #toastDiv> +    <span>{{this.message}}</span> +    <a *ngIf="this.action" (click)="this.action.onAction()">{{this.action.label}}</a> +    <button (click)="hide()"> +        <span class="icon">close</span> +    </button> +</div> diff --git a/ufund-ui/src/app/components/toast/toast.component.ts b/ufund-ui/src/app/components/toast/toast.component.ts new file mode 100644 index 0000000..47fd7ff --- /dev/null +++ b/ufund-ui/src/app/components/toast/toast.component.ts @@ -0,0 +1,37 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import {ToastType} from '../../services/toasts.service'; + +@Component({ +  selector: 'app-toast', +  standalone: false, +  templateUrl: './toast.component.html', +  styleUrl: './toast.component.css' +}) +export class ToastComponent implements OnInit{ +    @Input() type!: ToastType +    @Input() message!: string +    @Input() action?: {label: string, onAction: () => void} + +    @ViewChild("toastDiv") toastDiv!: ElementRef<HTMLDivElement> + +    ngOnInit() { +        setTimeout(() => { +            this.hide(); +        }, 3000) +    } + +    hide() { +        console.log(this.toastDiv, typeof this.toastDiv) +        this.toastDiv.nativeElement.classList.add('hide') +    } + +    getColor() { +        switch (this.type) { +            case ToastType.ERROR: return "red"; +            case ToastType.INFO: return ""; +            case ToastType.WARNING: return "yellow"; +        } +    } + +    protected readonly ToastType = ToastType; +} diff --git a/ufund-ui/src/app/services/auth.service.ts b/ufund-ui/src/app/services/auth.service.ts index 6bc7145..b75c931 100644 --- a/ufund-ui/src/app/services/auth.service.ts +++ b/ufund-ui/src/app/services/auth.service.ts @@ -1,7 +1,8 @@ -import {Injectable} from '@angular/core'; +import {Injectable, Injector} from '@angular/core';  import {BehaviorSubject, firstValueFrom} from 'rxjs';  import {User} from '../models/User';  import {HttpClient, HttpHeaders} from '@angular/common/http'; +import {UsersService} from './users.service';  @Injectable({      providedIn: 'root' @@ -24,7 +25,9 @@ export class AuthService {      });      constructor( -        private http: HttpClient +        private http: HttpClient, +        // private userService: UsersService +        private injector: Injector      ) {}      async login(username: string, password: string) { @@ -42,6 +45,13 @@ export class AuthService {          // this.currentUser.subscribe(r => console.log("currentUser: "+r.username))      } +    async restoreLogin(username: string, key: string) { + +        const userService = this.injector.get(UsersService); +        this.apiKey = key; +        this.currentUser.next(await firstValueFrom(userService.getUser(username))) +    } +      getCurrentUserSubject() {          return this.currentUser;      } diff --git a/ufund-ui/src/app/services/toasts.service.ts b/ufund-ui/src/app/services/toasts.service.ts index 0c35e45..4fd024e 100644 --- a/ufund-ui/src/app/services/toasts.service.ts +++ b/ufund-ui/src/app/services/toasts.service.ts @@ -1,4 +1,5 @@ -import {Injectable} from '@angular/core'; +import {Injectable, ViewContainerRef} from '@angular/core'; +import {ToastComponent} from '../components/toast/toast.component';  export enum ToastType {      INFO, @@ -11,9 +12,16 @@ export enum ToastType {  })  export class ToastsService { -    constructor() {} +    private vcr?: ViewContainerRef      sendToast(type: ToastType, message: string, action?: {label: string, onAction: () => void}) { +        let compRef = this.vcr?.createComponent(ToastComponent)! +        compRef.setInput("message", message) +        compRef.setInput("type", type) +        compRef.setInput("action", action) +    } +    setRootViewContainerRef(vcr: ViewContainerRef) { +        this.vcr = vcr      }  } diff --git a/ufund-ui/src/styles.css b/ufund-ui/src/styles.css index b3ecbd0..b152e61 100644 --- a/ufund-ui/src/styles.css +++ b/ufund-ui/src/styles.css @@ -32,7 +32,7 @@ input {      }  } -button, .button { +button, input[type=button], input[type=reset], input[type=submit], .button {      font-size: 14pt;      padding: 6px 16px;      border-radius: 9999px;  | 
