Skip to content
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

Migrated Scribe to a CARE App + Context #8469

Merged
merged 40 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ee30ef2
init
shivankacker Aug 25, 2024
199c265
fix merge conflicts
shivankacker Aug 31, 2024
5df356d
Merge branch 'develop' of https://github.com/ohcnetwork/care_fe into …
shivankacker Sep 2, 2024
b4d1f2a
stashing
shivankacker Sep 3, 2024
e9a6cc0
Made Scribe aware of context
shivankacker Sep 3, 2024
9401e17
Added context for diagnoses
shivankacker Sep 3, 2024
96efa60
fixed merge conflicts
shivankacker Sep 5, 2024
55c0abe
Merge branch 'develop' of https://github.com/ohcnetwork/care_fe into …
shivankacker Sep 12, 2024
45f11cc
Merge branch 'develop' of https://github.com/ohcnetwork/care_fe into …
shivankacker Sep 14, 2024
913acc1
added step by step review (in progress)
shivankacker Sep 15, 2024
2db3e72
fixed merge conflicts
shivankacker Oct 13, 2024
90537eb
some cleanup
shivankacker Oct 13, 2024
2a58cfc
fixed merge conlicts
shivankacker Oct 13, 2024
598acc7
shelfing
shivankacker Oct 14, 2024
fa36618
Merge branch 'develop' of https://github.com/ohcnetwork/care_fe into …
shivankacker Oct 16, 2024
88fede3
fix merge conflicts
shivankacker Oct 17, 2024
4d22a5f
Moved Scribe to app, made changes to appengine
shivankacker Oct 20, 2024
8009295
stashing
shivankacker Oct 22, 2024
4d9b8fd
fix merge conflicts
shivankacker Oct 23, 2024
7c2a171
added support for radio and combo boxes
shivankacker Oct 23, 2024
2c06bd1
fix merge conflicts
shivankacker Oct 24, 2024
c17f5e6
fix merge conflict
shivankacker Oct 28, 2024
cc378b8
stashing
shivankacker Oct 29, 2024
92a6d96
fix merge conflicts
shivankacker Nov 1, 2024
6482ea6
I have lost track
shivankacker Nov 5, 2024
67d698f
Removed references of Scribe
shivankacker Nov 5, 2024
694a414
Cleanup plugin engine updates
shivankacker Nov 5, 2024
2210122
lint cleanup
shivankacker Nov 5, 2024
6814b09
Fixed tests
shivankacker Nov 5, 2024
a02d155
Polished, eliminated bugs and dressed up nicely
shivankacker Nov 6, 2024
f7f5372
cleaned up package lock
shivankacker Nov 6, 2024
8c186e5
code rabbit improvements and test fixes
shivankacker Nov 6, 2024
df9a8d5
resolve some edge cases
shivankacker Nov 6, 2024
228856c
fixed merge conflicts
shivankacker Nov 6, 2024
9f55db6
restore unwanted changes
shivankacker Nov 6, 2024
394cd67
weird lint errors
shivankacker Nov 6, 2024
2771ec6
Trigger tests
shivankacker Nov 6, 2024
07cc8bb
fix merge conflicts
shivankacker Nov 13, 2024
c13d3d7
ignored scribe for oral issue
shivankacker Nov 13, 2024
01bf5af
reverted
shivankacker Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cypress/pageobject/Patient/PatientLogupdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ class PatientLogupdate {
}

typePulse(pulse: string) {
cy.typeAndSelectOption("#pulse", pulse);
cy.get("#pulse").click().type(pulse);
}

typeTemperature(temperature: string) {
cy.get("#temperature").click().type(temperature);
}

typeRespiratory(respiratory: string) {
cy.typeAndSelectOption("#resp", respiratory);
cy.get("#resp").click().type(respiratory);
}

typeSpo2(spo: string) {
cy.typeAndSelectOption("#ventilator_spo2", spo);
cy.get("#ventilator_spo2").click().type(spo);
}

