Skip to content

Commit

Permalink
Minor fixes in Encounter, Medication, Administration (#10488)
Browse files Browse the repository at this point in the history
  • Loading branch information
amjithtitus09 authored Feb 10, 2025
1 parent f4e9416 commit be85955
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 133 deletions.
3 changes: 2 additions & 1 deletion public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1878,11 +1878,12 @@
"search_for_allergies_to_add": "Search for allergies to add",
"search_for_diagnoses_to_add": "Search for diagnoses to add",
"search_for_facility": "Search for Facility",
"search_for_medications_to_add": "Search for medications to add",
"search_for_symptoms_to_add": "Search for symptoms to add",
"search_icd11_placeholder": "Search for ICD-11 Diagnoses",
"search_investigation_placeholder": "Search Investigation & Groups",
"search_medication": "Search Medication",
"search_medications": "Search for medications to add",
"search_medications": "Search Medications",
"search_medicine": "Search Medicine",
"search_patient_page_text": "Search for existing patients using their phone number or create a new patient record",
"search_patients": "Search Patients",
Expand Down
85 changes: 40 additions & 45 deletions src/components/Facility/ConsultationDetails/QuickAccess.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useQuery } from "@tanstack/react-query";
import { Link } from "raviger";
import { useTranslation } from "react-i18next";

Expand All @@ -9,23 +8,17 @@ import { Button } from "@/components/ui/button";

import LinkDepartmentsSheet from "@/components/Patient/LinkDepartmentsSheet";

import query from "@/Utils/request/query";
import useQuestionnaireOptions from "@/hooks/useQuestionnaireOptions";

import { Encounter } from "@/types/emr/encounter";
import questionnaireApi from "@/types/questionnaire/questionnaireApi";

interface QuickAccessProps {
encounter: Encounter;
}

export default function QuickAccess({ encounter }: QuickAccessProps) {
const { t } = useTranslation();

const { data: response } = useQuery({
queryKey: ["questionnaires"],
queryFn: query(questionnaireApi.list),
});

const questionnaireList = response?.results || [];
const questionnaireOptions = useQuestionnaireOptions("encounter_actions");

const encounterSettings = [
{ id: "encounter_settings", label: t("encounter_settings") },
Expand All @@ -34,45 +27,47 @@ export default function QuickAccess({ encounter }: QuickAccessProps) {
return (
<div className="flex flex-col gap-6">
{/* Questionnaire Section */}
<section className="space-y-2 p-2">
<h3 className="text-lg font-semibold mb-3">{t("questionnaire")}</h3>
<div className="space-y-3 p-2 font-semibold">
{questionnaireList.map((item) => (
<Link
className="flex items-center gap-2 text-sm hover:text-gray-500 text-gray-900"
key={item.id}
// className="w-full justify-start gap-2 h-auto py-2"
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/questionnaire/${item.slug}`}
>
<CareIcon icon="l-file-alt" className="h-4 w-4 text-gray-950" />
{item.title}
</Link>
))}
</div>
</section>

<div className="w-full border-t border-dashed border-gray-300" />

{/* Update Encounter Details */}
<section className="text-gray-950">
<h3 className="text-lg font-medium mb-3">
{t("update_encounter_details")}
</h3>
<div className="space-y-2">
{encounterSettings.map((item) => (
<div key={item.id} className="flex items-center space-x-2 px-4">
{encounter.status !== "completed" && (
<section className="space-y-2 p-2">
<h3 className="text-lg font-semibold mb-3">{t("questionnaire")}</h3>
<div className="space-y-3 p-2 font-semibold">
{questionnaireOptions.map((option) => (
<Link
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/questionnaire/encounter`}
className="text-sm text-gray-950 underline font-semibold"
key={option.slug}
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/questionnaire/${option.slug}`}
className="flex items-center gap-2 text-sm hover:text-gray-500 text-gray-900"
data-cy="update-encounter-option"
>
{item.label}
<CareIcon icon="l-file-alt" className="h-4 w-4 text-gray-950" />
{t(option.title)}
</Link>
</div>
))}
</div>
</section>
))}
</div>
<div className="w-full border-t border-dashed border-gray-300" />
</section>
)}

<div className="w-full border-t border-dashed border-gray-300" />
{/* Update Encounter Details */}
{encounter.status !== "completed" && (
<section className="text-gray-950 space-y-2">
<h3 className="text-lg font-medium mb-3">
{t("update_encounter_details")}
</h3>
<div>
{encounterSettings.map((item) => (
<div key={item.id} className="flex items-center space-x-2 px-4">
<Link
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/questionnaire/encounter`}
className="text-sm text-gray-950 underline font-semibold"
>
{item.label}
</Link>
</div>
))}
</div>
<div className="w-full border-t border-dashed border-gray-300" />
</section>
)}

