Skip to content

Commit

Permalink
feat(filter): enable multi-selection filter
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwwinter committed Jan 10, 2024
1 parent 3c4b653 commit 8995d09
Show file tree
Hide file tree
Showing 26 changed files with 366 additions and 332 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Angulartics2Module } from "angulartics2";
import { MatMenuModule } from "@angular/material/menu";
import { FaDynamicIconComponent } from "../../../core/common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { RouteTarget } from "../../../route-target";
import { DataFilter } from "../../../core/common-components/entity-subrecord/entity-subrecord/entity-subrecord-config";

/**
* additional config specifically for NotesManagerComponent
Expand Down Expand Up @@ -63,28 +64,27 @@ export class NotesManagerComponent implements OnInit {
{
key: "urgent",
label: $localize`:Filter-option for notes:Urgent`,
filter: { "warningLevel.id": WarningLevel.URGENT },
filter: { "warningLevel.id": WarningLevel.URGENT } as DataFilter<any>,
},
{
key: "follow-up",
label: $localize`:Filter-option for notes:Needs Follow-Up`,
filter: {
"warningLevel.id": { $in: [WarningLevel.URGENT, WarningLevel.WARNING] },
},
"warningLevel.id": { $in: [WarningLevel.WARNING] },
} as DataFilter<any>,
},
{ key: "", label: $localize`All`, filter: {} },
];

private dateFS: FilterSelectionOption<Note>[] = [
{
key: "current-week",
label: $localize`:Filter-option for notes:This Week`,
filter: { date: this.getWeeksFilter(0) },
filter: { date: this.getWeeksFilter(0) } as DataFilter<any>,
},
{
key: "last-week",
label: $localize`:Filter-option for notes:Since Last Week`,
filter: { date: this.getWeeksFilter(1) },
filter: { date: this.getWeeksFilter(1) } as DataFilter<any>,
},
{ key: "", label: $localize`All`, filter: {} },
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
(mouseenter)="preselectAllRange()"
(mouseleave)="unselectRange()"
(click)="selectRangeAndClose('all')"
[class.selected-option]="filter.selectedOption === '_'"
[class.selected-option]="filter.selectedOptionsKeys.length === 0"
>
All
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { HarnessLoader } from "@angular/cdk/testing";
import { DateRange } from "@angular/material/datepicker";
import { MatCalendarHarness } from "@angular/material/datepicker/testing";
import moment from "moment";
import { DateFilter } from "../../../../filter/filters/filters";

import { DateFilter } from "../../../../filter/filters/dateFilter";

describe("DateRangeFilterPanelComponent", () => {
let component: DateRangeFilterPanelComponent;
Expand All @@ -22,7 +23,7 @@ describe("DateRangeFilterPanelComponent", () => {

beforeEach(async () => {
dateFilter = new DateFilter("test", "Test", defaultDateFilters);
dateFilter.selectedOption = "1";
dateFilter.selectedOptionsKeys = ["1"];
jasmine.clock().mockDate(moment("2023-04-08").toDate());
await TestBed.configureTestingModule({
imports: [MatNativeDateModule],
Expand Down Expand Up @@ -85,7 +86,7 @@ describe("DateRangeFilterPanelComponent", () => {
moment("2023-04-08").startOf("day").toDate(),
);
expect(filterRange.end).toEqual(moment("2023-04-08").endOf("day").toDate());
expect(dateFilter.selectedOption).toBe("0");
expect(dateFilter.selectedOptionsKeys).toEqual(["0"]);
});

it("should highlight the date range when hovering over a option", async () => {
Expand Down Expand Up @@ -114,9 +115,9 @@ describe("DateRangeFilterPanelComponent", () => {
}
});

it("should return '_' as filter.selectedOption when 'all' option has been chosen", async () => {
it("should return empty array as filter.selectedOption when 'all' option has been chosen", async () => {
component.selectRangeAndClose("all");
expect(dateFilter.selectedOption).toEqual("_");
expect(dateFilter.selectedOptionsKeys).toEqual([]);
});

it("should correctly calculate date ranges based on the config", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component, Inject } from "@angular/core";
import {
DateRange,
MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
MatDatepickerModule,
MatDateSelectionModel,
MatRangeDateSelectionModel,
MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
} from "@angular/material/datepicker";
import {
MAT_DIALOG_DATA,
Expand All @@ -16,8 +16,8 @@ import { NgForOf } from "@angular/common";
import { DateRangeFilterConfigOption } from "../../../../entity-list/EntityListConfig";
import moment from "moment";
import { FormsModule } from "@angular/forms";
import { DateFilter } from "../../../../filter/filters/filters";
import { dateToString } from "../../../../../utils/utils";
import { DateFilter } from "../../../../filter/filters/dateFilter";

export const defaultDateFilters: DateRangeFilterConfigOption[] = [
{
Expand Down Expand Up @@ -91,9 +91,9 @@ export class DateRangeFilterPanelComponent {

selectRangeAndClose(index: number | "all"): void {
if (typeof index === "number") {
this.filter.selectedOption = index.toString();
this.filter.selectedOptionsKeys = [index.toString()];
} else {
this.filter.selectedOption = "_";
this.filter.selectedOptionsKeys = [];
}
this.dialogRef.close();
}
Expand All @@ -102,11 +102,11 @@ export class DateRangeFilterPanelComponent {
if (!this.selectedRangeValue?.start || this.selectedRangeValue?.end) {
this.selectedRangeValue = new DateRange(selectedDate, null);
} else {
const start = this.selectedRangeValue.start;
this.filter.selectedOption =
const start: Date = this.selectedRangeValue.start;
this.filter.selectedOptionsKeys =
start < selectedDate
? dateToString(start) + "_" + dateToString(selectedDate)
: dateToString(selectedDate) + "_" + dateToString(start);
? [dateToString(start), dateToString(selectedDate)]
: [dateToString(selectedDate), dateToString(start)];
this.dialogRef.close();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { DateRangeFilterComponent } from "./date-range-filter.component";
import { MatDialog } from "@angular/material/dialog";
import { MatNativeDateModule } from "@angular/material/core";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { DateFilter } from "../../../filter/filters/filters";
import { defaultDateFilters } from "./date-range-filter-panel/date-range-filter-panel.component";
import moment from "moment";
import { DateFilter } from "../../../filter/filters/dateFilter";

describe("DateRangeFilterComponent", () => {
let component: DateRangeFilterComponent<any>;
Expand All @@ -30,65 +30,65 @@ describe("DateRangeFilterComponent", () => {
it("should set the correct date filter when a new option is selected", () => {
const dateFilter = new DateFilter("test", "Test", defaultDateFilters);

dateFilter.selectedOption = "9";
dateFilter.selectedOptionsKeys = ["9"];
component.filterConfig = dateFilter;
expect(component.dateFilter.getFilter()).toEqual({});
expect(component.dateFilter.getFilters()).toEqual([{}]);

jasmine.clock().mockDate(moment("2023-05-18").toDate());
dateFilter.selectedOption = "0";
dateFilter.selectedOptionsKeys = ["0"];
component.filterConfig = dateFilter;
let expectedDataFilter = {
test: {
$gte: "2023-05-18",
$lte: "2023-05-18",
},
};
expect(component.dateFilter.getFilter()).toEqual(expectedDataFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDataFilter]);

dateFilter.selectedOption = "1";
dateFilter.selectedOptionsKeys = ["1"];
component.filterConfig = dateFilter;
expectedDataFilter = {
test: {
$gte: "2023-05-14",
$lte: "2023-05-20",
},
};
expect(component.dateFilter.getFilter()).toEqual(expectedDataFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDataFilter]);

dateFilter.selectedOption = "_";
dateFilter.selectedOptionsKeys = [];
component.filterConfig = dateFilter;
expect(component.dateFilter.getFilter()).toEqual({});
expect(component.dateFilter.getFilters()).toEqual([{}]);
jasmine.clock().uninstall();
});

it("should set the correct date filter when inputting a specific date range via the URL", () => {
let dateFilter = new DateFilter("test", "test", []);

dateFilter.selectedOption = "1_2_3";
dateFilter.selectedOptionsKeys = ["1_2_3"];
component.filterConfig = dateFilter;
expect(component.dateFilter.getFilter()).toEqual({});
expect(component.dateFilter.getFilters()).toEqual([{}]);

dateFilter.selectedOption = "_";
dateFilter.selectedOptionsKeys = [];
component.filterConfig = dateFilter;
expect(component.dateFilter.getFilter()).toEqual({});
expect(component.dateFilter.getFilters()).toEqual([{}]);

dateFilter.selectedOption = "2022-9-18_";
dateFilter.selectedOptionsKeys = ["2022-9-18", ""];
component.filterConfig = dateFilter;
let testFilter: { $gte?: string; $lte?: string } = { $gte: "2022-09-18" };
let expectedDateFilter = {
test: testFilter,
};
expect(component.dateFilter.getFilter()).toEqual(expectedDateFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDateFilter]);

dateFilter.selectedOption = "_2023-01-3";
dateFilter.selectedOptionsKeys = ["", "2023-01-3"];
component.filterConfig = dateFilter;
testFilter = { $lte: "2023-01-03" };
expectedDateFilter = {
test: testFilter,
};
expect(component.dateFilter.getFilter()).toEqual(expectedDateFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDateFilter]);

dateFilter.selectedOption = "2022-9-18_2023-01-3";
dateFilter.selectedOptionsKeys = ["2022-9-18", "2023-01-3"];
component.filterConfig = dateFilter;
testFilter = {
$gte: "2022-09-18",
Expand All @@ -97,7 +97,7 @@ describe("DateRangeFilterComponent", () => {
expectedDateFilter = {
test: testFilter,
};
expect(component.dateFilter.getFilter()).toEqual(expectedDateFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDateFilter]);
});

it("should set the correct date filter when changing the date range manually", () => {
Expand All @@ -107,15 +107,16 @@ describe("DateRangeFilterComponent", () => {

component.dateChangedManually();

expect(component.dateFilter.selectedOption).toEqual(
"2021-10-28_2024-02-12",
);
expect(component.dateFilter.selectedOptionsKeys).toEqual([
"2021-10-28",
"2024-02-12",
]);
let expectedDataFilter = {
test: {
$gte: "2021-10-28",
$lte: "2024-02-12",
},
};
expect(component.dateFilter.getFilter()).toEqual(expectedDataFilter);
expect(component.dateFilter.getFilters()).toEqual([expectedDataFilter]);
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { Entity } from "../../../entity/model/entity";
import { DateFilter, Filter } from "../../../filter/filters/filters";
import { Filter } from "../../../filter/filters/filters";
import { DateRangeFilterPanelComponent } from "./date-range-filter-panel/date-range-filter-panel.component";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { FormsModule } from "@angular/forms";
import { dateToString, isValidDate } from "../../../../utils/utils";
import { DateFilter } from "../../../filter/filters/dateFilter";

@Component({
selector: "app-date-range-filter",
Expand All @@ -20,7 +21,7 @@ export class DateRangeFilterComponent<T extends Entity> {
toDate: Date;
dateFilter: DateFilter<T>;

@Output() selectedOptionChange = new EventEmitter<string>();
@Output() selectedOptionChange = new EventEmitter<string[]>();

@Input() set filterConfig(value: Filter<T>) {
this.dateFilter = value as DateFilter<T>;
Expand All @@ -37,16 +38,16 @@ export class DateRangeFilterComponent<T extends Entity> {
) {
this.fromDate = range.start;
this.toDate = range.end;
this.selectedOptionChange.emit(this.dateFilter.selectedOption);
this.selectedOptionChange.emit(this.dateFilter.selectedOptionsKeys);
}
}

dateChangedManually() {
this.dateFilter.selectedOption =
(isValidDate(this.fromDate) ? dateToString(this.fromDate) : "") +
"_" +
(isValidDate(this.toDate) ? dateToString(this.toDate) : "");
this.selectedOptionChange.emit(this.dateFilter.selectedOption);
this.dateFilter.selectedOptionsKeys = [
isValidDate(this.fromDate) ? dateToString(this.fromDate) : "",
isValidDate(this.toDate) ? dateToString(this.toDate) : "",
];
this.selectedOptionChange.emit(this.dateFilter.selectedOptionsKeys);
}

openDialog(e: Event) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { InteractionType } from "../../../child-dev-project/notes/model/interaction-type.interface";

export const defaultInteractionTypes: InteractionType[] = [
{
id: "",
label: "",
},
{
id: "VISIT",
label: $localize`:Interaction type/Category of a Note:Home Visit`,
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/entity-list/EntityListConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface EntityListConfig {

/**
* Optional config for which columns are displayed.
* By default all columns are shown
* By default, all columns are shown
*/
columnGroups?: ColumnGroupsConfig;

Expand Down Expand Up @@ -55,7 +55,7 @@ export interface ColumnGroupsConfig {
default?: string;

/**
* The name of the group group that should be selected by default on a mobile device.
* The name of the group that should be selected by default on a mobile device.
* Default is the name of the first group.
*/
mobile?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/entity/model/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Entity {
/**
* True if this type's schema has been customized dynamically from the config.
*/
static _isCustomizedType?: boolean;
static _isCustomizedType?: boolean; // todo should be private or renamed to "isCustomizedType"

/**
* Defining which attribute values of an entity should be shown in the `.toString()` method.
Expand Down
Loading

0 comments on commit 8995d09

Please sign in to comment.