selectRhythm(rhythm: string) {
Expand Down
17 changes: 17 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@
"abha_number_exists_description": "There is an ABHA Number already linked with the given Aadhaar Number, Do you want to create a new ABHA Address?",
"abha_number_linked_successfully": "ABHA Number has been linked successfully.",
"abha_profile": "ABHA Profile",
"accept": "Accept",
"accept_all": "Accept All",
"access_level": "Access Level",
"action_irreversible": "This action is irreversible",
"active": "Active",
Expand Down Expand Up @@ -342,6 +344,7 @@
"auth_method_unsupported": "This authentication method is not supported, please try a different method",
"authorize_shift_delete": "Authorize shift delete",
"auto_generated_for_care": "Auto Generated for Care",
"autofilled_fields": "Autofilled Fields",
"available_features": "Available Features",
"available_in": "Available in",
"average_weekly_working_hours": "Average weekly working hours",
Expand Down Expand Up @@ -500,6 +503,8 @@
"continue_watching": "Continue watching",
"contribute_github": "Contribute on Github",
"copied_to_clipboard": "Copied to clipboard",
"copilot_thinking": "Copilot is thinking...",
"could_not_autofill": "We could not autofill any fields from what you said",
"countries_travelled": "Countries travelled",
"covid_19_cat_gov": "Covid_19 Clinical Category as per Govt. of Kerala guideline (A/B/C)",
"covid_19_death_reporting_form_1": "Covid-19 Death Reporting : Form 1",
Expand Down Expand Up @@ -722,6 +727,7 @@
"health_facility__registered_2": "No Action Required",
"health_facility__registered_3": "Registered",
"health_facility__validation__hf_id_required": "Health Facility Id is required",
"hearing": "We are hearing you...",
"help_confirmed": "There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.",
"help_differential": "One of a set of potential (and typically mutually exclusive) diagnoses asserted to further guide the diagnostic process and preliminary treatment.",
"help_entered-in-error": "The statement was entered in error and is not valid.",
Expand Down Expand Up @@ -1041,6 +1047,7 @@
"prn_prescriptions": "PRN Prescriptions",
"procedure_suggestions": "Procedure Suggestions",
"procedures_select_placeholder": "Select procedures to add details",
"process_transcript": "Process Again",
"profile": "Profile",
"provisional": "Provisional",
"qualification": "Qualification",
Expand Down Expand Up @@ -1068,6 +1075,7 @@
"refuted": "Refuted",
"register_hospital": "Register Hospital",
"register_page_title": "Register As Hospital Administrator",
"reject": "Reject",
"reload": "Reload",
"remove": "Remove",
"rename": "Rename",
Expand Down Expand Up @@ -1097,6 +1105,7 @@
"result_on": "Result on",
"resume": "Resume",
"retake": "Retake",
"retake_recording": "Retake Recording",
"return_to_care": "Return to CARE",
"return_to_login": "Return to Login",
"return_to_password_reset": "Return to Password Reset",
Expand All @@ -1117,6 +1126,8 @@
"save_and_continue": "Save and Continue",
"save_investigation": "Save Investigation",
"scan_asset_qr": "Scan Asset QR!",
"scribe__reviewing_field": "Reviewing field {{currentField}} / {{totalFields}}",
"scribe_error": "Could not autofill fields",
"search_by_username": "Search by username",
"search_for_facility": "Search for Facility",
"search_icd11_placeholder": "Search for ICD-11 Diagnoses",
Expand Down Expand Up @@ -1181,9 +1192,11 @@
"staff_list": "Staff List",
"start_datetime": "Start Date/Time",
"start_dosage": "Start Dosage",
"start_review": "Start Review",
"state": "State",
"status": "Status",
"stop": "Stop",
"stop_recording": "Stop Recording",
"stream_stop_due_to_inativity": "The live feed will stop streaming due to inactivity",
"stream_stopped_due_to_inativity": "The live feed has stopped streaming due to inactivity",
"stream_uuid": "Stream UUID",
Expand All @@ -1200,6 +1213,7 @@
"support": "Support",
"switch": "Switch",
"switch_camera_is_not_available": "Switch camera is not available.",
"symptoms": "Symptoms",
"systolic": "Systolic",
"tachycardia": "Tachycardia",
"target_dosage": "Target Dosage",
Expand All @@ -1212,6 +1226,8 @@
"total_beds": "Total Beds",
"total_staff": "Total Staff",
"total_users": "Total Users",
"transcript_edit_info": "You can update this if we made an error",
"transcript_information": "This is what we heard",
"transfer_in_progress": "TRANSFER IN PROGRESS",
"transfer_to_receiving_facility": "Transfer to receiving facility",
"travel_within_last_28_days": "Domestic/international Travel (within last 28 days)",
Expand Down Expand Up @@ -1301,6 +1317,7 @@
"vitals": "Vitals",
"vitals_monitor": "Vitals Monitor",
"vitals_present": "Vitals Monitor present",
"voice_autofill": "Voice Autofill",
"ward": "Ward",
"warranty_amc_expiry": "Warranty / AMC Expiry",
"what_facility_assign_the_patient_to": "What facility would you like to assign the patient to",
Expand Down
29 changes: 28 additions & 1 deletion src/CAREUI/interactive/KeyboardShortcut.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Fragment } from "react/jsx-runtime";
import useKeyboardShortcut from "use-keyboard-shortcut";

