Skip to content

Commit 1f4562d

Browse files
committed
Create Profile Page
Profile page is under '/account' route. It allows users to change account details and password. I moved around some files and refactored getters from register.component into forms.utils.service. Slightly changed behavior of user service update user. Did not understand what it was trying to do before, so I changed it to work. It feels like it works, but not extensively tested. Known bugs: (1) Enter does not submit edit forms. (2) Edit profile form does not inherit theme from primeng.
1 parent f85a63b commit 1f4562d

18 files changed

+606
-89
lines changed

frontend/src/_services/authentication.service.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ export class AuthenticationService extends ApiService {
6868
.pipe(switchMap(() => this.login(username, password))); // auto login after registration
6969
}
7070

71+
updateAccount(username: string, email: string, password: string) {
72+
return this.http
73+
.patch<UServRes>(
74+
`${this.apiUrl}/users/${this.userValue!.id}`,
75+
{ username: username, email: email, password: password },
76+
{ observe: 'response' },
77+
)
78+
.pipe(switchMap(() => this.login(username, password))); // login to update local storage and subject
79+
}
80+
7181
logout() {
7282
// remove user from local storage to log user out
7383
localStorage.removeItem('user');
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Injectable } from '@angular/core';
2+
import { AbstractControl, FormGroup } from '@angular/forms';
3+
import { PASSWORD_LOWERCASE } from '../app/account/_validators/lowercase-password';
4+
import { PASSWORD_UPPERCASE } from '../app/account/_validators/uppercase-password';
5+
import { PASSWORD_NUMERIC } from '../app/account/_validators/numeric-password';
6+
import { PASSWORD_SPECIAL } from '../app/account/_validators/special-password';
7+
import { PASSWORD_SHORT } from '../app/account/_validators/short-password';
8+
import { PASSWORD_WEAK } from '../app/account/_validators/weak-password.validator';
9+
import { PASSWORD_MISMATCH } from '../app/account/_validators/mismatch-password.validator';
10+
import { USERNAME_INVALID } from '../app/account/_validators/invalid-username.validator';
11+
import { PASSWORD_INVALID } from '../app/account/_validators/invalid-password.validator';
12+
13+
@Injectable({
14+
providedIn: 'root',
15+
})
16+
export class FormUtilsService {
17+
get isUsernameInvalid(): (form: FormGroup) => boolean {
18+
return (form: FormGroup) => {
19+
const usernameControl = form.controls['username'];
20+
return usernameControl.dirty && usernameControl.hasError(USERNAME_INVALID);
21+
};
22+
}
23+
24+
get isEmailInvalid(): (form: FormGroup) => boolean {
25+
return (form: FormGroup) => {
26+
const emailControl = form.controls['email'];
27+
return emailControl.dirty && emailControl.invalid;
28+
};
29+
}
30+
31+
get passwordControl(): (form: FormGroup) => AbstractControl {
32+
return (form: FormGroup) => form.controls['password'];
33+
}
34+
35+
get isPasswordControlDirty(): (form: FormGroup) => boolean {
36+
return (form: FormGroup) => this.passwordControl(form).dirty;
37+
}
38+
39+
get passwordHasNoLowercase(): (form: FormGroup) => boolean {
40+
return (form: FormGroup) => this.passwordControl(form).pristine || this.passwordControl(form).hasError(PASSWORD_LOWERCASE);
41+
}
42+
43+
get passwordHasNoUppercase(): (form: FormGroup) => boolean {
44+
return (form: FormGroup) => this.passwordControl(form).pristine || this.passwordControl(form).hasError(PASSWORD_UPPERCASE);
45+
}
46+
47+
get passwordHasNoNumeric(): (form: FormGroup) => boolean {
48+
return (form: FormGroup) => this.passwordControl(form).pristine || this.passwordControl(form).hasError(PASSWORD_NUMERIC);
49+
}
50+
51+
get passwordHasNoSpecial(): (form: FormGroup) => boolean {
52+
return (form: FormGroup) => this.passwordControl(form).pristine || this.passwordControl(form).hasError(PASSWORD_SPECIAL);
53+
}
54+
55+
get isPasswordShort(): (form: FormGroup) => boolean {
56+
return (form: FormGroup) => this.passwordControl(form).pristine || this.passwordControl(form).hasError(PASSWORD_SHORT);
57+
}
58+
59+
get isPasswordWeak(): (form: FormGroup) => boolean {
60+
return (form: FormGroup) => this.passwordControl(form).dirty && this.passwordControl(form).hasError(PASSWORD_WEAK);
61+
}
62+
63+
get isPasswordStrong(): (form: FormGroup) => boolean {
64+
return (form: FormGroup) => this.passwordControl(form).dirty && !this.passwordControl(form).hasError(PASSWORD_WEAK);
65+
}
66+
67+
get isPasswordInvalid(): (form: FormGroup) => boolean {
68+
return (form: FormGroup) => this.passwordControl(form).dirty && this.passwordControl(form).hasError(PASSWORD_INVALID);
69+
}
70+
71+
get hasPasswordMismatch(): (form: FormGroup) => boolean {
72+
return (form: FormGroup) => {
73+
const confirmPasswordControl = form.controls['confirmPassword'];
74+
return this.passwordControl(form).valid && confirmPasswordControl.dirty && form.hasError(PASSWORD_MISMATCH);
75+
};
76+
}
77+
}

