aboutsummaryrefslogtreecommitdiff
path: root/ufund-ui/src
diff options
context:
space:
mode:
Diffstat (limited to 'ufund-ui/src')
-rw-r--r--ufund-ui/src/app/app-routing.module.ts4
-rw-r--r--ufund-ui/src/app/app.component.ts8
-rw-r--r--ufund-ui/src/app/app.module.ts2
-rw-r--r--ufund-ui/src/app/components/cupboard/cupboard.component.ts63
-rw-r--r--ufund-ui/src/app/components/dashboard/dashboard.component.ts20
-rw-r--r--ufund-ui/src/app/components/funding-basket/funding-basket.component.ts122
-rw-r--r--ufund-ui/src/app/components/home-page/home-page.component.ts10
-rw-r--r--ufund-ui/src/app/components/login/login.component.html2
-rw-r--r--ufund-ui/src/app/components/login/login.component.ts14
-rw-r--r--ufund-ui/src/app/components/need-list/need-list.component.ts2
-rw-r--r--ufund-ui/src/app/components/need-page/need-page.component.ts38
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.css47
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.html26
-rw-r--r--ufund-ui/src/app/components/signup/signup.component.ts165
-rw-r--r--ufund-ui/src/app/models/Need.ts20
-rw-r--r--ufund-ui/src/app/models/User.ts2
-rw-r--r--ufund-ui/src/app/services/auth.service.ts57
-rw-r--r--ufund-ui/src/app/services/cupboard.service.ts30
-rw-r--r--ufund-ui/src/app/services/users.service.ts73
19 files changed, 472 insertions, 233 deletions
diff --git a/ufund-ui/src/app/app-routing.module.ts b/ufund-ui/src/app/app-routing.module.ts
index 4b76654..a6ea806 100644
--- a/ufund-ui/src/app/app-routing.module.ts
+++ b/ufund-ui/src/app/app-routing.module.ts
@@ -6,6 +6,7 @@ import {LoginComponent} from './components/login/login.component';
import {HomePageComponent} from './components/home-page/home-page.component';
import {FundingBasketComponent} from './components/funding-basket/funding-basket.component';
import {NeedPageComponent} from './components/need-page/need-page.component';
+import {SignupComponent} from './components/signup/signup.component';
const routes: Routes = [
{path: '', component: HomePageComponent},
@@ -13,7 +14,8 @@ const routes: Routes = [
{path: 'cupboard', component: CupboardComponent},
{path: 'dashboard', component: DashboardComponent},
{path: 'basket', component: FundingBasketComponent},
- {path: 'need/:id', component: NeedPageComponent}
+ {path: 'need/:id', component: NeedPageComponent},
+ {path: 'signup', component: SignupComponent},
];
@NgModule({
diff --git a/ufund-ui/src/app/app.component.ts b/ufund-ui/src/app/app.component.ts
index 7dc8ffb..86717c4 100644
--- a/ufund-ui/src/app/app.component.ts
+++ b/ufund-ui/src/app/app.component.ts
@@ -1,7 +1,7 @@
import {Component, OnInit, Inject} from '@angular/core';
-import {UsersService} from './services/users.service';
import {BehaviorSubject} from 'rxjs';
import { DOCUMENT } from '@angular/common';
+import {AuthService} from './services/auth.service';
@Component({
selector: 'app-root',
@@ -14,16 +14,16 @@ export class AppComponent implements OnInit {
currentUser$: BehaviorSubject<string> = new BehaviorSubject<string>("Logged out.");
constructor(
- private userService: UsersService,
+ private authService: AuthService,
@Inject(DOCUMENT) private document: Document
) {}
reloadPage() {
this.document.defaultView?.location.reload();
- }
+ }
ngOnInit() {
- this.userService.getCurrentUserSubject().subscribe(r => {
+ this.authService.getCurrentUserSubject().subscribe(r => {
this.currentUser$?.next(r
? "Logged in as " + r.username
: "Logged out."
diff --git a/ufund-ui/src/app/app.module.ts b/ufund-ui/src/app/app.module.ts
index 9f525fe..156ef5f 100644
--- a/ufund-ui/src/app/app.module.ts
+++ b/ufund-ui/src/app/app.module.ts
@@ -14,6 +14,7 @@ import {RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router';
import {DashboardComponent} from './components/dashboard/dashboard.component';
import {CommonModule} from '@angular/common';
import {LoginComponent} from './components/login/login.component';
+import { SignupComponent } from './components/signup/signup.component';
@NgModule({
declarations: [
@@ -25,6 +26,7 @@ import {LoginComponent} from './components/login/login.component';
NeedListComponent,
DashboardComponent,
LoginComponent,
+ SignupComponent,
],
imports: [
BrowserModule,
diff --git a/ufund-ui/src/app/components/cupboard/cupboard.component.ts b/ufund-ui/src/app/components/cupboard/cupboard.component.ts
index ad68c38..85ffd17 100644
--- a/ufund-ui/src/app/components/cupboard/cupboard.component.ts
+++ b/ufund-ui/src/app/components/cupboard/cupboard.component.ts
@@ -1,10 +1,10 @@
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import { CupboardService } from '../../services/cupboard.service';
-import { UsersService } from '../../services/users.service';
import { Need, GoalType } from '../../models/Need';
import { userType } from '../../models/User';
import { BehaviorSubject, catchError, of } from 'rxjs';
import { NeedListComponent } from '../need-list/need-list.component';
+import {AuthService} from '../../services/auth.service';
@Component({
selector: 'app-cupboard',
@@ -18,8 +18,12 @@ export class CupboardComponent implements OnInit {
protected statusText = new BehaviorSubject("")
selectedForm = "create";
needs: any;
- @ViewChild("needList") needList?: NeedListComponent;
- constructor(private cupboardService: CupboardService, private usersService: UsersService) { }
+ @ViewChild("needList") needList?: NeedListComponent
+
+ constructor(
+ private cupboardService: CupboardService,
+ private authService: AuthService
+ ) {}
ngOnInit(): void {
this.cupboardService.getNeeds().subscribe(n => this.needs = n);
@@ -73,7 +77,7 @@ export class CupboardComponent implements OnInit {
}
isManager() {
- const type = this.usersService.getCurrentUser()?.type;
+ const type = this.authService.getCurrentUser()?.type;
return type === ("MANAGER" as unknown as userType);
}
@@ -89,9 +93,9 @@ export class CupboardComponent implements OnInit {
filterAttributes: [],
current: 0
};
-
+
this.cupboardService.updateNeed(need.id, need)
- .pipe(catchError((ex, r) => {
+ .pipe(catchError((ex, _) => {
if (ex.status == 500) {
this.statusText.next("Fields cannot be blank");
} else if (ex.status == 400) {
@@ -128,7 +132,7 @@ export class CupboardComponent implements OnInit {
console.log("need:", need);
console.log("form submitted. creating need: ", need);
this.cupboardService.createNeed(need)
- .pipe(catchError((ex, r) => {
+ .pipe(catchError((ex, _) => {
if (ex.status == 500) {
this.statusText.next("Fields cannot be blank");
} else if (ex.status == 400) {
@@ -155,48 +159,3 @@ export class CupboardComponent implements OnInit {
}
}
-
-let friendlyHttpStatus: { [key: number]: string } = {
- 200: 'OK',
- 201: 'Created',
- 202: 'Accepted',
- 203: 'Non-Authoritative Information',
- 204: 'No Content',
- 205: 'Reset Content',
- 206: 'Partial Content',
- 300: 'Multiple Choices',
- 301: 'Moved Permanently',
- 302: 'Found',
- 303: 'See Other',
- 304: 'Not Modified',
- 305: 'Use Proxy',
- 306: 'Unused',
- 307: 'Temporary Redirect',
- 400: 'Bad Request',
- 401: 'Unauthorized',
- 402: 'Payment Required',
- 403: 'Forbidden',
- 404: 'Not Found',
- 405: 'Method Not Allowed',
- 406: 'Not Acceptable',
- 407: 'Proxy Authentication Required',
- 408: 'Request Timeout',
- 409: 'Conflict',
- 410: 'Gone',
- 411: 'Length Required',
- 412: 'Precondition Required',
- 413: 'Request Entry Too Large',
- 414: 'Request-URI Too Long',
- 415: 'Unsupported Media Type',
- 416: 'Requested Range Not Satisfiable',
- 417: 'Expectation Failed',
- 418: 'I\'m a teapot',
- 422: 'Unprocessable Entity',
- 429: 'Too Many Requests',
- 500: 'Internal Server Error',
- 501: 'Not Implemented',
- 502: 'Bad Gateway',
- 503: 'Service Unavailable',
- 504: 'Gateway Timeout',
- 505: 'HTTP Version Not Supported',
-};
diff --git a/ufund-ui/src/app/components/dashboard/dashboard.component.ts b/ufund-ui/src/app/components/dashboard/dashboard.component.ts
index b9faefa..a0ad566 100644
--- a/ufund-ui/src/app/components/dashboard/dashboard.component.ts
+++ b/ufund-ui/src/app/components/dashboard/dashboard.component.ts
@@ -1,21 +1,21 @@
-import { Component } from '@angular/core';
-import { UsersService } from '../../services/users.service';
-import { userType } from '../../models/User';
+import {Component} from '@angular/core';
+import {userType} from '../../models/User';
+import {AuthService} from '../../services/auth.service';
@Component({
- selector: 'app-dashboard',
- standalone: false,
- templateUrl: './dashboard.component.html',
- styleUrl: './dashboard.component.css'
+ selector: 'app-dashboard',
+ standalone: false,
+ templateUrl: './dashboard.component.html',
+ styleUrl: './dashboard.component.css'
})
export class DashboardComponent {
constructor(
- protected usersService: UsersService,
+ protected authService: AuthService,
) {}
isManager() {
- const type = this.usersService.getCurrentUser()?.type;
+ const type = this.authService.getCurrentUser()?.type;
return type === ("MANAGER" as unknown as userType);
- }
+ }
}
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 e654711..faa7e0b 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
@@ -1,11 +1,9 @@
import {Component, Input, OnInit, ViewChild} from '@angular/core';
-import {User} from '../../models/User';
-import { UsersService } from '../../services/users.service';
-import { Need } from '../../models/Need';
-import { NeedListComponent } from '../need-list/need-list.component';
-import { Router } from '@angular/router';
-import { CupboardService } from '../../services/cupboard.service';
-import { BehaviorSubject, catchError, firstValueFrom, Observable } from 'rxjs';
+import {UsersService} from '../../services/users.service';
+import {Router} from '@angular/router';
+import {CupboardService} from '../../services/cupboard.service';
+import {catchError, firstValueFrom, Observable} from 'rxjs';
+import {AuthService} from '../../services/auth.service';
@Component({
selector: 'app-funding-basket',
@@ -14,67 +12,67 @@ import { BehaviorSubject, catchError, firstValueFrom, Observable } from 'rxjs';
styleUrl: './funding-basket.component.css'
})
export class FundingBasketComponent implements OnInit {
- statusText: any;
+ statusText: any;
- constructor(
- private router: Router,
- protected cupboardService: CupboardService,
- protected usersService: UsersService
- ) {}
+ constructor(
+ private router: Router,
+ protected cupboardService: CupboardService,
+ protected usersService: UsersService,
+ private authService: AuthService
+ ) {}
- @ViewChild("contribution") contribution?: Input;
- @Input() isValid: boolean = true;
+ @ViewChild("contribution") contribution?: Input;
+ @Input() isValid: boolean = true;
- // this is for login rerouting
- ngOnInit(): void {
- if (!this.usersService.getCurrentUser()) {
- this.router.navigate(['/login'], {queryParams: {redir: this.router.url}});
- return;
- }
-
- this.usersService.refreshBasket();
- // this.usersService.removeNeed(); <- call this to remove
- }
+ // this is for login rerouting
+ ngOnInit(): void {
+ if (!this.authService.getCurrentUser()) {
+ this.router.navigate(['/login'], {queryParams: {redir: this.router.url}});
+ return;
+ }
- async checkout() {
- this.isValid = true;
- for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {
- let contribution = c as HTMLInputElement;
- contribution.setAttribute("style","");
- if ( contribution.value == '' || contribution.valueAsNumber <= 0) {
- this.isValid = false;
- contribution.setAttribute("style","color: #ff0000");
- }
+ this.usersService.refreshBasket();
+ // this.usersService.removeNeed(); <- call this to remove
}
- if (this.isValid) {
- for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {
- let contribution = c as HTMLInputElement;
- let need = await firstValueFrom(this.cupboardService.getNeed(+contribution.id));
- need.current +=+ contribution.value;
- this.usersService.removeNeed(+need.id);
- this.cupboardService.updateNeed(need.id, need)
- .pipe(catchError((ex, r) => {
- if (ex.status == 500) {
- this.statusText.next('Fields cannot be blank');
- } else if (ex.status == 400) {
- this.statusText.next('Goal must be greater than 0');
- } else {
- this.statusText.next('Error on creating need');
- }
- return new Observable<string>();
- }))
- .subscribe((result) => {
- if (result) {
- console.log('need updated successfully');
- //this.needList?.refresh()
- } else {
- console.log('need update failed');
- }
- });
- }
- }
- }
+ async checkout() {
+ this.isValid = true;
+ for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {
+ let contribution = c as HTMLInputElement;
+ contribution.setAttribute("style", "");
+ if (contribution.value == '' || contribution.valueAsNumber <= 0) {
+ this.isValid = false;
+ contribution.setAttribute("style", "color: #ff0000");
+ }
+ }
+ if (this.isValid) {
+ for (let c of document.getElementById("funding-basket")?.querySelectorAll('.contribution')!) {
+ let contribution = c as HTMLInputElement;
+ let need = await firstValueFrom(this.cupboardService.getNeed(+contribution.id));
+ need.current += +contribution.value;
+ this.usersService.removeNeed(+need.id);
+ this.cupboardService.checkoutNeed(need.id, +contribution.value)
+ .pipe(catchError((ex, _) => {
+ if (ex.status == 500) {
+ this.statusText.next('Fields cannot be blank');
+ } else if (ex.status == 400) {
+ this.statusText.next('Goal must be greater than 0');
+ } else {
+ this.statusText.next('Error on creating need');
+ }
+ return new Observable<string>();
+ }))
+ .subscribe((result) => {
+ if (result) {
+ console.log('need updated successfully');
+ //this.needList?.refresh()
+ } else {
+ console.log('need update failed');
+ }
+ });
+ }
+ }
+ }
}
diff --git a/ufund-ui/src/app/components/home-page/home-page.component.ts b/ufund-ui/src/app/components/home-page/home-page.component.ts
index 5b2277c..95e8962 100644
--- a/ufund-ui/src/app/components/home-page/home-page.component.ts
+++ b/ufund-ui/src/app/components/home-page/home-page.component.ts
@@ -1,10 +1,10 @@
-import { Component } from '@angular/core';
+import {Component} from '@angular/core';
@Component({
- selector: 'app-home-page',
- standalone: false,
- templateUrl: './home-page.component.html',
- styleUrl: './home-page.component.css'
+ selector: 'app-home-page',
+ standalone: false,
+ templateUrl: './home-page.component.html',
+ styleUrl: './home-page.component.css'
})
export class HomePageComponent {
diff --git a/ufund-ui/src/app/components/login/login.component.html b/ufund-ui/src/app/components/login/login.component.html
index 2cdb6d0..a6441f4 100644
--- a/ufund-ui/src/app/components/login/login.component.html
+++ b/ufund-ui/src/app/components/login/login.component.html
@@ -3,5 +3,5 @@
<input placeholder="Username" type="text" #username>
<input placeholder="Password" type="password" #password>
<button type="button" (click)="login(username.value, password.value)">Login</button>
-<button type="button" (click)="signup(username.value, password.value)">Create Account</button>
+<button type="button" routerLink="/signup">Create Account...</button>
<span *ngIf="statusText">{{statusText | async}}</span>
diff --git a/ufund-ui/src/app/components/login/login.component.ts b/ufund-ui/src/app/components/login/login.component.ts
index 9d806f5..f6a2996 100644
--- a/ufund-ui/src/app/components/login/login.component.ts
+++ b/ufund-ui/src/app/components/login/login.component.ts
@@ -2,12 +2,13 @@ import {Component, OnInit} from '@angular/core'
import {UsersService} from '../../services/users.service';
import {ActivatedRoute, Router} from '@angular/router';
import {BehaviorSubject} from 'rxjs';
+import {AuthService} from '../../services/auth.service';
@Component({
- selector: 'app-login',
- standalone: false,
- templateUrl: './login.component.html',
- styleUrl: './login.component.css'
+ selector: 'app-login',
+ standalone: false,
+ templateUrl: './login.component.html',
+ styleUrl: './login.component.css'
})
export class LoginComponent implements OnInit {
@@ -17,7 +18,8 @@ export class LoginComponent implements OnInit {
constructor(
protected usersService: UsersService,
protected router: Router,
- private route: ActivatedRoute
+ private route: ActivatedRoute,
+ private authService: AuthService
) {}
ngOnInit() {
@@ -31,7 +33,7 @@ export class LoginComponent implements OnInit {
return;
}
- this.usersService.login(username, password).then(() => {
+ this.authService.login(username, password).then(() => {
this.router.navigate([next]);
}).catch(ex => {
this.statusText.next("Unable to login: " + friendlyHttpStatus[ex.status])
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 17bb3e6..2bbacb0 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
@@ -128,7 +128,7 @@ export class NeedListComponent {
} else {
this.searchResults = n.sort(this.currentSortAlgo).reverse();
}
-
+
console.log(currentSearchValue, this.searchResults);
});
}
diff --git a/ufund-ui/src/app/components/need-page/need-page.component.ts b/ufund-ui/src/app/components/need-page/need-page.component.ts
index 597d0e0..e38554c 100644
--- a/ufund-ui/src/app/components/need-page/need-page.component.ts
+++ b/ufund-ui/src/app/components/need-page/need-page.component.ts
@@ -2,30 +2,30 @@ import {Component, Input} from '@angular/core';
import {GoalType, Need} from '../../models/Need';
import {ActivatedRoute} from "@angular/router";
import {CupboardService} from "../../services/cupboard.service";
-import { NgFor } from '@angular/common';
+import {NgFor} from '@angular/common';
@Component({
- selector: 'app-need-page',
- standalone: false,
- templateUrl: './need-page.component.html',
- styleUrl: './need-page.component.css'
+ selector: 'app-need-page',
+ standalone: false,
+ templateUrl: './need-page.component.html',
+ styleUrl: './need-page.component.css'
})
export class NeedPageComponent {
- constructor(
- private route: ActivatedRoute,
- private cupboardService: CupboardService,
- ) {}
+ constructor(
+ private route: ActivatedRoute,
+ private cupboardService: CupboardService,
+ ) {}
- public GoalType = GoalType;
+ public GoalType = GoalType;
- @Input() need?: Need;
+ @Input() need?: Need;
- ngOnInit(): void {
- const id = Number(this.route.snapshot.paramMap.get('id'));
- this.cupboardService.getNeed(id).subscribe(n => this.need = n);
- }
+ ngOnInit(): void {
+ const id = Number(this.route.snapshot.paramMap.get('id'));
+ this.cupboardService.getNeed(id).subscribe(n => this.need = n);
+ }
- back() {
- window.history.back();
- }
-} \ No newline at end of file
+ back() {
+ window.history.back();
+ }
+}
diff --git a/ufund-ui/src/app/components/signup/signup.component.css b/ufund-ui/src/app/components/signup/signup.component.css
new file mode 100644
index 0000000..f286cf9
--- /dev/null
+++ b/ufund-ui/src/app/components/signup/signup.component.css
@@ -0,0 +1,47 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ max-width: 300px;
+ gap: 10px;
+
+ & > div {
+ display: flex;
+ flex-direction: column;
+ }
+}
+
+.border {
+ border-style: solid;
+ border-width: 1px;
+ padding: 10px;
+ margin: 10px;
+ position: absolute;
+ background-color: white;
+ box-shadow: 0 0 10px 10px black;
+}
+
+#bar {
+ height: 5px;
+ width: 100%;
+ appearance: none;
+ overflow: hidden;
+ /*margin-top: -5px;*/
+}
+
+#bar::-webkit-progress-bar {
+ background-color: lightgray;
+ transition: width 0.5s ease-in-out, background-color 0.5s ease-in-out;
+}
+
+.color0::-webkit-progress-value { background: rgba(255, 0 ,0, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color1::-webkit-progress-value { background: rgba(255, 0 ,0, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color2::-webkit-progress-value { background: rgba(255, 165, 0, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color3::-webkit-progress-value { background: rgba(255, 255, 0, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color4::-webkit-progress-value { background: rgba(173, 255, 47, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color5::-webkit-progress-value { background: rgba(50, 205, 50, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+.color6::-webkit-progress-value { background: rgba(0, 128, 0, 1); transition: background-color 0.5s ease-in-out, width 0.5s ease-in-out; }
+
+#requirement2, #statusText, #passwordStatusText, #usernameStatusText {
+ color: red;
+}
+
diff --git a/ufund-ui/src/app/components/signup/signup.component.html b/ufund-ui/src/app/components/signup/signup.component.html
new file mode 100644
index 0000000..ebedc2a
--- /dev/null
+++ b/ufund-ui/src/app/components/signup/signup.component.html
@@ -0,0 +1,26 @@
+<p>Signup:</p>
+<div>
+ <input placeholder="Username" type="text" (input)="validate(username.value, confirmPass.value, password.value)" #username>
+ <span *ngIf="usernameStatusText">{{usernameStatusText | async}}</span>
+</div>
+
+<div>
+ <input placeholder="Password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #password>
+ <progress [ngClass]="'color' + strength.getValue()" id="bar" [value]="strength | async" max="6"> </progress>
+ <span *ngIf="passwordStatusText">{{passwordStatusText | async}}</span>
+
+ <span *ngFor="let requirement of Object.values(passwordRequirements)">
+ <span *ngIf="passwordRequirements" [style.color]="requirement.value ? 'green' : 'red'"> {{requirement.title}} </span>
+ </span>
+</div>
+
+<div>
+ <input placeholder="Confirm password" type="password" (input)="validate(username.value, confirmPass.value, password.value)" #confirmPass>
+ <span *ngIf="confirmPassStatusText">{{confirmPassStatusText | async}}</span>
+</div>
+
+<div>
+ <button [disabled]="!(ableToCreateAccount | async)" (click)="signup(username.value, password.value)">Create Account</button>
+ <span *ngIf="showSuccessMessage | async">Account created <a routerLink="/login">Proceed to login</a></span>
+ <span *ngIf="statusText | async">{{statusText | async}}</span>
+</div>
diff --git a/ufund-ui/src/app/components/signup/signup.component.ts b/ufund-ui/src/app/components/signup/signup.component.ts
new file mode 100644
index 0000000..3b43287
--- /dev/null
+++ b/ufund-ui/src/app/components/signup/signup.component.ts
@@ -0,0 +1,165 @@
+import {Component} from '@angular/core';
+import {UsersService} from '../../services/users.service';
+import {Router} from '@angular/router';
+import {BehaviorSubject} from 'rxjs';
+
+class PasswordRequirements {
+ sixLong: {title: string, value: boolean} = {title: 'Is 6 characters or longer' , value: false}
+ twelveLong: {title: string, value: boolean} = {title: 'Is 12 characters or longer', value: false}
+ lowercase: {title: string, value: boolean} = {title: 'Includes lowercase letter' , value: false}
+ uppercase: {title: string, value: boolean} = {title: 'Includes uppercase letter' , value: false}
+ number: {title: string, value: boolean} = {title: 'Includes number' , value: false}
+ symbol: {title: string, value: boolean} = {title: 'Includes symbol' , value: false}
+}
+
+@Component({
+ selector: 'app-signup',
+ standalone: false,
+ templateUrl: './signup.component.html',
+ styleUrl: './signup.component.css'
+})
+
+export class SignupComponent {
+
+ protected passwordStatusText = new BehaviorSubject("")
+ protected confirmPassStatusText = new BehaviorSubject("")
+ protected usernameStatusText = new BehaviorSubject("")
+ protected showSuccessMessage = new BehaviorSubject(false)
+ protected passwordStrongEnough = new BehaviorSubject(false)
+ protected ableToCreateAccount = new BehaviorSubject(false)
+ protected passwordRequirements: PasswordRequirements = new PasswordRequirements()
+ protected strength = new BehaviorSubject(0)
+ protected statusText = new BehaviorSubject("");
+
+ constructor(
+ protected usersService: UsersService,
+ protected router: Router,
+ ) {}
+
+ signup(username: string | null, password: string | null) {
+ console.log(`attempting to sign up with ${username} ${password}`)
+ if (!username || !password) {
+ return;
+ }
+
+ this.usersService.createUser(username, password).then(() => {
+ this.showSuccessMessage.next(true);
+ }).catch(ex => {
+ this.statusText.next("Unable to create account: " + friendlyHttpStatus[ex.status])
+ console.log(ex)
+ })
+ }
+
+ validate(username: string, passConfirm:string, password: string) {
+ this.confirmPassStatusText.next("")
+ this.usernameStatusText.next("")
+ this.checkPasswordStrength(password);
+
+ if (username === "") {
+ this.usernameStatusText.next("Username field can't be blank")
+ }
+
+ if (!(password === passConfirm) && !!passConfirm) {
+ this.confirmPassStatusText.next("Passwords don't match")
+ }
+ this.ableToCreateAccount.next(this.passwordStrongEnough.getValue() && password === passConfirm && !!username)
+ }
+
+ checkPasswordStrength(password: string) {
+ this.strength.next(0)
+ this.passwordRequirements = new PasswordRequirements()
+ this.passwordStrongEnough.next(false)
+
+ if (password.match(/[^!-~]/g)) {
+ this.passwordStatusText.next("Invalid characters")
+
+ return
+ }
+
+ if (password.length > 6) {
+ this.passwordRequirements.sixLong.value = true
+ }
+ if (password.length > 12) {
+ this.passwordRequirements.twelveLong.value = true
+ }
+ if (password.match(/[a-z]/g)) {
+ this.passwordRequirements.lowercase.value = true
+ }
+ if (password.match(/[A-Z]/g)) {
+ this.passwordRequirements.uppercase.value = true
+ }
+ if (password.match(/[0-9]/g)) {
+ this.passwordRequirements.number.value = true
+ }
+ if (password.match(/[^A-Za-z0-9]/g)) {
+ this.passwordRequirements.symbol.value = true
+ }
+
+ let strength = 0
+ Object.values(this.passwordRequirements).forEach(k => {
+ k.value && strength++
+ })
+
+ if (strength >= 5) {
+ this.passwordStrongEnough.next(true)
+ this.passwordStatusText.next("")
+ } else if (strength == 0) {
+ this.passwordStatusText.next("")
+ } else {
+ this.passwordStatusText.next("Password does not meet requirements")
+ }
+
+ this.strength.next(strength)
+ }
+
+ getColor() {
+ return `rgba(${(this.strength.getValue()/7) * 255}, ${255 - (this.strength.getValue()/7) * 255}, 0)`
+ }
+
+ protected readonly length = length;
+ protected readonly Object = Object;
+}
+
+let friendlyHttpStatus: {[key: number]: string} = {
+ 200: 'OK',
+ 201: 'Created',
+ 202: 'Accepted',
+ 203: 'Non-Authoritative Information',
+ 204: 'No Content',
+ 205: 'Reset Content',
+ 206: 'Partial Content',
+ 300: 'Multiple Choices',
+ 301: 'Moved Permanently',
+ 302: 'Found',
+ 303: 'See Other',
+ 304: 'Not Modified',
+ 305: 'Use Proxy',
+ 306: 'Unused',
+ 307: 'Temporary Redirect',
+ 400: 'Bad Request',
+ 401: 'Unauthorized',
+ 402: 'Payment Required',
+ 403: 'Forbidden',
+ 404: 'Not Found',
+ 405: 'Method Not Allowed',
+ 406: 'Not Acceptable',
+ 407: 'Proxy Authentication Required',
+ 408: 'Request Timeout',
+ 409: 'Conflict',
+ 410: 'Gone',
+ 411: 'Length Required',
+ 412: 'Precondition Required',
+ 413: 'Request Entry Too Large',
+ 414: 'Request-URI Too Long',
+ 415: 'Unsupported Media Type',
+ 416: 'Requested Range Not Satisfiable',
+ 417: 'Expectation Failed',
+ 418: 'I\'m a teapot',
+ 429: 'Too Many Requests',
+ 500: 'Internal Server Error',
+ 501: 'Not Implemented',
+ 502: 'Bad Gateway',
+ 503: 'Service Unavailable',
+ 504: 'Gateway Timeout',
+ 505: 'HTTP Version Not Supported',
+};
diff --git a/ufund-ui/src/app/models/Need.ts b/ufund-ui/src/app/models/Need.ts
index de6504a..1451cad 100644
--- a/ufund-ui/src/app/models/Need.ts
+++ b/ufund-ui/src/app/models/Need.ts
@@ -1,15 +1,15 @@
export interface Need {
- name: string,
- id: number,
- filterAttributes: string[],
- location: string;
- type: GoalType;
- maxGoal: number;
- current: number;
- urgent: boolean;
+ name: string,
+ id: number,
+ filterAttributes: string[],
+ location: string;
+ type: GoalType;
+ maxGoal: number;
+ current: number;
+ urgent: boolean;
}
export enum GoalType {
- MONETARY,
- PHYSICAL
+ MONETARY,
+ PHYSICAL
}
diff --git a/ufund-ui/src/app/models/User.ts b/ufund-ui/src/app/models/User.ts
index f4396f6..e6848fa 100644
--- a/ufund-ui/src/app/models/User.ts
+++ b/ufund-ui/src/app/models/User.ts
@@ -1,5 +1,3 @@
-import {Need} from './Need';
-
export enum userType {
HELPER,
MANAGER
diff --git a/ufund-ui/src/app/services/auth.service.ts b/ufund-ui/src/app/services/auth.service.ts
new file mode 100644
index 0000000..6bc7145
--- /dev/null
+++ b/ufund-ui/src/app/services/auth.service.ts
@@ -0,0 +1,57 @@
+import {Injectable} from '@angular/core';
+import {BehaviorSubject, firstValueFrom} from 'rxjs';
+import {User} from '../models/User';
+import {HttpClient, HttpHeaders} from '@angular/common/http';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthService {
+
+ private authUrl = "http://localhost:8080/auth"
+ private userUrl = "http://localhost:8080/users"
+
+ private currentUser : BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null);
+ private apiKey: string = "";
+
+ httpOptions2 = () => ({
+ headers: new HttpHeaders({
+ 'Content-Type': 'application/json',
+ "jelly-api-key": this.apiKey
+ }),
+ responseType: "text" as "json" // don't ask me how or why this works, bc i have no clue...
+ // see the relevant angular bug report https://github.com/angular/angular/issues/18586
+ });
+
+ constructor(
+ private http: HttpClient
+ ) {}
+
+ async login(username: string, password: string) {
+ let res = this.http.post<string>(this.authUrl, {username: username, password: password}, this.httpOptions2());
+ this.apiKey = await firstValueFrom(res);
+ console.log("apikey: "+this.apiKey)
+ let res2 = this.http.get<User>(`${this.userUrl}/${username}`, {
+ headers: new HttpHeaders({
+ 'Content-Type': 'application/json',
+ "jelly-api-key": this.apiKey
+ })
+ })
+ let currentU = await firstValueFrom(res2);
+ this.currentUser.next(currentU);
+ // this.currentUser.subscribe(r => console.log("currentUser: "+r.username))
+ }
+
+ getCurrentUserSubject() {
+ return this.currentUser;
+ }
+
+ getCurrentUser() {
+ return this.currentUser.getValue()
+ }
+
+ getApiKey() {
+ return this.apiKey;
+ }
+
+}
diff --git a/ufund-ui/src/app/services/cupboard.service.ts b/ufund-ui/src/app/services/cupboard.service.ts
index 9e14106..9232c0c 100644
--- a/ufund-ui/src/app/services/cupboard.service.ts
+++ b/ufund-ui/src/app/services/cupboard.service.ts
@@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Need} from '../models/Need';
import {Observable} from 'rxjs';
+import {AuthService} from './auth.service';
@Injectable({
providedIn: 'root'
@@ -9,35 +10,44 @@ import {Observable} from 'rxjs';
export class CupboardService {
private url = "http://localhost:8080/cupboard"
- private httpOptions = {
- headers: new HttpHeaders({'Content-Type': 'application/json'})
- };
+
+ httpOptions = () => ({
+ headers: new HttpHeaders({
+ 'Content-Type': 'application/json',
+ "jelly-api-key": this.authService.getApiKey()
+ })
+ });
constructor(
- private http: HttpClient
+ private http: HttpClient,
+ private authService: AuthService
) {}
createNeed(need: Need): Observable<boolean> {
- return this.http.post<boolean>(this.url, need, this.httpOptions)
+ return this.http.post<boolean>(this.url, need, this.httpOptions())
}
getNeeds(): Observable<Need[]> {
- return this.http.get<Need[]>(this.url, this.httpOptions)
+ return this.http.get<Need[]>(this.url, this.httpOptions())
}
searchNeeds(name: String): Observable<Need[]> {
- return this.http.get<Need[]>(`${this.url}/?name=${name}`, this.httpOptions)
+ return this.http.get<Need[]>(`${this.url}/?name=${name}`, this.httpOptions())
}
getNeed(id: number): Observable<Need> {
- return this.http.get<Need>(`${this.url}/${id}`, this.httpOptions)
+ return this.http.get<Need>(`${this.url}/${id}`, this.httpOptions())
}
updateNeed(id: number, data: Need): Observable<boolean> {
- return this.http.put<boolean>(`${this.url}/${id}`, data, this.httpOptions)
+ return this.http.put<boolean>(`${this.url}/${id}`, data, this.httpOptions())
}
deleteNeed(id: number): Observable<boolean> {
- return this.http.delete<boolean>(`${this.url}/${id}`, this.httpOptions)
+ return this.http.delete<boolean>(`${this.url}/${id}`, this.httpOptions())
+ }
+
+ checkoutNeed(id: number, quantity: number) {
+ return this.http.put(`${this.url}/checkout`, {needID: id, amount: quantity}, this.httpOptions())
}
}
diff --git a/ufund-ui/src/app/services/users.service.ts b/ufund-ui/src/app/services/users.service.ts
index dba8185..4080ebf 100644
--- a/ufund-ui/src/app/services/users.service.ts
+++ b/ufund-ui/src/app/services/users.service.ts
@@ -1,96 +1,69 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
-import {BehaviorSubject, firstValueFrom, Observable} from 'rxjs';
+import {BehaviorSubject, catchError, firstValueFrom, Observable, of} from 'rxjs';
import {User} from '../models/User';
import { Need } from '../models/Need';
import { CupboardService } from './cupboard.service';
+import {AuthService} from './auth.service';
@Injectable({
providedIn: 'root'
})
export class UsersService {
- private currentUser : BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null);
- private apiKey: string = "";
private basket = new BehaviorSubject<Need[]>([]);
-
private url = "http://localhost:8080/users"
- private authUrl = "http://localhost:8080/auth"
- private httpOptions = {
+
+ httpOptions = () => ({
headers: new HttpHeaders({
'Content-Type': 'application/json',
- "jelly-api-key": this.apiKey
+ "jelly-api-key": this.authService.getApiKey()
})
- };
- private httpOptions2 = {
- headers: new HttpHeaders({
- 'Content-Type': 'application/json',
- "jelly-api-key": this.apiKey
- }),
- responseType: "text" as "json" // don't ask me how or why this works, bc i have no clue...
- // see the relevant angular bug report https://github.com/angular/angular/issues/18586
- };
+ });
constructor(
private http: HttpClient,
private cupboardService: CupboardService,
+ private authService: AuthService
) {}
async createUser(username:string, password:string) {
- await firstValueFrom(this.http.post<User>(this.url, {username: username, password: password}, this.httpOptions))
+ await firstValueFrom(this.http.post<User>(this.url, {username: username, password: password}, this.httpOptions()))
}
getUser(id: string): Observable<User> {
- return this.http.get<User>(`${this.url}/${id}`, this.httpOptions)
+ return this.http.get<User>(`${this.url}/${id}`, this.httpOptions())
}
updateUser(user: User): Observable<User> {
- return this.http.put<User>(`${this.url}/${user.username}`,user, this.httpOptions2)
+ console.log(`${this.url}/${user.username}`, user, this.httpOptions)
+ return this.http.put<User>(`${this.url}/${user.username}`, user, this.httpOptions())
}
deleteUser(id: number): Observable<boolean> {
- return this.http.delete<boolean>(`${this.url}/${id}`, this.httpOptions)
- }
-
- getCurrentUserSubject() {
- return this.currentUser;
- }
-
- getCurrentUser() {
- return this.currentUser.getValue()
- }
-
- async login(username: string, password: string) {
- let res = this.http.post<string>(this.authUrl, {username: username, password: password}, this.httpOptions2);
- this.apiKey = await firstValueFrom(res);
- console.log("apikey: "+this.apiKey)
- let res2 = this.http.get<User>(`${this.url}/${username}`, {
- headers: new HttpHeaders({
- 'Content-Type': 'application/json',
- "jelly-api-key": this.apiKey
- })
- })
- let currentU = await firstValueFrom(res2);
- this.currentUser.next(currentU);
- // this.currentUser.subscribe(r => console.log("currentUser: "+r.username))
+ return this.http.delete<boolean>(`${this.url}/${id}`, this.httpOptions())
}
refreshBasket() {
- let promiseArr = this.getCurrentUser()!.basket.map(async needID => {
+ let promiseArr = this.authService.getCurrentUser()!.basket.map(async needID => {
return await firstValueFrom(this.cupboardService.getNeed(needID));
})
Promise.all(promiseArr).then(r => this.basket.next(r));
}
-
+
removeNeed(id: number) {
let newArr = this.basket.getValue().filter(v => v.id != id);
this.basket.next(newArr);
- this.getCurrentUser()!.basket = newArr.map(need => need.id);
- this.updateUser(this.getCurrentUser()!).subscribe(() => {
+ this.authService.getCurrentUser()!.basket = newArr.map(need => need.id);
+ this.updateUser(this.authService.getCurrentUser()!)
+ .pipe(
+ catchError((err: any, _) => {
+ console.error(err);
+ return of();
+ })
+ )
+ .subscribe(() => {
this.refreshBasket();
- error: (err: any) => {
- console.error(err);
- }
});
}