import { classNames, isAppleDevice } from "@/Utils/utils";
import { classNames, isAppleDevice } from "../../Utils/utils";

interface Props {
children?: React.ReactNode;
Expand Down Expand Up @@ -70,3 +71,29 @@ const SHORTCUT_KEY_MAP = {
ArrowLeft: "←",
ArrowRight: "→",
} as Record<string, string>;

export function KeyboardShortcutKey(props: {
shortcut: string[];
useShortKeys?: boolean;
}) {
const { shortcut, useShortKeys } = props;

return (
<div className="hidden shrink-0 items-center md:flex">
{shortcut.map((key, idx, keys) => (
<Fragment key={idx}>
<kbd className="relative z-10 flex h-6 min-w-6 shrink-0 items-center justify-center rounded-md border border-b-4 border-secondary-400 bg-secondary-100 px-2 text-xs text-black">
{SHORTCUT_KEY_MAP[key]
? useShortKeys
? SHORTCUT_KEY_MAP[key][0]
: SHORTCUT_KEY_MAP[key]
: key}
</kbd>
{idx !== keys.length - 1 && (
<span className="px-1 text-zinc-300/60"> + </span>
)}
</Fragment>
))}
</div>
);
}
5 changes: 4 additions & 1 deletion src/Routers/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ export default function AppRouter() {
id="pages"
className="flex-1 overflow-y-scroll bg-gray-100 pb-4 focus:outline-none md:py-0"
>
<div className="max-w-8xl mx-auto mt-4 min-h-[96vh] rounded-lg border bg-gray-50 p-3 shadow">
<div
className="max-w-8xl mx-auto mt-4 min-h-[96vh] rounded-lg border bg-gray-50 p-3 shadow"
data-cui-page
>
{pages}
</div>
</main>
Expand Down
31 changes: 0 additions & 31 deletions src/Utils/request/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ import {
CreateFileResponse,
FileUploadModel,
} from "@/components/Patient/models";
import { ScribeModel } from "@/components/Scribe/Scribe";
import {
SkillModel,
SkillObjectModel,
Expand Down Expand Up @@ -111,36 +110,6 @@ export interface LoginCredentials {
}

const routes = {
createScribe: {
path: "/api/care_scribe/scribe/",
method: "POST",
TReq: Type<ScribeModel>(),
TRes: Type<ScribeModel>(),
},
getScribe: {
path: "/api/care_scribe/scribe/{external_id}/",
method: "GET",
TRes: Type<ScribeModel>(),
},
updateScribe: {
path: "/api/care_scribe/scribe/{external_id}/",
method: "PUT",
TReq: Type<ScribeModel>(),
TRes: Type<ScribeModel>(),
},
createScribeFileUpload: {
path: "/api/care_scribe/scribe_file/",
method: "POST",
TBody: Type<CreateFileRequest>(),
TRes: Type<CreateFileResponse>(),
},
editScribeFileUpload: {
path: "/api/care_scribe/scribe_file/{id}/?file_type={fileType}&associating_id={associatingId}",
method: "PATCH",
TBody: Type<Partial<FileUploadModel>>(),
TRes: Type<FileUploadModel>(),
},

// Auth Endpoints
login: {
path: "/api/v1/auth/login/",
Expand Down
16 changes: 14 additions & 2 deletions src/Utils/useSegmentedRecorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const useSegmentedRecording = () => {
const [recorder, setRecorder] = useState<MediaRecorder | null>(null);
const [audioBlobs, setAudioBlobs] = useState<Blob[]>([]);
const [restart, setRestart] = useState(false);
const [microphoneAccess, setMicrophoneAccess] = useState(false); // New state
const { t } = useTranslation();

const bufferInterval = 1 * 1000;
Expand All @@ -25,6 +26,7 @@ const useSegmentedRecording = () => {
requestRecorder().then(
(newRecorder) => {
setRecorder(newRecorder);
setMicrophoneAccess(true); // Set access to true on success
if (restart) {
setIsRecording(true);
}
Expand All @@ -34,6 +36,7 @@ const useSegmentedRecording = () => {
msg: t("audio__permission_message"),
});
setIsRecording(false);
setMicrophoneAccess(false); // Set access to false on failure
},
);
}
Expand Down Expand Up @@ -98,8 +101,16 @@ const useSegmentedRecording = () => {
return () => recorder.removeEventListener("dataavailable", handleData);
}, [recorder, isRecording, bufferInterval, audioBlobs, restart]);

const startRecording = () => {
setIsRecording(true);
const startRecording = async () => {
try {
const newRecorder = await requestRecorder();
setRecorder(newRecorder);
setMicrophoneAccess(true);
setIsRecording(true);
} catch (error) {
setMicrophoneAccess(false);
throw new Error("Microphone access denied");
}
};

const stopRecording = () => {
Expand All @@ -116,6 +127,7 @@ const useSegmentedRecording = () => {
stopRecording,
resetRecording,
audioBlobs,
microphoneAccess, // Return microphoneAccess
shivankacker marked this conversation as resolved.
Show resolved Hide resolved
};
};

Expand Down
55 changes: 55 additions & 0 deletions src/Utils/useValueInjectionObserver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useEffect, useState } from "react";

/**
* A custom React hook that observes changes to a specific attribute of a DOM element
* and returns a new value when the attribute changes. It is primarily useful
* for detecting updates to the value of a custom CUI component through layers where
* the component's state cannot be determined or mutated (example. CARE Scribe).
*
* @template T
* @param {Object} options - Configuration options for the observer.
* @param {HTMLElement | null} options.targetElement - The DOM element to observe for attribute changes.
* @param {string} [options.attribute="value"] - The name of the attribute to observe (default is "value").
*
* @example
* const targetElement = document.getElementById('my-input');
* const DOMValue = useValueInjectionObserver({
* targetElement: targetElement,
* attribute: 'value',
* });
*
* @returns {unknown} This hook returns the current value of the attribute.
*/
export function useValueInjectionObserver<T = unknown>(options: {
targetElement: HTMLElement | null;
attribute?: string;
}) {
const { targetElement, attribute = "value" } = options;
const [value, setValue] = useState<T>();

shivankacker marked this conversation as resolved.
Show resolved Hide resolved
useEffect(() => {
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (
mutation.type === "attributes" &&
mutation.attributeName === attribute
) {
const newValue = JSON.parse(
targetElement?.getAttribute(attribute) || '""',
);
setValue(newValue);
}
});
});

const config = {
attributes: true,
attributeFilter: [attribute],
};

targetElement && observer.observe(targetElement, config);
return () => observer.disconnect();
}, [targetElement]);
shivankacker marked this conversation as resolved.
Show resolved Hide resolved

return value;
}
Loading
Loading