Skip to content
Open
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
3 changes: 3 additions & 0 deletions client/angular.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"cli": {
"analytics": false
},
"version": 1,
"newProjectRoot": "projects",
"projects": {
Expand Down
5 changes: 5 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"classlist.js": "^1.1.20150312",
"foundation-sites": "^6.6.3",
"fuse.js": "^6.4.6",
"fuzzy-search": "^3.2.1",
"graphql": "^15.5.0",
"graphql-tag": "^2.11.0",
"html2canvas": "1.0.0-rc.7",
Expand Down
19 changes: 19 additions & 0 deletions client/src/app/services/guest.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class GuestService {

constructor() { }
chartItemSelected = new Subject();
chartItemSelected$ = this.chartItemSelected.asObservable();
setChartItemSelected(value: string[]) {
this.chartItemSelected.next(value);
}

getchartItemSelected() {
return this.chartItemSelected$;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {isPlatformBrowser} from '@angular/common';

import * as am4core from '@amcharts/amcharts4/core';
import * as am4charts from '@amcharts/amcharts4/charts';
import { __values } from 'tslib';
import { GuestService } from 'src/app/services/guest.service';

@Component({
selector: 'app-column',
Expand All @@ -38,7 +40,9 @@ export class ColumnComponent implements OnInit, AfterViewInit, OnChanges, OnDest

private chart: am4charts.XYChart;

constructor(@Inject(PLATFORM_ID) private platformId, private zone: NgZone) {
constructor(@Inject(PLATFORM_ID) private platformId,
private zone: NgZone,
private guestService: GuestService) {
}

// Run the function only in the browser
Expand Down Expand Up @@ -150,8 +154,29 @@ export class ColumnComponent implements OnInit, AfterViewInit, OnChanges, OnDest
chart.cursor.behavior = 'panX';
chart.data = this.data;
this.chart = chart;
const guestService = this.guestService;

chart.legend.itemContainers.template.events.on("hit", function(ev) {
let name = ev.target.dataItem.dataContext['_legendDataItem']['name'];
const active = ev.target['_isActive'];
let itemsActive = [];
chart.legend?.labels?.values?.forEach(item => {
if((name != item?.currentText && !item?.isActive) || (name == item?.currentText && active)) {
itemsActive = [...itemsActive, ...[item.currentText]];
}
});
guestService.setChartItemSelected(itemsActive);
});
});
}

setSerieActive(series: any[], name: string) {
series.forEach(item => {
console.log(item.name == name);
if(item.name == name) item.isActive = false;
console.log(item.name);
});
console.log(series);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import * as am4charts from '@amcharts/amcharts4/charts';
import {isPlatformBrowser} from '@angular/common';
import * as am4core from '@amcharts/amcharts4/core';
import { GuestService } from 'src/app/services/guest.service';

@Component({
selector: 'app-pie',
Expand All @@ -34,7 +35,7 @@ export class PieComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy
private chart: am4charts.SlicedChart;
iconPath = 'M53.5,476c0,14,6.833,21,20.5,21s20.5-7,20.5-21V287h21v189c0,14,6.834,21,20.5,21 c13.667,0,20.5-7,20.5-21V154h10v116c0,7.334,2.5,12.667,7.5,16s10.167,3.333,15.5,0s8-8.667,8-16V145c0-13.334-4.5-23.667-13.5-31 s-21.5-11-37.5-11h-82c-15.333,0-27.833,3.333-37.5,10s-14.5,17-14.5,31v133c0,6,2.667,10.333,8,13s10.5,2.667,15.5,0s7.5-7,7.5-13 V154h10V476 M61.5,42.5c0,11.667,4.167,21.667,12.5,30S92.333,85,104,85s21.667-4.167,30-12.5S146.5,54,146.5,42 c0-11.335-4.167-21.168-12.5-29.5C125.667,4.167,115.667,0,104,0S82.333,4.167,74,12.5S61.5,30.833,61.5,42.5z';

constructor(@Inject(PLATFORM_ID) private platformId, private zone: NgZone) {
constructor(@Inject(PLATFORM_ID) private platformId, private zone: NgZone, private guestService: GuestService) {
}

// Run the function only in the browser
Expand Down Expand Up @@ -84,6 +85,18 @@ export class PieComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy

this.chart = chart;
this.chart.data = this.data;
const guestService = this.guestService;
chart.legend.itemContainers.template.events.on("hit", function(ev) {
let name = ev.target.dataItem.dataContext['_legendDataItem']['name'];
const active = ev.target['_isActive'];
let itemsActive = [];
chart.legend?.labels?.values?.forEach(item => {
if((name != item?.currentText && !item?.isActive) || (name == item?.currentText && active)) {
itemsActive = [...itemsActive, ...[item.currentText]];
}
});
guestService.setChartItemSelected(itemsActive);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {ProcessApisMockService} from '../../../apis/process/process.apis.mock.se

</div>
</div>
<app-guest-list></app-guest-list>
<div class="flex-container align-justify margin-top-2">
<ng-content></ng-content>
</div>
Expand Down
5 changes: 4 additions & 1 deletion client/src/app/shared/features/dashboard/dashboard.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {StatisticComponent} from "./statistic/statistic.component";
import {ChartModule} from "../chart/chart.module";
import {MatButtonModule} from "@angular/material/button";
import {RouterModule} from "@angular/router";
import { PredictionResultModule } from '../prediction-result/prediction-result.module';



@NgModule({
Expand All @@ -15,7 +17,8 @@ import {RouterModule} from "@angular/router";
CommonModule,
ChartModule,
MatButtonModule,
RouterModule
RouterModule,
PredictionResultModule
],
exports: [DashboardComponent,
StatisticComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.guest-container {
.guest-table-info {
width: 100%;
}
.guest-select {
padding-left: 10px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import { Component, OnInit, ChangeDetectionStrategy, OnDestroy, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
import { map, mergeMap, takeUntil, tap } from 'rxjs/operators';
import { ProcessApisMockService } from 'src/app/apis/process/process.apis.mock.service';
import { ProcessApisService } from 'src/app/apis/process/process.apis.service';
import { GuestService } from 'src/app/services/guest.service';
import { environment } from 'src/environments/environment';
import FuzzySearch from 'fuzzy-search';
import { ActivatedRoute } from '@angular/router';
export interface Guest {
fullname: string;
email: string;
low: number;
mid: number;
high: number;
type: string;
}

interface Type {
value: string;
viewValue: string;
}
@Component({
selector: 'app-guest-list',
template: `
<div class="grid-container full guest-container">
<div class="grid-x grid-padding-x align-right">
<div>
<mat-form-field appearance="standard" class="">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. test" #input>
</mat-form-field>
</div>
<div class="guest-select">
<mat-form-field appearance="standard">
<mat-label>Choose an option</mat-label>
<mat-select [(ngModel)]="selectedValue" name="type" (selectionChange)="selectionChange($event)">
<mat-option *ngFor="let type of types" [value]="type.value">
{{type.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>




<table mat-table [dataSource]="guests" class="guest-table-info">
<ng-container matColumnDef="fullname">
<th mat-header-cell *matHeaderCellDef> Fullname </th>
<td mat-cell *matCellDef="let element"> {{element.fullname}} </td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef> Email </th>
<td mat-cell *matCellDef="let element"> {{element.email}} </td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> Type </th>
<td mat-cell *matCellDef="let element"> {{element.type}} </td>
</ng-container>
<ng-container matColumnDef="low">
<th mat-header-cell *matHeaderCellDef> Low </th>
<td mat-cell *matCellDef="let element"> {{element.low}} </td>
</ng-container>
<ng-container matColumnDef="mid">
<th mat-header-cell *matHeaderCellDef> Mid </th>
<td mat-cell *matCellDef="let element"> {{element.mid}} </td>
</ng-container>

<ng-container matColumnDef="high">
<th mat-header-cell *matHeaderCellDef> high </th>
<td mat-cell *matCellDef="let element"> {{element.high}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter</td>
</tr>
</table>

<mat-paginator #paginator [pageSizeOptions]="[5, 10, 20]"
showFirstLastButtons
aria-label="Select page of guest list">
</mat-paginator>
`,
styleUrls: ['./guest-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: ProcessApisService,
useClass: environment.production ? ProcessApisService : ProcessApisMockService,
},
]
})


export class GuestListComponent implements OnInit, OnDestroy, AfterViewInit {

constructor(private processApiService: ProcessApisService, private guestService: GuestService,
private cdr: ChangeDetectorRef,
private route: ActivatedRoute) { }
displayedColumns: String[] = ["fullname", "email", "type", "low", "mid", "high"];
guests: MatTableDataSource<Guest>;
unscrible = new Subject();
resultsLength: number = 0;
@ViewChild(MatPaginator) paginator: MatPaginator;
selectedValue: string;
selectedCar: string;
types: Type[] = [
{ value: '1st-Time Guest', viewValue: '1st-Time Guest' },
{ value: 'Returning Guest', viewValue: 'Returning Guest' },
];
dataStore: Guest[] = [];

ngOnInit(): void {
const processId = this.route.snapshot.queryParams?.id;
combineLatest(this.guestService.getchartItemSelected(), this.processApiService.getCustomerLifetimeValueList({ filter: { processId } })).pipe(
tap(([nameFilter, resData]) => {
let _nameFilter: string[] = [...[], ...nameFilter as string[]];
let results = [...[], ...resData];
results = results.filter(item => _nameFilter?.includes(item.type))
.map(i => ({
fullname: `${i?.firstName} ${i?.lastName}`,
email: i?.email,
low: i?.low,
mid: i?.mid,
high: i?.high,
type: i?.type
}))

this.updateDatasource(results as Guest[]);
this.dataStore = [...[], ...results as Guest[]];
this.cdr.detectChanges();
})
).subscribe()
}

ngAfterViewInit() {
const processId = this.route.snapshot.queryParams?.id;
this.processApiService.getCustomerLifetimeValueList({ filter: { processId } })
.pipe(
takeUntil(this.unscrible),
map(x => x?.map(i => ({
fullname: `${i?.firstName} ${i?.lastName}`,
email: i?.email,
low: i?.low,
mid: i?.mid,
high: i?.high,
type: i?.type
})))).subscribe(rs => {
this.updateDatasource(rs);
this.dataStore = [...[], ...rs as Guest[]];
});
}

ngOnDestroy() {
if (this.unscrible) {
this.unscrible.next();
this.unscrible.complete();
}
}

applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
const searcher = new FuzzySearch(this.guests.data, ["fullname"], {
caseSensitive: false
});
const result = searcher.search(filterValue.trim().toLowerCase());
this.updateDatasource(result);

if (filterValue.trim().toLowerCase() == '') {
this.guests = new MatTableDataSource<Guest>([...[], ...this.dataStore]);
this.updateDatasource(this.dataStore);
}
}

updateDatasource(data: Guest[]) {
this.guests = new MatTableDataSource<Guest>([...[], ...data]);
this.paginator.pageIndex = 0;
this.guests.paginator = this.paginator;
}



selectionChange(event: any) {
this.guestService.setChartItemSelected([this.selectedValue]);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-prediction-result',
template: `
<p>
prediction-result works!
</p>
`,
styleUrls: ['./prediction-result.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PredictionResultComponent implements OnInit {

constructor() { }

ngOnInit(): void {
}

}
Loading