Initial Implementation of Profile Pictures

This commit is contained in:
2023-08-21 02:46:50 -03:00
parent 9b8d0e248f
commit 1328ca7c4c
13 changed files with 130 additions and 67 deletions

View File

@@ -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',
@@ -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 {

View File

@@ -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;
} }

View File

@@ -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>

View File

@@ -1,13 +1,17 @@
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;
@@ -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();
} }

View File

@@ -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 {

View File

@@ -16,8 +16,15 @@
<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 <app-header-dropdown
class="dropdown" class="dropdown"
(clickOutside)="closeDropdown()" (clickOutside)="closeDropdown()"
@@ -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> -->

View File

@@ -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;
@@ -28,11 +32,32 @@ export class HeaderComponent {
@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 {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}; };