src/app/home/home.component.ts
import { Component, OnInit, ViewChild, ElementRef, DoCheck, AfterViewChecked, HostListener, OnDestroy } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
import { environment } from '../../environments/environment';
import { UserService } from '../shared/user.service';
import { CouchService } from '../shared/couchdb.service';
import { Router } from '@angular/router';
import { Subject, interval, of } from 'rxjs';
import { switchMap, takeUntil, tap, catchError } from 'rxjs/operators';
import { debug } from '../debug-operator';
import { findDocuments } from '../shared/mangoQueries';
import { PouchAuthService } from '../shared/database/pouch-auth.service';
import { StateService } from '../shared/state.service';
import { DeviceInfoService } from '../shared/device-info.service';
import { NotificationsService } from '../notifications/notifications.service';
@Component({
templateUrl: './home.component.html',
styleUrls: [ './home.scss' ],
animations: [
trigger('sidenavState', [
state('closed', style({
width: '72px'
})),
state('open', style({
width: '175px'
})),
transition('closed <=> open', animate('500ms ease'))
])
]
})
export class HomeComponent implements OnInit, DoCheck, AfterViewChecked, OnDestroy {
notifications = [];
user: any = {};
userImgSrc = '';
layout = 'classic';
forceModern: boolean;
sidenavState = 'closed';
classicToolbarWidth = 0;
@ViewChild('content') private mainContent;
@ViewChild('toolbar', { read: ElementRef }) private toolbar: ElementRef;
planetName;
isAndroid: boolean;
showBanner = true;
// Sets the margin for the main content to match the sidenav width
animObs = interval(15).pipe(
debug('Menu animation'),
tap(() => {
this.mainContent.updateContentMargins();
this.mainContent._changeDetectorRef.markForCheck();
}
));
// For disposable returned by observer to unsubscribe
animDisp: any;
onlineStatus = 'offline';
configuration = this.stateService.configuration;
planetType = this.stateService.configuration.planetType;
private onDestroy$ = new Subject<void>();
constructor(
private couchService: CouchService,
private router: Router,
private userService: UserService,
private pouchAuthService: PouchAuthService,
private stateService: StateService,
private deviceInfoService: DeviceInfoService,
private notificationsService: NotificationsService
) {
this.userService.userChange$.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.onUserUpdate();
});
this.couchService.get('_node/nonode@nohost/_config/planet').subscribe((res: any) => this.layout = res.layout || 'classic');
this.onlineStatus = this.stateService.configuration.registrationRequest;
this.isAndroid = this.deviceInfoService.isAndroid();
}
ngOnInit() {
this.getNotification();
this.onUserUpdate();
this.userService.notificationStateChange$.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
this.getNotification();
});
this.planetName = this.stateService.configuration.name;
this.stateService.couchStateListener('configurations').subscribe((res) => {
if (res !== undefined) {
this.planetName = this.stateService.configuration.name;
}
});
this.subscribeToLogoutClick();
}
ngDoCheck() {
this.onResize();
}
ngAfterViewChecked() {
const toolbarElement = this.toolbar.nativeElement;
const toolbarStyle = window.getComputedStyle(toolbarElement);
const navbarCenter = toolbarElement.querySelector('.navbar-center');
if (navbarCenter !== null) {
this.classicToolbarWidth =
toolbarElement.querySelector('.navbar-left').offsetWidth +
navbarCenter.offsetWidth +
toolbarElement.querySelector('.navbar-right').offsetWidth +
parseInt(toolbarStyle.paddingLeft, 10) +
parseInt(toolbarStyle.paddingRight, 10);
this.mainContent._changeDetectorRef.markForCheck();
}
}
ngOnDestroy() {
this.onDestroy$.next();
this.onDestroy$.complete();
}
@HostListener('window:resize') onResize() {
const isScreenTooNarrow = window.innerWidth < this.classicToolbarWidth;
if (this.forceModern !== isScreenTooNarrow) {
this.forceModern = isScreenTooNarrow;
}
}
// Used to swap in different background.
// Should remove when background is finalized.
backgroundRoute() {
const url = this.router.url;
const routesWithBackground = [
'resources', 'courses', 'feedback', 'users', 'meetups', 'requests', 'associated', 'submissions', 'teams', 'surveys', 'news',
'mySurveys', 'myHealth', 'myCourses', 'myLibrary', 'myTeams', 'enterprises', 'certifications', 'myDashboard', 'nation', 'earth',
'health', 'myPersonals', 'community'
];
// Leaving the exception variable in so we can easily use this while still testing backgrounds
const routesWithoutBackground = [];
const isException = routesWithoutBackground
.findIndex((route) => url.indexOf(route) > -1) > -1;
const isRoute = routesWithBackground
.findIndex((route) => url.indexOf(route) > -1) > -1;
return url === '/' || isRoute && !isException;
}
onUserUpdate() {
this.user = this.userService.get();
if (this.user._attachments) {
const filename = Object.keys(this.user._attachments)[0];
this.userImgSrc = environment.couchAddress + '/_users/org.couchdb.user:' + this.user.name + '/' + filename;
} else {
this.userImgSrc = '';
}
}
subscribeToLogoutClick() {
this.userService.userLogout$
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => this.logoutClick());
}
logoutClick() {
const configuration = this.stateService.configuration;
const errorCatch = error => {
console.log(error);
return of({});
};
this.userService.endSessionLog().pipe(
catchError(errorCatch),
switchMap(() => this.pouchAuthService.logout()),
switchMap(() => {
const localAdminName = configuration.adminName.split('@')[0];
if (localAdminName === this.userService.get().name) {
return this.couchService.delete('_session', { withCredentials: true, domain: configuration.parentDomain });
}
return of({});
}),
catchError(errorCatch)
).subscribe((response: any) => {
this.userService.unset();
this.router.navigate([ '/login' ], {});
});
}
getNotification() {
const userFilter = [ {
'user': 'org.couchdb.user:' + this.userService.get().name
} ];
if (this.userService.get().isUserAdmin) {
userFilter.push({ 'user': 'SYSTEM' });
}
this.couchService.findAll('notifications', findDocuments(
{ '$or': userFilter,
// The sorted item must be included in the selector for sort to work
'time': { '$gt': 0 },
'status': 'unread'
},
0,
[ { 'time': 'desc' } ]))
.subscribe(data => {
this.notifications = data;
}, (error) => console.log(error));
}
readNotification(notification) {
const updateNotificaton = { ...notification, 'status': 'read' };
this.couchService.put('notifications/' + notification._id, updateNotificaton).subscribe((data) => {
this.userService.setNotificationStateChange();
}, (err) => console.log(err));
}
/**
* Used for marking all notifications as read from navigation bar
*/
readAllNotification() {
this.notificationsService.setNotificationsAsRead(this.notifications);
}
sizeChange(forceModern: boolean) {
this.forceModern = forceModern;
}
toggleNav() {
this.sidenavState = this.sidenavState === 'open' ? 'closed' : 'open';
this.animDisp = this.animObs.subscribe();
}
endAnimation() {
if (this.animDisp) {
this.animDisp.unsubscribe();
}
}
}