From 2675c426746c6e2c4bcd20ec185809a3c9965450 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sun, 10 May 2020 19:37:17 +0300 Subject: [PATCH 1/3] Task 5 - Added new service in according to requirements - Made some refactoring in the base code - Implemented loginpage + logic for it - Added logic for header component - Added modalwindow which show when you try to delete a course from the courseList --- angular.json | 7 ++- package-lock.json | 27 ++++++++-- package.json | 4 +- .../{mocked-data.ts => mocked-courses.ts} | 0 src/app/core/mocks/mocked-user.ts | 10 ++++ src/app/core/models/user-info.interface.ts | 3 ++ src/app/core/modules/course-page.module.ts | 10 ---- src/app/core/modules/material.module.ts | 39 ++++++++++++++ src/app/core/pipes/orderByTitleName.pipe.ts | 12 ++++- src/app/core/services/auth.service.ts | 45 ++++++++++++++++ src/app/core/services/home-page.service.ts | 41 +++++++++++++++ .../course-item/course-item.component.html | 7 ++- .../course-item/course-item.component.ts | 24 ++++++++- .../course-list/course-list.component.html | 1 - .../course-list/course-list.component.less | 4 ++ .../course-list/course-list.component.ts | 5 +- src/app/home-page/home-page.component.html | 1 + src/app/home-page/home-page.component.ts | 12 +++-- src/app/home-page/home-page.service.spec.ts | 16 ------ src/app/home-page/home-page.service.ts | 20 -------- .../toolbox/search/search.component.ts | 4 +- src/app/login-page/login-page.component.html | 51 ++++++++++++++++++- src/app/login-page/login-page.component.less | 34 +++++++++++++ src/app/login-page/login-page.component.ts | 33 +++++++++++- src/app/login-page/login-page.module.ts | 9 +++- src/app/root/app-routing.module.ts | 4 +- src/app/root/app.component.html | 6 +-- src/app/root/app.component.less | 6 +++ src/app/root/app.component.ts | 22 +++++++- src/app/root/app.module.ts | 11 +++- .../confirmation-dialog.component.html | 7 +++ .../confirmation-dialog.component.less | 37 ++++++++++++++ .../confirmation-dialog.component.spec.ts | 25 +++++++++ .../confirmation-dialog.component.ts | 17 +++++++ .../header-login/header-login.component.html | 29 +++++++++-- .../header-login/header-login.component.less | 40 +++++++++++---- .../header-login/header-login.component.ts | 23 +++++++-- .../header-logo/header-logo.component.html | 2 +- src/app/shared/header/header.component.html | 5 +- src/app/shared/header/header.component.ts | 29 ++++++++++- src/app/shared/shared.module.ts | 13 ++++- src/assets/less/modules/variables.less | 1 + src/index.html | 4 +- src/styles.less | 17 +++++++ 44 files changed, 613 insertions(+), 104 deletions(-) rename src/app/core/mocks/{mocked-data.ts => mocked-courses.ts} (100%) create mode 100644 src/app/core/mocks/mocked-user.ts delete mode 100644 src/app/core/modules/course-page.module.ts create mode 100644 src/app/core/modules/material.module.ts create mode 100644 src/app/core/services/auth.service.ts create mode 100644 src/app/core/services/home-page.service.ts delete mode 100644 src/app/home-page/home-page.service.spec.ts delete mode 100644 src/app/home-page/home-page.service.ts create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.html create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.less create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.ts diff --git a/angular.json b/angular.json index 1d636b6..c182ff8 100644 --- a/angular.json +++ b/angular.json @@ -28,6 +28,7 @@ "src/assets" ], "styles": [ + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.less" ], "scripts": [] @@ -92,6 +93,7 @@ "src/assets" ], "styles": [ + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.less" ], "scripts": [] @@ -123,6 +125,7 @@ } } } - }}, + } + }, "defaultProject": "angular-project" -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9439b71..dc35ea6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -195,9 +195,25 @@ } }, "@angular/animations": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.3.tgz", - "integrity": "sha512-QTQZSnXxr9SCgrN2SZsTMzS/UldrZ65y6Kuqs9yyghNc694eMbabgiPdeegjvcKlDhVPCN2x9Bjfb1vXPOfdvQ==" + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.6.tgz", + "integrity": "sha512-7Pp7aqNNcH4fu1BnOVpvqJJHjE7RZ5K1oD396OWCh35pgpLowLSpFjhbVhzGrcAuxHyKnnHSX3etLn2hDaHxmQ==" + }, + "@angular/cdk": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.2.3.tgz", + "integrity": "sha512-tQr/yt8GNGsZ/DTT+PMq7XdRmL56hwVCyf8F12JQAawutSLfTfMb+S1lpN7L/0Pb/L5JBuCfG2HmXK7vHo02gw==", + "requires": { + "parse5": "^5.0.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + } + } }, "@angular/cli": { "version": "9.1.3", @@ -470,6 +486,11 @@ "integrity": "sha512-mcZDO6C2BpDinMjDeMAdohTefpFxNu/S0JEqewYQIQ8TXtKm77xDPUdNdNb4qD4zYW+c46f7UXNMX/tbYCicQw==", "dev": true }, + "@angular/material": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-9.2.3.tgz", + "integrity": "sha512-QJltLNp8a/eoozPgkFLISEWgdlX9q9+fZaLJ8c9tHEp2IT5sFYBFHf8dPl0pUyxgOXkS/0HD43I1qki71/T7Kw==" + }, "@angular/platform-browser": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.3.tgz", diff --git a/package.json b/package.json index 9c8413a..8b9955d 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,13 @@ }, "private": true, "dependencies": { - "@angular/animations": "~9.1.3", + "@angular/animations": "^9.1.6", + "@angular/cdk": "^9.2.3", "@angular/common": "~9.1.3", "@angular/compiler": "~9.1.3", "@angular/core": "~9.1.3", "@angular/forms": "~9.1.3", + "@angular/material": "^9.2.3", "@angular/platform-browser": "~9.1.3", "@angular/platform-browser-dynamic": "~9.1.3", "@angular/router": "~9.1.3", diff --git a/src/app/core/mocks/mocked-data.ts b/src/app/core/mocks/mocked-courses.ts similarity index 100% rename from src/app/core/mocks/mocked-data.ts rename to src/app/core/mocks/mocked-courses.ts diff --git a/src/app/core/mocks/mocked-user.ts b/src/app/core/mocks/mocked-user.ts new file mode 100644 index 0000000..76d47a4 --- /dev/null +++ b/src/app/core/mocks/mocked-user.ts @@ -0,0 +1,10 @@ +import { UserInfo } from '../models'; + +export const fakeUserInfo: UserInfo = { + id: 1, + firstName: 'Vasya', + lastName: 'Pupkin', + login: 'vasya', + password: '12345', + token: 'randomtoken_1234556789$', +}; diff --git a/src/app/core/models/user-info.interface.ts b/src/app/core/models/user-info.interface.ts index 6241fc3..5dbe5fe 100644 --- a/src/app/core/models/user-info.interface.ts +++ b/src/app/core/models/user-info.interface.ts @@ -2,4 +2,7 @@ export interface UserInfo { id: number; firstName: string; lastName: string; + login: string; + password: string; + token: string; } diff --git a/src/app/core/modules/course-page.module.ts b/src/app/core/modules/course-page.module.ts deleted file mode 100644 index fb6bd6f..0000000 --- a/src/app/core/modules/course-page.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { CoursePageComponent } from '../../course-page/course-page.component'; - -@NgModule({ - declarations: [CoursePageComponent], - exports: [CoursePageComponent], - imports: [CommonModule] -}) -export class CoursePageModule { } diff --git a/src/app/core/modules/material.module.ts b/src/app/core/modules/material.module.ts new file mode 100644 index 0000000..865cf0b --- /dev/null +++ b/src/app/core/modules/material.module.ts @@ -0,0 +1,39 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatInputModule } from '@angular/material/input'; +import { MatTableModule } from '@angular/material/table'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; + +@NgModule({ + imports: [ + CommonModule, + MatToolbarModule, + MatButtonModule, + MatCardModule, + MatInputModule, + MatDialogModule, + MatTableModule, + MatMenuModule, + MatIconModule, + MatProgressSpinnerModule + ], + exports: [ + CommonModule, + MatToolbarModule, + MatButtonModule, + MatCardModule, + MatInputModule, + MatDialogModule, + MatTableModule, + MatMenuModule, + MatIconModule, + MatProgressSpinnerModule + ], + }) +export class CustomMaterialModule { } diff --git a/src/app/core/pipes/orderByTitleName.pipe.ts b/src/app/core/pipes/orderByTitleName.pipe.ts index 76c2927..997793f 100644 --- a/src/app/core/pipes/orderByTitleName.pipe.ts +++ b/src/app/core/pipes/orderByTitleName.pipe.ts @@ -16,8 +16,16 @@ export class OrderByTitleNamePipe implements PipeTransform { if (!Array.isArray(array)) { return; } - return array.sort((one, two) => { - return one.title < two.title ? -1 : 1; + + return array.sort((currentElem: CourseItemInfo, nextElem: CourseItemInfo) => { + if (currentElem.title < nextElem.title) { + return -1; + } + + if (currentElem.title > nextElem.title) { + return 1; + } + return 0; }); } } diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts new file mode 100644 index 0000000..75597c5 --- /dev/null +++ b/src/app/core/services/auth.service.ts @@ -0,0 +1,45 @@ +import { Injectable, OnInit } from '@angular/core'; +import { fakeUserInfo } from '../mocks/mocked-user'; +import { UserInfo } from '../models'; +import { Subject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + private _userInfoSource: Subject = new Subject(); + public userInfo$: Observable = this._userInfoSource.asObservable(); + + public getUserInfo(): UserInfo { + const userInfo: UserInfo = fakeUserInfo; + return userInfo; + } + + public userLogin(sentLogin: string, sentPassword: string): UserInfo { + const userInfo: UserInfo = this.getUserInfo(); + const { + login, + password, + firstName, + lastName, + token + } = userInfo; + + if (sentLogin === login && sentPassword === password) { + localStorage.setItem('userData', JSON.stringify({ firstName, lastName, token })); + this._userInfoSource.next('changed'); + return userInfo; + } + } + + public userLogout(): boolean { + localStorage.removeItem('userData'); + this._userInfoSource.next('changed'); + return this.isAuthentificated(); + } + + public isAuthentificated(): boolean { + const userDataFromLS: UserInfo = JSON.parse(localStorage.getItem('userData')); + return userDataFromLS && !!userDataFromLS.token; + } +} diff --git a/src/app/core/services/home-page.service.ts b/src/app/core/services/home-page.service.ts new file mode 100644 index 0000000..74bd420 --- /dev/null +++ b/src/app/core/services/home-page.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; +import { fakeVideoList } from '../mocks/mocked-courses'; +import { CourseItemInfo } from '../models'; +import { OrderByTitleNamePipe } from '../pipes/orderByTitleName.pipe'; +import { Subject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class HomePageService { + private coursesList: CourseItemInfo[]; + private _courseListSource: Subject = new Subject(); + public courseList$: Observable = this._courseListSource.asObservable(); + + constructor(private orderByTitleNamePipe: OrderByTitleNamePipe) { + this.courseList$.subscribe((value) => { + this.coursesList = value; + }); + } + + public getCourses(): CourseItemInfo[] { + const courseList: CourseItemInfo[] = fakeVideoList; + this._courseListSource.next(courseList); + return courseList; + } + + public sortListByName(): void { + this._courseListSource.next( + this.orderByTitleNamePipe.transform(this.coursesList) + ); + } + + public deleteCourseById(id: number): void { + const filteredArray: CourseItemInfo[] = this.coursesList.filter(item => item.id !== id); + this._courseListSource.next(filteredArray); + } + + // TODO: it'll be implement in a next module + /* public createCourse() {}; + public updateItem() {}; */ +} diff --git a/src/app/home-page/course-list/course-item/course-item.component.html b/src/app/home-page/course-list/course-item/course-item.component.html index 317f1d3..381aaa4 100644 --- a/src/app/home-page/course-list/course-item/course-item.component.html +++ b/src/app/home-page/course-list/course-item/course-item.component.html @@ -7,7 +7,10 @@
- + title: {{item.title | uppercase}} Edit - diff --git a/src/app/home-page/course-list/course-item/course-item.component.ts b/src/app/home-page/course-list/course-item/course-item.component.ts index 019bd79..dee5a73 100644 --- a/src/app/home-page/course-list/course-item/course-item.component.ts +++ b/src/app/home-page/course-list/course-item/course-item.component.ts @@ -2,6 +2,8 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; import { IconDefinition, faEdit, faTrash, faClock, faCalendar, faStar } from '@fortawesome/free-solid-svg-icons'; import { CourseItemInfo } from 'src/app/core/models'; import { Router } from '@angular/router'; +import { MatDialogConfig, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { ConfirmationDialogComponent } from 'src/app/shared/confirmation-dialog/confirmation-dialog.component'; @Component({ selector: 'app-course-item', @@ -19,7 +21,25 @@ export class CourseItemComponent { public calendarButtonIcon: IconDefinition = faCalendar; public topRatedIcon: IconDefinition = faStar; - public onDeleteCourseEmit(id: number): void { - return this.onDeleteCourse.emit(id); + constructor(public matDialog: MatDialog) { } + + public onDeleteCourseEmit(id: number, title: string): void { + this.openDialog(id, title); + } + + public openDialog(id: number, title: string): void { + const dialogRef: MatDialogRef = this.matDialog.open(ConfirmationDialogComponent, { + width: '400px', + height: '150px', + id: 'modal-component', + disableClose: true, + data: `Do you confirm the deletion "${title}?"` + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + return this.onDeleteCourse.emit(id); + } + }); } } diff --git a/src/app/home-page/course-list/course-list.component.html b/src/app/home-page/course-list/course-list.component.html index fe6c020..8ae0b23 100644 --- a/src/app/home-page/course-list/course-list.component.html +++ b/src/app/home-page/course-list/course-list.component.html @@ -3,7 +3,6 @@ (onDeleteCourse)="onDeleteCourse($event)" *ngFor="let item of courses | orderByDateCreation" [item]="item" - [routerLink]="['/courses', item.id]" > diff --git a/src/app/home-page/course-list/course-list.component.less b/src/app/home-page/course-list/course-list.component.less index 3f10dea..cf870eb 100644 --- a/src/app/home-page/course-list/course-list.component.less +++ b/src/app/home-page/course-list/course-list.component.less @@ -15,5 +15,9 @@ background-color: @color-white; border-radius: 6px; font-family: 'SourseSansPro Regular'; + font-size: 16px; + p { + margin-bottom: 0; + } } } \ No newline at end of file diff --git a/src/app/home-page/course-list/course-list.component.ts b/src/app/home-page/course-list/course-list.component.ts index 7d249b3..8cd4cfa 100644 --- a/src/app/home-page/course-list/course-list.component.ts +++ b/src/app/home-page/course-list/course-list.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from '@angular/core'; import { CourseItemInfo } from 'src/app/core/models'; +import { HomePageService } from '../../core/services/home-page.service'; @Component({ selector: 'app-course-list', @@ -9,7 +10,9 @@ import { CourseItemInfo } from 'src/app/core/models'; export class CourseListComponent { @Input() public courses: CourseItemInfo[] = []; + constructor (private homePageService: HomePageService) {} + public onDeleteCourse(id: number): void { - console.log(id); + this.homePageService.deleteCourseById(id); } } diff --git a/src/app/home-page/home-page.component.html b/src/app/home-page/home-page.component.html index 40912dd..52aa1ac 100644 --- a/src/app/home-page/home-page.component.html +++ b/src/app/home-page/home-page.component.html @@ -5,4 +5,5 @@
+ \ No newline at end of file diff --git a/src/app/home-page/home-page.component.ts b/src/app/home-page/home-page.component.ts index 45f38bc..424a73b 100644 --- a/src/app/home-page/home-page.component.ts +++ b/src/app/home-page/home-page.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { CourseItemInfo } from '../core/models'; -import { HomePageService } from './home-page.service'; +import { HomePageService } from '../core/services/home-page.service'; @Component({ selector: 'app-home-page', @@ -11,9 +11,13 @@ export class HomePageComponent implements OnInit { public courses: CourseItemInfo[]; - constructor( - private homePageService: HomePageService, - ) { } + constructor(private homePageService: HomePageService) { + homePageService.courseList$.subscribe( + courseList => { + this.courses = courseList; + } + ); + } public ngOnInit(): void { this.courses = this.getCourses(); diff --git a/src/app/home-page/home-page.service.spec.ts b/src/app/home-page/home-page.service.spec.ts deleted file mode 100644 index d9f5765..0000000 --- a/src/app/home-page/home-page.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { HomePageService } from './home-page.service'; - -describe('HomePageService', () => { - let service: HomePageService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(HomePageService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/home-page/home-page.service.ts b/src/app/home-page/home-page.service.ts deleted file mode 100644 index 4ca4a7d..0000000 --- a/src/app/home-page/home-page.service.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable } from '@angular/core'; -import { fakeVideoList } from '../core/mocks/mocked-data'; -import { CourseItemInfo } from '../core/models'; -import { OrderByTitleNamePipe } from '../core/pipes/orderByTitleName.pipe'; - -@Injectable({ - providedIn: 'root' -}) -export class HomePageService { - constructor(private orderByTitleNamePipe: OrderByTitleNamePipe) { } - - public getCourses(): CourseItemInfo[] { - const coursesList: CourseItemInfo[] = fakeVideoList; - return coursesList; - } - - public sendMessageSortByName(): void { - this.orderByTitleNamePipe.transform(fakeVideoList); - } -} diff --git a/src/app/home-page/toolbox/search/search.component.ts b/src/app/home-page/toolbox/search/search.component.ts index 73fe1ad..024dd57 100644 --- a/src/app/home-page/toolbox/search/search.component.ts +++ b/src/app/home-page/toolbox/search/search.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { IconDefinition, faSearch } from '@fortawesome/free-solid-svg-icons'; -import { HomePageService } from '../../home-page.service'; +import { HomePageService } from '../../../core/services/home-page.service'; @Component({ selector: 'app-search', @@ -14,6 +14,6 @@ export class SearchComponent { constructor (private homePageService: HomePageService) {} public searchCourses(): void { - this.homePageService.sendMessageSortByName(); + this.homePageService.sortListByName(); } } diff --git a/src/app/login-page/login-page.component.html b/src/app/login-page/login-page.component.html index d4d1e1d..78f463c 100644 --- a/src/app/login-page/login-page.component.html +++ b/src/app/login-page/login-page.component.html @@ -1 +1,50 @@ -

login-page works!

+ \ No newline at end of file diff --git a/src/app/login-page/login-page.component.less b/src/app/login-page/login-page.component.less index e69de29..69cffd2 100644 --- a/src/app/login-page/login-page.component.less +++ b/src/app/login-page/login-page.component.less @@ -0,0 +1,34 @@ +@import '../../assets/less/modules/variables'; + +mat-card { + display: flex; + flex-direction: column; + max-width: 320px; + text-align: center; + padding: 40px; + position: absolute; + right: 0; + left: 0; + margin: 0 auto; + transform: translate(0%, 100%); +} + +mat-card-header { + margin-bottom: 20px; +} + +mat-card-content { + + .mat-card-content-message { + display: flex; + flex-direction: column; + } + + form table { + min-width: 100%; + } +} + +mat-form-field { + display: block; +} diff --git a/src/app/login-page/login-page.component.ts b/src/app/login-page/login-page.component.ts index f01f74c..7cf7568 100644 --- a/src/app/login-page/login-page.component.ts +++ b/src/app/login-page/login-page.component.ts @@ -1,8 +1,37 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { AuthService } from '../core/services/auth.service'; +import { UserInfo } from '../core/models'; @Component({ selector: 'app-login-page', templateUrl: './login-page.component.html', styleUrls: ['./login-page.component.less'] }) -export class LoginPageComponent { } +export class LoginPageComponent implements OnInit { + public username: string; + public password: string; + public userInfo: UserInfo; + public authentification: boolean = false; + + constructor(private authService: AuthService) { } + + public ngOnInit(): void { + this.authService.userInfo$.subscribe((data: string) => { + this.authentification = this.isAuthentificated(); + }); + } + + public loginUser(): UserInfo { + const isLogged: UserInfo = this.authService.userLogin(this.username, this.password); + if (isLogged) { + this.userInfo = isLogged; + this.authentification = this.authService.isAuthentificated(); + } else { + return undefined; + } + } + + public isAuthentificated(): boolean { + return this.authService.isAuthentificated(); + } +} diff --git a/src/app/login-page/login-page.module.ts b/src/app/login-page/login-page.module.ts index 77cb63e..652f603 100644 --- a/src/app/login-page/login-page.module.ts +++ b/src/app/login-page/login-page.module.ts @@ -1,11 +1,16 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { LoginPageComponent } from './login-page.component'; - +import { CustomMaterialModule } from '../core/modules/material.module'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; @NgModule({ declarations: [LoginPageComponent], imports: [ - CommonModule + CommonModule, + CustomMaterialModule, + FormsModule, + RouterModule ] }) export class LoginPageModule { } diff --git a/src/app/root/app-routing.module.ts b/src/app/root/app-routing.module.ts index 7222fdd..d816af9 100644 --- a/src/app/root/app-routing.module.ts +++ b/src/app/root/app-routing.module.ts @@ -2,10 +2,12 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomePageComponent } from '../home-page/home-page.component'; import { CoursePageComponent } from '../course-page/course-page.component'; +import { LoginPageComponent } from '../login-page/login-page.component'; const routes: Routes = [ { path: '', component: HomePageComponent }, - { path: 'course-page', component: CoursePageComponent } + { path: 'courses/:courseId', component: CoursePageComponent }, + { path: 'login', component: LoginPageComponent } ]; @NgModule({ diff --git a/src/app/root/app.component.html b/src/app/root/app.component.html index a826fdc..6bfac83 100644 --- a/src/app/root/app.component.html +++ b/src/app/root/app.component.html @@ -1,8 +1,8 @@ - +
-
diff --git a/src/app/root/app.component.less b/src/app/root/app.component.less index b8dc27a..5e29cdf 100644 --- a/src/app/root/app.component.less +++ b/src/app/root/app.component.less @@ -12,4 +12,10 @@ align-items: center; display: flex; height: 50px; +} + +#logout-button { + color: white; + background-color: #4b4b4b; + border: 1px solid black; } \ No newline at end of file diff --git a/src/app/root/app.component.ts b/src/app/root/app.component.ts index ea64448..0dc87fd 100644 --- a/src/app/root/app.component.ts +++ b/src/app/root/app.component.ts @@ -1,8 +1,26 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { Location } from '@angular/common'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.less'] }) -export class AppComponent { } +export class AppComponent implements OnInit { + public route: string; + + constructor(location: Location, router: Router) { + router.events.subscribe(val => { + if (location.path() !== '') { + this.route = location.path(); + } else { + this.route = '/'; + } + }); + } + + public ngOnInit(): void { + localStorage.clear(); + } +} diff --git a/src/app/root/app.module.ts b/src/app/root/app.module.ts index 7f39d32..eb937b3 100644 --- a/src/app/root/app.module.ts +++ b/src/app/root/app.module.ts @@ -8,10 +8,14 @@ import { LoginPageModule } from '../login-page/login-page.module'; import { HomePageModule } from '../home-page/home-page.module'; import { SharedModule } from '../shared/shared.module'; import { CoursePageModule } from '../course-page/course-page.module'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +import { MatButtonModule } from '@angular/material/button'; +import { MatDialogModule } from '@angular/material/dialog'; @NgModule({ declarations: [ - AppComponent + AppComponent, ], imports: [ BrowserModule, @@ -20,7 +24,10 @@ import { CoursePageModule } from '../course-page/course-page.module'; SharedModule, CoursePageModule, LoginPageModule, - HomePageModule + HomePageModule, + BrowserAnimationsModule, + MatButtonModule, + MatDialogModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.html b/src/app/shared/confirmation-dialog/confirmation-dialog.component.html new file mode 100644 index 0000000..7baa59f --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.html @@ -0,0 +1,7 @@ +
+ {{message}} +
+
+ + +
\ No newline at end of file diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.less b/src/app/shared/confirmation-dialog/confirmation-dialog.component.less new file mode 100644 index 0000000..a15575f --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.less @@ -0,0 +1,37 @@ +@import "../../../assets/less/modules/variables"; + +.mat-dialog-content { + color: @color-white; + font-size: 14px; + display: flex; + justify-content: center; +} + +.mat-dialog-actions { + justify-content: center; + margin-top: 25px; + button { + + &:first-child { + background-color: @color-red; + } + &:last-child { + background-color: @color-gray; + } + padding: 6px 30px; + background-color: #e7e7e7; color: black; + border-radius: 4px; + transition-duration: 0.4s; + border: none; + outline: none; + line-height: 20px; + + &:not(:first-child) { + margin-left: 25px; + } + } + + button:hover { + box-shadow: inset 0 0 100px 100px rgba(255, 255, 255, 0.1); + } +} \ No newline at end of file diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts b/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts new file mode 100644 index 0000000..4610829 --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfirmationDialogComponent } from './confirmation-dialog.component'; + +describe('ConfirmationDialogComponent', () => { + let component: ConfirmationDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfirmationDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmationDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts b/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts new file mode 100644 index 0000000..499fa01 --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts @@ -0,0 +1,17 @@ +import { Component, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-confirmation-dialog', + templateUrl: './confirmation-dialog.component.html', + styleUrls: ['./confirmation-dialog.component.less'] +}) +export class ConfirmationDialogComponent { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public message: string) { } + + public onNoClick(): void { + this.dialogRef.close(); + } +} diff --git a/src/app/shared/header/header-login/header-login.component.html b/src/app/shared/header/header-login/header-login.component.html index 1032f21..da1e740 100644 --- a/src/app/shared/header/header-login/header-login.component.html +++ b/src/app/shared/header/header-login/header-login.component.html @@ -1,21 +1,40 @@ - \ No newline at end of file diff --git a/src/app/home-page/home-page.component.ts b/src/app/home-page/home-page.component.ts index 424a73b..61234ab 100644 --- a/src/app/home-page/home-page.component.ts +++ b/src/app/home-page/home-page.component.ts @@ -7,23 +7,24 @@ import { HomePageService } from '../core/services/home-page.service'; templateUrl: './home-page.component.html', styleUrls: ['./home-page.component.less'] }) -export class HomePageComponent implements OnInit { +export class HomePageComponent { public courses: CourseItemInfo[]; constructor(private homePageService: HomePageService) { - homePageService.courseList$.subscribe( - courseList => { - this.courses = courseList; - } - ); + this.courses = []; } public ngOnInit(): void { - this.courses = this.getCourses(); + this.homePageService.getCourses().subscribe( + courseList => this.courses = courseList + ); + this.homePageService.getRefreshedData().subscribe( + courseList => this.courses = courseList + ); } - public getCourses(): CourseItemInfo[] { + /* public getCourses(): CourseItemInfo[] { return this.homePageService.getCourses(); - } + } */ } diff --git a/src/app/home-page/toolbox/search/search.component.ts b/src/app/home-page/toolbox/search/search.component.ts index 024dd57..4a2b848 100644 --- a/src/app/home-page/toolbox/search/search.component.ts +++ b/src/app/home-page/toolbox/search/search.component.ts @@ -1,6 +1,7 @@ import { Component } from '@angular/core'; import { IconDefinition, faSearch } from '@fortawesome/free-solid-svg-icons'; import { HomePageService } from '../../../core/services/home-page.service'; +import { switchMap } from 'rxjs/operators'; @Component({ selector: 'app-search', @@ -14,6 +15,8 @@ export class SearchComponent { constructor (private homePageService: HomePageService) {} public searchCourses(): void { - this.homePageService.sortListByName(); + this.homePageService.sortListByName() + .pipe(switchMap(() => this.homePageService.getCourses())) + .subscribe(data => this.homePageService.refreshData(data)); } } diff --git a/src/app/login-page/login-page.component.ts b/src/app/login-page/login-page.component.ts index 7cf7568..09cb8b5 100644 --- a/src/app/login-page/login-page.component.ts +++ b/src/app/login-page/login-page.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { AuthService } from '../core/services/auth.service'; import { UserInfo } from '../core/models'; +import { switchMap } from 'rxjs/operators'; +import { Observable } from 'rxjs'; @Component({ selector: 'app-login-page', @@ -11,27 +13,28 @@ export class LoginPageComponent implements OnInit { public username: string; public password: string; public userInfo: UserInfo; - public authentification: boolean = false; + public authentification: boolean; constructor(private authService: AuthService) { } public ngOnInit(): void { - this.authService.userInfo$.subscribe((data: string) => { - this.authentification = this.isAuthentificated(); + this.authService.isAuthentificated().subscribe((data: boolean) => { + this.authentification = data; }); + + this.authService.getRefreshedData().subscribe( + data => this.authentification = data + ); } - public loginUser(): UserInfo { - const isLogged: UserInfo = this.authService.userLogin(this.username, this.password); + public loginUser(): void { + const isLogged: Observable = this.authService.userLogin(this.username, this.password); if (isLogged) { - this.userInfo = isLogged; - this.authentification = this.authService.isAuthentificated(); + isLogged + .pipe(switchMap(() => this.authService.isAuthentificated())) + .subscribe(data => this.authService.refreshData(data)); } else { return undefined; } } - - public isAuthentificated(): boolean { - return this.authService.isAuthentificated(); - } } diff --git a/src/app/root/app.component.ts b/src/app/root/app.component.ts index 0dc87fd..a013399 100644 --- a/src/app/root/app.component.ts +++ b/src/app/root/app.component.ts @@ -7,7 +7,7 @@ import { Location } from '@angular/common'; templateUrl: './app.component.html', styleUrls: ['./app.component.less'] }) -export class AppComponent implements OnInit { +export class AppComponent { public route: string; constructor(location: Location, router: Router) { @@ -19,8 +19,4 @@ export class AppComponent implements OnInit { } }); } - - public ngOnInit(): void { - localStorage.clear(); - } } diff --git a/src/app/shared/header/header-login/header-login.component.ts b/src/app/shared/header/header-login/header-login.component.ts index 5743ac3..d687a6b 100644 --- a/src/app/shared/header/header-login/header-login.component.ts +++ b/src/app/shared/header/header-login/header-login.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { IconDefinition, faUser, faArrowRight, faAddressCard } from '@fortawesome/free-solid-svg-icons'; import { AuthService } from 'src/app/core/services/auth.service'; import { UserInfo } from 'src/app/core/models/user-info.interface'; +import { switchMap } from 'rxjs/operators'; @Component({ selector: 'app-header-login', @@ -24,6 +25,8 @@ export class HeaderLoginComponent implements OnInit { } public userLogOut(): void { - this.isAuthentificated = this.authService.userLogout(); + this.authService.userLogout() + .pipe(switchMap(() => this.authService.isAuthentificated())) + .subscribe(data => this.authService.refreshData(data)); } } diff --git a/src/app/shared/header/header.component.ts b/src/app/shared/header/header.component.ts index cebeea4..9297213 100644 --- a/src/app/shared/header/header.component.ts +++ b/src/app/shared/header/header.component.ts @@ -14,9 +14,13 @@ export class HeaderComponent implements OnInit { constructor(private authService: AuthService) {} public ngOnInit(): void { - this.authService.userInfo$.subscribe((data: string) => { - this.authentification = this.isAuthentificated(); + this.authService.isAuthentificated().subscribe((data: boolean) => { + this.authentification = data; }); + + this.authService.getRefreshedData().subscribe( + data => this.authentification = data + ); } public checkingLoginRouter(): boolean { @@ -28,6 +32,6 @@ export class HeaderComponent implements OnInit { } public isAuthentificated(): boolean { - return this.authService.isAuthentificated(); + return this.authentification; } } From a15ea18f4438fd69337854b9948177b8e0884edd Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Fri, 15 May 2020 21:14:49 +0300 Subject: [PATCH 3/3] - Refactoring of services --- ...pipe.ts => order-by-date-creation.pipe.ts} | 0 ...me.pipe.ts => order-by-title-name.pipe.ts} | 0 src/app/core/services/auth.service.ts | 17 ++++---------- src/app/core/services/home-page.service.ts | 23 ++++++------------- .../course-list/course-list.component.ts | 8 +++---- src/app/home-page/home-page.component.html | 1 - src/app/home-page/home-page.component.ts | 15 +++--------- src/app/home-page/home-page.module.ts | 4 ++-- .../toolbox/search/search.component.ts | 4 +--- src/app/login-page/login-page.component.ts | 13 ++++------- .../header-login/header-login.component.ts | 6 ++--- src/app/shared/header/header.component.ts | 14 +++++------ 12 files changed, 35 insertions(+), 70 deletions(-) rename src/app/core/pipes/{orderByDateCreation.pipe.ts => order-by-date-creation.pipe.ts} (100%) rename src/app/core/pipes/{orderByTitleName.pipe.ts => order-by-title-name.pipe.ts} (100%) diff --git a/src/app/core/pipes/orderByDateCreation.pipe.ts b/src/app/core/pipes/order-by-date-creation.pipe.ts similarity index 100% rename from src/app/core/pipes/orderByDateCreation.pipe.ts rename to src/app/core/pipes/order-by-date-creation.pipe.ts diff --git a/src/app/core/pipes/orderByTitleName.pipe.ts b/src/app/core/pipes/order-by-title-name.pipe.ts similarity index 100% rename from src/app/core/pipes/orderByTitleName.pipe.ts rename to src/app/core/pipes/order-by-title-name.pipe.ts diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts index dc780e1..e95385a 100644 --- a/src/app/core/services/auth.service.ts +++ b/src/app/core/services/auth.service.ts @@ -1,32 +1,23 @@ -import { Injectable, OnInit } from '@angular/core'; +import { Injectable } from '@angular/core'; import { fakeUserInfo } from '../mocks/mocked-user'; import { UserInfo } from '../models'; -import { Subject, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { private userInfo: UserInfo; - private userInfoSource: Subject = new Subject(); constructor() { this.userInfo = fakeUserInfo; } - public refreshData(data: boolean): void { - this.userInfoSource.next(data); - } - - public getRefreshedData(): Observable { - return this.userInfoSource.asObservable(); - } - public getUserInfo(): UserInfo { return this.userInfo; } - public userLogin(sentLogin: string, sentPassword: string): Observable { + public userLogin(sentLogin: string, sentPassword: string): UserInfo { const { login, password, @@ -37,7 +28,7 @@ export class AuthService { if (sentLogin === login && sentPassword === password) { localStorage.setItem('userData', JSON.stringify({ firstName, lastName, token })); - return of(this.userInfo); + return this.userInfo; } } diff --git a/src/app/core/services/home-page.service.ts b/src/app/core/services/home-page.service.ts index 0ac723a..e53dfd3 100644 --- a/src/app/core/services/home-page.service.ts +++ b/src/app/core/services/home-page.service.ts @@ -1,38 +1,29 @@ import { Injectable } from '@angular/core'; import { fakeVideoList } from '../mocks/mocked-courses'; import { CourseItemInfo } from '../models'; -import { OrderByTitleNamePipe } from '../pipes/orderByTitleName.pipe'; -import { Subject, Observable, of, Observer } from 'rxjs'; +import { OrderByTitleNamePipe } from '../pipes/order-by-title-name.pipe'; +import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class HomePageService { private coursesList: CourseItemInfo[]; - private courseListSource: Subject = new Subject(); constructor(private orderByTitleNamePipe: OrderByTitleNamePipe) { this.coursesList = fakeVideoList; } - public refreshData(data: CourseItemInfo[]): void { - this.courseListSource.next(data); - } - - public getRefreshedData(): Observable { - return this.courseListSource.asObservable(); - } - public getCourses(): Observable { return of(this.coursesList); } - public sortListByName(): Observable { - return of(this.orderByTitleNamePipe.transform(this.coursesList)); + public sortListByName(): CourseItemInfo[] { + return this.orderByTitleNamePipe.transform(this.coursesList); } - public deleteCourseById(id: number): Observable { - const filteredList: CourseItemInfo[] = this.coursesList.filter(item => item.id !== id); - return of(this.coursesList = filteredList); + public deleteCourseById(id: number): Observable { + const newArr: CourseItemInfo[] = this.coursesList.filter(item => item.id !== id); + return of(this.coursesList = newArr); } } diff --git a/src/app/home-page/course-list/course-list.component.ts b/src/app/home-page/course-list/course-list.component.ts index 61b8cbe..68a2a4b 100644 --- a/src/app/home-page/course-list/course-list.component.ts +++ b/src/app/home-page/course-list/course-list.component.ts @@ -6,7 +6,7 @@ import { switchMap } from 'rxjs/operators'; @Component({ selector: 'app-course-list', templateUrl: './course-list.component.html', - styleUrls: ['./course-list.component.less'] + styleUrls: ['./course-list.component.less'], }) export class CourseListComponent { @Input() public courses: CourseItemInfo[] = []; @@ -14,8 +14,8 @@ export class CourseListComponent { constructor (private homePageService: HomePageService) {} public onDeleteCourse(id: number): void { - this.homePageService.deleteCourseById(id) - .pipe(switchMap(() => this.homePageService.getCourses())) - .subscribe(data => this.homePageService.refreshData(data)); + this.homePageService.deleteCourseById(id).subscribe(data => { + this.courses = data; + }); } } diff --git a/src/app/home-page/home-page.component.html b/src/app/home-page/home-page.component.html index ce47d0e..46b6701 100644 --- a/src/app/home-page/home-page.component.html +++ b/src/app/home-page/home-page.component.html @@ -7,5 +7,4 @@ [courses]='courses' > - \ No newline at end of file diff --git a/src/app/home-page/home-page.component.ts b/src/app/home-page/home-page.component.ts index 61234ab..c68b598 100644 --- a/src/app/home-page/home-page.component.ts +++ b/src/app/home-page/home-page.component.ts @@ -5,26 +5,17 @@ import { HomePageService } from '../core/services/home-page.service'; @Component({ selector: 'app-home-page', templateUrl: './home-page.component.html', - styleUrls: ['./home-page.component.less'] + styleUrls: ['./home-page.component.less'], }) export class HomePageComponent { public courses: CourseItemInfo[]; - constructor(private homePageService: HomePageService) { - this.courses = []; - } + constructor (private homePageService: HomePageService) { } public ngOnInit(): void { this.homePageService.getCourses().subscribe( - courseList => this.courses = courseList - ); - this.homePageService.getRefreshedData().subscribe( - courseList => this.courses = courseList + data => this.courses = data ); } - - /* public getCourses(): CourseItemInfo[] { - return this.homePageService.getCourses(); - } */ } diff --git a/src/app/home-page/home-page.module.ts b/src/app/home-page/home-page.module.ts index db2dd5e..489a8ef 100644 --- a/src/app/home-page/home-page.module.ts +++ b/src/app/home-page/home-page.module.ts @@ -10,8 +10,8 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { CourseItemComponent } from './course-list/course-item/course-item.component'; import { TransformMinutesToHoursPipe } from '../core/pipes/transform-minutes.pipe'; import { ChangeBorderColorDirective } from '../core/directives/change-border-color.directive'; -import { OrderByDateCreationPipe } from '../core/pipes/orderByDateCreation.pipe'; -import { OrderByTitleNamePipe } from '../core/pipes/orderByTitleName.pipe'; +import { OrderByDateCreationPipe } from '../core/pipes/order-by-date-creation.pipe'; +import { OrderByTitleNamePipe } from '../core/pipes/order-by-title-name.pipe'; import { RouterModule } from '@angular/router'; @NgModule({ diff --git a/src/app/home-page/toolbox/search/search.component.ts b/src/app/home-page/toolbox/search/search.component.ts index 4a2b848..b3b0195 100644 --- a/src/app/home-page/toolbox/search/search.component.ts +++ b/src/app/home-page/toolbox/search/search.component.ts @@ -15,8 +15,6 @@ export class SearchComponent { constructor (private homePageService: HomePageService) {} public searchCourses(): void { - this.homePageService.sortListByName() - .pipe(switchMap(() => this.homePageService.getCourses())) - .subscribe(data => this.homePageService.refreshData(data)); + this.homePageService.sortListByName(); } } diff --git a/src/app/login-page/login-page.component.ts b/src/app/login-page/login-page.component.ts index 09cb8b5..960d2f2 100644 --- a/src/app/login-page/login-page.component.ts +++ b/src/app/login-page/login-page.component.ts @@ -1,7 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { AuthService } from '../core/services/auth.service'; import { UserInfo } from '../core/models'; -import { switchMap } from 'rxjs/operators'; import { Observable } from 'rxjs'; @Component({ @@ -21,18 +20,14 @@ export class LoginPageComponent implements OnInit { this.authService.isAuthentificated().subscribe((data: boolean) => { this.authentification = data; }); - - this.authService.getRefreshedData().subscribe( - data => this.authentification = data - ); } public loginUser(): void { - const isLogged: Observable = this.authService.userLogin(this.username, this.password); + const isLogged: UserInfo = this.authService.userLogin(this.username, this.password); if (isLogged) { - isLogged - .pipe(switchMap(() => this.authService.isAuthentificated())) - .subscribe(data => this.authService.refreshData(data)); + this.authService.isAuthentificated().subscribe((data: boolean) => { + this.authentification = data; + }); } else { return undefined; } diff --git a/src/app/shared/header/header-login/header-login.component.ts b/src/app/shared/header/header-login/header-login.component.ts index d687a6b..2fae680 100644 --- a/src/app/shared/header/header-login/header-login.component.ts +++ b/src/app/shared/header/header-login/header-login.component.ts @@ -25,8 +25,8 @@ export class HeaderLoginComponent implements OnInit { } public userLogOut(): void { - this.authService.userLogout() - .pipe(switchMap(() => this.authService.isAuthentificated())) - .subscribe(data => this.authService.refreshData(data)); + this.authService.userLogout().subscribe(data => { + this.isAuthentificated = data; + }); } } diff --git a/src/app/shared/header/header.component.ts b/src/app/shared/header/header.component.ts index 9297213..2b68487 100644 --- a/src/app/shared/header/header.component.ts +++ b/src/app/shared/header/header.component.ts @@ -17,10 +17,14 @@ export class HeaderComponent implements OnInit { this.authService.isAuthentificated().subscribe((data: boolean) => { this.authentification = data; }); + } - this.authService.getRefreshedData().subscribe( - data => this.authentification = data - ); + public ngDoCheck(): void { + this.authService.isAuthentificated().subscribe((data: boolean) => { + if (this.authentification !== data) { + this.authentification = data; + } + }); } public checkingLoginRouter(): boolean { @@ -30,8 +34,4 @@ export class HeaderComponent implements OnInit { public userLogout(): void { this.authService.userLogout(); } - - public isAuthentificated(): boolean { - return this.authentification; - } }