diff --git a/ui/src/components/form/FormGenerator.tsx b/ui/src/components/form/FormGenerator.tsx index a65e937..49321ea 100644 --- a/ui/src/components/form/FormGenerator.tsx +++ b/ui/src/components/form/FormGenerator.tsx @@ -120,9 +120,23 @@ function transformData(data: any, re: RegExp) { }) } +function formatDraftDate(date: Date) { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + const seconds = String(date.getSeconds()).padStart(2, '0') + const ampm = date.toLocaleString('en-US', { timeZoneName: 'short' }).split(' ')[2] + const timeZone = date.toLocaleString('en-US', { timeZoneName: 'short' }).split(' ')[3] + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${ampm} ${timeZone}` +} + export function FormGenerator({ formMetadata, root }) { // State and context variables + const [lastDraftUpdate, setLastDraftUpdate] = useState("") const [lastSubmissionUpdate, setLastSubmissionUpdate] = useState(`Submissions-${new Date().toUTCString()}`) const [draftModified, setDraftModified] = useState(false) @@ -339,10 +353,12 @@ export function FormGenerator({ formMetadata, root }) { // sets the interval for saving drafts useEffect(() => { const seconds = 10 // save the drafts every ten seconds (10 * 1000 milliseconds) - const draftSaveInterval = draftModified + const validPatient = !!patientIdentifier.submitter_donor_id && !!patientIdentifier.program_id + const draftSaveInterval = draftModified && validPatient ? setInterval(() => { saveDraft() setDraftModified(false) + setLastDraftUpdate(formatDraftDate(new Date())) }, seconds * 1000) : null @@ -407,6 +423,7 @@ export function FormGenerator({ formMetadata, root }) { onCompleted: () => { setDraftModified(false) updateDraftID(null) + setLastDraftUpdate("") } }) @@ -517,6 +534,7 @@ export function FormGenerator({ formMetadata, root }) { // final render return (
+ { lastDraftUpdate !== "" ? <>Last autosaved at: {lastDraftUpdate}
: <> }
{ @@ -552,7 +570,7 @@ export function FormGenerator({ formMetadata, root }) { } field.name)} headers={tableHeaders} @@ -566,6 +584,7 @@ export function FormGenerator({ formMetadata, root }) { const isDisabled = field.conditionals === null ? false : doesFieldNotMeetAllConditions(field.conditionals, state.fields) + const isReadonly = field.readonly ?? false const errorMessage = isDisabled ? null : state.errorMessages[field.name] switch (String(field.component).toLowerCase()) { @@ -578,6 +597,7 @@ export function FormGenerator({ formMetadata, root }) { label={labels[field.name]} value={state.fields[field.name]} isDisabled={isDisabled} + isReadonly={isReadonly} errorMessage={errorMessage} validator={state.validators[field.name]} updateErrorMessage={updateErrorMessages} @@ -591,6 +611,7 @@ export function FormGenerator({ formMetadata, root }) { label={labels[field.name]} value={state.fields[field.name]} isDisabled={isDisabled} + isReadonly={isReadonly} validator={state.validators[field.name]} errorMessage={errorMessage} updateErrorMessage={updateErrorMessages} @@ -604,6 +625,7 @@ export function FormGenerator({ formMetadata, root }) { label={labels[field.name]} value={state.fields[field.name]} isDisabled={isDisabled} + isReadonly={isReadonly} validator={state.validators[field.name]} errorMessage={errorMessage} updateErrorMessage={updateErrorMessages} @@ -621,6 +643,7 @@ export function FormGenerator({ formMetadata, root }) { study={patientIdentifier.study} label={labels[field.name]} isDisabled={isDisabled} + isReadonly={isReadonly} errorMessage={errorMessage} options={state.options[field.name]} validator={state.validators[field.name]} @@ -635,6 +658,7 @@ export function FormGenerator({ formMetadata, root }) { study={patientIdentifier.study} label={labels[field.name]} isDisabled={isDisabled} + isReadonly={isReadonly} errorMessage={errorMessage} options={state.options[field.name]} validator={state.validators[field.name]} diff --git a/ui/src/components/form/fields/input.tsx b/ui/src/components/form/fields/input.tsx index b152578..54d075f 100644 --- a/ui/src/components/form/fields/input.tsx +++ b/ui/src/components/form/fields/input.tsx @@ -6,7 +6,7 @@ import "react-datepicker/dist/react-datepicker.css" import { fieldIsRequired } from "../utils" -export function DateInputField({ field, study, label, value, comparingDate = null, isDisabled, errorMessage, validator, updateErrorMessage, updateValue }) { +export function DateInputField({ field, study, label, value, comparingDate = null, isDisabled, isReadonly, errorMessage, validator, updateErrorMessage, updateValue }) { // calculate time difference in years between the current value and a given date const otherDate = comparingDate ?? new Date() const difference = dayjs(otherDate).diff(dayjs(value), 'years') @@ -56,12 +56,13 @@ export function DateInputField({ field, study, label, value, comparingDate = nul showMonthYearPicker showFullMonthYearPicker showFourColumnMonthYearPicker + readOnly={isReadonly} /> ) } -export function InputField({ field, study, label, value, isDisabled, errorMessage, validator, updateErrorMessage, updateValue }) { +export function InputField({ field, study, label, value, isDisabled, isReadonly, errorMessage, validator, updateErrorMessage, updateValue }) { return (
@@ -83,6 +84,7 @@ export function InputField({ field, study, label, value, isDisabled, errorMessag name={field.name} value={value ?? ''} type={field.type} + readOnly={isReadonly} placeholder={field.placeholder} onChange={(e) => { let newValue = ["number", "integer"].includes(field.type.toLowerCase()) diff --git a/ui/src/components/form/fields/select.tsx b/ui/src/components/form/fields/select.tsx index b5fc75e..c398d0b 100644 --- a/ui/src/components/form/fields/select.tsx +++ b/ui/src/components/form/fields/select.tsx @@ -3,10 +3,10 @@ import { Form, Icon, Popup } from "semantic-ui-react"; import * as R from "remeda"; import { constructDropdown, fieldIsRequired } from '../utils' -export function SmallSelectField({ field, study, label, isDisabled, errorMessage, options, validator, value, updateErrorMessage, updateValue }) { +export function SmallSelectField({ field, study, label, isDisabled, isReadonly, errorMessage, options, validator, value, updateErrorMessage, updateValue }) { const processedOptions = constructDropdown(options) return ( - +
* } @@ -22,7 +22,7 @@ export function SmallSelectField({ field, study, label, isDisabled, errorMessage inverted />
- + {R.map(processedOptions, (option) => { const isActive = value === option.value; return ( @@ -57,12 +57,12 @@ export function SmallSelectField({ field, study, label, isDisabled, errorMessage ) } -export function LargeSelectField({ field, study, label, isDisabled, errorMessage, options, validator, value, updateErrorMessage, updateValue }) { +export function LargeSelectField({ field, study, label, isDisabled, isReadonly, errorMessage, options, validator, value, updateErrorMessage, updateValue }) { const processedOptions = useMemo(() => { return constructDropdown(options) }, [options]) return ( - +
* } diff --git a/ui/src/components/form/fields/textarea.tsx b/ui/src/components/form/fields/textarea.tsx index 0527285..344707f 100644 --- a/ui/src/components/form/fields/textarea.tsx +++ b/ui/src/components/form/fields/textarea.tsx @@ -7,6 +7,7 @@ export function TextAreaField({ study, label, isDisabled, + isReadonly, validator, value, errorMessage, @@ -14,7 +15,7 @@ export function TextAreaField({ updateValue }) { return ( - +
* } diff --git a/ui/src/components/form/utils.js b/ui/src/components/form/utils.js index 50b8886..6e0730d 100644 --- a/ui/src/components/form/utils.js +++ b/ui/src/components/form/utils.js @@ -64,7 +64,7 @@ export const doesFieldNotMeetAllConditions = (conditionals, gfs) => { else { Array.isArray(conditionals[key]) ? check.push(conditionals[key].includes(gfs[key])) : - check.push(conditionals[key] === gfs[key]); + check.push(conditionals[key] === gfs[key] || conditionals[key] === Boolean(gfs[key])); } });