Skip to content

Commit

Permalink
fix: [DHIS2-15383] align mandatory behaviour for all value types (#3413)
Browse files Browse the repository at this point in the history
  • Loading branch information
superskip authored Nov 10, 2023
1 parent 2ba6014 commit b0eddc7
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 69 deletions.
5 changes: 4 additions & 1 deletion cypress/e2e/EnrollmentPage/StagesAndEventsWidget.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ Feature: User interacts with Stages and Events Widget

Scenario: User can close the Stages and Events Widget
Given you open the enrollment page
And the program stages should be displayed
When you click the stages and events widget toggle open close button
Then the stages and events widget should be closed

Scenario: User can close and reopen the Stages and Events Widget
Given you open the enrollment page
And the program stages should be displayed
When you click the stages and events widget toggle open close button
Then the stages and events widget should be closed
When you click the stages and events widget toggle open close button
And you click the stages and events widget toggle open close button
Then the program stages should be displayed

Scenario: User can view the list of events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type Props = {
mutate: (data: any) => Promise<any>
}

type State = {
fileSelectorOpen: boolean,
};

const styles = theme => ({
horizontalContainer: {
display: 'flex',
Expand Down Expand Up @@ -74,10 +78,18 @@ const styles = theme => ({
},
});

class D2FilePlain extends Component<Props> {
class D2FilePlain extends Component<Props, State> {
hiddenFileSelectorRef: any;
fileSelectorOpen: boolean;
constructor(props: Props) {
super(props);
this.state = {
fileSelectorOpen: false,
};
}

handleFileChange = (e: Object) => {
this.setState((state) => { state.fileSelectorOpen = false; });
e.preventDefault();
const file = e.target.files[0];
e.target.value = null;
Expand All @@ -100,12 +112,23 @@ class D2FilePlain extends Component<Props> {
}
handleButtonClick = () => {
this.hiddenFileSelectorRef.click();
this.setState((state) => { state.fileSelectorOpen = true; });
}

handleCancel = () => {
this.setState((state) => { state.fileSelectorOpen = false; });
}

handleRemoveClick = () => {
this.props.onBlur(null);
}

handleBlur = () => {
if (!this.state.fileSelectorOpen) {
this.props.onBlur(this.getFileUrl());
}
}

getFileUrl = () => {
const value = this.props.value;
if (value) {
Expand All @@ -122,14 +145,15 @@ class D2FilePlain extends Component<Props> {
const containerClass = isVertical ? classes.verticalContainer : classes.horizontalContainer;
const selectedFileTextContainerClass = isVertical ? classes.verticalSelectedFileTextContainer : classes.horizontalSelectedFileTextContainer;
return (
<div>
<div onBlur={this.handleBlur}>
<input
className={classes.input}
type="file"
ref={(hiddenFileSelector) => {
this.hiddenFileSelectorRef = hiddenFileSelector;
}}
onChange={e => this.handleFileChange(e)}
onCancel={this.handleCancel} // eslint-disable-line react/no-unknown-property
/>
{
(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type Props = {
mutate: (data: any) => Promise<any>
}

type State = {
imageSelectorOpen: boolean,
};

const styles = theme => ({
horizontalContainer: {
display: 'flex',
Expand Down Expand Up @@ -72,10 +76,18 @@ const styles = theme => ({
},
});

class D2ImagePlain extends Component<Props> {
class D2ImagePlain extends Component<Props, State> {
hiddenimageSelectorRef: any;
imageSelectorOpen: boolean;
constructor(props: Props) {
super(props);
this.state = {
imageSelectorOpen: false,
};
}

handleImageChange = (e: Object) => {
this.setState((state) => { state.imageSelectorOpen = false; });
e.preventDefault();
const image = e.target.files[0];
e.target.value = null;
Expand All @@ -98,13 +110,24 @@ class D2ImagePlain extends Component<Props> {
}
handleButtonClick = () => {
this.hiddenimageSelectorRef.click();
this.setState((state) => { state.imageSelectorOpen = true; });
}

handleCancel = () => {
this.setState((state) => { state.imageSelectorOpen = false; });
}

handleRemoveClick = () => {
this.props.onBlur(null);
}

getimageUrl = () => {
handleBlur = () => {
if (!this.state.imageSelectorOpen) {
this.props.onBlur(this.getImageUrl());
}
}

getImageUrl = () => {
const value = this.props.value;
if (value) {
return value.url || inMemoryFileStore.get(value.value);
Expand All @@ -116,13 +139,13 @@ class D2ImagePlain extends Component<Props> {
const { value, classes, asyncUIState, orientation, disabled } = this.props;
const isVertical = orientation === orientations.VERTICAL;
const isUploading = asyncUIState && asyncUIState.loading;
const imageUrl = this.getimageUrl();
const imageUrl = this.getImageUrl();
// $FlowFixMe[prop-missing] automated comment
const containerClass = isVertical ? classes.verticalContainer : classes.horizontalContainer;
// $FlowFixMe[prop-missing] automated comment
const selectedImageTextContainerClass = isVertical ? classes.verticalSelectedImageTextContainer : classes.horizontalSelectedImageTextContainer;
return (
<div>
<div onBlur={this.handleBlur}>
<input
className={classes.input}
type="file"
Expand All @@ -131,6 +154,7 @@ class D2ImagePlain extends Component<Props> {
this.hiddenimageSelectorRef = hiddenimageSelector;
}}
onChange={e => this.handleImageChange(e)}
onCancel={this.handleCancel} // eslint-disable-line react/no-unknown-property
/>
{
(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,27 @@ const MultiSelectFieldComponentPlain = (props: Props) => {
onSelect(multiSelectSelected.join(MULTI_TEXT_SEPARATOR));
};

const handleBlur = () => {
onBlur(selected ? selected.join(MULTI_TEXT_SEPARATOR) : null);
};

return (
<MultiSelectFieldUI
dataTest="multi-select-field"
onChange={onHandleChange}
onFocus={onFocus}
onBlur={onBlur}
onKeyDown={onFocus}
selected={selected}
filterable
filterPlaceholder={translations.filterPlaceholder}
noMatchText={translations.noMatchText}
>
{options.map(option => (
<MultiSelectOption key={option.id} label={option.label} value={option.value} />
))}
</MultiSelectFieldUI>
<div onBlur={handleBlur}>
<MultiSelectFieldUI
dataTest="multi-select-field"
onChange={onHandleChange}
onFocus={onFocus}
onKeyDown={onFocus}
selected={selected}
filterable
filterPlaceholder={translations.filterPlaceholder}
noMatchText={translations.noMatchText}
>
{options.map(option => (
<MultiSelectOption key={option.id} label={option.label} value={option.value} />
))}
</MultiSelectFieldUI>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type MultiSelectOptionConfig = {
export type Props = {
onSelect: (value?: string) => void,
onFocus: () => void,
onBlur: () => void,
onBlur: (value: ?string) => void,
options: Array<MultiSelectOptionConfig>,
value?: string,
translations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ type Props = {
onSetFocus: () => void,
onRemoveFocus: () => void,
inFocus: boolean,
onBlur?: ?(event: SyntheticEvent<HTMLInputElement>) => void,
onBlur?: (value: ?string) => void,
onFocus: () => void,
classes: {
inputWrapperFocused: string,
inputWrapperUnfocused: string,
}
};

export const withFocusHandler = () => (InnerCompnent: React.ComponentType<any>) =>
export const withFocusHandler = () => (InnerComponent: React.ComponentType<any>) =>
class FocusHandlerHOC extends React.Component<Props> {
handleRemoveFocus = () => {
handleRemoveFocus = (value: string) => {
this.props.onRemoveFocus();
this.props.onBlur && this.props.onBlur(value);
}

handleFocus = () => {
Expand All @@ -40,7 +41,7 @@ export const withFocusHandler = () => (InnerCompnent: React.ComponentType<any>)
className={classNames(defaultClasses.inputWrapper, inputWrapper)}
>
{/* $FlowFixMe[cannot-spread-inexact] automated comment */}
<InnerCompnent
<InnerComponent
onFocus={this.handleFocus}
onBlur={this.handleRemoveFocus}
onSelect={this.handleSelect}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const getStyles = () => ({

type Props = {
onSelectClick: (selectedOrgUnit: Object) => void,
onBlur: (selectedOrgUnit: Object) => void,
selected?: ?string,
maxTreeHeight?: ?number,
disabled?: ?boolean,
Expand All @@ -56,6 +57,7 @@ type Props = {
const OrgUnitFieldPlain = (props: Props) => {
const {
onSelectClick,
onBlur,
classes,
selected,
maxTreeHeight,
Expand Down Expand Up @@ -136,10 +138,15 @@ const OrgUnitFieldPlain = (props: Props) => {
setSearchText(event.currentTarget.value);
};

const handleBlur = () => {
onBlur && onBlur(null);
};

const styles = maxTreeHeight ? { maxHeight: maxTreeHeight, overflowY: 'auto' } : null;
return (
<div
className={classes.container}
onBlur={handleBlur}
>
<div className={classes.debounceFieldContainer}>
<DebounceField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ class OptionsSelectVirtualizedPlain extends React.Component<Props, State> {
);
}

onBlur = () => {
this.props.onSelect(this.props.value);
}

render() {
const {
options,
Expand Down Expand Up @@ -220,6 +224,7 @@ class OptionsSelectVirtualizedPlain extends React.Component<Props, State> {
>
<div
data-test={dataTest}
onBlur={this.onBlur}
>
{/* $FlowFixMe[cannot-spread-inexact] automated comment */}
<VirtualizedSelect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ const UserFieldPlain = (props: Props) => {
focusSelectedInput.current = true;
};

const handleBlur = () => {
// $FlowExpectedError
onSet(value);
};

if (value) {
return (
<Selected
Expand All @@ -66,7 +71,7 @@ const UserFieldPlain = (props: Props) => {
}

return (
<div>
<div onBlur={handleBlur}>
<UserSearch
onSet={handleSet}
inputWrapperClasses={classes}
Expand Down
21 changes: 5 additions & 16 deletions src/core_modules/capture-core/rules/converters/inputConverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const dateMomentFormat = 'YYYY-MM-DD';

const convertStringValue = (value: ?string): ?string => (value || null);
const convertNumericValue = (value: any): ?number => (typeof value === 'number' ? value : null);
const convertObjectToString = (value: ?{ name: string }) => (value ? value.name : null);

export const inputConverter: IConvertInputRulesValue = {
convertText: convertStringValue,
Expand Down Expand Up @@ -38,24 +39,12 @@ export const inputConverter: IConvertInputRulesValue = {
log.warn('convertTrackerAssociate not implemented', value);
return null;
},
convertUserName: (value: any): ?string => {
log.warn('convertUserName not implemented', value);
return null;
},
convertUserName: convertStringValue,
convertCoordinate: (value: any): ?string => (
(value && value.latitude && value.longitude) ? `[${value.latitude},${value.longitude}]` : null),
convertOrganisationUnit: (value: any): ?string => {
log.warn('convertOrganisationUnit not implemented', value);
return null;
},
convertOrganisationUnit: convertObjectToString,
convertAge: (value: any): ?string => inputConverter.convertDate(value),
convertUrl: convertStringValue,
convertFile(value: any): ?string {
log.warn('convertFile not implemented', value);
return null;
},
convertImage(value: any): ?string {
log.warn('convertImage not implemented', value);
return null;
},
convertFile: convertObjectToString,
convertImage: convertObjectToString,
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import moment from 'moment';
import type { IConvertOutputRulesEffectsValue } from '@dhis2/rules-engine-javascript';
import { convertMomentToDateFormatString } from '../../utils/converters/date';


// These functions are only used for creating assignment effects

const dateMomentFormat = 'YYYY-MM-DD';

export const outputConverter: IConvertOutputRulesEffectsValue = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import * as React from 'react';

import { MultiSelectionsBoxes } from '../internal/SelectionBoxes/MultiSelectionsBoxes/MultiSelectionsBoxes.component';
import { SingleSelectionBoxes } from '../internal/SelectionBoxes/SingleSelectionBoxes/SingleSelectionBoxes.component';
import { withKeyboardNavigation } from '../internal/SelectionBoxes/withKeyboardNavigation';

import { orientations } from '../constants/orientations.const';

type Props = {
multiSelect?: ?boolean,
};

export const SelectionBoxes = (props: Props) => {
const SelectionBoxesPlain = (props: Props) => {
const { multiSelect, ...passOnProps } = props;

if (multiSelect) {
Expand All @@ -31,3 +32,5 @@ export const SelectionBoxes = (props: Props) => {
/>
);
};

export const SelectionBoxes = withKeyboardNavigation()(SelectionBoxesPlain);
Loading

0 comments on commit b0eddc7

Please sign in to comment.