Initial Implementation of Help and My Profile Popup
This commit is contained in:
7
src/app/header/header-popup/help/help.component.css
Normal file
7
src/app/header/header-popup/help/help.component.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.help-container {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #555555;
|
||||
}
|
||||
28
src/app/header/header-popup/help/help.component.html
Normal file
28
src/app/header/header-popup/help/help.component.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<app-popup [state]="state"
|
||||
(stateChange)="onStateChange($event)"
|
||||
[ignoreClickOutside]="ignoreClickOutside">
|
||||
|
||||
<div class="help-container container m-0 overflow-hidden">
|
||||
|
||||
<p>
|
||||
This is a simple example project to demonstrate
|
||||
User Authentication and Authorization using
|
||||
<a href="https://spring.io/projects/spring-security" target="_blank">Spring Security</a>
|
||||
and
|
||||
<a href="https://docs.spring.io/spring-security/reference/servlet/oauth2/" target="_blank">OAuth2</a>.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
The only data stored is your email address, username and name.
|
||||
This data is stored in a database and is used to authenticate you
|
||||
and will not be used for any other purpose.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
All data can be deleted by clicking the "Delete Account" button
|
||||
on the "My Profile" option.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</app-popup>
|
||||
23
src/app/header/header-popup/help/help.component.spec.ts
Normal file
23
src/app/header/header-popup/help/help.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HelpComponent } from './help.component';
|
||||
|
||||
describe('HelpComponent', () => {
|
||||
let component: HelpComponent;
|
||||
let fixture: ComponentFixture<HelpComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HelpComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HelpComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
24
src/app/header/header-popup/help/help.component.ts
Normal file
24
src/app/header/header-popup/help/help.component.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-help',
|
||||
templateUrl: './help.component.html',
|
||||
styleUrls: ['./help.component.css']
|
||||
})
|
||||
export class HelpComponent {
|
||||
|
||||
@Input()
|
||||
state: boolean = false;
|
||||
|
||||
@Input()
|
||||
ignoreClickOutside!: HTMLDivElement[];
|
||||
|
||||
@Output()
|
||||
stateChange = new EventEmitter<boolean>();
|
||||
|
||||
constructor() { }
|
||||
|
||||
onStateChange(state: boolean) {
|
||||
this.stateChange.emit(state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.profile-container .row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
justify-content: space-around;
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
height: 200px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.separator-line {
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
margin: 30px 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 100%;
|
||||
border-bottom: 2px solid #80808076;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.profile-container button {
|
||||
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
height: 50px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.picture-btn {
|
||||
background-color: rgba(118, 118, 118, 0.7) !important;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background-color: rgba(216, 41, 28, 0.7) !important;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width:767px) {
|
||||
|
||||
.profile-container {
|
||||
all: unset;
|
||||
justify-content: space-around;
|
||||
width: 600px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.profile-container .row {
|
||||
all: unset;
|
||||
display: flex;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.separator-line {
|
||||
all: unset;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
margin: 0px 60px;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.line {
|
||||
all: unset;
|
||||
border-right: 2px solid #80808076;
|
||||
border-radius: 50px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<app-popup [state]="state"
|
||||
(stateChange)="onStateChange($event)"
|
||||
[ignoreClickOutside]="ignoreClickOutside">
|
||||
|
||||
<div class="container m-0 overflow-hidden"
|
||||
[@resizeContainerForErrorMessage]="hideErrorMessage()">
|
||||
|
||||
<app-error-box [errorMessage]="errorMessage"
|
||||
[@showErrorMessage]="showErrorMessage()">
|
||||
</app-error-box>
|
||||
|
||||
<div class="container profile-container"
|
||||
[@hideAuthContainer]="hideErrorMessage()"
|
||||
(@hideAuthContainer.done)="hideAuthContainer($event)">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="btn-container">
|
||||
<button class="picture-btn"
|
||||
(click)="onAddProfilePicture()">
|
||||
Add Profile Picture
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="separator-line">
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button class="delete-btn"
|
||||
(click)="onDeleteAccount()">
|
||||
Delete Account
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</app-popup>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MyProfileComponent } from './my-profile.component';
|
||||
|
||||
describe('MyProfileComponent', () => {
|
||||
let component: MyProfileComponent;
|
||||
let fixture: ComponentFixture<MyProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ MyProfileComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MyProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
162
src/app/header/header-popup/my-profile/my-profile.component.ts
Normal file
162
src/app/header/header-popup/my-profile/my-profile.component.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import {ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {AuthService} from "../../../shared/auth/auth.service";
|
||||
import {User} from "../../../shared/model/user/user.model";
|
||||
import {animate, animateChild, group, query, state, style, transition, trigger} from "@angular/animations";
|
||||
import {MatIconRegistry} from "@angular/material/icon";
|
||||
import {DomSanitizer} from "@angular/platform-browser";
|
||||
import {FormControl, FormGroup, Validators} from "@angular/forms";
|
||||
import {ValidateNotEmptyValidator} from "../../../shared/validators/validate-not-empty.validator";
|
||||
import {ValidatePasswordValidator} from "../../../shared/validators/validate-password.validator";
|
||||
import {first, take} from "rxjs";
|
||||
import UserChecker from "../../../shared/model/user/user.checker";
|
||||
import HttpErrorChecker from "../../../shared/model/httpError/httpErrorChecker";
|
||||
import {HttpError} from "../../../shared/model/httpError/httpError.model";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-profile',
|
||||
templateUrl: './my-profile.component.html',
|
||||
styleUrls: ['./my-profile.component.css'],
|
||||
animations: [
|
||||
trigger('resizeContainerForErrorMessage', [
|
||||
state('hide',
|
||||
style({
|
||||
height: '100px',
|
||||
width: '320px',
|
||||
})
|
||||
),
|
||||
transition(
|
||||
'show => hide',
|
||||
group([
|
||||
query(
|
||||
"@*",
|
||||
animateChild(),
|
||||
{ optional: true }
|
||||
),
|
||||
animate('1s ease')
|
||||
])
|
||||
)
|
||||
]),
|
||||
trigger('showErrorMessage', [
|
||||
state('show',
|
||||
style({
|
||||
opacity: 1,
|
||||
height: '100px',
|
||||
width: '320px',
|
||||
})
|
||||
),
|
||||
state('hide',
|
||||
style({
|
||||
opacity: 0,
|
||||
height: '0px',
|
||||
width: '0px',
|
||||
})
|
||||
),
|
||||
transition(
|
||||
'* => show',
|
||||
animate(
|
||||
'500ms ease-in'
|
||||
)
|
||||
),
|
||||
]),
|
||||
trigger('hideAuthContainer', [
|
||||
state('hide',
|
||||
style({
|
||||
opacity: 0,
|
||||
})
|
||||
),
|
||||
transition(
|
||||
'show => hide',
|
||||
group([
|
||||
query(
|
||||
"@*",
|
||||
animateChild(),
|
||||
{ optional: true }
|
||||
),
|
||||
animate(
|
||||
'250ms ease-out'
|
||||
)
|
||||
])
|
||||
)
|
||||
]),
|
||||
]
|
||||
})
|
||||
export class MyProfileComponent implements OnInit {
|
||||
|
||||
@Input()
|
||||
state: boolean = false;
|
||||
|
||||
@Input()
|
||||
user!: User | null;
|
||||
|
||||
@Input()
|
||||
ignoreClickOutside!: HTMLDivElement[];
|
||||
|
||||
@Output()
|
||||
stateChange = new EventEmitter<boolean>();
|
||||
|
||||
alterForm!: FormGroup;
|
||||
|
||||
errorMessage!: string | null;
|
||||
|
||||
isShowErrorMessage = false;
|
||||
|
||||
constructor(private authService: AuthService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.alterForm = new FormGroup({
|
||||
'username': new FormControl(null, [Validators.required, ValidateNotEmptyValidator]),
|
||||
'password': new FormControl(null, [Validators.required, ValidatePasswordValidator])
|
||||
});
|
||||
this.errorMessage = null;
|
||||
}
|
||||
|
||||
onStateChange(state: boolean) {
|
||||
this.stateChange.emit(state);
|
||||
}
|
||||
|
||||
public showErrorMessage(): string {
|
||||
if (this.isShowErrorMessage) {
|
||||
return "show";
|
||||
}
|
||||
return "hide";
|
||||
}
|
||||
|
||||
public hideErrorMessage(): string {
|
||||
if (!!this.errorMessage) {
|
||||
return "hide";
|
||||
}
|
||||
return "show";
|
||||
}
|
||||
|
||||
public onDeleteAccount() {
|
||||
this.authService.deleteAccount().subscribe({
|
||||
next: (res) => {
|
||||
if (res && UserChecker.test(res)) {
|
||||
this.closePopup()
|
||||
} if (HttpErrorChecker.test(res)) {
|
||||
this.errorMessage = (<HttpError>res).details;
|
||||
}
|
||||
}
|
||||
})
|
||||
// this.authService.logout()
|
||||
// this.onStateChange(false);
|
||||
}
|
||||
|
||||
public onAddProfilePicture() {
|
||||
this.authService.addProfilePicture()
|
||||
}
|
||||
|
||||
hideAuthContainer(event: any) {
|
||||
if (event.toState === "hide") {
|
||||
event.element.style.display = "none";
|
||||
this.isShowErrorMessage = true;
|
||||
}
|
||||
}
|
||||
|
||||
private closePopup() {
|
||||
this.onStateChange(false);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user