Initial Implementation of Profile Pictures
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
<div
|
<div
|
||||||
class="dropdown"
|
class="dropdown"
|
||||||
appClickedOutside
|
appClickedOutside
|
||||||
(clickOutside)="onClickedOutside()"
|
(clickOutside)="onClickedOutside()"
|
||||||
[includeClickedOutside]="[management]"
|
[includeClickedOutside]="[management]"
|
||||||
[ignoreElementList]="ignoreClickOutside"
|
[ignoreElementList]="ignoreClickOutside"
|
||||||
[@dropdownState]="dropDownState"
|
[@dropdownState]="dropDownState"
|
||||||
(@dropdownState.start)="$event.element.style.display = 'block'"
|
(@dropdownState.start)="$event.element.style.display = 'block'"
|
||||||
(@dropdownState.done)="$event.element.style.display = (state ? 'block' : 'none')">
|
(@dropdownState.done)="$event.element.style.display = (state ? 'block' : 'none')">
|
||||||
@@ -46,4 +46,4 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
import { faEdit, faQuestionCircle, faSignOutAlt, faUser } from '@fortawesome/free-solid-svg-icons';
|
import { faEdit, faQuestionCircle, faSignOutAlt, faUser } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { Subscription, timeout } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { AuthService } from 'src/app/shared/auth/auth.service';
|
import { AuthService } from 'src/app/shared/auth/auth.service';
|
||||||
import UserChecker from 'src/app/shared/model/user/user.checker';
|
import {User} from "../../shared/model/user/user.model";
|
||||||
import { User } from 'src/app/shared/model/user/user.model';
|
import UserChecker from "../../shared/model/user/user.checker";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header-dropdown',
|
selector: 'app-header-dropdown',
|
||||||
@@ -24,7 +24,7 @@ import { User } from 'src/app/shared/model/user/user.model';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class HeaderDropdownComponent implements OnInit, OnDestroy {
|
export class HeaderDropdownComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
userIcon = faUser;
|
userIcon = faUser;
|
||||||
|
|
||||||
editIcon = faEdit;
|
editIcon = faEdit;
|
||||||
@@ -57,6 +57,7 @@ export class HeaderDropdownComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.userSubscription = this.authService.authSubject.subscribe(
|
this.userSubscription = this.authService.authSubject.subscribe(
|
||||||
res => {
|
res => {
|
||||||
|
console.log(UserChecker.test(res));
|
||||||
if (res && UserChecker.test(res)) {
|
if (res && UserChecker.test(res)) {
|
||||||
this.user = <User>res;
|
this.user = <User>res;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -56,6 +56,11 @@
|
|||||||
width: 45px;
|
width: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile-picture {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
.profile .profile-btn {
|
.profile .profile-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 5px solid #ffffff;
|
border: 5px solid #ffffff;
|
||||||
@@ -63,10 +68,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
height: 45px;
|
height: 50px;
|
||||||
width: 45px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile .profile-btn fa-icon {
|
.profile .profile-btn fa-icon {
|
||||||
font-size: 25px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,13 @@
|
|||||||
#profile>
|
#profile>
|
||||||
<div class="profile-btn"
|
<div class="profile-btn"
|
||||||
(click)="onProfileButtonClicked()">
|
(click)="onProfileButtonClicked()">
|
||||||
<fa-icon class="fas fa-user" [icon]="userIcon"></fa-icon>
|
<fa-icon *ngIf="!loggedUser || !(loggedUser.profilePictureUrl)"
|
||||||
|
class="fas fa-user" [icon]="userIcon"></fa-icon>
|
||||||
|
<img *ngIf="!!loggedUser && !!(loggedUser.profilePictureUrl)"
|
||||||
|
class="profile-picture"
|
||||||
|
[ngSrc]="loggedUser.profilePictureUrl"
|
||||||
|
width="50" height="50"
|
||||||
|
alt="Profile Picture" priority/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
import {Component, EventEmitter, OnDestroy, OnInit, Output} from '@angular/core';
|
||||||
import { faUser } from '@fortawesome/free-solid-svg-icons';
|
import { faUser } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { SliderItemComponent } from 'src/app/shared/components/slider-item/slider-item.component';
|
import { SliderItemComponent } from 'src/app/shared/components/slider-item/slider-item.component';
|
||||||
|
import UserChecker from "../../../shared/model/user/user.checker";
|
||||||
|
import {User} from "../../../shared/model/user/user.model";
|
||||||
|
import {AuthService} from "../../../shared/auth/auth.service";
|
||||||
|
import {Subscription} from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nav-slider',
|
selector: 'app-nav-slider',
|
||||||
templateUrl: './nav-slider.component.html',
|
templateUrl: './nav-slider.component.html',
|
||||||
styleUrls: ['./nav-slider.component.css']
|
styleUrls: ['./nav-slider.component.css']
|
||||||
})
|
})
|
||||||
export class NavSliderComponent extends SliderItemComponent {
|
export class NavSliderComponent extends SliderItemComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
userIcon = faUser;
|
userIcon = faUser;
|
||||||
|
|
||||||
navLink = [
|
navLink = [
|
||||||
@@ -18,13 +22,34 @@ export class NavSliderComponent extends SliderItemComponent {
|
|||||||
{ page: "About", link: "/home" }
|
{ page: "About", link: "/home" }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
loggedUser!: User | null;
|
||||||
|
|
||||||
|
private userSubscription!: Subscription;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
profileButtonClicked = new EventEmitter();
|
profileButtonClicked = new EventEmitter();
|
||||||
|
|
||||||
constructor() {
|
constructor(private authService: AuthService) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.userSubscription = this.authService.authSubject.subscribe(
|
||||||
|
res => {
|
||||||
|
console.log(UserChecker.test(res));
|
||||||
|
if (res && UserChecker.test(res)) {
|
||||||
|
this.loggedUser = <User>res;
|
||||||
|
} else {
|
||||||
|
this.loggedUser = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.userSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
onProfileButtonClicked() {
|
onProfileButtonClicked() {
|
||||||
this.profileButtonClicked.emit();
|
this.profileButtonClicked.emit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,14 +104,14 @@ app-header-slider {
|
|||||||
all: unset;
|
all: unset;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-container {
|
.link-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-container li {
|
.link-container li {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -119,7 +119,7 @@ app-header-slider {
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-container li a {
|
.link-container li a {
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -136,6 +136,11 @@ app-header-slider {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile-picture {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
.profile .profile-btn {
|
.profile .profile-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 5px solid #ffffff;
|
border: 5px solid #ffffff;
|
||||||
@@ -143,8 +148,8 @@ app-header-slider {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
height: 45px;
|
height: 50px;
|
||||||
width: 45px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile .dropdown {
|
.profile .dropdown {
|
||||||
@@ -153,7 +158,7 @@ app-header-slider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profile .profile-btn fa-icon {
|
.profile .profile-btn fa-icon {
|
||||||
font-size: 25px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.burger-container {
|
.burger-container {
|
||||||
@@ -176,4 +181,4 @@ app-header-slider {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,18 @@
|
|||||||
|
|
||||||
<div class="profile" #profileDropdown>
|
<div class="profile" #profileDropdown>
|
||||||
<div class="profile-btn" (click)="toogleProfileDropdown()" #profileBtn>
|
<div class="profile-btn" (click)="toogleProfileDropdown()" #profileBtn>
|
||||||
<fa-icon class="fas fa-user" [icon]="userIcon"></fa-icon>
|
<fa-icon *ngIf="!loggedUser || !(loggedUser.profilePictureUrl)"
|
||||||
|
class="fas fa-user" [icon]="userIcon"></fa-icon>
|
||||||
|
<img *ngIf="!!loggedUser && !!(loggedUser.profilePictureUrl)"
|
||||||
|
class="profile-picture"
|
||||||
|
[ngSrc]="loggedUser.profilePictureUrl"
|
||||||
|
width="50" height="50"
|
||||||
|
alt="Profile Picture" priority/>
|
||||||
</div>
|
</div>
|
||||||
<app-header-dropdown
|
|
||||||
class="dropdown"
|
<app-header-dropdown
|
||||||
(clickOutside)="closeDropdown()"
|
class="dropdown"
|
||||||
|
(clickOutside)="closeDropdown()"
|
||||||
[ignoreClickOutside]="[profileBtn]"
|
[ignoreClickOutside]="[profileBtn]"
|
||||||
[state]="profileDropdownState"
|
[state]="profileDropdownState"
|
||||||
(loginPopupState)="loginPopupStateChange($event)"
|
(loginPopupState)="loginPopupStateChange($event)"
|
||||||
@@ -43,12 +50,12 @@
|
|||||||
</app-nav-slider>
|
</app-nav-slider>
|
||||||
</app-header-slider>
|
</app-header-slider>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div #user>
|
<div #user>
|
||||||
<app-header-slider
|
<app-header-slider
|
||||||
[(state)]="userSliderStatus"
|
[(state)]="userSliderStatus"
|
||||||
[ignoreClickOutside]="[header, nav]">
|
[ignoreClickOutside]="[header, nav]">
|
||||||
<app-user-slider
|
<app-user-slider
|
||||||
[state]="userSliderStatus"
|
[state]="userSliderStatus"
|
||||||
(loginPopupState)="loginPopupStateChange($event)"
|
(loginPopupState)="loginPopupStateChange($event)"
|
||||||
(signupPopupState)="signupPopupStateChange($event)">
|
(signupPopupState)="signupPopupStateChange($event)">
|
||||||
@@ -57,14 +64,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-spacer"></div>
|
<div class="header-spacer"></div>
|
||||||
|
|
||||||
<!-- <app-login
|
|
||||||
*ngIf="loginPopupState"
|
|
||||||
[(state)]="loginPopupState"
|
|
||||||
[ignoreClickOutside]="[profileBtn, profileDropdown, user]">
|
|
||||||
</app-login>
|
|
||||||
|
|
||||||
<app-signup
|
|
||||||
[(state)]="signupPopupState"
|
|
||||||
[ignoreClickOutside]="[profileBtn, profileDropdown, user]">
|
|
||||||
</app-signup> -->
|
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
import { Component, ComponentRef, ElementRef, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
|
import {Component, ComponentRef, ElementRef, OnDestroy, OnInit, ViewChild, ViewContainerRef} from '@angular/core';
|
||||||
import { faUser } from '@fortawesome/free-solid-svg-icons';
|
import { faUser } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { LoginComponent } from './header-popup/login/login.component';
|
import { LoginComponent } from './header-popup/login/login.component';
|
||||||
import { SignupComponent } from './header-popup/signup/signup.component';
|
import { SignupComponent } from './header-popup/signup/signup.component';
|
||||||
|
import {AuthService} from "../shared/auth/auth.service";
|
||||||
|
import UserChecker from "../shared/model/user/user.checker";
|
||||||
|
import {User} from "../shared/model/user/user.model";
|
||||||
|
import {Subscription} from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
styleUrls: ['./header.component.css']
|
styleUrls: ['./header.component.css']
|
||||||
})
|
})
|
||||||
export class HeaderComponent {
|
export class HeaderComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
userIcon = faUser;
|
userIcon = faUser;
|
||||||
|
|
||||||
@@ -21,18 +25,39 @@ export class HeaderComponent {
|
|||||||
|
|
||||||
@ViewChild('profileBtn')
|
@ViewChild('profileBtn')
|
||||||
profileBtnElementRef!: ElementRef;
|
profileBtnElementRef!: ElementRef;
|
||||||
|
|
||||||
@ViewChild('profileDropdown')
|
@ViewChild('profileDropdown')
|
||||||
profileDropdownElementRef!: ElementRef;
|
profileDropdownElementRef!: ElementRef;
|
||||||
|
|
||||||
@ViewChild('user')
|
@ViewChild('user')
|
||||||
userElementRef!: ElementRef;
|
userElementRef!: ElementRef;
|
||||||
|
|
||||||
|
loggedUser!: User | null;
|
||||||
|
|
||||||
|
private userSubscription!: Subscription;
|
||||||
|
|
||||||
private loginComponent!: ComponentRef<LoginComponent>;
|
private loginComponent!: ComponentRef<LoginComponent>;
|
||||||
|
|
||||||
private signupComponent!: ComponentRef<SignupComponent>;
|
private signupComponent!: ComponentRef<SignupComponent>;
|
||||||
|
|
||||||
constructor(private viewContainerRef: ViewContainerRef) { }
|
constructor(private viewContainerRef: ViewContainerRef, private authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.userSubscription = this.authService.authSubject.subscribe(
|
||||||
|
res => {
|
||||||
|
console.log(UserChecker.test(res));
|
||||||
|
if (res && UserChecker.test(res)) {
|
||||||
|
this.loggedUser = <User>res;
|
||||||
|
} else {
|
||||||
|
this.loggedUser = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.userSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public toogleProfileDropdown(): void {
|
public toogleProfileDropdown(): void {
|
||||||
@@ -63,7 +88,7 @@ export class HeaderComponent {
|
|||||||
if (this.userSliderStatus) {
|
if (this.userSliderStatus) {
|
||||||
this.userSliderStatus = false;
|
this.userSliderStatus = false;
|
||||||
} else {
|
} else {
|
||||||
this.navSliderStatus = false;
|
this.navSliderStatus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,4 +167,4 @@ export class HeaderComponent {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const HttpError = t.iface([], {
|
|||||||
"timestamp": "string",
|
"timestamp": "string",
|
||||||
});
|
});
|
||||||
|
|
||||||
const HttpErrorTI: t.ITypeSuite = {
|
const exportedTypeSuite: t.ITypeSuite = {
|
||||||
HttpError,
|
HttpError,
|
||||||
};
|
};
|
||||||
export default HttpErrorTI;
|
export default exportedTypeSuite;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createCheckers } from "ts-interface-checker";
|
import { createCheckers } from "ts-interface-checker";
|
||||||
import HttpErrorTI from "./httpError.model-ti";
|
import HttpError from "./httpError.model-ti";
|
||||||
|
|
||||||
const HttpErrorChecker = createCheckers(HttpErrorTI)['HttpError'];
|
const HttpErrorChecker = createCheckers(HttpError)['HttpError'];
|
||||||
export default HttpErrorChecker;
|
export default HttpErrorChecker;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createCheckers } from "ts-interface-checker";
|
import { createCheckers } from "ts-interface-checker";
|
||||||
import TokenTI from "../token/token.model-ti";
|
import User from "./user.model-ti";
|
||||||
import UserTI from "./user.model-ti";
|
import Token from "../token/token.model-ti";
|
||||||
|
|
||||||
const UserChecker = createCheckers(UserTI, TokenTI)['User'];
|
const UserChecker = createCheckers(User, Token)['User'];
|
||||||
export default UserChecker;
|
export default UserChecker;
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ export const User = t.iface([], {
|
|||||||
"email": t.opt("string"),
|
"email": t.opt("string"),
|
||||||
"username": "string",
|
"username": "string",
|
||||||
"password": t.opt("string"),
|
"password": t.opt("string"),
|
||||||
|
"profilePictureUrl": t.opt("string"),
|
||||||
"accessToken": t.opt("Token"),
|
"accessToken": t.opt("Token"),
|
||||||
"refreshToken": t.opt("Token"),
|
"refreshToken": t.opt("Token"),
|
||||||
"authorities": t.opt(t.array(t.iface([], {
|
"roles": t.opt(t.array("string")),
|
||||||
"authority": "string",
|
|
||||||
}))),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const UserTI: t.ITypeSuite = {
|
const exportedTypeSuite: t.ITypeSuite = {
|
||||||
User,
|
User,
|
||||||
};
|
};
|
||||||
export default UserTI;
|
export default exportedTypeSuite;
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ export interface User {
|
|||||||
email?: string,
|
email?: string,
|
||||||
username: string,
|
username: string,
|
||||||
password?: string,
|
password?: string,
|
||||||
|
profilePictureUrl?: string,
|
||||||
accessToken?: Token,
|
accessToken?: Token,
|
||||||
refreshToken?: Token,
|
refreshToken?: Token,
|
||||||
authorities?: Array<{authority: string}>,
|
roles?: Array<string>,
|
||||||
validateAccessToken?: () => Token | undefined;
|
validateAccessToken?: () => Token | undefined;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user