diff --git a/Phonebook.Frontend/src/app/app-routing.module.ts b/Phonebook.Frontend/src/app/app-routing.module.ts
index 55446a0f2..9076c6b50 100644
--- a/Phonebook.Frontend/src/app/app-routing.module.ts
+++ b/Phonebook.Frontend/src/app/app-routing.module.ts
@@ -1,11 +1,18 @@
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
-import { DashboardComponent } from 'src/app/pages/dashboard/dashboard.component';
+import { DashboardComponent } from 'src/app/pages/dashboard/components/dashboard/dashboard.component';
import { SettingsComponent } from 'src/app/pages/settings/settings.component';
import { environment } from 'src/environments/environment';
+import { TeamComponent } from './pages/dashboard/components/team/team.component';
+import { BookmarkedComponent } from './pages/dashboard/components/bookmarked/bookmarked.component';
const routes: Routes = [
- { path: '', component: DashboardComponent, pathMatch: 'full' },
+ { path: '', redirectTo: 'dashboard/bookmarks', pathMatch: 'full' },
+ {
+ path: 'dashboard',
+ loadChildren: () =>
+ import('src/app/pages/dashboard/dashboard.module').then((m) => m.DashboardModule),
+ },
{
path: 'search',
loadChildren: () => import('src/app/modules/table/table.module').then((m) => m.TableModule),
diff --git a/Phonebook.Frontend/src/app/app.module.ts b/Phonebook.Frontend/src/app/app.module.ts
index 92cc82d68..ba59f69f2 100644
--- a/Phonebook.Frontend/src/app/app.module.ts
+++ b/Phonebook.Frontend/src/app/app.module.ts
@@ -20,7 +20,7 @@ import { FeatureFlagModule } from 'src/app/modules/feature-flag/feature-flag.mod
import { NotImplementedModule } from 'src/app/modules/not-implemented/not-implemented.module';
import { ProfilePictureModule } from 'src/app/modules/profile-picture/profile-picture.module';
import { TableModule } from 'src/app/modules/table/table.module';
-import { DashboardComponent } from 'src/app/pages/dashboard/dashboard.component';
+import { DashboardComponent } from 'src/app/pages/dashboard/components/dashboard/dashboard.component';
import { SettingsModule } from 'src/app/pages/settings/settings.module';
import { UserPagesModule } from 'src/app/pages/users/user-pages.module';
import { ApiModule } from 'src/app/services/api/api.module';
@@ -58,13 +58,7 @@ import { FormsModule } from '@angular/forms';
declare const require;
@NgModule({
- declarations: [
- AppComponent,
- SearchComponent,
- DashboardComponent,
- NavigationComponent,
- OnlineBarComponent,
- ],
+ declarations: [AppComponent, SearchComponent, NavigationComponent, OnlineBarComponent],
imports: [
BrowserModule,
AppRoutingModule,
diff --git a/Phonebook.Frontend/src/app/modules/organigram/pages/organigram/organigram.component.ts b/Phonebook.Frontend/src/app/modules/organigram/pages/organigram/organigram.component.ts
index 453a8a0ca..156f597fc 100644
--- a/Phonebook.Frontend/src/app/modules/organigram/pages/organigram/organigram.component.ts
+++ b/Phonebook.Frontend/src/app/modules/organigram/pages/organigram/organigram.component.ts
@@ -13,7 +13,7 @@ export class OrganigramComponent implements OnInit {
constructor(private organigramService: OrganigramService) {}
public ngOnInit() {
- this.organigramService.getOrganigram().subscribe((organigram) => {
+ this.organigramService.getOrganigramTree().subscribe((organigram) => {
this.nodes = organigram;
});
}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.html b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.html
new file mode 100644
index 000000000..258f105ae
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.html
@@ -0,0 +1,106 @@
+
+
+
+ bookmark
+
+ Bookmarked People
+
+
+
+
+
+ Custom Order
+
+ Alphabetical asc
+
+ Alphabetical desc
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You haven't bookmarked anybody yet, look for the button
+
+ on a workmates page.
+
+
+
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.scss b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.scss
new file mode 100644
index 000000000..eec5ed661
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.scss
@@ -0,0 +1,50 @@
+.pb-bookmarked {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding-right: 10px;
+}
+
+.pb-small-card {
+ width: 320px;
+ height: 275px;
+}
+
+.card-container {
+ display: flex;
+}
+
+.pb-card:active {
+ cursor: -webkit-grabbing;
+ cursor: grabbing;
+}
+
+.cdk-drop-dragging .cdk-drag,
+.pb-card:not(.cdk-drag-placeholder) {
+ transition: transform 150ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.cdk-drag-animating {
+ transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.pb-bookmarked-title {
+ display: flex;
+ flex-direction: row;
+ mat-icon {
+ display: inline-flex;
+ vertical-align: middle;
+ height: 29px;
+ width: 29px;
+ }
+ h1 {
+ margin: 0;
+ }
+ mat-form-field {
+ margin-left: 16px;
+ }
+ ::ng-deep .mat-form-field-infix {
+ border: none;
+ }
+}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.ts b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.ts
new file mode 100644
index 000000000..4b6661a24
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/bookmarked/bookmarked.component.ts
@@ -0,0 +1,101 @@
+import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
+import { CdkDragEnd, CdkDragEnter, moveItemInArray } from '@angular/cdk/drag-drop';
+import { ChangeDetectorRef, Component, OnInit, OnDestroy, Input } from '@angular/core';
+import { Select, Store } from '@ngxs/store';
+import { Observable, Subscription } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Person, PhonebookSortDirection } from 'src/app/shared/models';
+import {
+ BookmarksState,
+ ToggleBookmark,
+ UpdateBookmarkOrder,
+ AppState,
+} from 'src/app/shared/states';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
+import { untilComponentDestroyed } from 'ng2-rx-componentdestroyed';
+import { Router } from '@angular/router';
+import { Layout } from 'src/app/shared/models/enumerables/Layout';
+
+@Component({
+ selector: 'app-bookmarked',
+ templateUrl: './bookmarked.component.html',
+ styleUrls: ['./bookmarked.component.scss'],
+ host: { class: 'pb-dashboard-component' },
+})
+export class BookmarkedComponent implements OnInit, OnDestroy {
+ public bookmarkedPersons: Person[];
+ public bookmarkedPersonsSubscriptions: Subscription | null = null;
+ public favoriteSort: PhonebookSortDirection = PhonebookSortDirection.none;
+ public lastFrom: number;
+ public lastTo: number;
+ @Select(BookmarksState)
+ public bookmarkedPersons$: Observable;
+ public currentUser: Person | null = null;
+ @Select(AppState.activeLayout)
+ public activeLayout$: Observable;
+ public layouts: string[] = Object.values(Layout);
+ public layout: typeof Layout = Layout;
+ constructor(
+ private store: Store,
+ private cd: ChangeDetectorRef,
+ private breakpointObserver: BreakpointObserver,
+ public router: Router,
+ private currentUserService: CurrentUserService
+ ) {}
+
+ public ngOnInit() {
+ this.changeOrder();
+ this.currentUserService
+ .getCurrentUser()
+ .pipe(untilComponentDestroyed(this))
+ .subscribe(
+ (user) => {
+ if (user != null) {
+ this.currentUser = user;
+ }
+ },
+ (error) => {
+ this.currentUser = null;
+ }
+ );
+ }
+
+ public changeOrder() {
+ if (this.bookmarkedPersonsSubscriptions) {
+ this.bookmarkedPersonsSubscriptions.unsubscribe();
+ }
+ this.bookmarkedPersonsSubscriptions = this.store
+ .select(BookmarksState.sortedBookmarks)
+ .pipe(map((filterFn) => filterFn(this.favoriteSort)))
+ .subscribe((persons) => {
+ this.bookmarkedPersons = persons;
+ });
+ }
+
+ public entered(e: CdkDragEnter) {
+ if (this.bookmarkedPersons && this.bookmarkedPersons.length === 1) {
+ return;
+ }
+
+ this.lastFrom = e.item.data;
+ this.lastTo = e.container.data;
+ }
+
+ public ended(e: CdkDragEnd) {
+ if (this.bookmarkedPersons && this.bookmarkedPersons.length === 1) {
+ return;
+ }
+ if (this.lastFrom === undefined || this.lastTo === undefined) {
+ return;
+ }
+ moveItemInArray(this.bookmarkedPersons, this.lastFrom, this.lastTo);
+ this.store.dispatch(new UpdateBookmarkOrder(this.bookmarkedPersons));
+ this.cd.detectChanges();
+ }
+
+ public removeFromBookmarkedPersons(person: Person) {
+ this.store.dispatch(new ToggleBookmark(person));
+ }
+
+ public ngOnDestroy(): void {}
+}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.html b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.html
new file mode 100644
index 000000000..ed73d32d9
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.html
@@ -0,0 +1,154 @@
+
+
+
+
+
+ Recent People
+
+
+
+
+
+
+
+
+
+
+ Looks like you haven't searched for any colleagues yet. Search for somebody to see how
+ it works! The most recent ones will be displayed here.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.scss b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.scss
similarity index 51%
rename from Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.scss
rename to Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.scss
index e509985b6..f6652dd3a 100644
--- a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.scss
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.scss
@@ -9,32 +9,6 @@ mat-drawer-container {
}
}
-.pb-bookmarked {
- height: 100%;
- margin-right: 50px;
- display: flex;
- flex-direction: column;
- flex: 1;
-
- .pb-bookmarked-title {
- display: flex;
- flex-direction: row;
- h1 {
- margin: 0;
- }
- mat-form-field {
- margin-left: 16px;
- }
- ::ng-deep .mat-form-field-infix {
- border: none;
- }
- }
-
- .pb-bookmarks-list {
- overflow-y: auto;
- }
-}
-
.pb-recent-people-drawer {
width: 370px;
background-color: unset;
@@ -57,7 +31,7 @@ mat-drawer-container {
z-index: 1;
right: 0;
top: 46%;
- padding-right: 10px;
+ padding-right: 20px;
button {
align-self: center;
@@ -67,32 +41,14 @@ mat-drawer-container {
}
}
-.pb-small-card {
- width: 320px;
- height: 275px;
-}
-
-.pb-card {
- margin: 5px;
- display: flex;
-}
-
-.card-container {
+.bottom-button {
+ bottom: 0%;
+ margin: 10px 0;
display: flex;
}
-.pb-card:active {
- cursor: -webkit-grabbing;
- cursor: grabbing;
-}
-
-.cdk-drop-dragging .cdk-drag,
-.pb-card:not(.cdk-drag-placeholder) {
- transition: transform 150ms cubic-bezier(0, 0, 0.2, 1);
-}
-
-.cdk-drag-animating {
- transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);
+.pb-expand {
+ flex-direction: column;
}
::ng-deep .selectLayout div.mat-select-arrow-wrapper {
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.ts b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.ts
similarity index 70%
rename from Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.ts
rename to Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.ts
index 6b57e304c..5b071fa6c 100644
--- a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.ts
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/dashboard/dashboard.component.ts
@@ -1,6 +1,7 @@
import { CdkDragEnd, CdkDragEnter, moveItemInArray } from '@angular/cdk/drag-drop';
-import { BreakpointObserver } from '@angular/cdk/layout';
-import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
+import { Router } from '@angular/router';
+import { ChangeDetectorRef, Component, OnInit, OnDestroy } from '@angular/core';
import { Select, Store } from '@ngxs/store';
import { untilComponentDestroyed } from 'ng2-rx-componentdestroyed';
import { Observable, Subscription } from 'rxjs';
@@ -21,6 +22,9 @@ import {
ResetLastPersons,
SetLastPersons,
} from 'src/app/shared/states/LastPersons.state';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
+import { MatDrawerMode } from '@angular/material/sidenav';
+import { BookmarkedComponent } from 'src/app/pages/dashboard/components/bookmarked/bookmarked.component';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
@@ -30,11 +34,6 @@ import {
export class DashboardComponent implements OnInit, OnDestroy {
@Select(LastPersonsState)
public lastPersons$: Observable;
- public bookmarkedPersons: Person[];
- public bookmarkedPersonsSubscriptions: Subscription | null = null;
- public favoriteSort: PhonebookSortDirection = PhonebookSortDirection.none;
- public lastFrom: number;
- public lastTo: number;
@Select(BookmarksState)
public bookmarkedPersons$: Observable;
public removedLastPersons: Person[] | null = null;
@@ -44,15 +43,18 @@ export class DashboardComponent implements OnInit, OnDestroy {
public layout: typeof Layout = Layout;
public drawerOpen: boolean = false;
+ public drawerMode: MatDrawerMode = 'side';
public smallScreen: boolean = false;
+ public currentUser: Person | null = null;
constructor(
private store: Store,
private cd: ChangeDetectorRef,
- private breakpointObserver: BreakpointObserver
+ private breakpointObserver: BreakpointObserver,
+ public router: Router,
+ private currentUserService: CurrentUserService
) {}
public ngOnInit() {
- this.changeOrder();
this.store
.select(AppState.recentPeopleDrawer)
.pipe(untilComponentDestroyed(this))
@@ -70,39 +72,19 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.drawerOpen = this.store.selectSnapshot(AppState.recentPeopleDrawer);
}
});
- }
-
- public changeOrder() {
- if (this.bookmarkedPersonsSubscriptions) {
- this.bookmarkedPersonsSubscriptions.unsubscribe();
- }
- this.bookmarkedPersonsSubscriptions = this.store
- .select(BookmarksState.sortedBookmarks)
- .pipe(map((filterFn) => filterFn(this.favoriteSort)))
- .subscribe((persons) => {
- this.bookmarkedPersons = persons;
- });
- }
-
- public entered(e: CdkDragEnter) {
- if (this.bookmarkedPersons && this.bookmarkedPersons.length === 1) {
- return;
- }
-
- this.lastFrom = e.item.data;
- this.lastTo = e.container.data;
- }
-
- public ended(e: CdkDragEnd) {
- if (this.bookmarkedPersons && this.bookmarkedPersons.length === 1) {
- return;
- }
- if (this.lastFrom === undefined || this.lastTo === undefined) {
- return;
- }
- moveItemInArray(this.bookmarkedPersons, this.lastFrom, this.lastTo);
- this.store.dispatch(new UpdateBookmarkOrder(this.bookmarkedPersons));
- this.cd.detectChanges();
+ this.currentUserService
+ .getCurrentUser()
+ .pipe(untilComponentDestroyed(this))
+ .subscribe(
+ (user) => {
+ if (user != null) {
+ this.currentUser = user;
+ }
+ },
+ (error) => {
+ this.currentUser = null;
+ }
+ );
}
public resetLastPersons() {
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.html b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.html
new file mode 100644
index 000000000..f372074f5
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.html
@@ -0,0 +1,49 @@
+
+
+
+ people
+
+ My Team
+
+
+
+
+
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.scss b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.scss
new file mode 100644
index 000000000..a060c7bbb
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.scss
@@ -0,0 +1,35 @@
+.pb-team {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding-right: 10px;
+}
+.pb-small-card {
+ width: 320px;
+ height: 275px;
+}
+
+.card-container {
+ display: flex;
+}
+
+.pb-team-title {
+ display: flex;
+ flex-direction: row;
+ mat-icon {
+ display: inline-flex;
+ vertical-align: middle;
+ height: 29px;
+ width: 29px;
+ }
+ h1 {
+ margin: 0;
+ }
+ mat-form-field {
+ margin-left: 16px;
+ }
+ ::ng-deep .mat-form-field-infix {
+ border: none;
+ }
+}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.ts b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.ts
new file mode 100644
index 000000000..88bb046b9
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/components/team/team.component.ts
@@ -0,0 +1,42 @@
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Select, Store } from '@ngxs/store';
+import { Observable } from 'rxjs';
+import { Person } from 'src/app/shared/models';
+import { AppState } from 'src/app/shared/states';
+import { OrganigramService } from 'src/app/services/api/organigram.service';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
+import { Router } from '@angular/router';
+import { Layout } from 'src/app/shared/models/enumerables/Layout';
+
+@Component({
+ selector: 'app-team',
+ templateUrl: './team.component.html',
+ styleUrls: ['./team.component.scss'],
+ host: { class: 'pb-dashboard-component' },
+})
+export class TeamComponent implements OnInit, OnDestroy {
+ public currentUser: Person | null = null;
+ public teamPersons: Person[];
+ public person: Person;
+ @Select(AppState.activeLayout)
+ public activeLayout$: Observable;
+ public layouts: string[] = Object.values(Layout);
+ public layout: typeof Layout = Layout;
+
+ constructor(private organigramService: OrganigramService) {}
+
+ public ngOnInit() {
+ this.organigramService.getNodeForCurrentUser().subscribe((orgUnitOfUser) => {
+ if (orgUnitOfUser != null) {
+ this.teamPersons = [
+ ...orgUnitOfUser.supervisors,
+ ...orgUnitOfUser.assistents,
+ ...orgUnitOfUser.employees,
+ ...orgUnitOfUser.learners,
+ ];
+ }
+ });
+ }
+
+ public ngOnDestroy(): void {}
+}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/dashboard-routing.module.ts b/Phonebook.Frontend/src/app/pages/dashboard/dashboard-routing.module.ts
new file mode 100644
index 000000000..fde49e4ba
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/dashboard-routing.module.ts
@@ -0,0 +1,40 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { DashboardComponent } from 'src/app/pages/dashboard/components/dashboard/dashboard.component';
+import { BookmarkedComponent } from 'src/app/pages/dashboard/components/bookmarked/bookmarked.component';
+import { TeamComponent } from 'src/app/pages/dashboard/components/team/team.component';
+import { HasBookmarksGuard } from 'src/app/pages/dashboard/has-bookmarks.guard';
+import { IsAuthenticatedGuard } from 'src/app/shared/guards/is-authenticated.guard';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: DashboardComponent,
+ children: [
+ {
+ path: '',
+ pathMatch: 'full',
+ redirectTo: '/dashboard/bookmarks',
+ },
+ {
+ path: 'bookmarks',
+ component: BookmarkedComponent,
+ pathMatch: 'full',
+ canActivate: [HasBookmarksGuard],
+ },
+ {
+ path: 'team',
+ component: TeamComponent,
+ canActivate: [IsAuthenticatedGuard],
+ data: { guard: { redirectTo: '/dashboard/bookmarks' } },
+ },
+ ],
+ },
+ { path: '**', redirectTo: 'bookmarks' },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class DashboardRoutingModule {}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.html b/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.html
deleted file mode 100644
index b24fa48e3..000000000
--- a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.component.html
+++ /dev/null
@@ -1,202 +0,0 @@
-
-
-
-
-
- Recent People
-
-
-
-
-
-
-
-
-
-
- Looks like you haven't searched for any colleagues yet. Search for somebody to see how
- it works! The most recent ones will be displayed here.
-
-
-
-
-
-
-
-
-
- Bookmarked People
-
-
-
-
- Custom Order
-
- Alphabetical asc
-
- Alphabetical desc
-
-
-
-
-
-
-
- You haven't bookmarked anybody yet, look for the button
-
- on a workmates page.
-
-
-
-
-
-
-
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/dashboard.module.ts b/Phonebook.Frontend/src/app/pages/dashboard/dashboard.module.ts
new file mode 100644
index 000000000..b41d75256
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/dashboard.module.ts
@@ -0,0 +1,25 @@
+import { DragDropModule } from '@angular/cdk/drag-drop';
+import { NgModule } from '@angular/core';
+import { DashboardComponent } from 'src/app/pages/dashboard/components/dashboard/dashboard.component';
+import { UserModule } from 'src/app/shared/components/user/user.module';
+import { MaterialModule } from 'src/app/shared/material.module';
+import { BookmarkedComponent } from 'src/app/pages/dashboard/components/bookmarked/bookmarked.component';
+import { TeamComponent } from 'src/app/pages/dashboard/components/team/team.component';
+import { DashboardRoutingModule } from 'src/app/pages/dashboard/dashboard-routing.module';
+import { PipesModule } from 'src/app/shared/pipes/pipes.module';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+@NgModule({
+ declarations: [DashboardComponent, TeamComponent, BookmarkedComponent],
+ imports: [
+ CommonModule,
+ DashboardRoutingModule,
+ MaterialModule,
+ DragDropModule,
+ PipesModule,
+ UserModule,
+ FormsModule,
+ ],
+})
+export class DashboardModule {}
diff --git a/Phonebook.Frontend/src/app/pages/dashboard/has-bookmarks.guard.ts b/Phonebook.Frontend/src/app/pages/dashboard/has-bookmarks.guard.ts
new file mode 100644
index 000000000..3e7e76836
--- /dev/null
+++ b/Phonebook.Frontend/src/app/pages/dashboard/has-bookmarks.guard.ts
@@ -0,0 +1,37 @@
+import { Injectable } from '@angular/core';
+import {
+ CanActivate,
+ ActivatedRouteSnapshot,
+ RouterStateSnapshot,
+ UrlTree,
+ Router,
+} from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { Store } from '@ngxs/store';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
+import { BookmarksState } from 'src/app/shared/states';
+import { map, catchError } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class HasBookmarksGuard implements CanActivate {
+ constructor(
+ private store: Store,
+ private currentUserService: CurrentUserService,
+ private router: Router
+ ) {}
+ canActivate(): Observable | Promise | boolean | UrlTree {
+ return this.currentUserService.getCurrentUser().pipe(
+ map((user) => {
+ if (user != null && !this.store.selectSnapshot(BookmarksState.hasBookmarks)) {
+ return this.router.parseUrl('/dashboard/team');
+ }
+ return true;
+ }),
+ catchError((error) => {
+ return of(true);
+ })
+ );
+ }
+}
diff --git a/Phonebook.Frontend/src/app/services/api/organigram.service.spec.ts b/Phonebook.Frontend/src/app/services/api/organigram.service.spec.ts
index ff6b21923..05e708433 100644
--- a/Phonebook.Frontend/src/app/services/api/organigram.service.spec.ts
+++ b/Phonebook.Frontend/src/app/services/api/organigram.service.spec.ts
@@ -1,11 +1,14 @@
import { inject, TestBed } from '@angular/core/testing';
-import { OrganigramService } from './organigram.service';
+import { OrganigramService, UnitTreeNode } from './organigram.service';
import { PersonService } from './person.service';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { Person, Business } from 'src/app/shared/models';
import { HttpClient } from '@angular/common/http';
describe('OrganigramService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
providers: [
OrganigramService,
{ provide: PersonService, useValue: null },
@@ -13,8 +16,105 @@ describe('OrganigramService', () => {
],
});
});
-
it('should be created', inject([OrganigramService], (service: OrganigramService) => {
expect(service).toBeTruthy();
}));
+
+ const ORG_UNIT_ID: string = 'targetOrgUnit';
+ const nodeOfUser: UnitTreeNode = {
+ id: ORG_UNIT_ID,
+ name: 'bla',
+ depth: 0,
+ children: [],
+ supervisors: [],
+ assistents: [],
+ employees: [],
+ learners: [],
+ };
+ it('should return users OrgUnit (first level)', inject(
+ [OrganigramService],
+ (service: OrganigramService) => {
+ const user: Partial = {
+ Business: {
+ ShortOrgUnit: [ORG_UNIT_ID],
+ OrgUnit: [ORG_UNIT_ID],
+ } as Business,
+ };
+
+ const organigram: UnitTreeNode[] = [nodeOfUser];
+
+ expect(service.getNodeForUser(user as Person, organigram, 0)).toEqual(nodeOfUser);
+ }
+ ));
+
+ it('should return users OrgUnit (second level)', inject(
+ [OrganigramService],
+ (service: OrganigramService) => {
+ const user: Partial = {
+ Business: {
+ ShortOrgUnit: ['firstLevel', ORG_UNIT_ID],
+ OrgUnit: ['firstLevelName', ORG_UNIT_ID],
+ } as Business,
+ };
+ const organigram: UnitTreeNode[] = [
+ {
+ id: 'firstLevel',
+ name: 'firstLevelName',
+ children: [{ ...nodeOfUser, depth: 1 }],
+ } as UnitTreeNode,
+ ];
+
+ expect(service.getNodeForUser(user as Person, organigram, 0)).toEqual({
+ ...nodeOfUser,
+ depth: 1,
+ });
+ }
+ ));
+
+ it('should return users OrgUnit (third level)', inject(
+ [OrganigramService],
+ (service: OrganigramService) => {
+ const user: Partial = {
+ Business: {
+ ShortOrgUnit: ['firstLevel', 'secondLevel', ORG_UNIT_ID],
+ OrgUnit: ['firstLevelName', 'secondLevelName', ORG_UNIT_ID],
+ } as Business,
+ };
+
+ const organigram: UnitTreeNode[] = [
+ {
+ id: 'firstLevel',
+ name: 'firstLevelName',
+ children: [
+ {
+ id: 'secondLevel',
+ name: 'secondLevelName',
+ children: [{ ...nodeOfUser, depth: 2 }],
+ },
+ ],
+ } as UnitTreeNode,
+ ];
+
+ expect(service.getNodeForUser(user as Person, organigram, 0)).toEqual({
+ ...nodeOfUser,
+ depth: 2,
+ });
+ }
+ ));
+
+ it('should return null if OrgUnit not found', inject(
+ [OrganigramService],
+ (service: OrganigramService) => {
+ const user: Partial = {
+ Business: {
+ ShortOrgUnit: [ORG_UNIT_ID],
+ OrgUnit: [ORG_UNIT_ID],
+ } as Business,
+ };
+
+ const organigram: UnitTreeNode[] = [];
+
+ expect(service.getNodeForUser(user as Person, organigram, 0)).toEqual(null);
+ }
+ ));
});
diff --git a/Phonebook.Frontend/src/app/services/api/organigram.service.ts b/Phonebook.Frontend/src/app/services/api/organigram.service.ts
index c81ef15de..253fd8a11 100644
--- a/Phonebook.Frontend/src/app/services/api/organigram.service.ts
+++ b/Phonebook.Frontend/src/app/services/api/organigram.service.ts
@@ -1,32 +1,64 @@
import { Injectable } from '@angular/core';
-import { Observable, forkJoin, of } from 'rxjs';
+import { Observable, forkJoin, of, combineLatest } from 'rxjs';
import { map, flatMap, publishReplay, refCount } from 'rxjs/operators';
import { Person } from 'src/app/shared/models';
import { PersonService } from './person.service';
import { HttpClient } from '@angular/common/http';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
@Injectable()
export class OrganigramService {
- constructor(private http: HttpClient, private personService: PersonService) {}
+ constructor(
+ private http: HttpClient,
+ private personService: PersonService,
+ private currentUserService: CurrentUserService
+ ) {}
public organigram: Observable;
- public getOrganigram(): Observable {
+ public orgUnits: Observable;
+ public team: UnitTreeNode;
+
+ public getOrgUnits(): Observable {
+ if (this.orgUnits != null) {
+ return this.orgUnits;
+ }
+ this.orgUnits = this.http.get('/api/OrgUnit').pipe(
+ publishReplay(1), // this tells Rx to cache the latest emitted
+ refCount()
+ );
+ return this.orgUnits;
+ }
+
+ public getOrganigramTree(): Observable {
if (this.organigram != null) {
return this.organigram;
}
- this.organigram = this.http.get('/api/OrgUnit').pipe(
+ this.organigram = this.getOrgUnits().pipe(
flatMap((d) => this.ConvertOrgUnitsToUnitTree(d)),
publishReplay(1), // this tells Rx to cache the latest emitted
refCount()
);
return this.organigram;
}
+ public getOrganigramById(id: string): Observable {
+ return this.getOrganigramTree().pipe(
+ map((orgUnitArray) => {
+ const orgUnit = orgUnitArray.find((x) => {
+ return x.id === id;
+ });
+ if (orgUnit === undefined) {
+ return null;
+ }
+ return orgUnit;
+ })
+ );
+ }
private ConvertOrgUnitsToUnitTree(
orgUnits: OrgUnit[],
depth: number = 0
): Observable {
return forkJoin(
orgUnits.map((o) => {
- var TaShortNames = o.OrgUnitToFunctions.filter((f) => f.RoleName == 'TA').map(
+ let TaShortNames = o.OrgUnitToFunctions.filter((f) => f.RoleName == 'TA').map(
(t) => t.Person.ShortName
);
return forkJoin(
@@ -42,7 +74,7 @@ export class OrganigramService {
o.ShortName == null ? of([]) : this.personService.getByOrgUnit(o.ShortName)
).pipe(
map(([childs, headofOrgUnit, assistents, members]) => {
- var tree = new UnitTreeNode(
+ let tree = new UnitTreeNode(
o.ShortName == null ? '' : o.ShortName,
o.Name == null ? '' : o.Name,
depth,
@@ -58,6 +90,40 @@ export class OrganigramService {
})
);
}
+
+ public getNodeForCurrentUser(): Observable {
+ return combineLatest([this.currentUserService.getCurrentUser(), this.getOrganigramTree()]).pipe(
+ map(([user, organigram]) => {
+ if (user === null) {
+ return null;
+ }
+ return this.getNodeForUser(user, organigram, 0);
+ })
+ );
+ }
+
+ public getNodeForUser(
+ user: Person,
+ nodeChilds: UnitTreeNode[],
+ depth: number
+ ): UnitTreeNode | null {
+ if (user.Business.ShortOrgUnit.length > depth) {
+ for (const node of nodeChilds) {
+ if (node.id === user.Business.ShortOrgUnit[depth] && node.depth === depth) {
+ if (user.Business.ShortOrgUnit.length == depth + 1) {
+ return node;
+ }
+ return this.getNodeForUser(user, node.children, depth + 1);
+ }
+ if (node.id !== user.Business.ShortOrgUnit[depth] && node.depth === depth) {
+ continue;
+ } else {
+ return this.getNodeForUser(user, node.children, depth + 1);
+ }
+ }
+ }
+ return null;
+ }
}
export class UnitTreeNode {
diff --git a/Phonebook.Frontend/src/app/shared/guards/is-authenticated.guard.ts b/Phonebook.Frontend/src/app/shared/guards/is-authenticated.guard.ts
new file mode 100644
index 000000000..6ac2385b0
--- /dev/null
+++ b/Phonebook.Frontend/src/app/shared/guards/is-authenticated.guard.ts
@@ -0,0 +1,41 @@
+import { Injectable } from '@angular/core';
+import {
+ CanActivate,
+ ActivatedRouteSnapshot,
+ RouterStateSnapshot,
+ UrlTree,
+ Router,
+} from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { CurrentUserService } from 'src/app/services/api/current-user.service';
+import { Store } from '@ngxs/store';
+import { catchError, map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class IsAuthenticatedGuard implements CanActivate {
+ public defaultPath: string = '/';
+
+ constructor(
+ private store: Store,
+ private currentUserService: CurrentUserService,
+ private router: Router
+ ) {}
+ canActivate(
+ next: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot
+ ): Observable | Promise | boolean | UrlTree {
+ return this.currentUserService.getCurrentUser().pipe(
+ map((user) => {
+ if (user === null) {
+ return this.router.parseUrl(next.data.guard.redirectTo || this.defaultPath);
+ }
+ return true;
+ }),
+ catchError((error) => {
+ return of(this.router.parseUrl(next.data.guard.redirectTo || this.defaultPath));
+ })
+ );
+ }
+}
diff --git a/Phonebook.Frontend/src/app/shared/states/Bookmarks.state.ts b/Phonebook.Frontend/src/app/shared/states/Bookmarks.state.ts
index 3d72366ee..be5ce35a3 100644
--- a/Phonebook.Frontend/src/app/shared/states/Bookmarks.state.ts
+++ b/Phonebook.Frontend/src/app/shared/states/Bookmarks.state.ts
@@ -33,6 +33,11 @@ export class BookmarksState {
};
}
+ @Selector()
+ public static hasBookmarks(state: Person[]) {
+ return state.length > 0;
+ }
+
@Action(ToggleBookmark)
public toggleBookmark(ctx: StateContext, action: ToggleBookmark) {
const state = ctx.getState();
diff --git a/Phonebook.Frontend/src/i18n/messages.de.xlf b/Phonebook.Frontend/src/i18n/messages.de.xlf
index 57fd64de7..45613908a 100644
--- a/Phonebook.Frontend/src/i18n/messages.de.xlf
+++ b/Phonebook.Frontend/src/i18n/messages.de.xlf
@@ -401,6 +401,10 @@
Title of the Bookmarked people
section
DashboardComponent
+
+ Mein Team
+ Title of the Team people section
+ DashboardComponent
Eigene Reihenfolge
diff --git a/Phonebook.Frontend/src/i18n/messages.en.xlf b/Phonebook.Frontend/src/i18n/messages.en.xlf
index db3394a93..b5cbca910 100644
--- a/Phonebook.Frontend/src/i18n/messages.en.xlf
+++ b/Phonebook.Frontend/src/i18n/messages.en.xlf
@@ -327,6 +327,10 @@
Title of the Bookmarked people
section
DashboardComponent
+
+ My Team
+ Title of the Team people section
+ DashboardComponent
Custom Order
The standard (customizable) order of the favorite
diff --git a/Phonebook.Frontend/src/i18n/messages.xlf b/Phonebook.Frontend/src/i18n/messages.xlf
index 78871a898..b850e16de 100644
--- a/Phonebook.Frontend/src/i18n/messages.xlf
+++ b/Phonebook.Frontend/src/i18n/messages.xlf
@@ -199,6 +199,11 @@
section
DashboardComponent
+
+
+ Title of the Team people section
+ DashboardComponent
+
The standard (customizable) order of the favorite
diff --git a/Phonebook.Frontend/src/styles.scss b/Phonebook.Frontend/src/styles.scss
index 0b60f0167..9690a1d7c 100644
--- a/Phonebook.Frontend/src/styles.scss
+++ b/Phonebook.Frontend/src/styles.scss
@@ -20,6 +20,13 @@ app-root {
display: flex;
}
+.pb-dashboard-component {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ overflow: auto;
+}
+
.circle {
border-radius: 50%;
overflow: hidden;
@@ -52,6 +59,10 @@ app-root {
flex-grow: 1;
}
+.pb-margin-0 {
+ margin: 0 !important;
+}
+
.pb-margin-20 {
margin: 20px;
}
@@ -150,6 +161,11 @@ app-root {
}
}
+.pb-card {
+ margin: 5px;
+ display: flex;
+}
+
.pb-margin-left-right-responsive {
margin: auto 15%;
diff --git a/Phonebook.Frontend/src/styles/overrides.scss b/Phonebook.Frontend/src/styles/overrides.scss
index 5274047bf..3e7eba1a5 100644
--- a/Phonebook.Frontend/src/styles/overrides.scss
+++ b/Phonebook.Frontend/src/styles/overrides.scss
@@ -47,3 +47,14 @@ mat-card.mat-card {
}
}
}
+
+// Centers icons in mat-button
+
+button[mat-button] {
+ div {
+ display: flex;
+ mat-icon {
+ margin: auto 15px auto 0;
+ }
+ }
+}