Skip to content

Commit

Permalink
Merge pull request #579 from masslight/develop
Browse files Browse the repository at this point in the history
Release Ottehr Psel v0.16
  • Loading branch information
GiladSchneider authored Nov 11, 2024
2 parents 2467fda + ba7b129 commit a41892e
Show file tree
Hide file tree
Showing 38 changed files with 329 additions and 142 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ottehr",
"version": "0.15.0",
"version": "0.16.0",
"private": true,
"scripts": {
"test": "pnpm recursive run test",
Expand Down
1 change: 1 addition & 0 deletions packages/ehr-utils/lib/types/user.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum RoleType {
Manager = 'Manager',
Staff = 'Staff',
Provider = 'Provider',
Prescriber = 'Prescriber',
FrontDesk = 'Front Desk',
Inactive = 'Inactive',
}
2 changes: 1 addition & 1 deletion packages/ehr-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ehr-utils",
"private": true,
"version": "0.15.0",
"version": "0.16.0",
"main": "lib/main.ts",
"types": "lib/main.ts",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/ottehr-components/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ottehr-components",
"private": true,
"version": "0.15.0",
"version": "0.16.0",
"main": "lib/main.ts",
"types": "lib/main.ts",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions packages/telemed-ehr/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "telemed-ehr-app",
"version": "0.15.0",
"version": "0.16.0",
"private": true,
"browserslist": {
"production": [
Expand Down Expand Up @@ -37,7 +37,7 @@
"@mui/x-data-grid-pro": "^6.3.0",
"@mui/x-date-pickers": "^5.0.20",
"@mui/x-date-pickers-pro": "^5.0.20",
"@photonhealth/elements": "^0.12.7",
"@photonhealth/elements": "^0.13.0",
"@twilio/conversations": "^2.4.1",
"@zapehr/sdk": "1.0.15",
"amazon-chime-sdk-component-library-react": "^3.7.0",
Expand Down
11 changes: 9 additions & 2 deletions packages/telemed-ehr/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ function App(): ReactElement {
const wasEnrolledInERX = useProviderERXStateStore((state) => state.wasEnrolledInERX);

const roleUnknown =
!currentUser || !currentUser.hasRole([RoleType.Administrator, RoleType.Staff, RoleType.Manager, RoleType.Provider]);
!currentUser ||
!currentUser.hasRole([
RoleType.Administrator,
RoleType.Staff,
RoleType.Manager,
RoleType.Provider,
RoleType.Prescriber,
]);

return (
<CustomThemeProvider>
Expand All @@ -73,7 +80,7 @@ function App(): ReactElement {
showWhenAuthenticated={
<>
{isERXEnabled &&
((currentUser?.hasRole([RoleType.Provider]) && currentUser.isPractitionerEnrolledInERX) ||
((currentUser?.hasRole([RoleType.Prescriber]) && currentUser.isPractitionerEnrolledInERX) ||
wasEnrolledInERX) ? (
<photon-client
id={import.meta.env.VITE_APP_PHOTON_CLIENT_ID}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Box } from '@mui/material';
import { ReactElement } from 'react';
import { UCAppointmentInformation } from 'ehr-utils';
import { classifyAppointments } from '../helpers';
import { getAppointmentStatusChip } from './AppointmentTableRow';
import { getInPersonAppointmentStatusChip } from './AppointmentTableRow';

export interface AppointmentChip {
appointments: UCAppointmentInformation[];
Expand Down Expand Up @@ -33,7 +33,7 @@ export const AppointmentsStatusChipsCount = ({ appointments }: AppointmentChip):
ORDER_STATUS.indexOf(statusOne) - ORDER_STATUS.indexOf(statusTwo),
)
.map(([status, count]) => (
<Box key={status}>{getAppointmentStatusChip(status, count)}</Box>
<Box key={status}>{getInPersonAppointmentStatusChip(status, count)}</Box>
))}
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { Operation } from 'fast-json-patch';
import { getPatchBinary, getStatusFromExtension } from 'ehr-utils';
import { VisitStatus, STATI } from '../helpers/mappingUtils';
import { useApiClients } from '../hooks/useAppClients';
import { getAppointmentStatusChip } from './AppointmentTableRow';
import { Box } from '@mui/system';
import { getInPersonAppointmentStatusChip } from './AppointmentTableRow';

const statuses = STATI;

Expand All @@ -17,6 +16,7 @@ export const switchStatus = async (
appointment: Appointment,
encounter: Encounter,
status: VisitStatus,
onStatusChange: (status: VisitStatus) => void,
): Promise<void> => {
if (status === 'unknown') {
throw new Error(`Invalid status: ${status}`);
Expand Down Expand Up @@ -52,16 +52,20 @@ export const switchStatus = async (
}),
],
});

onStatusChange(status);
};

interface AppointmentStatusSwitcherProps {
appointment: Appointment;
encounter: Encounter;
onStatusChange: (status: VisitStatus) => void;
}

export default function AppointmentStatusSwitcher({
appointment,
encounter,
onStatusChange,
}: AppointmentStatusSwitcherProps): ReactElement {
const { fhirClient } = useApiClients();
const [statusLoading, setStatusLoading] = React.useState<boolean>(false);
Expand All @@ -70,7 +74,7 @@ export default function AppointmentStatusSwitcher({
const handleChange = async (event: SelectChangeEvent): Promise<void> => {
const value = event.target.value;
setStatusLoading(true);
await switchStatus(fhirClient, currentAppointment, encounter, value as VisitStatus);
await switchStatus(fhirClient, currentAppointment, encounter, value as VisitStatus, onStatusChange);
const newAppointment = (await fhirClient?.readResource({
resourceType: 'Appointment',
resourceId: appointment.id || '',
Expand Down Expand Up @@ -100,7 +104,7 @@ export default function AppointmentStatusSwitcher({
labelId="status-select-label"
value={getStatusFromExtension(currentAppointment)}
onChange={async (event) => await handleChange(event)}
renderValue={(selected) => getAppointmentStatusChip(selected)}
renderValue={(selected) => getInPersonAppointmentStatusChip(selected)}
sx={{
boxShadow: 'none',
'.MuiOutlinedInput-notchedOutline': { border: 0 },
Expand All @@ -113,10 +117,10 @@ export default function AppointmentStatusSwitcher({
}}
>
{statuses
.filter((status) => status !== 'unknown')
.filter((status) => status !== 'unknown' && status !== 'cancelled')
.map((status) => (
<MenuItem key={status} value={status}>
{getAppointmentStatusChip(status)}
{getInPersonAppointmentStatusChip(status)}
</MenuItem>
))}
</Select>
Expand Down
10 changes: 5 additions & 5 deletions packages/telemed-ehr/app/src/components/AppointmentTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const FLAGGED_REASONS_FOR_VISIT: string[] = [
'Allergic reaction',
];

export function getAppointmentStatusChip(status: string, count?: number): ReactElement {
export function getInPersonAppointmentStatusChip(status: string, count?: number): ReactElement {
if (!status) {
return <span>todo1</span>;
}
Expand Down Expand Up @@ -444,17 +444,17 @@ export default function AppointmentTableRow({
}}
>
{isLongWaitingTime && longWaitFlag}
{getStatiForVisitTimeCalculation(appointment.visitStatusHistory, appointment.start).map((statusTemp) => {
{getStatiForVisitTimeCalculation(appointment.visitStatusHistory, appointment.start).map((statusTemp, index) => {
return (
<Box sx={{ display: 'flex', gap: 1 }}>
<Box key={index} sx={{ display: 'flex', gap: 1 }}>
<Typography
variant="body2"
color={theme.palette.getContrastText(theme.palette.background.default)}
style={{ display: 'inline', fontWeight: 700, marginTop: 1 }}
>
{formatMinutes(getDurationOfStatus(statusTemp, appointment, appointment.visitStatusHistory, now))} mins
</Typography>
{getAppointmentStatusChip(statusTemp.label as keyof typeof CHIP_STATUS_MAP)}
{getInPersonAppointmentStatusChip(statusTemp.label as keyof typeof CHIP_STATUS_MAP)}
</Box>
);
})}
Expand Down Expand Up @@ -529,7 +529,7 @@ export default function AppointmentTableRow({
&nbsp;&nbsp;<strong>{start}</strong>
</Typography>
</Box>
<Box mt={1}>{getAppointmentStatusChip(appointment.status)}</Box>
<Box mt={1}>{getInPersonAppointmentStatusChip(appointment.status)}</Box>
</Link>
</Box>
</TableCell>
Expand Down
121 changes: 64 additions & 57 deletions packages/telemed-ehr/app/src/components/EmployeeInformationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ const AVAILABLE_ROLES: {
{
value: RoleType.Provider,
label: 'Provider',
hint: `No settings changes; essentially read-only`,
hint: `A clinician, such as a doctor, a PA or an NP`,
},
{
value: RoleType.Prescriber,
label: 'Prescriber',
hint: `A clinician that is allowed to prescribe`,
},
];

Expand All @@ -93,12 +98,12 @@ if (import.meta.env.MODE === 'default' || import.meta.env.MODE === 'development'
},
{
value: RoleType.RegionalTelemedLead,
label: 'Regional Telemed lead',
label: 'Regional Telemed Lead',
hint: 'Todo description',
},
{
value: RoleType.CallCentre,
label: 'Call Centre',
label: 'Call Center',
hint: 'Todo description',
},
{
Expand Down Expand Up @@ -494,61 +499,63 @@ export default function EmployeeInformationForm({
Add New State Qualification
</AccordionSummary>
<AccordionDetails>
<Grid container direction={'row'} spacing={1}>
<Grid item xs={4}>
<Autocomplete
options={displaystates}
getOptionLabel={(option: string) => option}
renderInput={(params) => (
<TextField
{...params}
label="State"
error={errors.state}
required
helperText={errors.state ? 'Please select a state' : null}
/>
)}
value={newLicenseState || null}
onChange={(event, value) => setNewLicenseState(value || undefined)}
/>
</Grid>
<Grid item xs={4}>
<Autocomplete
options={Object.keys(PractitionerQualificationCodesLabels)}
getOptionLabel={(option: string) => option}
renderInput={(params) => (
<TextField
{...params}
label="Qualification"
error={errors.qualification}
required
helperText={errors.qualification ? 'Please select a qualification' : null}
/>
)}
value={newLicenseCode || null}
onChange={(event, value) => setNewLicenseCode(value || undefined)}
/>
</Grid>
<Grid item xs={4} alignContent={'center'}>
<Button
variant="contained"
endIcon={<AddIcon />}
sx={{ textTransform: 'none', fontWeight: 'bold', borderRadius: 28 }}
onClick={handleAddLicense}
fullWidth
>
Add
</Button>
<form>
<Grid container direction={'row'} spacing={1}>
<Grid item xs={4}>
<Autocomplete
options={displaystates}
getOptionLabel={(option: string) => option}
renderInput={(params) => (
<TextField
{...params}
label="State"
error={errors.state}
required
helperText={errors.state ? 'Please select a state' : null}
/>
)}
value={newLicenseState || null}
onChange={(event, value) => setNewLicenseState(value || undefined)}
/>
</Grid>
<Grid item xs={4}>
<Autocomplete
options={Object.keys(PractitionerQualificationCodesLabels)}
getOptionLabel={(option: string) => option}
renderInput={(params) => (
<TextField
{...params}
label="Qualification"
error={errors.qualification}
required
helperText={errors.qualification ? 'Please select a qualification' : null}
/>
)}
value={newLicenseCode || null}
onChange={(event, value) => setNewLicenseCode(value || undefined)}
/>
</Grid>
<Grid item xs={4} alignContent={'center'}>
<Button
variant="contained"
endIcon={<AddIcon />}
sx={{ textTransform: 'none', fontWeight: 'bold', borderRadius: 28 }}
fullWidth
onClick={handleAddLicense}
>
Add
</Button>
</Grid>
{errors.duplicateLicense && (
<Typography
color="error"
variant="body2"
mt={1}
mx={1}
>{`License already exists.`}</Typography>
)}
</Grid>
{errors.duplicateLicense && (
<Typography
color="error"
variant="body2"
mt={1}
mx={1}
>{`License already exists.`}</Typography>
)}
</Grid>
</form>
</AccordionDetails>
</Accordion>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { telemedCancellationReasons, inPersonCancellationReasons } from '../../t

interface CancelVisitDialogProps {
onClose: () => void;
appointmentType: 'telemed' | 'in-person';
appointmentType: 'telemedicine' | 'in-person';
}

const CancelVisitDialog = ({ onClose, appointmentType }: CancelVisitDialogProps): ReactElement => {
Expand All @@ -33,7 +33,8 @@ const CancelVisitDialog = ({ onClose, appointmentType }: CancelVisitDialogProps)
const { id: appointmentID } = useParams();
const navigate = useNavigate();

const cancellationReasons = appointmentType === 'telemed' ? telemedCancellationReasons : inPersonCancellationReasons;
const cancellationReasons =
appointmentType === 'telemedicine' ? telemedCancellationReasons : inPersonCancellationReasons;

const handleReasonChange = (event: SelectChangeEvent<string>): void => {
setReason(event.target.value);
Expand All @@ -56,7 +57,7 @@ const CancelVisitDialog = ({ onClose, appointmentType }: CancelVisitDialogProps)
if (!zambdaIntakeClient) throw new Error('Zambda client not found');
try {
let response;
if (appointmentType === 'telemed') {
if (appointmentType === 'telemedicine') {
console.log('canceling telemed appointment', appointmentID, reason, otherReason);
response = await cancelTelemedAppointment(zambdaIntakeClient, {
appointmentID: appointmentID || '',
Expand All @@ -76,7 +77,7 @@ const CancelVisitDialog = ({ onClose, appointmentType }: CancelVisitDialogProps)
console.error('Failed to cancel appointment', error);
} finally {
setIsCancelling(false);
if (appointmentType === 'telemed') {
if (appointmentType === 'telemedicine') {
navigate('/telemed/appointments');
} else if (appointmentType === 'in-person') {
navigate('/in-person/appointments');
Expand Down
Loading

0 comments on commit a41892e

Please sign in to comment.