Skip to content

Commit

Permalink
feat(anni): add warning level
Browse files Browse the repository at this point in the history
  • Loading branch information
jannis-baum committed Jul 5, 2022
1 parent 2be255a commit bb79d6b
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 7 deletions.
3 changes: 2 additions & 1 deletion annotation-interface/common/server-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type WarningLevel = 'ok' | 'warning' | 'danger';
export const warningLevelValues = ['ok', 'warning', 'danger'] as const;
export type WarningLevel = typeof warningLevelValues[number];

export type ServerGuidelineOverview = {
id: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,3 @@ export const MedAnnotation = (
export const GuidelineAnnotation = (
props: Props<ServerGuideline, IGuidelineAnnotation<string, string>>,
) => <BrickAnnotation {...props} apiEndpoint="guidelines" />;

// TODO: warning level annotation
120 changes: 120 additions & 0 deletions annotation-interface/components/annotations/WarningLevelAnnotation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {
CheckCircleIcon,
ExclamationIcon,
TrashIcon,
UploadIcon,
XCircleIcon,
XIcon,
} from '@heroicons/react/solid';
import axios from 'axios';
import { useEffect, useRef, useState } from 'react';

import {
ServerGuideline,
WarningLevel,
warningLevelValues,
} from '../../common/server-types';
import { IGuidelineAnnotation } from '../../database/models/GuidelineAnnotation';
import WithIcon from '../common/WithIcon';
import AbstractAnnotation, {
AbstractAnnotationRef,
AnnotationMissing,
} from './AbstractAnnotation';

type Props = {
refetch: () => void;
displayContext: string;
serverData: ServerGuideline | undefined;
annotation: IGuidelineAnnotation<string, string> | null | undefined;
};

const iconForLevel: Map<WarningLevel, typeof CheckCircleIcon> = new Map([
['ok', CheckCircleIcon],
['warning', ExclamationIcon],
['danger', XCircleIcon],
]);

const WarningLevelAnnotation = ({
refetch,
displayContext,
serverData,
annotation,
}: Props) => {
const annotationRef = useRef<null | AbstractAnnotationRef>(null);
const [selection, setSelection] = useState<WarningLevel | null>(null);
useEffect(
() => setSelection(annotation?.warningLevel ?? null),
[annotation],
);

const save = async () => {
if (!serverData) return;
const patch = {
annotation: { warningLevel: selection },
serverData: { warningLevel: selection },
};
await axios.patch(
`/api/annotations/guidelines/${serverData.id}`,
patch,
);
done();
};
const done = () => {
annotationRef.current?.hideOverlay();
refetch();
};

return (
<AbstractAnnotation
serverValue={serverData?.warningLevel}
hasChanges={serverData?.warningLevel !== selection}
displayContext={displayContext}
displayName="warning level"
ref={annotationRef}
>
{!selection && <AnnotationMissing />}
<div className="border border-opacity-40 border-white py-6 px-2 my-4 flex justify-evenly">
{warningLevelValues.map((level, index) => (
<WithIcon
key={index}
icon={iconForLevel.get(level)!}
as="button"
onClick={() => setSelection(level)}
className={`py-2 px-4 rounded-full border border-white bg-black ${
level === selection
? 'border-opacity-40 bg-opacity-50'
: 'border-opacity-0 bg-opacity-0'
}`}
>
{level[0].toUpperCase() + level.slice(1)}
</WithIcon>
))}
</div>
<div className="flex justify-between py-2">
<WithIcon as="button" icon={XIcon} onClick={done}>
Cancel
</WithIcon>
<div className="flex space-x-4">
<WithIcon
as="button"
icon={TrashIcon}
reverse
onClick={() => setSelection(null)}
>
Clear
</WithIcon>
<WithIcon
as="button"
icon={UploadIcon}
reverse
onClick={save}
>
Save
</WithIcon>
</div>
</div>
</AbstractAnnotation>
);
};

export default WarningLevelAnnotation;
14 changes: 12 additions & 2 deletions annotation-interface/database/models/GuidelineAnnotation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import mongoose, { Types } from 'mongoose';

import { ServerGuidelineOverview } from '../../common/server-types';
import {
ServerGuidelineOverview,
WarningLevel,
warningLevelValues,
} from '../../common/server-types';
import { MongooseId, OptionalId } from '../helpers/types';
import AbstractAnnotation, {
annotationBrickValidators,
Expand All @@ -15,6 +19,7 @@ export interface IGuidelineAnnotation<
geneResult: string;
recommendation?: BrickIdT[] | undefined;
implication?: BrickIdT[] | undefined;
warningLevel?: WarningLevel | null;
}

interface GuidelineAnnotationModel
Expand Down Expand Up @@ -42,12 +47,17 @@ const guidelineAnnotationSchema = new mongoose.Schema<
default: undefined,
validate: annotationBrickValidators('Implication'),
},
warningLevel: {
type: String,
enum: warningLevelValues,
default: undefined,
},
});

guidelineAnnotationSchema.pre<
IGuidelineAnnotation<Types.ObjectId, Types.ObjectId>
>('validate', function (next) {
if (!this.recommendation && !this.implication)
if (!this.recommendation && !this.implication && !this.warningLevel)
next(new Error('At least one category needs to be defined'));
next();
});
Expand Down
7 changes: 7 additions & 0 deletions annotation-interface/pages/annotations/guidelines/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '../../../common/server-types';
import { GuidelineAnnotation } from '../../../components/annotations/BrickAnnotations';
import CpicGuidelineBox from '../../../components/annotations/CpicGuidelineBox';
import WarningLevelAnnotation from '../../../components/annotations/WarningLevelAnnotation';
import PageHeading from '../../../components/common/PageHeading';
import dbConnect from '../../../database/helpers/connect';
import {
Expand Down Expand Up @@ -66,6 +67,12 @@ const GuidelineDetail = ({
serverData={guideline}
category="recommendation"
/>
<WarningLevelAnnotation
refetch={refetch}
annotation={annotation}
serverData={guideline}
displayContext={displayContext}
/>
</div>
</>
);
Expand Down
13 changes: 11 additions & 2 deletions annotation-interface/pages/api/annotations/guidelines/[id].ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ const api: NextApiHandler = async (req, res) => {
{ id: serverGuideline.id, ...serverPatch },
]);

if (!annotation && (patch.implication || patch.recommendation)) {
if (
!annotation &&
(patch.implication ||
patch.recommendation ||
patch.warningLevel)
) {
annotation = {
medicationRxCUI: serverGuideline.medication.rxcui,
medicationName: serverGuideline.medication.name,
Expand All @@ -69,7 +74,11 @@ const api: NextApiHandler = async (req, res) => {
await GuidelineAnnotation!.create(annotation);
} else if (annotation) {
annotation = { ...annotation, ...patch };
if (annotation.implication || annotation.recommendation) {
if (
annotation.implication ||
annotation.recommendation ||
patch.warningLevel
) {
await GuidelineAnnotation!
.findByIdAndUpdate(annotation._id!, annotation, {
runValidators: true,
Expand Down
1 change: 1 addition & 0 deletions annotation-interface/pages/api/annotations/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const api: NextApiHandler = async (req, res) =>
resolver,
annotation.recommendation,
),
warningLevel: annotation.warningLevel,
};
})
.filter((patch) => patch);
Expand Down

0 comments on commit bb79d6b

Please sign in to comment.