Skip to content

Commit

Permalink
feat: [DHIS2-14799] Working list for follow up (#3521)
Browse files Browse the repository at this point in the history
Co-authored-by: Joakim Storløkken Melseth <joakim@dhis2.org>
  • Loading branch information
eirikhaugstulen and JoakimSM authored Mar 6, 2024
1 parent 444682e commit 0ad3891
Show file tree
Hide file tree
Showing 23 changed files with 159 additions and 51 deletions.
3 changes: 3 additions & 0 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,9 @@ msgstr "Inactive"
msgid "Enrollment status"
msgstr "Enrollment status"

msgid "Follow up"
msgstr "Follow up"

msgid "Choose a program stage to filter by {{label}}"
msgstr "Choose a program stage to filter by {{label}}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import { D2TrueFalse } from '../../FormFields/Generic/D2TrueFalse.component';
import { orientations } from '../../FormFields/Options/SelectBoxes'; // TODO: Refactor
import { getBooleanFilterData } from './booleanFilterDataGetter';
import {
getMultiSelectBooleanFilterData,
getSingleSelectBooleanFilterData,
} from './booleanFilterDataGetter';
import type { UpdatableFilterContent } from '../types';

const getStyles = (theme: Theme) => ({
Expand All @@ -12,11 +15,12 @@ const getStyles = (theme: Theme) => ({
},
});

type Value = ?Array<any>;
type Value = ?Array<any> | string;

type Props = {
value: Value,
onCommitValue: (value: Value) => void,
allowMultiple: boolean,
classes: {
selectBoxesContainer: string,
},
Expand All @@ -27,13 +31,17 @@ class BooleanFilterPlain extends Component<Props> implements UpdatableFilterCont
booleanFieldInstance: ?D2TrueFalse;

onGetUpdateData() {
const value = this.props.value;
const { value, allowMultiple } = this.props;

if (!value) {
if (!value && value !== false) {
return null;
}

return getBooleanFilterData(value);
if (!allowMultiple) {
return getSingleSelectBooleanFilterData(value);
}

return getMultiSelectBooleanFilterData(value);
}

onIsValid() { //eslint-disable-line
Expand All @@ -53,7 +61,7 @@ class BooleanFilterPlain extends Component<Props> implements UpdatableFilterCont
>
<D2TrueFalse
ref={this.setBooleanFieldInstance}
allowMultiple
allowMultiple={this.props.allowMultiple}
value={value}
onBlur={onCommitValue}
orientation={orientations.VERTICAL}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
// @flow
import * as React from 'react';
import { BooleanFilter } from './BooleanFilter.component';
import type { BooleanFilterData } from './types';
import type { BooleanFilterStringified } from './types';

type Props = {
filter: ?BooleanFilterData,
filter: ?BooleanFilterStringified,
filterTypeRef: Function,
handleCommitValue: () => void,
singleSelect: boolean,
};

type State = {
value: ?Array<string>,
value: ?Array<string> | string,
};

export class BooleanFilterManager extends React.Component<Props, State> {
static calculateDefaultValueState(filter: ?BooleanFilterData): ?Array<string> {
static calculateDefaultValueState(
filter: ?BooleanFilterStringified,
singleSelect: boolean,
): ?(Array<string> | string) {
if (!filter) {
return undefined;
}

return filter
.values
.map(value => (value ? 'true' : 'false'));
return singleSelect ? filter.values[0] : filter.values;
}

constructor(props: Props) {
super(props);
this.state = {
value: BooleanFilterManager.calculateDefaultValueState(this.props.filter),
value: BooleanFilterManager.calculateDefaultValueState(this.props.filter, this.props.singleSelect),
};
}

Expand All @@ -39,14 +41,15 @@ export class BooleanFilterManager extends React.Component<Props, State> {
}

render() {
const { filter, filterTypeRef, ...passOnProps } = this.props;
const { filter, filterTypeRef, singleSelect, ...passOnProps } = this.props;

return (
// $FlowFixMe[cannot-spread-inexact] automated comment
<BooleanFilter
value={this.state.value}
innerRef={filterTypeRef}
onCommitValue={this.handleCommitValue}
allowMultiple={!singleSelect}
{...passOnProps}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// @flow
import type { BooleanFilterData } from './types';
import type { BooleanFilterStringified } from './types';

export function getBooleanFilterData(
values: Array<string>,
): BooleanFilterData {
): BooleanFilterStringified {
return {
values: values
.map(value => (value === 'true')),
values: values.map(value => value),
};
}

export const getSingleSelectBooleanFilterData = (value: any) => getBooleanFilterData([value]);

export const getMultiSelectBooleanFilterData = (values: any) => getBooleanFilterData(values);
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
export type BooleanFilterData = {|
values: Array<boolean>,
|};

export type BooleanFilterStringified = {|
values: Array<string>,
|};
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// @flow
export { BooleanFilterData } from './boolean.types';
export { BooleanFilterData, BooleanFilterStringified } from './boolean.types';
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export class D2TrueFalse extends Component<Props> {
const falseText = i18n.t('No');

const optionSet = new OptionSet();
optionSet.addOption(new Option((o) => { o.text = trueText; o.value = 'true'; }));
optionSet.addOption(new Option((o) => { o.text = falseText; o.value = 'false'; }));
optionSet.addOption(new Option((o) => { o.text = trueText; o.value = true; }));
optionSet.addOption(new Option((o) => { o.text = falseText; o.value = false; }));
return optionSet;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const useContents = ({ filterValue, classes, type, options, multiValueFilter, is
{...passOnProps}
filter={filterValue}
type={type}
singleSelect={!multiValueFilter}
handleCommitValue={() => setUpdateDisabled(false)}
disabledUpdate={disabledUpdate}
disabledReset={filterValue === undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import i18n from '@dhis2/d2-i18n';
import { pipe } from 'capture-core-utils';
import type { BooleanFilterData } from '../../../../../FiltersForTypes';

const getText = (key: boolean) => (key ? i18n.t('Yes') : i18n.t('No'));
const textValuesByKey = {
true: i18n.t('Yes'),
false: i18n.t('No'),
};

const getText = (key: string) => textValuesByKey[key];

export function convertBoolean(filter: BooleanFilterData): string {
return pipe(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @flow
import React, { memo } from 'react';
import React, { memo, useMemo } from 'react';
import log from 'loglevel';
import { withStyles } from '@material-ui/core/styles';
import { errorCreator } from 'capture-core-utils';
import { FilterButton } from './FilterButton';
import { FilterRestMenu } from './FilterRestMenu/FilterRestMenu.component';
import { filterTypesObject } from './filters.const';
import type { Column, StickyFilters, FiltersOnly, AdditionalFilters } from '../types';
import type { Column, StickyFilters, FiltersOnly, AdditionalFilters, FilterOnly } from '../types';

const getStyles = (theme: Theme) => ({
filterButtonContainer: {
Expand Down Expand Up @@ -54,8 +54,10 @@ const getValidElementConfigsVisiblePrioritized = (columns: Array<Column>) =>
.map(container => [container.element.id, container.element]),
);

const getValidFilterConfigs = (filtersOnly: FiltersOnly) => new Map(filtersOnly.map(filter => [filter.id, filter]));

const splitBasedOnHasValueOnInit =
(elementConfigs: Map<string, Column>, filtersWithValueOnInit: ?Object) => {
(elementConfigs: Map<string, Column | FilterOnly>, filtersWithValueOnInit: ?Object) => {
const filtersNotEmpty = filtersWithValueOnInit || {};
return Object
.keys(filtersNotEmpty)
Expand All @@ -82,7 +84,7 @@ const splitBasedOnHasValueOnInit =
};

const fillUpIndividualElements = (
elementConfigs: Map<string, Column>,
elementConfigs: Map<string, Column | FilterOnly>,
occupiedSpots: number,
) => {
const INDIVIDUAL_DISPLAY_COUNT_BASE = 4;
Expand All @@ -104,7 +106,7 @@ const fillUpIndividualElements = (
};

const getUserSelectedElements = (
elementConfigs: Map<string, Column>,
elementConfigs: Map<string, Column | FilterOnly>,
userSelectedFilters: ?Object,
) => {
const userSelectedFiltersNonEmpty = userSelectedFilters || {};
Expand All @@ -131,7 +133,7 @@ const getUserSelectedElements = (
};

const addAdditionalFiltersElements = (
elementConfigs: Map<string, Column>,
elementConfigs: Map<string, Column | FilterOnly>,
additionalFilters?: AdditionalFilters,
filtersWithValueOnInit: Object = {},
userSelectedFilters: Object = {},
Expand All @@ -152,12 +154,34 @@ const addAdditionalFiltersElements = (
return { remainingElements: elementConfigs };
};

const addShowInMoreFilters = (
elementConfigs: Map<string, Column | FilterOnly>,
filtersOnlyForShowInMoreFilters: FiltersOnly,
filtersWithValueOnInit: Object = {},
userSelectedFilters: Object = {},
) => {
const remainingElements: Map<string, Column | FilterOnly> =
new Map([...elementConfigs]);
if (filtersOnlyForShowInMoreFilters.length > 0) {
filtersOnlyForShowInMoreFilters.forEach((filter) => {
const addToRemainingElements =
!filtersWithValueOnInit[filter.id] && !userSelectedFilters[filter.id];

if (addToRemainingElements) {
remainingElements.set(filter.id, filter);
}
});
return { remainingElements };
}
return { remainingElements: elementConfigs };
};

const getIndividualElementsArray = (
validElementConfigs: Map<string, Column>,
initValueElements: Map<string, Column>,
fillUpElements: Map<string, Column>,
userSelectedElements: Map<string, Column>,
): Array<Column> => [...validElementConfigs.entries()]
validElementConfigs: Map<string, Column | FilterOnly>,
initValueElements: Map<string, Column | FilterOnly>,
fillUpElements: Map<string, Column | FilterOnly>,
userSelectedElements: Map<string, Column | FilterOnly>,
): Array<Column | FilterOnly> => [...validElementConfigs.entries()]
.map(entry => entry[1])
.map((element) => {
if (initValueElements.has(element.id) ||
Expand All @@ -180,7 +204,7 @@ const renderIndividualFilterButtons = ({
onRemoveFilter,
classes,
}: {
individualElementsArray: Array<Column>,
individualElementsArray: Array<Column | FilterOnly>,
filtersOnly?: FiltersOnly,
visibleSelectorId: ?string,
onSetVisibleSelector: Function,
Expand Down Expand Up @@ -217,7 +241,7 @@ const renderIndividualFilterButtons = ({
);

const renderRestButton = (
restElementsArray: Array<Column>,
restElementsArray: Array<Column | FilterOnly>,
onSelectRestMenuItem: Function,
) => (restElementsArray.length > 0 ? (
<FilterRestMenu
Expand All @@ -243,11 +267,24 @@ const FiltersPlain = memo<Props>((props: Props) => {
} = props;

const [visibleSelectorId, setVisibleSelector] = React.useState(props.visibleSelectorId);
const filtersOnlyCount = filtersOnly ? filtersOnly.length : 0;
const defaultFiltersOnly = useMemo(() =>
(filtersOnly || []).filter(filter => !filter.showInMoreFilters), [filtersOnly]);
const defaultFiltersOnlyCount = defaultFiltersOnly.length;


const elementsContainer = React.useMemo(() => {
const notEmptyColumns = columns || [];
const validElementConfigs = getValidElementConfigsVisiblePrioritized(notEmptyColumns);
const filtersOnlyForShowInMoreFilters: FiltersOnly = (filtersOnly || [])
.filter(filter => filter.showInMoreFilters);

const validColumnElementConfigs = getValidElementConfigsVisiblePrioritized(notEmptyColumns);
const validFilterConfigs = getValidFilterConfigs(filtersOnlyForShowInMoreFilters);

const validElementConfigs: Map<string, Column | FilterOnly> = new Map([
...validColumnElementConfigs,
...validFilterConfigs,
]);

const { filtersWithValueOnInit, userSelectedFilters } = stickyFilters;

const { initValueElements, remainingElements: remainingElementsAfterInitSplit } =
Expand All @@ -256,12 +293,19 @@ const FiltersPlain = memo<Props>((props: Props) => {
const { fillUpElements, remainingElements: remainingElementsAfterFillUp } =
fillUpIndividualElements(
remainingElementsAfterInitSplit,
initValueElements.size + filtersOnlyCount,
initValueElements.size + defaultFiltersOnlyCount,
);

const { remainingElements: remainingElementsWithShowInMoreFilters } = addShowInMoreFilters(
remainingElementsAfterFillUp,
filtersOnlyForShowInMoreFilters,
filtersWithValueOnInit,
userSelectedFilters,
);

const { remainingElements: remainingElementsWithAdditionalFilters } =
addAdditionalFiltersElements(
remainingElementsAfterFillUp, additionalFilters, filtersWithValueOnInit, userSelectedFilters);
remainingElementsWithShowInMoreFilters, additionalFilters, filtersWithValueOnInit, userSelectedFilters);

const { userSelectedElements, remainingElements } =
getUserSelectedElements(remainingElementsWithAdditionalFilters, userSelectedFilters);
Expand All @@ -283,7 +327,8 @@ const FiltersPlain = memo<Props>((props: Props) => {
}, [
columns,
stickyFilters,
filtersOnlyCount,
filtersOnly,
defaultFiltersOnlyCount,
additionalFilters,
]);

Expand All @@ -304,7 +349,7 @@ const FiltersPlain = memo<Props>((props: Props) => {
onUpdateFilter,
onClearFilter,
onRemoveFilter,
filtersOnly,
filtersOnly: defaultFiltersOnly,
classes,
});

Expand All @@ -326,7 +371,7 @@ const FiltersPlain = memo<Props>((props: Props) => {
onUpdateFilter,
onClearFilter,
onRemoveFilter,
filtersOnly,
defaultFiltersOnly,
]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type FilterOnly = {
multiValueFilter?: boolean,
tooltipContent?: string,
disabled?: boolean,
showInMoreFilters?: boolean,
transformRecordsFilter: (rawFilter: any) => Object,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const getTEIMetaDataConfig = (attributes: Array<DataElement>, orgUnitId: ?string
type,
header: formName || name,
options: optionSet && optionSet.options.map(({ text, value }) => ({ text, value })),
multiValueFilter: !!optionSet,
multiValueFilter: !!optionSet || type === dataElementTypes.BOOLEAN,
filterHidden: !(orgUnitId || searchable || unique),
}));

Expand Down
Loading

0 comments on commit 0ad3891

Please sign in to comment.