-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(feat) O3-3632 - Add config for maxDate and minDate to DateObsField #1261
Changes from 2 commits
e40f4c0
0cd381b
32486f2
e1aa33b
f95c9bb
9f1979a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,13 +3,15 @@ import classNames from 'classnames'; | |||||
import { Field } from 'formik'; | ||||||
import { useTranslation } from 'react-i18next'; | ||||||
import { InlineNotification, Layer, Select, SelectItem } from '@carbon/react'; | ||||||
import { OpenmrsDatePicker, useConfig } from '@openmrs/esm-framework'; | ||||||
import { OpenmrsDatePicker, translateFrom, useConfig } from '@openmrs/esm-framework'; | ||||||
import { type ConceptResponse } from '../../patient-registration.types'; | ||||||
import { type FieldDefinition, type RegistrationConfig } from '../../../config-schema'; | ||||||
import { Input } from '../../input/basic-input/input/input.component'; | ||||||
import { useConcept, useConceptAnswers } from '../field.resource'; | ||||||
import { PatientRegistrationContext } from '../../patient-registration-context'; | ||||||
import styles from './../field.scss'; | ||||||
import dayjs from 'dayjs'; | ||||||
import { moduleName } from '../../../constants'; | ||||||
|
||||||
export interface ObsFieldProps { | ||||||
fieldDefinition: FieldDefinition; | ||||||
|
@@ -57,8 +59,8 @@ export function ObsField({ fieldDefinition }: ObsFieldProps) { | |||||
concept={concept} | ||||||
label={fieldDefinition.label} | ||||||
required={fieldDefinition.validation.required} | ||||||
dateFormat={fieldDefinition.dateFormat} | ||||||
placeholder={fieldDefinition.placeholder} | ||||||
minDate={fieldDefinition.minDate} | ||||||
maxDate={fieldDefinition.maxDate} | ||||||
/> | ||||||
); | ||||||
case 'Coded': | ||||||
|
@@ -159,14 +161,43 @@ interface DateObsFieldProps { | |||||
concept: ConceptResponse; | ||||||
label: string; | ||||||
required?: boolean; | ||||||
dateFormat?: string; | ||||||
placeholder?: string; | ||||||
minDate?: string; | ||||||
maxDate?: string; | ||||||
} | ||||||
|
||||||
function DateObsField({ concept, label, required, placeholder }: DateObsFieldProps) { | ||||||
const evaluateConfigDate = (dateString: string, dateType: string): Date | null => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So basically, the real feature being supported by this PR is the ability to specify There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically, the question here is "why don't we just build that instead of this?" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1, I would support a config interface like, for example,
does what's actually needed, is easier to maintain and code, and easier to understand and use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ibacher & @brandones, my question here would be, don't we anticipate a scenario where someone would pass a fixed date e.g 2024-10-01 as either the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I just can't really imagine a use case for that. It is good not to build things no one needs, or to design and build things with no use case. It is valuable to keep our code easy to understand, maintain, and use. If someday a use case comes up, we'll implement it then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ibacher / @brandones / @kajambiya please keep in mind that "today" from the perspective of a field on a form often needs to be "as of the encounter date" not "as of the entry date". So it is not sufficient to say we are only going to support past and future as of a "new Date()" object. So this might be an example of where a parent component (eg. a parent form with an encounterDate variable would want to set that as the minDate / maxDate / defaultDate on an obsField it contains). Sorry if this is not relevant, but wanted to mention it in case it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mseaton Yeah, retrospective registration probably requires a redesign of the app. Here, though, we're just passing in a value from the configuration, so the issue is kind of orthogonal to that concern (i.e., we could implement this so that it interprets "today" relative to the user's current selected time for the registration to happen). The issue here is that there's isn't a lot of use for handling strings like '2020-01-05'. |
||||||
if (!dateString) { | ||||||
return null; | ||||||
} | ||||||
if (dateString === 'today') { | ||||||
return dayjs(new Date()).toDate(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
const parsedDate = dayjs(dateString); | ||||||
if (!parsedDate.isValid()) { | ||||||
throw new Error( | ||||||
translateFrom(moduleName, 'invalidObsDateErrorMessage', `The ${dateType} date value provided is invalid!`), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would, of course, be better to include some example of what is valid. |
||||||
); | ||||||
} | ||||||
|
||||||
return parsedDate.toDate(); | ||||||
}; | ||||||
|
||||||
function DateObsField({ concept, label, required, maxDate, minDate }: DateObsFieldProps) { | ||||||
const { t } = useTranslation(); | ||||||
const fieldName = `obs.${concept.uuid}`; | ||||||
const { setFieldValue } = useContext(PatientRegistrationContext); | ||||||
let evaluatedMinDate = null; | ||||||
let evaluatedMaxDate = null; | ||||||
let configDateError = ''; | ||||||
|
||||||
try { | ||||||
evaluatedMinDate = evaluateConfigDate(minDate, 'Min'); | ||||||
evaluatedMaxDate = evaluateConfigDate(maxDate, 'Max'); | ||||||
} catch (error) { | ||||||
configDateError = error.message; | ||||||
console.error(configDateError); | ||||||
} | ||||||
|
||||||
const onDateChange = (date: Date) => { | ||||||
setFieldValue(fieldName, date); | ||||||
|
@@ -185,9 +216,11 @@ function DateObsField({ concept, label, required, placeholder }: DateObsFieldPro | |||||
isRequired={required} | ||||||
onChange={onDateChange} | ||||||
labelText={label ?? concept.display} | ||||||
isInvalid={errors[fieldName] && touched[fieldName]} | ||||||
invalidText={t(meta.error)} | ||||||
isInvalid={(errors[fieldName] && touched[fieldName]) || configDateError} | ||||||
invalidText={t(meta.error) || configDateError} | ||||||
value={field.value} | ||||||
minDate={evaluatedMinDate} | ||||||
maxDate={evaluatedMaxDate} | ||||||
/> | ||||||
</> | ||||||
); | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You modified the interface but did not change the actual config schema. Also why did you get rid of
placeholder
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had removed it because the placeholder for the
datepicker
is now defined by theopenMRSDatepicker
component depending on the locale but I've realized that placeholder usage is not fordatepicker
alone so I'm going to add it back.