Skip to content

Commit

Permalink
BRS-351: Add Missing/Null Values Data Export (#370)
Browse files Browse the repository at this point in the history
* add missing data export tab

Signed-off-by: David <daveclaveau@gmail.com>

* add missing functions from rebase

Signed-off-by: David <daveclaveau@gmail.com>

* missing report - export all set true by default

Signed-off-by: David <daveclaveau@gmail.com>

---------

Signed-off-by: David <daveclaveau@gmail.com>
  • Loading branch information
davidclaveau authored Aug 30, 2024
1 parent b24ebd8 commit 272a602
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 36 deletions.
57 changes: 56 additions & 1 deletion src/app/export-reports/export-reports.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ <h1>Export Report</h1>
role="tab" aria-controls="variance" aria-selected="false"
(click)="changeActiveTab('variance')">Variance</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="missing-tab" data-bs-toggle="tab" data-bs-target="#missing" type="button"
role="tab" aria-controls="missing" aria-selected="false"
(click)="changeActiveTab('missing')">Missing</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="standard" role="tabpanel" aria-labelledby="standard-tab">
Expand Down Expand Up @@ -59,8 +64,58 @@ <h3 class="card-title">Export variance data</h3>

</div>
</div>
</div>

<div class="tab-pane fade" id="missing" role="tabpanel" aria-labelledby="missing-tab">
<div>
<h3 class="card-title">Export missing data</h3>
<p class="card-text text-muted">
Generate a report of missing records.
</p>

<hr />

<div class="row mb-3">
<div class="col-md-12 col-lg-4">
<ngds-date-input
[control]="form?.controls?.['year']"
[dateRange]="true"
[label]="'Fiscal year'"
[hideSecondCalendar]="true"
[fixedRangeSize]="duration"
[minMode]="2"
[rangeSeparator]="'-'"
[dateFormat]="dateFormat"
[dateDisplayFormat]="'LLLL yyyy'"
[placeholder]="'Select fiscal year'"
[maxDate]="maxDate">
<div
ngdsInputPrepend
class="bi bi-calendar px-2"></div>
</ngds-date-input>

<div class="my-4 py-3">
<label class="d-flex align-items-center">
<input type="checkbox" [(ngModel)]="exportAllCheck" (click)="toggleExportAllCheck()"/>
<div class="col-10 mx-2 card-text fs-6">Export all</div>
</label>
</div>
<div class="col-md-12 col-lg-8">
<ngds-typeahead-input
[control]="form?.controls?.['park']"
[label]="'Park'"
[selectionListItems]="_parks?.value"
[resetButton]="true"
[placeholder]="'Search by park name'"
[disabled]="exportAllCheck"
>
</ngds-typeahead-input>

</div>
</div>

</div>
</div>
</div>
<div class="mt-5 pb-2">
<div class="card-text fw-bold">Exporter status:</div>
<div>{{ status }}</div>
Expand Down
4 changes: 4 additions & 0 deletions src/app/export-reports/export-reports.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
input[type="checkbox"] {
height: 16px;
width: 16px;
}
92 changes: 86 additions & 6 deletions src/app/export-reports/export-reports.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { ChangeDetectorRef, Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core';
import { Subscription, BehaviorSubject, debounceTime } from 'rxjs';
import { DataService } from '../services/data.service';
import { ExportService } from '../services/export.service';
import { Constants } from '../shared/utils/constants';
import { DateTime, Duration } from 'luxon';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import {
UntypedFormControl,
UntypedFormGroup,
FormsModule,
} from '@angular/forms';

@Component({
selector: 'app-export-reports',
Expand All @@ -24,6 +28,7 @@ export class ExportReportsComponent implements OnDestroy {
ERROR: 99,
};

public _parks = new BehaviorSubject(null);
public status = 'Standing by';
public percentageComplete = 0;
public progressBarTextOverride;
Expand All @@ -40,6 +45,7 @@ export class ExportReportsComponent implements OnDestroy {
public fiscalYearRangeString = this.defaultRangeString;
public modelDate = NaN;
public activeTab = '';
public exportAllCheck = true;

public tz = Constants.timezone;
public maxDate = DateTime.now().setZone(this.tz);
Expand All @@ -49,6 +55,7 @@ export class ExportReportsComponent implements OnDestroy {

public form = new UntypedFormGroup({
year: new UntypedFormControl(null),
park: new UntypedFormControl(null),
});

public exportMessage = 'Last export: -';
Expand Down Expand Up @@ -93,6 +100,33 @@ export class ExportReportsComponent implements OnDestroy {
this.jobUpdate(res);
}),
);
this.subscriptions.add(
dataService
.watchItem(Constants.dataIds.ENTER_DATA_PARK)
.subscribe((res) => {
if (res && res.length) {
this._parks.next(this.createTypeaheadObj(res, 'parkName'));
}
}),
);
this.subscriptions.add(
this.form.controls['park'].valueChanges
.pipe(debounceTime(0))
.subscribe((changes) => {
if (changes) {
this.form.controls['park'].setValue(
this.getLocalStorageParkById(changes.orcs),
);
}
}),
);
this.subscriptions.add(
this.dataService
.watchItem(Constants.dataIds.EXPORT_MISSING_POLLING_DATA)
.subscribe((res) => {
this.jobUpdate(res);
}),
);
}

setMaxDate() {
Expand All @@ -105,6 +139,30 @@ export class ExportReportsComponent implements OnDestroy {
this.maxDate = DateTime.local(year);
}

// Get park object by orcs
getLocalStorageParkById(orcs) {
let park = this._parks?.value?.find((p) => p?.value?.orcs === orcs);
return park?.value || null;
}

// create typeahead object
createTypeaheadObj(items, display) {
let list = [];
for (const item of items) {
list.push({
value: item,
display: item[display],
});
}
return list;
}

toggleExportAllCheck() {
this.exportAllCheck = !this.exportAllCheck;
// Remove any park that was selected
this.form.controls['park'].setValue('');
}

jobUpdate(res) {
if (res) {
this.initialLoad = false;
Expand Down Expand Up @@ -157,13 +215,23 @@ export class ExportReportsComponent implements OnDestroy {
'variance',
{ fiscalYearEnd: year },
);
} else if (this.activeTab === 'missing') {
const year = this.form.controls['year'].value[1].slice(0, 4);
const orcs = this.form.controls['park'].value?.orcs || '';
this.exportService.generateReport(
Constants.dataIds.EXPORT_MISSING_POLLING_DATA,
'missing',
{
fiscalYearEnd: year,
orcs: orcs,
},
);
} else {
this.exportService.generateReport(
Constants.dataIds.EXPORT_ALL_POLLING_DATA,
'standard',
);
}
this.cd.detectChanges();
}

setState(state) {
Expand Down Expand Up @@ -241,13 +309,21 @@ export class ExportReportsComponent implements OnDestroy {
);
}
return;
} else if (this.activeTab === 'missing') {
if (this.modelDate) {
this.exportService.checkForReports(
Constants.dataIds.EXPORT_MISSING_POLLING_DATA,
'missing',
{ fiscalYearEnd: this.modelDate },
);
}
return;
} else {
this.exportService.checkForReports(
Constants.dataIds.EXPORT_ALL_POLLING_DATA,
'standard',
);
}
this.cd.detectChanges();
return;
}

Expand Down Expand Up @@ -279,10 +355,14 @@ export class ExportReportsComponent implements OnDestroy {
this.exportMessage = 'No previous report found. Click generate report.';
}
}
this.cd.detectChanges();
}

