Skip to content

Commit

Permalink
Merge pull request #1418 from tidepool-org/WEB-3020-disable-ace-calcu…
Browse files Browse the repository at this point in the history
…lator-palmtree

[WEB-3020] Disable ace calculator step for palmtree pumps
  • Loading branch information
clintonium-119 authored Aug 16, 2024
2 parents 1bf7bb0 + a9e5929 commit 5a6bb7a
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 155 deletions.
275 changes: 144 additions & 131 deletions app/pages/prescription/PrescriptionForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import moment from 'moment';
import { FastField, withFormik, useFormikContext } from 'formik';
import { PersistFormikValues } from 'formik-persist-values';
import each from 'lodash/each';
import every from 'lodash/every';
import find from 'lodash/find';
import forEach from 'lodash/forEach';
import get from 'lodash/get';
Expand Down Expand Up @@ -55,6 +56,7 @@ import {
defaultUnits,
deviceIdMap,
prescriptionStateOptions,
pumpDeviceOptions,
stepValidationFields,
validCountryCodes,
} from './prescriptionFormConstants';
Expand Down Expand Up @@ -284,7 +286,7 @@ export const PrescriptionForm = props => {
const selectedClinicId = useSelector((state) => state.blip.selectedClinicId);
const stepperId = 'prescription-form-steps';
const bgUnits = get(values, 'initialSettings.bloodGlucoseUnits', defaultUnits.bloodGlucose);
const pumpId = get(values, 'initialSettings.pumpId', deviceIdMap.omnipodHorizon);
const pumpId = get(values, 'initialSettings.pumpId', deviceIdMap.palmtree);
const pump = find(devices.pumps, { id: pumpId });
const prescriptionState = get(prescription, 'state', 'draft');
const prescriptionStates = keyBy(prescriptionStateOptions, 'value');
Expand Down Expand Up @@ -332,107 +334,10 @@ export const PrescriptionForm = props => {
const [initialFocusedInput, setInitialFocusedInput] = useState();
const [singleStepEditValues, setSingleStepEditValues] = useState(values);
const isSingleStepEdit = !!pendingStep.length;
const isLastStep = activeStep === stepValidationFields.length - 1;
const validationFields = [ ...stepValidationFields ];
const isLastStep = activeStep === validationFields.length - 1;
const isNewPrescription = isEmpty(get(values, 'id'));

useEffect(() => {
// Determine the latest incomplete step, and default to starting there
if (isEditable && (isUndefined(activeStep) || isUndefined(activeSubStep))) {
let firstInvalidStep;
let firstInvalidSubStep;
let currentStep = 0;
let currentSubStep = 0;

while (isUndefined(firstInvalidStep) && currentStep < stepValidationFields.length) {
while (currentSubStep < stepValidationFields[currentStep].length) {
if (!fieldsAreValid(stepValidationFields[currentStep][currentSubStep], schema, values)) {
firstInvalidStep = currentStep;
firstInvalidSubStep = currentSubStep;
break;
}
currentSubStep++
}

currentStep++;
currentSubStep = 0;
}

setActiveStep(isInteger(firstInvalidStep) ? firstInvalidStep : 4);
setActiveSubStep(isInteger(firstInvalidSubStep) ? firstInvalidSubStep : 0);
}

// When a user comes to this component initially, without the active step and subStep set by the
// Stepper component in the url, or when editing an existing prescription,
// we delete any persisted state from localStorage.
if (status.isPrescriptionEditFlow || (get(localStorage, storageKey) && activeStepsParam === null)) {
delete localStorage[storageKey];
}

// Only use the localStorage persistence for new prescriptions - not while editing an existing one.
setFormPersistReady(!prescription);
}, []);

// Save whether or not we are editing a single step to the formik form status for easy reference
useEffect(() => {
setStatus({
...status,
isSingleStepEdit,
});
}, [isSingleStepEdit])

// Save the hydrated localStorage values to the formik form status for easy reference
useEffect(() => {
if (formPersistReady) setStatus({
...status,
hydratedValues: JSON.parse(get(localStorage, storageKey, JSON.stringify(status.hydratedValues))),
});
}, [formPersistReady]);

// Handle changes to stepper async state for completed prescription creation and revision updates
useEffect(() => {
const isRevision = !!get(values, 'id');
const isDraft = get(values, 'state') === 'draft';
const { inProgress, completed, notification, prescriptionId } = isRevision ? creatingPrescriptionRevision : creatingPrescription;

if (prescriptionId) setFieldValue('id', prescriptionId);

if (!isFirstRender && !inProgress) {
if (completed) {
setStepAsyncState(asyncStates.completed);
if (isLastStep) {

let messageAction = isRevision ? t('updated') : t('created');
if (isPrescriber) messageAction = t('finalized and sent');

setToast({
message: t('You have successfully {{messageAction}} a Tidepool Loop prescription.', { messageAction }),
variant: 'success',
});

history.push('/clinic-workspace/prescriptions');
}
}

if (completed === false) {
setToast({
message: get(notification, 'message'),
variant: 'danger',
});

setStepAsyncState(asyncStates.failed);
}
}
}, [creatingPrescription, creatingPrescriptionRevision]);

useEffect(() => {
if (stepAsyncState.complete === false) {
// Allow resubmission of form after a second
setTimeout(() => {
setStepAsyncState(asyncStates.initial);
}, 1000);
}
}, [stepAsyncState.complete]);

const handlers = {
activeStepUpdate: ([step, subStep], fromStep = [], initialFocusedInput) => {
setActiveStep(step);
Expand Down Expand Up @@ -476,7 +381,7 @@ export const PrescriptionForm = props => {
// entered in the later steps.
if (!isLastStep) {
const emptyFieldsInFutureSteps = remove(
flattenDeep(slice(stepValidationFields, activeStep + 1)),
flattenDeep(slice(validationFields, activeStep + 1)),
fieldPath => {
const value = get(values, fieldPath);

Expand Down Expand Up @@ -544,6 +449,143 @@ export const PrescriptionForm = props => {

const subStepProps = subSteps => map(subSteps, subStep => stepProps(subStep));

const steps = [
{
...accountFormStepsProps,
onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
subSteps: subStepProps(accountFormStepsProps.subSteps),
},
{
...profileFormStepsProps,
onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
subSteps: subStepProps(profileFormStepsProps.subSteps),
},
{
...settingsCalculatorFormStepsProps,
onComplete: handlers.stepSubmit,
asyncState: stepAsyncState,
subSteps: subStepProps(settingsCalculatorFormStepsProps.subSteps),
},
{
...stepProps(therapySettingsFormStepProps),
onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
},
{
...reviewFormStepProps,
onComplete: handlers.stepSubmit,
asyncState: stepAsyncState,
},
];

// Remove calculator step if selected pump, or all available pump options are set to skip aace calculator
const pumpDevices = pumpDeviceOptions(devices);
const skipCalculator = !!(pumpDevices.length && every(pumpDevices, { skipCalculator: true })) || !!find(devices, { value: pumpId })?.skipCalculator;
if (skipCalculator) {
validationFields.splice(2, 1);
steps.splice(2, 1);
}

useEffect(() => {
// Determine the latest incomplete step, and default to starting there
if (isEditable && (isUndefined(activeStep) || isUndefined(activeSubStep))) {
let firstInvalidStep;
let firstInvalidSubStep;
let currentStep = 0;
let currentSubStep = 0;

while (isUndefined(firstInvalidStep) && currentStep < validationFields.length) {
while (currentSubStep < validationFields[currentStep].length) {
if (!fieldsAreValid(validationFields[currentStep][currentSubStep], schema, values)) {
firstInvalidStep = currentStep;
firstInvalidSubStep = currentSubStep;
break;
}
currentSubStep++
}

currentStep++;
currentSubStep = 0;
}

setActiveStep(isInteger(firstInvalidStep) ? firstInvalidStep : steps.length - 1);
setActiveSubStep(isInteger(firstInvalidSubStep) ? firstInvalidSubStep : 0);
}

// When a user comes to this component initially, without the active step and subStep set by the
// Stepper component in the url, or when editing an existing prescription,
// we delete any persisted state from localStorage.
if (status.isPrescriptionEditFlow || (get(localStorage, storageKey) && activeStepsParam === null)) {
delete localStorage[storageKey];
}

// Only use the localStorage persistence for new prescriptions - not while editing an existing one.
setFormPersistReady(!prescription);
}, []);

// Save whether or not we are editing a single step to the formik form status for easy reference
useEffect(() => {
setStatus({
...status,
isSingleStepEdit,
});
}, [isSingleStepEdit])

// Save the hydrated localStorage values to the formik form status for easy reference
useEffect(() => {
if (formPersistReady) setStatus({
...status,
hydratedValues: JSON.parse(get(localStorage, storageKey, JSON.stringify(status.hydratedValues))),
});
}, [formPersistReady]);

// Handle changes to stepper async state for completed prescription creation and revision updates
useEffect(() => {
const isRevision = !!get(values, 'id');
const isDraft = get(values, 'state') === 'draft';
const { inProgress, completed, notification, prescriptionId } = isRevision ? creatingPrescriptionRevision : creatingPrescription;

if (prescriptionId) setFieldValue('id', prescriptionId);

if (!isFirstRender && !inProgress) {
if (completed) {
setStepAsyncState(asyncStates.completed);
if (isLastStep) {

let messageAction = isRevision ? t('updated') : t('created');
if (isPrescriber) messageAction = t('finalized and sent');

setToast({
message: t('You have successfully {{messageAction}} a Tidepool Loop prescription.', { messageAction }),
variant: 'success',
});

history.push('/clinic-workspace/prescriptions');
}
}

if (completed === false) {
setToast({
message: get(notification, 'message'),
variant: 'danger',
});

setStepAsyncState(asyncStates.failed);
}
}
}, [creatingPrescription, creatingPrescriptionRevision]);

useEffect(() => {
if (stepAsyncState.complete === false) {
// Allow resubmission of form after a second
setTimeout(() => {
setStepAsyncState(asyncStates.initial);
}, 1000);
}
}, [stepAsyncState.complete]);

const stepperProps = {
activeStep,
activeSubStep,
Expand All @@ -563,36 +605,7 @@ export const PrescriptionForm = props => {

log('Step to', newStep.join(','));
},
steps: [
{
...accountFormStepsProps,
onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
subSteps: subStepProps(accountFormStepsProps.subSteps),
},
{
...profileFormStepsProps,
onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
subSteps: subStepProps(profileFormStepsProps.subSteps),
},
{
...settingsCalculatorFormStepsProps,
onComplete: handlers.stepSubmit,
asyncState: stepAsyncState,
subSteps: subStepProps(settingsCalculatorFormStepsProps.subSteps),
},
{
...stepProps(therapySettingsFormStepProps),
onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : handlers.stepSubmit,
asyncState: isSingleStepEdit ? null : stepAsyncState,
},
{
...reviewFormStepProps,
onComplete: handlers.stepSubmit,
asyncState: stepAsyncState,
},
],
steps,
themeProps: {
wrapper: {
padding: 4,
Expand Down
31 changes: 18 additions & 13 deletions app/pages/prescription/prescriptionFormConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,30 @@ export const validDeviceIds = {
],
};

export const deviceExtraInfo = {
[deviceIdMap.dexcomG6]: (
<Trans>
Find information on how to prescribe Dexcom G6 sensors and transmitters and more <Link to="#">here</Link>.
</Trans>
),
[deviceIdMap.palmtree]: (
<Trans>
Find information on how to prescribe Palmtree products <Link to="#">here</Link>.
</Trans>
),
export const deviceDetails = {
[deviceIdMap.dexcomG6]: {
description: (
<Trans>
Find information on how to prescribe Dexcom G6 sensors and transmitters and more <Link to="#">here</Link>.
</Trans>
),
},
[deviceIdMap.palmtree]: {
description: (
<Trans>
Find information on how to prescribe Palmtree products <Link to="#">here</Link>.
</Trans>
),
skipCalculator: true,
},
};

export const pumpDeviceOptions = ({ pumps } = {}) => map(
filter(pumps, pump => includes(validDeviceIds.pumps, pump.id)),
pump => ({
value: pump.id,
label: t('{{displayName}}', { displayName: pump.displayName }),
extraInfo: deviceExtraInfo[pump.id] || null,
...(deviceDetails[pump.id] || {}),
}),
);

Expand All @@ -63,7 +68,7 @@ export const cgmDeviceOptions = ({ cgms } = {}) => map(
cgm => ({
value: cgm.id,
label: t('{{displayName}}', { displayName: cgm.displayName }),
extraInfo: deviceExtraInfo[cgm.id] || null,
...(deviceDetails[cgm.id] || {}),
}),
);

Expand Down
4 changes: 2 additions & 2 deletions app/pages/prescription/profileFormSteps.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export const PatientDevices = withTranslation()(props => {
}}
{...checkboxStyles}
/>
<Caption mt={1}>{device.extraInfo}</Caption>
<Caption mt={1}>{device.description}</Caption>
</React.Fragment>
))}
</Flex>
Expand All @@ -187,7 +187,7 @@ export const PatientDevices = withTranslation()(props => {
error={getFieldError('initialSettings.cgmId', formikContext)}
{...checkboxStyles}
/>
<Caption mt={1}>{device.extraInfo}</Caption>
<Caption mt={1}>{device.description}</Caption>
</React.Fragment>
))}
</Flex>
Expand Down
Loading

0 comments on commit 5a6bb7a

Please sign in to comment.