import {
AfterViewInit,
Component,
OnInit,
QueryList,
ViewChild,
ViewChildren,
} from '@angular/core';
import { UntypedFormGroup, FormBuilder } from '@angular/forms';
import {
Column,
ColumnChooserService,
FilterService,
FilterSettings,
FreezeService,
GridComponent,
GridLine,
LoadingIndicator,
PageService,
ReorderService,
ResizeService,
SelectionService,
SelectionSettings,
SortService,
SortSettings,
ToolbarService,
} from '@syncfusion/ej2-angular-grids';
import { TabComponent } from '@syncfusion/ej2-angular-navigations';
import { TranslateService } from '@ngx-translate/core';
import { Status } from '@shared/enums/status.enum';
import { FilterPanelComponent } from '@shared/components';
import { Department } from '../../models';
import data from '../../../../../../mocks/my-projects.mock.json';
import departmentData from '../../../../../../mocks/department-tree.mock.json';
@Component({
selector: 'am-my-projects',
templateUrl: './my-projects.component.html',
styleUrls: ['./my-projects.component.scss'],
providers: [
ToolbarService,
ColumnChooserService,
SelectionService,
PageService,
FilterService,
FreezeService,
ReorderService,
ResizeService,
SortService,
],
})
export class MyProjectsComponent implements OnInit, AfterViewInit {
@ViewChildren('grid') public grids: QueryList<GridComponent>;
@ViewChild('tabs') public tabs: TabComponent;
@ViewChild('filterPanel') public filterPanel: FilterPanelComponent;
public grid: GridComponent;
public status = Status;
public projectLeadData: any[] = [];
public userLeadData: any[] = [];
public sponsorData: any[] = [];
public resourceData: any[] = [];
public projectLeadDataCount = 0;
public userLeadDataCount = 0;
public sponsorDataCount = 0;
public resourceDataCount = 0;
// Toolbar states for each tab
public projectLeadToolbarState: any | undefined;
public userLeadToolbarState: any | undefined;
public sponsorToolbarState: any | undefined;
public resourceToolbarState: any | undefined;
public loadingIndicator: Partial<LoadingIndicator>;
public selectOptions: Partial<SelectionSettings>;
public toolbar: (string | object)[];
public filterSettings: Partial<FilterSettings>;
public sortSettings: Partial<SortSettings>;
public lines: GridLine;
public freezingOptions: { text: string; field: string }[];
public selectedFrozenColumns: string[] = [];
public headers: { text: string }[] = [];
public externalFilters: UntypedFormGroup | undefined;
public statusOptions: { value: Status; label: string }[] = [];
public statusFields: { text: string; value: string };
public departments: Department[] = [];
public departmentFields: any | undefined;
constructor(
private readonly translateService: TranslateService,
private readonly fb: FormBuilder
) {}
public ngOnInit(): void {
this.departments = departmentData;
this.loadingIndicator = { indicatorType: 'Shimmer' };
this.projectLeadData = data.filter((x) => x.role === 'Project Lead');
this.projectLeadDataCount = this.projectLeadData.length;
this.userLeadData = data.filter((x) => x.role === 'User Lead');
this.userLeadDataCount = this.userLeadData.length;
this.sponsorData = data.filter((x) => x.role === 'Sponsor');
this.sponsorDataCount = this.sponsorData.length;
this.resourceData = data.filter((x) => x.role === 'Resource');
this.resourceDataCount = this.resourceData.length;
this.selectOptions = { persistSelection: true };
this.configureToolbar();
this.configureHeaders();
this.configureExternalFilters();
this.statusFields = { text: 'label', value: 'value' };
this.configureStatusOptions();
this.departmentFields = {
dataSource: this.departments,
value: 'id',
text: 'name',
child: 'children',
};
}
public ngAfterViewInit() {
this.setActiveGrid();
this.loadGridState();
}
public openColumnChooser() {
const gridElem = this.grid.getContent();
const gridRect = gridElem.getBoundingClientRect();
this.grid.columnChooserModule.openColumnChooser(gridRect.right - gridRect.left - 250, 38);
}
public filterChangeHandler(type: string) {
this.filterSettings = { type: type as FilterSettings['type'] };
setTimeout(() => {
this.saveGridState();
}, 0);
}
public gridLinesChangeHandler(type: string) {
this.lines = type as GridLine;
this.saveGridState();
setTimeout(() => {
this.grid.refresh();
}, 0);
}
public handleFreezeChange(args: any, fieldColumn: string) {
const isChecked = args.checked;
if (isChecked) {
this.selectedFrozenColumns.push(fieldColumn);
} else {
this.selectedFrozenColumns = this.selectedFrozenColumns.filter((x) => x !== fieldColumn);
}
this.grid.refreshColumns();
this.applyFreezing();
this.saveGridState();
}
public dataBound() {
this.configureFreezingOptions();
}
public configureHeaders() {
this.headers.push({
text: `${this.translateService.instant('Dashboard.MyProjects.Tabs.ProjectLead')} (${
this.projectLeadData.length
})`,
});
this.headers.push({
text: `${this.translateService.instant('Dashboard.MyProjects.Tabs.UserLead')} (${
this.userLeadData.length
})`,
});
this.headers.push({
text: `${this.translateService.instant('Dashboard.MyProjects.Tabs.Sponsor')} (${
this.sponsorData.length
})`,
});
this.headers.push({
text: `${this.translateService.instant('Dashboard.MyProjects.Tabs.Resource')} (${
this.resourceData.length
})`,
});
}
public getStatusClass(status: Status): string {
switch (status) {
case Status.Idea:
return 'idea';
case Status.IdeaAccepted:
return 'idea-accepted';
case Status.IdeaToBeApprovedByMAC:
return 'idea-to-be-approved';
case Status.IdeaRejected:
return 'idea-rejected';
case Status.InPreperation:
return 'in-preperation';
case Status.InExecution:
return 'in-execution';
case Status.OnHold:
return 'on-hold';
case Status.Stopped:
return 'stopped';
case Status.Aftercare:
return 'aftercare';
case Status.Finished:
return 'finished';
default:
return '';
}
}
// Switch because we work with local data
// When this is remote data, this will be done on server
public searchList(searchTerm: string) {
const selectedTab = this.tabs.selectedItem;
switch (selectedTab) {
case 0:
this.projectLeadData = data.filter(
(x) =>
x.role === 'Project Lead' &&
(!searchTerm ||
Object.keys(x).some((key) =>
x[key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())
))
);
break;
case 1:
this.userLeadData = data.filter(
(x) =>
x.role === 'User Lead' &&
(!searchTerm ||
Object.keys(x).some((key) =>
x[key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())
))
);
break;
case 2:
this.sponsorData = data.filter(
(x) =>
x.role === 'Sponsor' &&
(!searchTerm ||
Object.keys(x).some((key) =>
x[key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())
))
);
break;
case 3:
this.resourceData = data.filter(
(x) =>
x.role === 'Resource' &&
(!searchTerm ||
Object.keys(x).some((key) =>
x[key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())
))
);
break;
default:
break;
}
}
public toggleFilterPanel() {
this.filterPanel.togglePanel();
}
// Switch because we work with local data
// When this is remote data, this will be done on server
public applyExternalFilters() {
const selectedTab = this.tabs.selectedItem;
const externalFilters = this.externalFilters.value;
const { status, startDate, endDate, department } = externalFilters;
// Define a function to apply all filters
const applyFilters = (y) => {
return y
.filter((x) => !status || status.length === 0 || status.some((z) => z === x.status)) // Filter by status if provided
.filter((x) => !startDate || new Date(x.startDate) >= new Date(startDate)) // Filter by startDate if provided
.filter((x) => !endDate || new Date(x.endDate) <= new Date(endDate)) // Filter by endDate if provided
.filter(
(x) =>
!department ||
department.length === 0 ||
department.some((z) => parseInt(z, 10) === x.departmentId)
); // Filter by department if provided
};
switch (selectedTab) {
case 0:
this.projectLeadData = applyFilters(data.filter((x) => x.role === 'Project Lead'));
break;
case 1:
this.userLeadData = applyFilters(data.filter((x) => x.role === 'User Lead'));
break;
case 2:
this.sponsorData = applyFilters(data.filter((x) => x.role === 'Sponsor'));
break;
case 3:
this.resourceData = applyFilters(data.filter((x) => x.role === 'Resource'));
break;
default:
break;
}
}
public saveGridState() {
const persistData = this.grid.getPersistData();
const persistDataObj = JSON.parse(persistData);
const selectedTab = this.tabs.selectedItem;
persistDataObj['lines'] = this.lines;
persistDataObj['selectedFrozenColumns'] = this.selectedFrozenColumns;
localStorage.setItem(`gridState${selectedTab}`, JSON.stringify(persistDataObj));
}
public onTabChange() {
this.setActiveGrid();
this.loadGridState();
}
private applyFreezing() {
(this.grid.columns as Column[]).forEach((column: Column) => {
if (
(this.selectedFrozenColumns.includes(column.field) && column.freeze !== 'Right') ||
(column.customAttributes && column.customAttributes['class'] === 'status')
) {
column.freeze = 'Left';
} else if (column.type !== 'checkbox' && column.index !== 0 && column.freeze !== 'Right') {
column.freeze = 'None';
}
});
this.grid.refreshColumns();
}
private configureToolbar() {
const filterTypeText =
this.translateService.instant('Dashboard.MyProjects.FilterType.Text') ?? 'Filter type';
const filterTypeTooltip =
this.translateService.instant('Dashboard.MyProjects.FilterType.Tooltip') ??
'Choose filter type';
const gridLinesText =
this.translateService.instant('Dashboard.MyProjects.GridLines.Text') ?? 'Grid lines';
const gridLinesTooltip =
this.translateService.instant('Dashboard.MyProjects.GridLines.Tooltip') ??
'Choose grid lines';
const freezingText =
this.translateService.instant('Dashboard.MyProjects.Freezing.Text') ?? 'Freezing';
const freezingTooltip =
this.translateService.instant('Dashboard.MyProjects.Freezing.Tooltip') ??
'Choose fixed columns/rows';
this.toolbar = [
{ text: filterTypeText, tooltipText: filterTypeTooltip, id: 'filterType' },
{ text: gridLinesText, tooltipText: gridLinesTooltip, id: 'gridlines' },
{ text: freezingText, tooltipText: freezingTooltip, id: 'freezing' },
'ColumnChooser',
];
}
private configureFreezingOptions() {
if (this.grid) {
this.freezingOptions = this.grid
?.getVisibleColumns()
.map((column) => ({ text: column.headerText, field: column.field }))
.filter((x) => !!x.field)
.sort((a, b) => a.text?.localeCompare(b.text));
}
}
private configureExternalFilters() {
this.externalFilters = this.fb.group({
status: this.fb.control([]),
startDate: this.fb.control(undefined),
endDate: this.fb.control(undefined),
department: this.fb.control([]),
});
}
private configureStatusOptions() {
this.statusOptions = [
{ value: Status.Idea, label: this.translateService.instant('Status.Idea') },
{ value: Status.IdeaAccepted, label: this.translateService.instant('Status.IdeaAccepted') },
{
value: Status.IdeaToBeApprovedByMAC,
label: this.translateService.instant('Status.IdeaToBeApprovedByMAC'),
},
{ value: Status.IdeaRejected, label: this.translateService.instant('Status.IdeaRejected') },
{ value: Status.InPreperation, label: this.translateService.instant('Status.InPreperation') },
{ value: Status.InExecution, label: this.translateService.instant('Status.InExecution') },
{ value: Status.OnHold, label: this.translateService.instant('Status.OnHold') },
{ value: Status.Stopped, label: this.translateService.instant('Status.Stopped') },
{ value: Status.Aftercare, label: this.translateService.instant('Status.Aftercare') },
{ value: Status.Finished, label: this.translateService.instant('Status.Finished') },
];
}
private loadGridState() {
setTimeout(() => {
const selectedTab = this.tabs.selectedItem;
const gridState = localStorage.getItem(`gridState${selectedTab}`);
if (!this.grid) {
return;
}
if (gridState) {
const persistData = JSON.parse(gridState);
this.resetGridToDefault();
this.grid.columns = this.rebuildColumns(this.grid.columns as Column[], persistData.columns);
this.selectedFrozenColumns = persistData.selectedFrozenColumns || [];
this.grid.setProperties({
sortSettings: persistData.sortSettings,
filterSettings: persistData.filterSettings,
columns: this.grid.columns,
});
this.lines = persistData.lines;
this.grid.refreshColumns();
this.applyFreezing();
} else {
this.resetGridToDefault();
}
}, 0);
}
private rebuildColumns(gridColumns: Column[], persistedColumns: Column[]): Column[] {
return gridColumns.map((column: Column, i: number) => {
const persistedColumn = persistedColumns[i];
return Object.assign(column, {
width: persistedColumn.width,
freeze: persistedColumn.freeze,
visible: persistedColumn.visible,
customAttributes: persistedColumn.customAttributes,
index: persistedColumn.index,
});
});
}
private resetGridToDefault() {
this.grid.clearSorting();
this.grid.clearFiltering();
this.grid.clearSelection();
this.selectedFrozenColumns = [];
this.lines = 'Default';
this.filterSettings = { type: 'FilterBar' };
this.grid.refreshColumns();
this.applyFreezing();
}
private setActiveGrid() {
setTimeout(() => {
const selectedTab = this.tabs.selectedItem;
const gridArray = this.grids.toArray();
this.grid = gridArray[selectedTab];
}, 0);
}
}