Skip to content

Commit 76c3080

Browse files
authored
WFPREV-781: Selected filters should persist (#1119)
1 parent ece203e commit 76c3080

File tree

5 files changed

+151
-36
lines changed

5 files changed

+151
-36
lines changed

client/wfprev-war/src/main/angular/src/app/components/edit-project/wfprev-performance-update/wfprev-performance-updates.component.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ export class PerformanceUpdatesComponent implements OnChanges {
6161
private readonly route: ActivatedRoute,
6262
private dialog: MatDialog,
6363
private readonly snackbarService: MatSnackBar
64-
) {
65-
console.info('PerformanceUpdatesComponent constructor called')
66-
}
64+
) {}
6765

6866
ngOnChanges(changes: SimpleChanges): void {
6967
if (changes['fiscalGuid'] && changes['fiscalGuid'].currentValue && !this.isUpdatesCalled) {
@@ -80,8 +78,6 @@ export class PerformanceUpdatesComponent implements OnChanges {
8078
this.projectService.getPerformanceUpdates(this.projectGuid, this.fiscalGuid).subscribe({
8179
next: (data) => {
8280
this.updates = data?._embedded?.performanceUpdate ?? [];
83-
console.info('JSON responce is:', this.updates);
84-
console.info('Lenth is:', this.updates.length);
8581
},
8682
error: (error) => {
8783
console.error('Error fetching performance updates:', error);

client/wfprev-war/src/main/angular/src/app/components/list-panel/projects-list/projects-list.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export class ProjectsListComponent implements OnInit {
7373
}
7474
ngOnInit(): void {
7575
this.loadCodeTables();
76-
this.loadProjects();
7776

7877
this.sharedService.selectedProject$.subscribe(project => {
7978
if (!project) {

client/wfprev-war/src/main/angular/src/app/components/search-filter/search-filter.component.ts

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnInit } from '@angular/core';
1+
import { Component, effect, OnInit } from '@angular/core';
22
import { MatFormFieldModule } from '@angular/material/form-field';
33
import { MatSelectModule } from '@angular/material/select';
44
import { FormsModule } from '@angular/forms';
@@ -13,6 +13,9 @@ import { Subject } from 'rxjs';
1313
import { debounceTime } from 'rxjs/operators';
1414
import { MatOptionSelectionChange } from '@angular/material/core';
1515
import { WildfireOrgUnitTypeCodes } from 'src/app/utils/constants';
16+
import { ActivatedRoute } from '@angular/router';
17+
import { ProjectFilterStateService } from 'src/app/services/project-filter-state.service';
18+
import { ProjectFilter } from '../models';
1619
@Component({
1720
selector: 'wfprev-search-filter',
1821
standalone: true,
@@ -34,8 +37,27 @@ export class SearchFilterComponent implements OnInit {
3437
constructor(
3538
private readonly sharedCodeTableService: SharedCodeTableService,
3639
private readonly codeTableService: CodeTableServices,
37-
private sharedService: SharedService
38-
) { }
40+
private sharedService: SharedService,
41+
private readonly projectFilterStateService: ProjectFilterStateService,
42+
private route: ActivatedRoute,
43+
) {
44+
effect(() => {
45+
this.route.snapshot.url;
46+
const saved = this.projectFilterStateService.filters();
47+
if (saved) {
48+
this.searchText = saved.searchText ?? "";
49+
this.selectedProjectType = saved.projectTypeCodes ?? [];
50+
this.selectedBusinessArea = saved.programAreaGuids ?? [];
51+
this.selectedFiscalYears = saved.fiscalYears ?? [];
52+
this.selectedActivity = saved.activityCategoryCodes ?? [];
53+
this.selectedForestRegion = saved.forestRegionOrgUnitIds ?? [];
54+
this.selectedForestDistrict = saved.forestDistrictOrgUnitIds ?? [];
55+
this.selectedFireCentre = saved.fireCentreOrgUnitIds ?? [];
56+
this.selectedFiscalStatus = saved.planFiscalStatusCodes ?? [];
57+
}
58+
59+
});
60+
}
3961

4062
searchText: string = '';
4163
searchTextChanged: Subject<string> = new Subject<string>();
@@ -59,6 +81,18 @@ export class SearchFilterComponent implements OnInit {
5981
noYearAssigned: string = 'No Year Assigned'
6082

6183
ngOnInit(): void {
84+
const savedFilters = this.projectFilterStateService.filters();
85+
if (savedFilters) {
86+
this.searchText = savedFilters?.searchText ?? '';
87+
this.selectedProjectType = savedFilters?.projectTypeCodes ?? [];
88+
this.selectedBusinessArea = savedFilters?.programAreaGuids ?? [];
89+
this.selectedFiscalYears = savedFilters?.fiscalYears ?? [];
90+
this.selectedActivity = savedFilters?.activityCategoryCodes ?? [];
91+
this.selectedForestRegion = savedFilters?.forestRegionOrgUnitIds ?? [];
92+
this.selectedForestDistrict = savedFilters?.forestDistrictOrgUnitIds ?? [];
93+
this.selectedFireCentre = savedFilters?.fireCentreOrgUnitIds ?? [];
94+
this.selectedFiscalStatus = savedFilters?.planFiscalStatusCodes ?? [];
95+
}
6296
this.generateFiscalYearOptions();
6397
this.setupCodeTableSubscription();
6498
this.setupSearchDebounce();
@@ -79,21 +113,34 @@ export class SearchFilterComponent implements OnInit {
79113
return sanitize(this.selectedFiscalYears);
80114
};
81115

82-
this.sharedService.updateFilters({
116+
117+
this.projectFilterStateService.update({
83118
searchText: this.searchText,
84-
projectTypeCode: sanitize(this.selectedProjectType),
85-
programAreaGuid: sanitize(this.selectedBusinessArea),
86-
fiscalYear: resolveFiscalYears(),
87-
activityCategoryCode: sanitize(this.selectedActivity),
88-
forestRegionOrgUnitId: sanitize(this.selectedForestRegion),
89-
forestDistrictOrgUnitId: sanitize(this.selectedForestDistrict),
90-
fireCentreOrgUnitId: sanitize(this.selectedFireCentre),
91-
planFiscalStatusCode: sanitize(this.selectedFiscalStatus)
119+
projectTypeCodes: this.selectedProjectType,
120+
programAreaGuids: this.selectedBusinessArea,
121+
fiscalYears: this.selectedFiscalYears,
122+
activityCategoryCodes: this.selectedActivity,
123+
forestRegionOrgUnitIds: this.selectedForestRegion,
124+
forestDistrictOrgUnitIds: this.selectedForestDistrict,
125+
fireCentreOrgUnitIds: this.selectedFireCentre,
126+
planFiscalStatusCodes: this.selectedFiscalStatus
92127
});
128+
const flt = {
129+
searchText: this.searchText,
130+
projectTypeCodes: sanitize(this.selectedProjectType),
131+
programAreaGuids: sanitize(this.selectedBusinessArea),
132+
fiscalYears: resolveFiscalYears(),
133+
activityCategoryCodes: sanitize(this.selectedActivity),
134+
forestRegionOrgUnitIds: sanitize(this.selectedForestRegion),
135+
forestDistrictOrgUnitIds: sanitize(this.selectedForestDistrict),
136+
fireCentreOrgUnitIds: sanitize(this.selectedFireCentre),
137+
planFiscalStatusCodes: sanitize(this.selectedFiscalStatus)
138+
}
139+
140+
this.sharedService.updateFilters(flt);
93141
}
94142

95143
onSearch() {
96-
console.log('Searching for:', this.searchText);
97144
this.emitFilters();
98145
}
99146

@@ -199,7 +246,6 @@ export class SearchFilterComponent implements OnInit {
199246
options: { value: string }[]
200247
) {
201248
if (!event.isUserInput) return;
202-
203249
const allOptionValue = '__ALL__';
204250
const allIndividualValues = options
205251
.map(o => o.value)
@@ -230,14 +276,23 @@ export class SearchFilterComponent implements OnInit {
230276
if (value !== allOptionValue && event.source.selected) {
231277
const updated = new Set([...currentSelected, value]);
232278
const hasAllIndividuals = allIndividualValues.every(v => updated.has(v));
233-
234279
if (hasAllIndividuals && !updated.has(allOptionValue)) {
235280
setTimeout(() => {
236281
(this[model] as string[]) = [allOptionValue, ...allIndividualValues];
237282
this.emitFilters();
238283
}, 0);
284+
return;
239285
}
240286
}
287+
288+
//Case 4: User selects "All" => select all
289+
if (value === allOptionValue && event.source.selected) {
290+
setTimeout(() => {
291+
(this[model] as string[]) = [allOptionValue, ...allIndividualValues];
292+
this.emitFilters();
293+
}, 0);
294+
}
295+
241296
}
242297

243298

@@ -306,30 +361,39 @@ export class SearchFilterComponent implements OnInit {
306361
.pipe(debounceTime(3000)) // 3s debounce time
307362
.subscribe((value: string) => {
308363
this.searchText = value;
364+
this.projectFilterStateService.update({
365+
searchText: value
366+
});
309367
this.onSearch();
310368
});
369+
this.onSearch();
311370
}
312371

313372
clearSearch(): void {
314373
this.searchText = '';
374+
this.projectFilterStateService.update({
375+
searchText: this.searchText
376+
});
315377
this.emitFilters();
316378
}
317379

318380
assignDefaultFiscalYear(emit: boolean = true): void {
319-
const today = new Date();
320-
// April has an index of 3
321-
const fiscalYearStart = today.getMonth() >= 3 ? today.getFullYear() : today.getFullYear() - 1;
322-
const fiscalYearValue = fiscalYearStart.toString();
323-
324-
const currentFiscalExists = this.fiscalYearOptions.some(opt => opt.value === fiscalYearValue);
325-
const noYearAssignedExists = this.fiscalYearOptions.some(opt => opt.value === 'null');
326-
327-
// automatically assign current fiscal year and 'No Year Assigned'
328-
this.selectedFiscalYears = [
329-
...(currentFiscalExists ? [fiscalYearValue] : []),
330-
...(noYearAssignedExists ? ['null'] : [])
331-
];
332-
333-
if (emit) this.emitFilters();
381+
if (!this.projectFilterStateService?.filters()?.fiscalYears) {
382+
const today = new Date();
383+
// April has an index of 3
384+
const fiscalYearStart = today.getMonth() >= 3 ? today.getFullYear() : today.getFullYear() - 1;
385+
const fiscalYearValue = fiscalYearStart.toString();
386+
387+
const currentFiscalExists = this.fiscalYearOptions.some(opt => opt.value === fiscalYearValue);
388+
const noYearAssignedExists = this.fiscalYearOptions.some(opt => opt.value === 'null');
389+
390+
// automatically assign current fiscal year and 'No Year Assigned'
391+
this.selectedFiscalYears = [
392+
...(currentFiscalExists ? [fiscalYearValue] : []),
393+
...(noYearAssignedExists ? ['null'] : [])
394+
];
395+
396+
if (emit) this.emitFilters();
397+
}
334398
}
335399
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { ProjectFilterStateService } from './project-filter-state.service';
4+
5+
describe('ProjectFilterStateService', () => {
6+
let service: ProjectFilterStateService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(ProjectFilterStateService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Injectable, signal } from '@angular/core';
2+
import { ProjectFilter } from '../components/models';
3+
4+
@Injectable({
5+
providedIn: 'root'
6+
})
7+
export class ProjectFilterStateService {
8+
9+
private readonly STORAGE_KEY = 'project-filters';
10+
11+
filters = signal<ProjectFilter | null>(this.load());
12+
13+
set(filters: ProjectFilter) {
14+
this.filters.set(filters);
15+
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(filters));
16+
}
17+
18+
update(changes: Partial<ProjectFilter>) {
19+
this.filters.update(current => {
20+
const updated = {
21+
...current,
22+
...changes
23+
};
24+
25+
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(updated));
26+
return updated;
27+
});
28+
}
29+
30+
clear() {
31+
this.filters.set(null);
32+
sessionStorage.removeItem(this.STORAGE_KEY);
33+
}
34+
35+
private load(): ProjectFilter | null {
36+
const raw = sessionStorage.getItem(this.STORAGE_KEY);
37+
return raw ? JSON.parse(raw) : null;
38+
}
39+
40+
}

0 commit comments

Comments
 (0)