Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue 243] Initial profile summaries export component #269

Merged
7 commits merged into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 141 additions & 1 deletion src/app/+data-and-analytics/data-and-analytics.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,141 @@
<span class="h1">Data And Analytics</span>
<scholars-sidebar>
<!-- view navigation -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page">
<a [routerLink]="['/data-and-analytics']">{{ 'DATA_AND_ANALYTICS.LABEL' | translate }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page" *ngIf="dataAndAnalyticsView | async; let view">
<a [routerLink]="['/data-and-analytics', view.name]">{{ view.name }} </a>
</li>
</ol>
</nav>

<!-- organization navigation -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb" *ngIf="organizations | async; let organizations">
<ng-template ngFor let-organization [ngForOf]="organizations" let-i="organization" let-index="index" [ngForTrackBy]="trackByIndex">
<li class="breadcrumb-item active" aria-current="page">
<a (click)="onNavigateOrganization(organizations, index)">{{ organization.name }}</a>
</li>
</ng-template>
</ol>
</nav>

<div *ngIf="displayView | async; let displayView">
<div *ngIf="selectedOrganization | async; let organization">

<div class="card-columns" *ngIf="isDashboard | async" [@fadeIn]>
<ng-template ngFor let-view [ngForOf]="dataAndAnalyticsViews | async" let-i="view" [ngForTrackBy]="trackByIndex">
<div class="card">
<a [routerLink]="[view.name]" [queryParams]="getQueryParams(queryParams | async, displayView, view)" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<div class="card-header">
<div class="h4 text-bold text-nowrap">{{ organization.name }}</div>
<div class="h5 text-bold">{{ view.name }}</div>
</div>
<div class="card-body" [ngSwitch]="view.layout">
<div *ngSwitchCase="'CONTAINER'">
<div [ngSwitch]="view.type">
<div *ngSwitchCase="'ACADEMIC_AGE_GROUP'">
<span>{{ view.type }}</span>
</div>
<div *ngSwitchCase="'QUANTITY_DISTRIBUTION'">
<span>{{ view.type }}</span>
</div>
<div *ngSwitchCase="'PROFILE_SUMMARIES_EXPORT'">
<span>{{ view.type }}</span>
</div>
<div *ngSwitchDefault>{{ view.layout }} Unknown</div>
</div>
</div>
<div *ngSwitchCase="'GRID'">{{ view.layout }} Not Supported</div>
<div *ngSwitchCase="'LIST'">{{ view.layout }} Not Supported</div>
<div *ngSwitchDefault>{{ view.layout }} Unknown</div>
</div>
</a>
</div>
</ng-template>
</div>

<div [@fadeIn] *ngIf="dataAndAnalyticsView | async; let dataAndAnalyticsView">
<div class="card-deck">
<div class="card">
<div class="card-header">
{{ dataAndAnalyticsView.name }}
</div>
<div class="card-body" [ngSwitch]="dataAndAnalyticsView.layout">

<div class="row p-1 mb-2">
<div class="col-12">
<span class="h4 font-weight-bold">{{ label | async }}</span>
</div>
</div>

<div class="row p-1 mb-3">
<div class="col-12">
<span class="h4 font-weight-bold">{{ 'DATA_AND_ANALYTICS.ORGANIZATION' | translate }}: </span>
<span class="h4">{{ organization.name }} ({{ organization.people.length }})</span>
</div>
</div>

<div class="row p-1">
<div class="col-4" *ngIf="(colleges | async).length > 0">
<div class="form-group">
<label class="font-weight-bold">{{ 'DATA_AND_ANALYTICS.COLLEGE' | translate }}</label>
<select class="form-control" ngModel (ngModelChange)="onSelectOrganization($event)">
<option value="" disabled selected>{{ 'DATA_AND_ANALYTICS.SELECT' | translate }}</option>
<option *ngFor="let so of colleges | async" [ngValue]="so.id">{{ so.label }}</option>
</select>
</div>
</div>
<div class="col-4" *ngIf="(departments | async).length > 0">
<div class="form-group">
<label class="font-weight-bold">{{ 'DATA_AND_ANALYTICS.DEPARTMENT' | translate }}</label>
<select class="form-control" ngModel (ngModelChange)="onSelectOrganization($event)">
<option value="" disabled selected>{{ 'DATA_AND_ANALYTICS.SELECT' | translate }}</option>
<option *ngFor="let so of departments | async" [ngValue]="so.id">{{ so.label }}</option>
</select>
</div>
</div>
<div class="col-4" *ngIf="(others | async).length > 0">
<div class="form-group">
<label class="font-weight-bold">{{ 'DATA_AND_ANALYTICS.OTHERS' | translate }}</label>
<select class="form-control" ngModel (ngModelChange)="onSelectOrganization($event)">
<option value="" disabled selected>{{ 'DATA_AND_ANALYTICS.SELECT' | translate }}</option>
<option *ngFor="let so of others | async" [ngValue]="so.id">{{ so.label }}</option>
</select>
</div>
</div>
</div>

<div *ngSwitchCase="'CONTAINER'">
<div [ngSwitch]="dataAndAnalyticsView.type">
<div *ngSwitchCase="'ACADEMIC_AGE_GROUP'">
<span>{{ dataAndAnalyticsView.type }} In Progress</span>
</div>
<div *ngSwitchCase="'QUANTITY_DISTRIBUTION'">
<span>{{ dataAndAnalyticsView.type }} In Progress</span>
</div>
<div *ngSwitchCase="'PROFILE_SUMMARIES_EXPORT'">
<scholars-profile-summaries-export
[organization]="selectedOrganization | async"
[displayView]="displayView"
[dataAndAnalyticsView]="dataAndAnalyticsView"
(labelEvent)="onLabelEvent($event)">
</scholars-profile-summaries-export>
</div>
<div *ngSwitchDefault>{{ dataAndAnalyticsView.type }} Unknown</div>
</div>
</div>
<div *ngSwitchCase="'GRID'">{{ dataAndAnalyticsView.layout }} Not Supported</div>
<div *ngSwitchCase="'LIST'">{{ dataAndAnalyticsView.layout }} Not Supported</div>
<div *ngSwitchDefault>{{ dataAndAnalyticsView.layout }} Unknown</div>
</div>
</div>
</div>
</div>

</div>
</div>

</scholars-sidebar>
23 changes: 23 additions & 0 deletions src/app/+data-and-analytics/data-and-analytics.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
:host {
width: 100%;
.card-columns {
.card {
a:hover {
text-decoration: none;
}
}
.card:hover {
border-color: rgba(82,168,236,.8);
box-shadow: 0 0px 0px rgba(82,168,236,.8) inset, 0 0 8px rgba(82,168,236,.8);
outline: 0 none;
}
}
.card-header {
color: black;
}
.breadcrumb-item {
a:hover {
cursor: pointer;
}
}
}
190 changes: 173 additions & 17 deletions src/app/+data-and-analytics/data-and-analytics.component.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,189 @@
import { ChangeDetectionStrategy, Component, Inject, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { ChangeDetectionStrategy, Component, HostListener, OnInit } from '@angular/core';
import { Params } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { BehaviorSubject, Observable, filter, map, take, tap, withLatestFrom } from 'rxjs';

import { APP_CONFIG, AppConfig } from '../app.config';
import { SolrDocument } from '../core/model/discovery';
import { DataAndAnalyticsView, DisplayView } from '../core/model/view';
import { ContainerType } from '../core/model/view/data-and-analytics-view';
import { AppState } from '../core/store';
import { selectRouterQueryParams, selectRouterState } from '../core/store/router';
import { selectAllResources, selectDisplayViewByTypes, selectResourceById } from '../core/store/sdr';
import { selectActiveThemeOrganizationId } from '../core/store/theme';
import { fadeIn } from '../shared/utilities/animation.utility';

import * as fromLayout from '../core/store/layout/layout.actions';
import * as fromSdr from '../core/store/sdr/sdr.actions';
import * as fromSidebar from '../core/store/sidebar/sidebar.actions';

@Component({
selector: 'scholars-data-and-analytics',
templateUrl: 'data-and-analytics.component.html',
styleUrls: ['data-and-analytics.component.scss'],
animations: [fadeIn],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DataAndAnalyticsComponent implements OnDestroy {
export class DataAndAnalyticsComponent implements OnInit {

public displayView: Observable<DisplayView>;

public dataAndAnalyticsView: Observable<DataAndAnalyticsView>;

public dataAndAnalyticsViews: Observable<DataAndAnalyticsView[]>;

public organization: Observable<SolrDocument>;

public isDashboard: Observable<boolean>;

public queryParams: Observable<Params>;

public organizations: Observable<SolrDocument[]>;

public selectedOrganizationSubject: BehaviorSubject<SolrDocument>;

public selectedOrganization: Observable<SolrDocument>;

public labelSubject: BehaviorSubject<string>;

private subscriptions: Subscription[];
public get colleges(): Observable<any[]> {
return this.selectedOrganization.pipe(
map((org: SolrDocument) => this.filterSubOrganization(org, ['College']))
);
};

constructor(
@Inject(APP_CONFIG) private appConfig: AppConfig,
private store: Store<AppState>,
private router: Router,
private route: ActivatedRoute
) {
this.subscriptions = [];
public get departments(): Observable<any[]> {
return this.selectedOrganization.pipe(
map((org: SolrDocument) => this.filterSubOrganization(org, ['AcademicDepartment']))
);
};

public get others(): Observable<any[]> {
return this.selectedOrganization.pipe(
map((org: SolrDocument) => this.filterSubOrganization(org, ['!College', '!Department']))
);
};

public get label(): Observable<string> {
return this.labelSubject.asObservable();
}

@HostListener('window:resize', ['$event'])
public onResize(event): void {
this.store.dispatch(new fromLayout.CloseSidebarAction());
}

constructor(private store: Store<AppState>) {
this.selectedOrganizationSubject = new BehaviorSubject<SolrDocument>(undefined);
this.selectedOrganization = this.selectedOrganizationSubject.asObservable()
.pipe(filter((org: SolrDocument) => !!org));
this.labelSubject = new BehaviorSubject<string>('Test');
}

ngOnDestroy() {
this.subscriptions.forEach((subscription: Subscription) => {
subscription.unsubscribe();
ngOnInit() {
this.store.dispatch(new fromSidebar.UnloadSidebarAction());
this.store.dispatch(new fromLayout.CloseSidebarAction());
this.store.dispatch(new fromSdr.ClearResourcesAction('individual'));

this.queryParams = this.store.pipe(select(selectRouterQueryParams));

this.dataAndAnalyticsViews = this.store.pipe(select(selectAllResources<DataAndAnalyticsView>('dataAndAnalyticsViews')));

this.dataAndAnalyticsView = this.store.pipe(
select(selectRouterState),
withLatestFrom(this.dataAndAnalyticsViews),
map(([router, views]) => views.find((view: DataAndAnalyticsView) => !!router && view.name === router.state.params.view))
);

this.isDashboard = this.store.pipe(
select(selectRouterState),
map((router: any) => !!router && router.state.url === '/data-and-analytics')
);

this.organizations = this.store.pipe(
select(selectAllResources('individual')),
tap((organizations: SolrDocument[]) => {
this.selectedOrganizationSubject.next(organizations[organizations.length - 1]);
})
);

this.store.select(selectActiveThemeOrganizationId)
.pipe(
filter(id => id !== undefined),
take(1)
).subscribe(id => {
this.store.pipe(
select(selectResourceById('individual', id)),
filter((document: SolrDocument) => document !== undefined)
).pipe(take(1))
.subscribe((document) => {

this.displayView = this.store.pipe(
select(selectDisplayViewByTypes(document.type)),
filter((displayView: DisplayView) => displayView !== undefined)
);

this.store.dispatch(
new fromSdr.FindByTypesInResourceAction('displayViews', {
types: document.type,
})
);
});

this.organization = this.store.select(selectResourceById('individual', id));

this.store.dispatch(new fromSdr.GetOneResourceAction('individual', { id }));
});
}

public trackByIndex(index, item) {
return index;
}

public onNavigateOrganization(organizations: SolrDocument[], index: number): void {
let org;
while (!!(org = organizations[++index])) {
const id = org.id;
kaladay marked this conversation as resolved.
Show resolved Hide resolved
this.store.dispatch(new fromSdr.ClearResourceByIdAction('individual', { id }));
}
}

public onSelectOrganization(id: any): void {
this.store.dispatch(new fromSdr.GetOneResourceAction('individual', { id }));
}

public getQueryParams(params: Params, displayView: DisplayView, view: DataAndAnalyticsView): Params {
const queryParams: Params = { ...params };

switch (view.type) {
case ContainerType.ACADEMIC_AGE_GROUP: break;
case ContainerType.QUANTITY_DISTRIBUTION: break;
case ContainerType.PROFILE_SUMMARIES_EXPORT:
if (displayView.exportViews.length > 0) {
queryParams.export = displayView.exportViews[0].name;
}
break;
default: break;
}

return queryParams;
}

public onLabelEvent(label: string): void {
this.labelSubject.next(label);
}

private filterSubOrganization(organization: any, types: string[]): any[] {
const subOrganizations = !!organization.hasSubOrganizations ? organization.hasSubOrganizations : [];

return subOrganizations.filter(so => {
for (const type of types) {
const match = type.startsWith('!') ? so.type !== type : so.type === type;
if (!match) {
return false;
}
}

return true;
});
}

Expand Down
8 changes: 6 additions & 2 deletions src/app/+data-and-analytics/data-and-analytics.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import { SharedModule } from '../shared/shared.module';
import { CustomMissingTranslationHandler } from '../core/handler/custom-missing-translation.handler';

import { DataAndAnalyticsComponent } from './data-and-analytics.component';
import { ProfileSummariesExportComponent } from './profile-summaries-export/profile-summaries-export.component';

import { routes } from './data-and-analytics.routes';

@NgModule({
declarations: [DataAndAnalyticsComponent],
declarations: [
DataAndAnalyticsComponent,
ProfileSummariesExportComponent
],
imports: [
CommonModule,
SharedModule,
Expand All @@ -24,7 +28,7 @@ import { routes } from './data-and-analytics.routes';
isolate: false,
}),
RouterModule.forChild(routes),
],
]
})
export class DataAndAnalyticsModule {

Expand Down
Loading
Loading