-
Notifications
You must be signed in to change notification settings - Fork 560
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Structured response view | Symptom, Diagnosis, Allergy (#9703)
- Loading branch information
1 parent
ccbc92d
commit e3daa67
Showing
8 changed files
with
464 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
src/components/Facility/ConsultationDetails/StructuredResponseView.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
|
||
import { AllergyTable } from "@/components/Patient/allergy/AllergyTable"; | ||
import { DiagnosisTable } from "@/components/Patient/diagnosis/DiagnosisTable"; | ||
import { SymptomTable } from "@/components/Patient/symptoms/SymptomTable"; | ||
|
||
import routes from "@/Utils/request/api"; | ||
import query from "@/Utils/request/query"; | ||
import { AllergyIntolerance } from "@/types/emr/allergyIntolerance"; | ||
import { Diagnosis } from "@/types/questionnaire/diagnosis"; | ||
import { Symptom } from "@/types/questionnaire/symptom"; | ||
|
||
interface Props { | ||
type: string; | ||
id: string; | ||
patientId: string; | ||
} | ||
|
||
export function StructuredResponseView({ type, id, patientId }: Props) { | ||
const getRouteAndParams = () => { | ||
const params: Record<string, string> = { patientId }; | ||
switch (type) { | ||
case "symptom": | ||
return { | ||
route: routes.getSymptomById, | ||
pathParams: { ...params, symptomId: id }, | ||
}; | ||
case "diagnosis": | ||
return { | ||
route: routes.getDiagnosisById, | ||
pathParams: { ...params, diagnosisId: id }, | ||
}; | ||
case "allergy_intolerance": | ||
return { | ||
route: routes.getAllergyById, | ||
pathParams: { ...params, allergyId: id }, | ||
}; | ||
default: | ||
return null; | ||
} | ||
}; | ||
|
||
const routeConfig = getRouteAndParams(); | ||
|
||
const { data, isLoading, error } = useQuery({ | ||
queryKey: [type, id], | ||
queryFn: query(routeConfig?.route as any, { | ||
pathParams: routeConfig?.pathParams || { patientId }, | ||
}), | ||
enabled: !!id && !!routeConfig, | ||
}); | ||
|
||
if (!routeConfig) return null; | ||
|
||
if (isLoading) { | ||
return <div className="animate-pulse h-20 bg-muted rounded-md" />; | ||
} | ||
|
||
if (error) { | ||
console.error(`Error loading ${type}:`, error); | ||
return <div>Error loading {type}</div>; | ||
} | ||
|
||
switch (type) { | ||
case "symptom": | ||
return ( | ||
<SymptomTable | ||
symptoms={[data as unknown as Symptom]} | ||
showHeader={true} | ||
/> | ||
); | ||
case "diagnosis": | ||
return ( | ||
<DiagnosisTable | ||
diagnoses={[data as unknown as Diagnosis]} | ||
showHeader={true} | ||
/> | ||
); | ||
case "allergy_intolerance": | ||
return ( | ||
<AllergyTable | ||
allergies={[data as unknown as AllergyIntolerance]} | ||
showHeader={true} | ||
/> | ||
); | ||
default: | ||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { | ||
BeakerIcon, | ||
CookingPotIcon, | ||
HeartPulseIcon, | ||
LeafIcon, | ||
} from "lucide-react"; | ||
|
||
import { Badge } from "@/components/ui/badge"; | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from "@/components/ui/table"; | ||
|
||
import { Avatar } from "@/components/Common/Avatar"; | ||
|
||
import { AllergyIntolerance } from "@/types/emr/allergyIntolerance"; | ||
|
||
type AllergyCategory = "food" | "medication" | "environment" | "biologic"; | ||
|
||
const CATEGORY_ICONS: Record<AllergyCategory, React.ReactNode> = { | ||
food: <CookingPotIcon className="h-4 w-4" />, | ||
medication: <BeakerIcon className="h-4 w-4" />, | ||
environment: <LeafIcon className="h-4 w-4" />, | ||
biologic: <HeartPulseIcon className="h-4 w-4" />, | ||
}; | ||
|
||
interface AllergyTableProps { | ||
allergies: AllergyIntolerance[]; | ||
showHeader?: boolean; | ||
} | ||
|
||
export function AllergyTable({ | ||
allergies, | ||
showHeader = true, | ||
}: AllergyTableProps) { | ||
return ( | ||
<Table> | ||
{showHeader && ( | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead className="w-[40px]"></TableHead> | ||
<TableHead>Substance</TableHead> | ||
<TableHead>Status</TableHead> | ||
<TableHead>Critical</TableHead> | ||
<TableHead>Verification</TableHead> | ||
<TableHead>Last Occurrence</TableHead> | ||
<TableHead>By</TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
)} | ||
<TableBody> | ||
{allergies.map((allergy) => ( | ||
<TableRow> | ||
<TableCell className="w-[40px]"> | ||
{allergy.category && | ||
CATEGORY_ICONS[allergy.category as AllergyCategory]} | ||
</TableCell> | ||
<TableCell className="font-medium"> | ||
{allergy.code.display} | ||
</TableCell> | ||
<TableCell> | ||
<Badge variant="outline" className="capitalize"> | ||
{allergy.clinical_status} | ||
</Badge> | ||
</TableCell> | ||
<TableCell> | ||
<Badge variant="secondary" className="capitalize"> | ||
{allergy.criticality} | ||
</Badge> | ||
</TableCell> | ||
<TableCell> | ||
<Badge variant="outline" className="capitalize"> | ||
{allergy.verification_status} | ||
</Badge> | ||
</TableCell> | ||
<TableCell className="whitespace-nowrap"> | ||
{allergy.last_occurrence | ||
? new Date(allergy.last_occurrence).toLocaleDateString() | ||
: "-"} | ||
</TableCell> | ||
<TableCell className="whitespace-nowrap flex items-center gap-2"> | ||
<Avatar | ||
name={`${allergy.created_by?.first_name} ${allergy.created_by?.last_name}`} | ||
className="w-4 h-4" | ||
imageUrl={allergy.created_by?.profile_picture_url} | ||
/> | ||
<span className="text-sm"> | ||
{allergy.created_by?.first_name} {allergy.created_by?.last_name} | ||
</span> | ||
</TableCell> | ||
{allergy.note && ( | ||
<TableRow> | ||
<TableCell colSpan={7} className="px-4 py-2 bg-muted/50"> | ||
<div className="text-xs text-muted-foreground mb-1"> | ||
Notes | ||
</div> | ||
<div className="text-sm">{allergy.note}</div> | ||
</TableCell> | ||
</TableRow> | ||
)} | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
); | ||
} |
Oops, something went wrong.