aboutsummaryrefslogtreecommitdiff
path: root/ufund-ui/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'ufund-ui/src/app')
-rw-r--r--ufund-ui/src/app/app.component.css47
-rw-r--r--ufund-ui/src/app/app.component.html12
-rw-r--r--ufund-ui/src/app/app.component.ts42
-rw-r--r--ufund-ui/src/app/app.module.ts2
-rw-r--r--ufund-ui/src/app/components/dashboard/dashboard.component.ts6
-rw-r--r--ufund-ui/src/app/components/funding-basket/funding-basket.component.ts21
-rw-r--r--ufund-ui/src/app/components/login/login.component.html1
-rw-r--r--ufund-ui/src/app/components/login/login.component.ts2
-rw-r--r--ufund-ui/src/app/components/need-list/need-list.component.html2
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.css57
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.html7
-rw-r--r--ufund-ui/src/app/components/toast/toast.component.ts37
-rw-r--r--ufund-ui/src/app/services/auth.service.ts14
-rw-r--r--ufund-ui/src/app/services/toasts.service.ts12
14 files changed, 194 insertions, 68 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
}
}