Skip to content

Commit

Permalink
Re-design Encounter Card (#10579)
Browse files Browse the repository at this point in the history
  • Loading branch information
AdityaJ2305 authored Feb 21, 2025
1 parent dcefa36 commit 569fecb
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 74 deletions.
19 changes: 19 additions & 0 deletions src/common/constants.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import {
Ambulance,
BedDouble,
Building2,
Home,
MonitorSmartphone,
Stethoscope,
} from "lucide-react";

import { IconName } from "@/CAREUI/icons/CareIcon";

import { EncounterClass } from "@/types/emr/encounter";

export const RESULTS_PER_PAGE_LIMIT = 14;

/**
Expand Down Expand Up @@ -354,6 +365,14 @@ export const FILE_EXTENSIONS = {
PRESENTATION: ["pptx"],
DOCUMENT: ["pdf", "docx"],
} as const;
export const encounterIcons = {
imp: <BedDouble />,
amb: <Ambulance />,
obsenc: <Stethoscope />,
emer: <Building2 />,
vr: <MonitorSmartphone />,
hh: <Home />,
} as const satisfies Record<EncounterClass, React.ReactNode>;

export const PREVIEWABLE_FILE_EXTENSIONS = [
"html",
Expand Down
174 changes: 100 additions & 74 deletions src/components/Facility/EncounterCard.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { t } from "i18next";
import { BedSingle, CircleCheck, CircleDashed, Clock } from "lucide-react";
import { BadgeCheck, CircleDashed, Clock, Eye } from "lucide-react";
import { Link } from "raviger";

import { cn } from "@/lib/utils";

import CareIcon from "@/CAREUI/icons/CareIcon";

import { Badge } from "@/components/ui/badge";
import { buttonVariants } from "@/components/ui/button";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";

import { encounterIcons } from "@/common/constants";

import { formatDateTime } from "@/Utils/utils";
import { Encounter, completedEncounterStatus } from "@/types/emr/encounter";
Expand All @@ -18,90 +20,114 @@ interface EncounterCardProps {

export const EncounterCard = (props: EncounterCardProps) => {
const { encounter } = props;

const Icon = encounterIcons[encounter.encounter_class];

return (
<>
<div className="pb-16 block relative border-l-2 px-4 border-l-secondary-300 hover:border-primary-500 transition-all before:absolute before:-left-[7px] before:top-0 before:w-3 before:aspect-square before:bg-secondary-400 before:rounded-full hover:before:bg-primary-500 before:transition-all">
<Badge
variant={
completedEncounterStatus.includes(encounter.status)
? "outline"
: "secondary"
}
className="inline-flex items-center gap-2 -translate-y-2"
>
<div className="flex gap-2">
<div className="flex flex-col items-center">
{completedEncounterStatus.includes(encounter.status) ? (
<CircleCheck className="w-4 h-4 text-green-300" />
<div className="p-1 rounded-full border border-teal-600 bg-green-100">
<BadgeCheck className="w-5 h-5 text-teal-600" />
</div>
) : (
<CircleDashed className="w-4 h-4 text-yellow-500" />
<div className="p-1 rounded-full border border-indigo-800 bg-purple-100">
<CircleDashed className="w-5 h-5 text-purple-400" />
</div>
)}
{t(`encounter_status__${encounter.status}`)}
</Badge>
<div className="h-full">
<Separator
orientation="vertical"
className="h-full bg-secondary-300"
/>
</div>
</div>
<Card className="flex-1">
<CardContent className="p-4 sm:p-2 space-y-4">
<div className="flex flex-wrap gap-2 sm:gap-4">
<Badge
variant="outline"
className={cn(
"inline-flex gap-2 py-1",
completedEncounterStatus.includes(encounter.status)
? "bg-green-100 text-green-800 border-green-200"
: "bg-purple-100 text-indigo-800 border-purple-200",
)}
>
{completedEncounterStatus.includes(encounter.status) ? (
<BadgeCheck className="w-4 h-4 text-teal-700" />
) : (
<CircleDashed className="w-4 h-4 text-indigo-800" />
)}
{t(`encounter_status__${encounter.status}`)}
</Badge>
<Badge
variant="outline"
className="inline-flex items-center gap-2 py-1 bg-gray-100 text-gray-800 border-gray-200"
>
{Icon}
{t(`encounter_class__${encounter.encounter_class}`)}
</Badge>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
{[
{
label: t("facility"),
value: (
<div className="flex items-center gap-2">
<div className="grid sm:flex sm:flex-wrap sm:justify-between gap-4">
<div className="w-full mx-3 sm:w-auto">
<div className="text-gray-600 text-sm">{t("facility")}</div>
<div className="font-semibold text-base flex items-center gap-2">
{encounter.facility.name}
</div>
),
},
{
label: t("encounter_class"),
value: (
<div className="flex items-center gap-2">
<BedSingle className="w-4 h-4 text-blue-400" />
{t(`encounter_class__${encounter.encounter_class}`)}
</div>

<div className="w-full mx-3 sm:w-auto">
<div className="text-gray-600 text-sm">{t("start_date")}</div>
<div className="font-semibold text-base">
{encounter.period.start
? formatDateTime(encounter.period.start)
: t("not_started")}
</div>
),
},
{
label: t("priority"),
value: (
<div className="flex items-center gap-2">
</div>

<div className="w-full mx-3 sm:w-auto">
<div className="text-gray-600 text-sm">{t("priority")}</div>
<div className="font-semibold text-base flex items-center gap-2">
<Clock className="w-4 h-4 text-yellow-500" />
{t(`encounter_priority__${encounter.priority.toLowerCase()}`)}
</div>
),
},
{
label: t("start_date"),
value: encounter.period.start
? formatDateTime(encounter.period.start)
: t("not_started"),
},
{
label: t("end_date"),
hide: !encounter.period.end,
value: formatDateTime(encounter.period.end),
},
{
label: t("external_id"),
hide: !encounter.external_identifier,
value: encounter.external_identifier,
},
]
.filter((f) => !f.hide)
.map((field, i) => (
<div key={i}>
<div className="text-sm text-gray-600">{field.label}</div>
<div className="font-bold">{field.value}</div>
</div>
))}
</div>
{encounter.period.end && (
<div className="w-full mx-3 sm:w-auto">
<div className="text-gray-600 text-sm">{t("end_date")}</div>
<div className="font-semibold text-base">
{formatDateTime(encounter.period.end)}
</div>
</div>
)}

<Link
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/updates`}
className={cn(
buttonVariants({ variant: "secondary" }),
"mt-2 shadow-none border border-secondary-300",
!encounter.period.start && "pointer-events-none opacity-50",
)}
>
<CareIcon icon="l-plus-circle" />
{t("view_encounter")}
</Link>
{encounter.external_identifier && (
<div className="w-full mx-3 sm:w-auto">
<div className="text-gray-600 text-sm">
{t("external_id")}
</div>
<div className="font-semibold text-base">
{encounter.external_identifier}
</div>
</div>
)}
</div>
<div className="w-full py-2 bg-gray-100 px-2">
<Button variant="outline" className="p-2 border border-black">
<Link
href={`/facility/${encounter.facility.id}/patient/${encounter.patient.id}/encounter/${encounter.id}/updates`}
className="flex items-center gap-2"
>
<Eye className="w-4 h-4" />
<span>{t("view_encounter")}</span>
</Link>
</Button>
</div>
</CardContent>
</Card>
</div>
</>
);
Expand Down

0 comments on commit 569fecb

Please sign in to comment.