{/* Departments and Teams */}
<section>
Expand Down
145 changes: 101 additions & 44 deletions src/components/Medicine/MedicationAdministration/AdministrationTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
MedicationAdministration,
MedicationAdministrationRequest,
} from "@/types/emr/medicationAdministration/medicationAdministration";
import { MedicationRequestRead } from "@/types/emr/medicationRequest";
import {
ACTIVE_MEDICATION_STATUSES,
INACTIVE_MEDICATION_STATUSES,
MedicationRequestRead,
} from "@/types/emr/medicationRequest";
import medicationRequestApi from "@/types/emr/medicationRequest/medicationRequestApi";

import { MedicineAdminDialog } from "./MedicineAdminDialog";
Expand All @@ -40,14 +44,6 @@ import {
createMedicationAdministrationRequest,
} from "./utils";

const ACTIVE_STATUSES = ["active", "on-hold", "draft", "unknown"] as const;
const INACTIVE_STATUSES = [
"ended",
"completed",
"cancelled",
"entered_in_error",
] as const;

// Utility Functions
function isTimeInSlot(
date: Date,
Expand Down Expand Up @@ -211,9 +207,13 @@ const MedicationRow: React.FC<MedicationRowProps> = ({
onEditAdministration,
onDiscontinue,
}) => {
const isInactive = INACTIVE_MEDICATION_STATUSES.includes(
medication.status as (typeof INACTIVE_MEDICATION_STATUSES)[number],
);

return (
<React.Fragment>
<div className="p-4 border-t">
<div className={`p-4 border-t ${isInactive ? "bg-gray-100" : ""}`}>
<div className="font-semibold truncate">
{medication.medication?.display}
</div>
Expand Down Expand Up @@ -247,7 +247,7 @@ const MedicationRow: React.FC<MedicationRowProps> = ({
return (
<div
key={`${format(slot.date, "yyyy-MM-dd")}-${slot.start}`}
className="p-4 border-t relative text-sm"
className={`p-4 border-t relative text-sm ${isInactive ? "bg-gray-100" : ""}`}
>
{administrationRecords?.map((admin) => {
const colorClass =
Expand All @@ -260,16 +260,34 @@ const MedicationRow: React.FC<MedicationRowProps> = ({
className={`flex font-medium items-center gap-2 rounded-md p-2 mb-2 cursor-pointer justify-between border ${colorClass}`}
onClick={() => onEditAdministration(medication, admin)}
>
<div className="flex items-center gap-1">
<CareIcon icon="l-check-circle" className="h-3 w-3" />
{new Date(admin.occurrence_period_start).toLocaleTimeString(
"en-US",
{
<div className="flex flex-col md:flex-row items-center gap-1">
<div>
<CareIcon
icon="l-check-circle"
className="h-3 w-3 self-center"
/>
{new Date(
admin.occurrence_period_start,
).toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
hour12: true,
},
)}
})}
</div>
<div>
{admin.occurrence_period_end && (
<>
{"- "}
{new Date(
admin.occurrence_period_end,
).toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
hour12: true,
})}
</>
)}
</div>
</div>
{admin.note && (
<Button
Expand Down Expand Up @@ -297,9 +315,11 @@ const MedicationRow: React.FC<MedicationRowProps> = ({
);
})}

<div className="p-4 border-t flex justify-center">
{ACTIVE_STATUSES.includes(
medication.status as (typeof ACTIVE_STATUSES)[number],
<div
className={`p-4 border-t flex justify-center ${isInactive ? "bg-gray-100" : ""}`}
>
{ACTIVE_MEDICATION_STATUSES.includes(
medication.status as (typeof ACTIVE_MEDICATION_STATUSES)[number],
) && (
<Popover>
<PopoverTrigger asChild>
Expand Down Expand Up @@ -336,6 +356,7 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
const currentDate = new Date();
const [endSlotDate, setEndSlotDate] = useState(currentDate);
const [showStopped, setShowStopped] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [endSlotIndex, setEndSlotIndex] = useState(
Math.floor(currentDate.getHours() / 6),
);
Expand Down Expand Up @@ -369,7 +390,7 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
queryParams: {
encounter: encounterId,
limit: 100,
status: ACTIVE_STATUSES.join(","),
status: ACTIVE_MEDICATION_STATUSES.join(","),
},
}),
enabled: !!patientId,
Expand All @@ -382,7 +403,7 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
queryParams: {
encounter: encounterId,
limit: 100,
status: INACTIVE_STATUSES.join(","),
status: INACTIVE_MEDICATION_STATUSES.join(","),
},
}),
enabled: !!patientId,
Expand Down Expand Up @@ -581,36 +602,33 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
]
: activeMedications?.results || [];

const filteredMedications = medications.filter(
(med: MedicationRequestRead) => {
if (!searchQuery.trim()) return true;
const searchTerm = searchQuery.toLowerCase().trim();
const medicationName = med.medication?.display?.toLowerCase() || "";
return medicationName.includes(searchTerm);
},
);

let content;
if (!activeMedications || !stoppedMedications) {
return (
content = (
<div className="min-h-[200px] flex items-center justify-center">
<Loading />
</div>
);
}

if (!medications?.length) {
return (
} else if (!medications?.length) {
content = (
<EmptyState
message={t("no_active_medications")}
description={t("no_medications_to_administer")}
/>
);
}

return (
<div className="flex flex-col gap-2 m-2">
<div className="flex justify-end">
<Button
variant="outline"
className="text-emerald-600 border-emerald-600 hover:bg-emerald-50"
onClick={() => setIsSheetOpen(true)}
>
<CareIcon icon="l-plus" className="mr-2 h-4 w-4" />
{t("administer_medicine")}
</Button>
</div>

} else if (searchQuery && !filteredMedications.length) {
content = <EmptyState searching searchQuery={searchQuery} />;
} else {
content = (
<ScrollArea className="w-full whitespace-nowrap rounded-md">
<Card className="w-full border-none shadow-none min-w-[640px]">
<div className="grid grid-cols-[minmax(200px,2fr),repeat(4,minmax(140px,1fr)),40px]">
Expand Down Expand Up @@ -684,7 +702,7 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
<div className="border-t bg-[#F3F4F6]" />

{/* Medication rows */}
{medications?.map((medication) => (
{filteredMedications?.map((medication) => (
<MedicationRow
key={medication.id}
medication={medication}
Expand Down Expand Up @@ -718,6 +736,45 @@ export const AdministrationTab: React.FC<AdministrationTabProps> = ({
</Card>
<ScrollBar orientation="horizontal" />
</ScrollArea>
);
}

return (
<div className="flex flex-col gap-2 mt-4 mx-2">
<div className="flex justify-between items-center gap-2">
<div className="flex items-center gap-2 flex-1">
<div className="flex items-center gap-2 flex-1">
<CareIcon icon="l-search" className="text-lg text-gray-500" />
<input
type="text"
placeholder={t("search_medications")}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="flex-1 bg-transparent text-sm outline-none placeholder:text-gray-500"
/>
{searchQuery && (
<Button
variant="ghost"
size="sm"
className="h-6 px-2 text-gray-500 hover:text-foreground"
onClick={() => setSearchQuery("")}
>
<CareIcon icon="l-times" className="text-lg" />
</Button>
)}
</div>
</div>
<Button
variant="outline"
className="text-emerald-600 border-emerald-600 hover:bg-emerald-50"
onClick={() => setIsSheetOpen(true)}
>
<CareIcon icon="l-plus" className="mr-2 h-4 w-4" />
{t("administer_medicine")}
</Button>
</div>

<div className="mt-4">{content}</div>

{selectedMedication && administrationRequest && (
<MedicineAdminDialog
Expand Down
Loading

0 comments on commit be85955

Please sign in to comment.