disableGenerateButton() {
if (this.activeTab === 'variance' && !this.form?.controls?.['year'].value) {
if (
(this.activeTab === 'variance' || this.activeTab === 'missing') &&
!this.form?.controls?.['year'].value
) {
return true;
}
if (![0, 2, 99].includes(this.currentState)) {
Expand Down
10 changes: 9 additions & 1 deletion src/app/export-reports/export-reports.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgdsTabsModule } from '@digitalspace/ngds-toolkit';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { NgdsFormsModule } from '@digitalspace/ngds-forms';
import { FormsModule } from '@angular/forms';

@NgModule({
declarations: [ExportReportsComponent],
imports: [CommonModule, NgbModule, NgdsTabsModule, NgdsFormsModule, BsDatepickerModule.forRoot()],
imports: [
CommonModule,
NgbModule,
NgdsTabsModule,
NgdsFormsModule,
BsDatepickerModule.forRoot(),
FormsModule,
],
exports: [ExportReportsComponent],
})
export class ExportReportsModule {}
32 changes: 23 additions & 9 deletions src/app/guards/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { Injectable } from '@angular/core';
import { UrlTree, Router, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router';
import {
UrlTree,
Router,
RouterStateSnapshot,
ActivatedRouteSnapshot,
} from '@angular/router';
import { KeycloakService } from '../services/keycloak.service';

@Injectable({
providedIn: 'root',
})
export class AuthGuard {
export class AuthGuard {
constructor(
private readonly keycloakService: KeycloakService,
private readonly router: Router
private readonly router: Router,
) {}

canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
state: RouterStateSnapshot,
): boolean | UrlTree {
// When a successful login occurs, we store the identity provider used in sessionStorage.
const lastIdp = sessionStorage.getItem(
this.keycloakService.LAST_IDP_AUTHENTICATED
this.keycloakService.LAST_IDP_AUTHENTICATED,
);

// Not authenticated
Expand Down Expand Up @@ -48,7 +53,7 @@ export class AuthGuard {
if (idp !== '') {
sessionStorage.setItem(
this.keycloakService.LAST_IDP_AUTHENTICATED,
idp
idp,
);
}
}
Expand All @@ -59,15 +64,24 @@ export class AuthGuard {
return this.router.parseUrl('/unauthorized');
}

if (!this.keycloakService.isAllowed('export-reports') && state.url === '/export-reports') {
if (
!this.keycloakService.isAllowed('export-reports') &&
state.url === '/export-reports'
) {
return this.router.parseUrl('/');
}

if (!this.keycloakService.isAllowed('lock-records') && state.url === '/lock-records') {
if (
!this.keycloakService.isAllowed('lock-records') &&
state.url === '/lock-records'
) {
return this.router.parseUrl('/');
}

if (!this.keycloakService.isAllowed('review-data') && state.url === '/review-data') {
if (
!this.keycloakService.isAllowed('review-data') &&
state.url === '/review-data'
) {
return this.router.parseUrl('/');
}

Expand Down
6 changes: 3 additions & 3 deletions src/app/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class HomeComponent {
cardText:
'Use this section to enter attendance and revenue and send to BC Parks. You can also view and edit past enteries.',
navigation: 'enter-data',
}
},
];
constructor(protected keyCloakService: KeycloakService) {
if (keyCloakService.isAllowed('export-reports')) {
Expand All @@ -30,7 +30,8 @@ export class HomeComponent {
this.cardConfig.push({
cardHeader: 'Lock/Unlock Records',
cardTitle: 'Lock/Unlock by fiscal year',
cardText: 'Use this section to lock/unlock fiscal years (April-March) against editing.',
cardText:
'Use this section to lock/unlock fiscal years (April-March) against editing.',
navigation: 'lock-records',
});
}
Expand All @@ -42,6 +43,5 @@ export class HomeComponent {
navigation: 'review-data',
});
}

}
}
Loading

0 comments on commit 272a602

Please sign in to comment.