Skip to content

Commit

Permalink
feat(medic#9558): Task filter by household
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaunKrog committed Oct 23, 2024
1 parent e8e4918 commit 67e9c60
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 53 deletions.
45 changes: 44 additions & 1 deletion webapp/src/css/inbox.less
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ mm-analytics-filters {
background-color: @background-color;
}

.reports .inbox-items, .contacts .inbox-items, .messages .inbox-items {
.reports .inbox-items, .contacts .inbox-items, .messages .inbox-items, .tasks .inbox-items {
overflow-y: hidden;
overflow-x: hidden;
height: 100%;
Expand Down Expand Up @@ -1115,6 +1115,49 @@ mm-search-bar {
}
}

mm-filter-slider-icon {
padding: 8px 0;
position: relative;
display: block;

.mm-filter-slider-container {
display: flex;
justify-content: flex-start;
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.8);

*, *:active, *:focus {
outline: none !important;
box-shadow: none;
}

.open-filter {
background-color: transparent;
margin: 0 3px;
font-size: @font-large;
position: relative;
border-radius: 0 px;

&:active {
box-shadow: none;
}

.filter-counter {
color: @chip-text-color;
font-size: @font-extra-extra-small;
background: @chip-background-color;
border-radius: 50%;
padding: 1px 5px;
vertical-align: middle;
}
}

&.disabled {
color: @inactive-color;
}
}
}

.more-options-menu-container {
margin-right: 20px;

Expand Down
3 changes: 3 additions & 0 deletions webapp/src/ts/components/components.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { ReportImageComponent } from '@mm-components/report-image/report-image.c
import { NavigationComponent } from '@mm-components/navigation/navigation.component';
import { EnketoComponent } from '@mm-components/enketo/enketo.component';
import { SearchBarComponent } from '@mm-components/search-bar/search-bar.component';
import { FilterSliderIconComponent } from '@mm-components/filter-slider-icon/filter-slider-icon.component';
import { MultiselectBarComponent } from '@mm-components/multiselect-bar/multiselect-bar.component';
import {
AnalyticsTargetsProgressComponent
Expand Down Expand Up @@ -61,6 +62,7 @@ import { ToolBarComponent } from '@mm-components/tool-bar/tool-bar.component';
FreetextFilterComponent,
FastActionButtonComponent,
SearchBarComponent,
FilterSliderIconComponent,
MultiselectBarComponent,
SortFilterComponent,
SenderComponent,
Expand Down Expand Up @@ -104,6 +106,7 @@ import { ToolBarComponent } from '@mm-components/tool-bar/tool-bar.component';
FastActionButtonComponent,
StatusFilterComponent,
SearchBarComponent,
FilterSliderIconComponent,
MultiselectBarComponent,
FreetextFilterComponent,
SortFilterComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<section class="mm-filter-slider-container" [class.disabled]="disabled">
<button
mat-flat-button
class="open-filter"
*ngIf="showFilter"
(click)="toggleFilter.emit()">
<span class="fa fa-sliders"></span>
<span class="open-filter-label">{{ 'search_bar.filter.label' | translate }}</span>
<span class="filter-counter" *ngIf="activeFilters">{{ activeFilters.toString() | translate }}</span>
</button>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
Component,
EventEmitter,
Input,
OnDestroy,
AfterContentInit,
AfterViewInit,
Output,
} from '@angular/core';
import { Store } from '@ngrx/store';
import { combineLatest, Subscription } from 'rxjs';

import { Selectors } from '@mm-selectors/index';
import { ResponsiveService } from '@mm-services/responsive.service';

@Component({
selector: 'mm-filter-slider-icon',
templateUrl: './filter-slider-icon.component.html'
})
export class FilterSliderIconComponent implements AfterContentInit, AfterViewInit, OnDestroy {
@Input() disabled;
@Input() showFilter;
@Input() lastVisitedDateExtras;
@Output() toggleFilter: EventEmitter<any> = new EventEmitter();

private filters;
subscription: Subscription = new Subscription();
activeFilters: number = 0;
openSearch = false;

constructor(
private store: Store,
private responsiveService: ResponsiveService,
) { }

ngAfterContentInit() {
this.subscribeToStore();
}

ngAfterViewInit() {
}

private subscribeToStore() {
const subscription = combineLatest(
this.store.select(Selectors.getSidebarFilter),
this.store.select(Selectors.getFilters),
).subscribe(([sidebarFilter, filters]) => {
this.activeFilters = sidebarFilter?.filterCount?.total || 0;
this.filters = filters;

if (!this.openSearch && this.filters?.search) {
this.toggleMobileSearch();
}
});
this.subscription.add(subscription);
}

clear() {
if (this.disabled) {
return;
}
this.toggleMobileSearch(false);
}

toggleMobileSearch(forcedValue?) {
if (forcedValue === undefined && (this.disabled || !this.responsiveService.isMobile())) {
return;
}

this.openSearch = forcedValue !== undefined ? forcedValue : !this.openSearch;
}

showSearchIcon() {
return !this.openSearch && !this.filters?.search;
}

showClearIcon() {
return this.openSearch || !!this.filters?.search;
}

ngOnDestroy() {
this.subscription.unsubscribe();
}
}
2 changes: 2 additions & 0 deletions webapp/src/ts/modules/modules.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
AnalyticsTargetAggregatesDetailComponent
} from '@mm-modules/analytics/analytics-target-aggregates-detail.component';
import { TasksComponent } from '@mm-modules/tasks/tasks.component';
import { TasksSidebarFilterComponent } from '@mm-modules/tasks/tasks-sidebar-filter.component';
import { TasksContentComponent } from '@mm-modules/tasks/tasks-content.component';
import { TasksGroupComponent } from '@mm-modules/tasks/tasks-group.component';
import { TestingComponent } from '@mm-modules/testing/testing.component';
Expand Down Expand Up @@ -75,6 +76,7 @@ import { DirectivesModule } from '@mm-directives/directives.module';
AnalyticsTargetAggregatesDetailComponent,
AnalyticsTargetAggregatesSidebarFilterComponent,
TasksComponent,
TasksSidebarFilterComponent,
TasksContentComponent,
TasksGroupComponent,
TestingComponent,
Expand Down
91 changes: 44 additions & 47 deletions webapp/src/ts/modules/tasks/tasks-content.component.html
Original file line number Diff line number Diff line change
@@ -1,55 +1,52 @@
<div class="content-pane right-pane">

<div class="col-sm-8 item-content empty-selection" *ngIf="loadingContent || loadingForm">
<div>
<div class="loader"></div>
</div>
<div class="empty-selection" *ngIf="loadingContent || loadingForm">
<div>
<div class="loader"></div>
</div>
</div>

<div class="col-sm-8 item-content empty-selection" *ngIf="!selectedTask && !loadingContent">
<div>{{'No task selected' | translate}}</div>
</div>
<div class="empty-selection" *ngIf="!selectedTask && !loadingContent">
<div>{{'No task selected' | translate}}</div>
</div>

<div class="col-sm-8 item-content empty-selection" *ngIf="!loadingContent && !loadingForm && contentError">
<div>{{ errorTranslationKey | translate}}</div>
</div>
<div class="empty-selection" *ngIf="!loadingContent && !loadingForm && contentError">
<div>{{ errorTranslationKey | translate}}</div>
</div>

<div class="col-sm-8 item-content" *ngIf="selectedTask && !form && !loadingContent && !loadingForm && !contentError">
<div class="body">
<div>
<ul>
<li>
<h2>{{selectedTask.title | translateFrom:selectedTask}}</h2>
</li>
<li>
<label>{{'task.date' | translate}}</label>
<p [innerHTML]="selectedTask.date | simpleDate"></p>
</li>
<li *ngIf="selectedTask.priority">
<label>{{'task.priority' | translate}}</label>
<p [ngClass]="{'high-priority': selectedTask.priority === 'high', 'medium-priority': selectedTask.priority === 'medium'}">
<span class="priority">
<i class="fa fa-exclamation-triangle high-priority-icon"></i>
<i class="fa fa-info-circle medium-priority-icon"></i>
</span>
{{selectedTask.priorityLabel | translateFrom:selectedTask}}
</p>
</li>
<li *ngFor="let field of selectedTask.fields">
<label>{{field.label | translateFrom:selectedTask}}</label>
<p>{{field.value | translateFrom:selectedTask}}</p>
</li>
<li class="actions" *ngIf="selectedTask.actions.length">
<a class="btn btn-primary" *ngFor="let action of selectedTask.actions" (click)="performAction(action)">{{action.label | translateFrom:selectedTask}}</a>
</li>
</ul>
</div>
<div id="tasks-content" class=".task-wrap" *ngIf="selectedTask && !form && !loadingContent && !loadingForm && !contentError">
<div class="body">
<div>
<ul>
<li>
<h2>{{selectedTask.title | translateFrom:selectedTask}}</h2>
</li>
<li>
<label>{{'task.date' | translate}}</label>
<p [innerHTML]="selectedTask.date | simpleDate"></p>
</li>
<li *ngIf="selectedTask.priority">
<label>{{'task.priority' | translate}}</label>
<p [ngClass]="{'high-priority': selectedTask.priority === 'high', 'medium-priority': selectedTask.priority === 'medium'}">
<span class="priority">
<i class="fa fa-exclamation-triangle high-priority-icon"></i>
<i class="fa fa-info-circle medium-priority-icon"></i>
</span>
{{selectedTask.priorityLabel | translateFrom:selectedTask}}
</p>
</li>
<li *ngFor="let field of selectedTask.fields">
<label>{{field.label | translateFrom:selectedTask}}</label>
<p>{{field.value | translateFrom:selectedTask}}</p>
</li>
<li class="actions" *ngIf="selectedTask.actions.length">
<a class="btn btn-primary" *ngFor="let action of selectedTask.actions" (click)="performAction(action)">{{action.label | translateFrom:selectedTask}}</a>
</li>
</ul>
</div>
</div>
</div>

<div class="col-sm-8 item-content" [hidden]="!selectedTask || !form || loadingForm || loadingContent || contentError">
<div class="body">
<mm-enketo formId="task-report" [status]="enketoStatus" (onSubmit)="save()" (onCancel)="navigationCancel()"></mm-enketo>
</div>
<div [hidden]="!selectedTask || !form || loadingForm || loadingContent || contentError">
<div class="body">
<mm-enketo formId="task-report" [status]="enketoStatus" (onSubmit)="save()" (onCancel)="navigationCancel()"></mm-enketo>
</div>
</div>
</div>
49 changes: 49 additions & 0 deletions webapp/src/ts/modules/tasks/tasks-sidebar-filter.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<section class="sidebar-filter">
<div class="sidebar-backdrop" [ngClass]="{ hidden: !isOpen }" (click)="toggleSidebarFilter()"></div>

<div class="sidebar-main" [ngClass]="{ hidden: !isOpen }">
<div class="sidebar-header">
<p class="sidebar-title">{{ 'reports.sidebar.filter.title' | translate }}</p>
<a class="sidebar-reset" [class.disabled]="disabled" (click)="resetFilters()">{{ 'reports.sidebar.filter.reset' | translate }}</a>
<a class="sidebar-close fa fa-times" (click)="toggleSidebarFilter()"></a>
</div>

<div class="sidebar-body">
<accordion [closeOthers]="true" [isAnimated]="true">
<!-- 1. Place -->
<accordion-group id="place-filter-accordion">
<ng-container
accordion-heading
[ngTemplateOutlet]="headerTemplate"
[ngTemplateOutletContext]="{
numSelected: filterCount.placeFilter,
label: 'reports.sidebar.filter.place',
filters: [ 'placeFilter' ]
}">
</ng-container>
<mm-facility-filter
class="filter"
fieldId="placeFilter"
(search)="applyFilters()"
[disabled]="disabled"
[inline]="true">
</mm-facility-filter>
</accordion-group>
</accordion>
</div>

<div class="sidebar-footer">
<button type="button" class="btn btn-primary" (click)="toggleSidebarFilter()">{{ 'reports.sidebar.filter.submit' | translate }}</button>
</div>
</div>
</section>

<ng-template #headerTemplate let-numSelected="numSelected" let-label="label" let-filters="filters">
<button class="btn btn-link">
<p class="title">{{ label | translate }}</p>
<div class="chip" *ngIf="numSelected" [class.disabled]="disabled">
<span>{{ numSelected | translate }}</span>
<span class="fa fa-times" (click)="clearFilters(filters); $event.stopPropagation();"></span>
</div>
</button>
</ng-template>
Loading

0 comments on commit 67e9c60

Please sign in to comment.