frontend/src/app/account/account.component.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { NgModule } from '@angular/core';
22
import { Routes, RouterModule } from '@angular/router';
33

4-
import { LoginComponent } from './login.component';
5-
import { RegisterComponent } from './register.component';
4+
import { LoginComponent } from './login/login.component';
5+
import { RegisterComponent } from './register/register.component';
66
import { LayoutComponent } from './layout.component';
7+
import { ProfileComponent } from './profile/profile.component';
8+
import { HistoryComponent } from './history/history.component';
79

810
const routes: Routes = [
911
{
@@ -13,6 +15,8 @@ const routes: Routes = [
1315
{ path: '', redirectTo: 'login', pathMatch: 'full' },
1416
{ path: 'login', component: LoginComponent },
1517
{ path: 'register', component: RegisterComponent },
18+
{ path: 'profile', component: ProfileComponent },
19+
{path: 'history', component: HistoryComponent},
1620
],
1721
},
1822
];

frontend/src/app/account/account.module.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { NgModule } from '@angular/core';
22
import { ReactiveFormsModule } from '@angular/forms';
33
import { CommonModule } from '@angular/common';
44

5-
import { LoginComponent } from './login.component';
6-
import { RegisterComponent } from './register.component';
5+
import { LoginComponent } from './login/login.component';
6+
import { RegisterComponent } from './register/register.component';
77
import { LayoutComponent } from './layout.component';
88
import { AccountRoutingModule } from './account.component';
9+
import { ProfileComponent } from './profile/profile.component';
10+
import { HistoryComponent } from './history/history.component';
911

1012
@NgModule({
1113
imports: [
@@ -15,6 +17,8 @@ import { AccountRoutingModule } from './account.component';
1517
LayoutComponent,
1618
LoginComponent,
1719
RegisterComponent,
20+
ProfileComponent,
21+
HistoryComponent,
1822
],
1923
})
2024
export class AccountModule {}

frontend/src/app/account/history/history.component.css

Whitespace-only changes.

frontend/src/app/account/history/history.component.html

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Component } from '@angular/core';
2+
import { MessageService } from 'primeng/api';
3+
import { AuthenticationService } from '../../../_services/authentication.service';
4+
5+
@Component({
6+
standalone: true,
7+
imports: [],
8+
providers: [MessageService],
9+
templateUrl: './history.component.html',
10+
styleUrl: './history.component.css',
11+
})
12+
export class HistoryComponent {
13+
constructor(
14+
private authenticationService: AuthenticationService,
15+
) {}
16+
17+
}
File renamed without changes.
File renamed without changes.

frontend/src/app/account/login.component.ts renamed to frontend/src/app/account/login/login.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import { PasswordModule } from 'primeng/password';
77
import { ButtonModule } from 'primeng/button';
88
import { ToastModule } from 'primeng/toast';
99
import { MessageService } from 'primeng/api';
10-
import { AuthenticationService } from '../../_services/authentication.service';
10+
import { AuthenticationService } from '../../../_services/authentication.service';
1111

1212
@Component({
1313
selector: 'app-login',
1414
standalone: true,
1515
imports: [RouterLink, FormsModule, InputTextModule, ButtonModule, SelectButtonModule, PasswordModule, ToastModule],
1616
providers: [MessageService],
1717
templateUrl: './login.component.html',
18-
styleUrl: './account.component.css',
18+
styleUrl: '../account.component.css',
1919
})
2020
export class LoginComponent {
2121
constructor(

0 commit comments

Comments
 (0)