From dfe1f5254504a207331b308d49e1e9bfb363d974 Mon Sep 17 00:00:00 2001 From: saksham vitwekar Date: Mon, 6 Apr 2026 08:59:10 +0530 Subject: [PATCH] Adding drug dose calculator (Atorvastatin), GRACE(Discharge) score --- src/app/utils/Input.tsx | 85 ++++--- src/app/utils/Result.tsx | 2 +- .../calculators/Drug Dose Calculator/Adult.ts | 146 ++++++++++++ .../drugs/Cardiology/atorvastatin.ts | 24 ++ .../drugs/Cardiology/metoprolol.ts | 23 ++ .../drugs/drug_registry.ts | 8 + .../General Cardiology/GRACE_Discharge.ts | 216 ++++++++++++++++++ src/app/utils/calculators/registry.ts | 14 +- src/app/utils/calculators/types.ts | 28 ++- 9 files changed, 505 insertions(+), 41 deletions(-) create mode 100644 src/app/utils/calculators/Drug Dose Calculator/Adult.ts create mode 100644 src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/atorvastatin.ts create mode 100644 src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/metoprolol.ts create mode 100644 src/app/utils/calculators/Drug Dose Calculator/drugs/drug_registry.ts create mode 100644 src/app/utils/calculators/General Cardiology/GRACE_Discharge.ts diff --git a/src/app/utils/Input.tsx b/src/app/utils/Input.tsx index 58d82c8..b3c2a38 100644 --- a/src/app/utils/Input.tsx +++ b/src/app/utils/Input.tsx @@ -7,6 +7,10 @@ export default function InputComponent({id, type, inputOptions, min, max, requir const [error, setError] = useState(); const [option, setOption] = useState(""); const [open, setOpen] = useState(false); + const [search, setSearch] = useState(""); + const filteredOptions = inputOptions?.filter(e => + e.label.toLowerCase().includes(search.toLowerCase()) + ); if(type === "number"){ return( <> @@ -127,51 +131,56 @@ export default function InputComponent({id, type, inputOptions, min, max, requir ) }else if(type === "search"){ console.log('ran'); - return( - <> + return (
- { info ? - <> -
- - - - - -
: null - } {name} {defaultUnit ? `(${defaultUnit})` : null}
- + {name} {defaultUnit ? `(${defaultUnit})` : null} + +
+ { - setOption(e.target.value); - if(e.target.value !== ""){ - setOpen(true); - }else{ - setOpen(false); + setSearch(e.target.value); + setOpen(true); + if(e.target.value === ""){ + return; } handleDataChange !== undefined ? handleDataChange(id, e.target.value) : null; }} - required={required} + onFocus={() => setOpen(true)} + /> - - {open && inputOptions?.map(e => { - return( - - {/* Optional */} + {open && ( +
+ {filteredOptions?.length ? ( + filteredOptions.map((e) => ( +
{ + setSearch(e.label); + setOpen(false); + + }} + onMouseDown={() => { + setSearch(e.label); + setOpen(false); + handleDataChange !== undefined ? handleDataChange(id, e.value) : null; + }} + > + {e.label} +
+ )) + ) : ( +
No results
+ )} +
+ )} +
- ); } } \ No newline at end of file diff --git a/src/app/utils/Result.tsx b/src/app/utils/Result.tsx index bef0e33..080c401 100644 --- a/src/app/utils/Result.tsx +++ b/src/app/utils/Result.tsx @@ -32,7 +32,7 @@ export default function Result({interpretation, calculated_value, unit, id, sect
{calc.name}
: null} -

Calculated Score/Value: {calculated_value} {unit}

+

Calculated Score/Value: {String(calculated_value)} {unit}

{message}

{diagnosis ?

Diagnosis: {diagnosis}

: null} {advice ?

Advice: {advice}

: null} diff --git a/src/app/utils/calculators/Drug Dose Calculator/Adult.ts b/src/app/utils/calculators/Drug Dose Calculator/Adult.ts new file mode 100644 index 0000000..a2ab33c --- /dev/null +++ b/src/app/utils/calculators/Drug Dose Calculator/Adult.ts @@ -0,0 +1,146 @@ +import { Calculator, Drug, Input, Interpretation, Values, inputOptions } from "../types" +import { DrugRegistry } from "./drugs/drug_registry" + +function generateDrugList():inputOptions[] { + const drugs:inputOptions[] = DrugRegistry.map(e => { + console.log(e.name); + const drug:inputOptions = { + label:e.name, + value:e.id + } + return drug; + }); + console.log(drugs); + return drugs; +} +const parameters:Input[] = [ + { + id:"drug", + name:"Drug name", + placeholder:"Select the drug by searching its name below", + type:"search", + inputOptions:generateDrugList() + }, + { + id:"weight", + name:"Weight", + placeholder:"Enter the weight of the patient", + type:"number" + }, + { + id:"ckd", + name:"CKD Stage", + placeholder:"Whether the patient has CKD, if yes, select the stage", + type:"select", + inputOptions:[ + { + label:"None", + value:"none" + }, + { + label:"CKD stage 3a", + value:"3A" + }, + { + label:"CKD Stage 3B", + value:"3B" + }, + { + label:"CKD Stage 4", + value:"4" + }, + { + label:"CKD Stage 5 / ESRD", + value:"5" + } + ] + }, + { + id:"cld", + name:"CLD Stage (Child Pugh)", + placeholder:"Whether the patient has CLD, if yes, select the Child Pugh Stage", + type:"select", + inputOptions:[ + { + label:"None", + value:"none" + }, + { + label:"Child Pugh A", + value:"A" + }, + { + label:"Child Pugh B", + value:"B" + }, + { + label:"Child Pugh C", + value:"C" + } + ] + } +] + +export const Adult_Drug_Calculator:Calculator = { + id:"adult_drug_calculator", + name:"Adult Dose Calculator", + desc:"Adult Dose Calculator can be used to calculate the drug dosing of different dose which also accounts for different comorbidities like CKD and CLD", + inputs:parameters, + calc_func:(values : Values) : string | number => { + const drugID = values.drug as string; + const weight = values.weight as number; + const ckd = values.ckd as "none" | "3A" | "3B" | "4" | "5"; + const cld = values.cld as "none" | "A" | "B" | "C"; + const drug = DrugRegistry.find(e => e.id === drugID); + if(drug){ + if(typeof drug.cld_dosing !== "undefined" && typeof drug.ckd_dosing !== "undefined" && ckd !== "none" && cld == "none"){ + const dosingObj = drug.cld_dosing.find(e => e.stage === cld); + if(drug.isWeightBased){ + return `${Math.floor(dosingObj?.dosing * weight)} ${drug.unit}`; + }else{ + return `${Math.floor(dosingObj?.dosing)} ${drug.unit}` || 0; + } + }else if(typeof drug.cld_dosing !== "undefined" && cld !== "none"){ + const dosingObj = drug.cld_dosing.find(e => e.stage === cld); + if(drug.isWeightBased){ + return `${Math.floor(dosingObj?.dosing * weight)} ${drug.unit}`; + }else{ + return `${Math.floor(dosingObj?.dosing)} ${drug.unit}` || 0; + } + }else if(typeof drug.ckd_dosing !== "undefined" && ckd !== "none"){ + const dosingObj = drug.ckd_dosing.find(e => e.stage === ckd); + if(drug.isWeightBased){ + return `${Math.floor(dosingObj?.dosing * weight)} ${drug.unit}`; + }else{ + return `${Math.floor(dosingObj?.dosing)} ${drug.unit}` || 0; + } + }else{ + if(drug.isWeightBased){ + return `${Math.floor(drug.adult_dosing * weight)} ${drug.unit}`; + }else{ + return `${drug.adult_dosing} ${drug.unit}`; + } + } + }else{ + return -1; + } + }, + interpret_func:(dosing:number | string):Interpretation => { + if(dosing === 0){ + return { + level:"severe", + message:"Drug is to be avoided in patient" + } + }else if(dosing === -1){ + return { + level:"none", + message:"Drug not found" + } + }else{ + return { + level:"low", + message:`Calculated dosing for the drug is ${dosing ? dosing : null}` + } + } + } +} \ No newline at end of file diff --git a/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/atorvastatin.ts b/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/atorvastatin.ts new file mode 100644 index 0000000..bfa26a5 --- /dev/null +++ b/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/atorvastatin.ts @@ -0,0 +1,24 @@ +import { Drug } from "../../../types"; + +export const Atorvastatin:Drug = { + id:"atorvastatin", + name:"Atorvastatin", + adult_dosing:"10mg to 20mg", + pediatric_dosing:"10mg to 20mg", + isWeightBased:false, + max_dose:"80mg", + max_dose_pediatric:"20mg", + unit:"mg", + cld_dosing:[ + { + stage:"B", + to_be_given:true, + dosing:"5-10mg OD", + max_dose:"20mg" + }, + { + stage:"C", + to_be_given:false + } + ] +}; \ No newline at end of file diff --git a/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/metoprolol.ts b/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/metoprolol.ts new file mode 100644 index 0000000..6fe3257 --- /dev/null +++ b/src/app/utils/calculators/Drug Dose Calculator/drugs/Cardiology/metoprolol.ts @@ -0,0 +1,23 @@ +import { Drug } from "../../../types"; + +export const metoprolol:Drug = { + id:"metoprolol", + name:"Metoprolol", + adult_dosing:1.5, + max_dose:"200mg", + isWeightBased:true, + unit:"mg", + pediatric_dosing:0.5, + cld_dosing:[ + { + stage:"B", + to_be_given:true, + dosing:0.5 + }, + { + stage:"C", + to_be_given:true, + dosing:0.25 + } + ] +} \ No newline at end of file diff --git a/src/app/utils/calculators/Drug Dose Calculator/drugs/drug_registry.ts b/src/app/utils/calculators/Drug Dose Calculator/drugs/drug_registry.ts new file mode 100644 index 0000000..1902293 --- /dev/null +++ b/src/app/utils/calculators/Drug Dose Calculator/drugs/drug_registry.ts @@ -0,0 +1,8 @@ +import { Drugs } from "../../types"; +import { Atorvastatin } from "./Cardiology/atorvastatin"; +import { metoprolol } from "./Cardiology/metoprolol"; + +export const DrugRegistry:Drugs = [ + Atorvastatin, + metoprolol +]; \ No newline at end of file diff --git a/src/app/utils/calculators/General Cardiology/GRACE_Discharge.ts b/src/app/utils/calculators/General Cardiology/GRACE_Discharge.ts new file mode 100644 index 0000000..992a4bb --- /dev/null +++ b/src/app/utils/calculators/General Cardiology/GRACE_Discharge.ts @@ -0,0 +1,216 @@ +import { Calculator, Input, Interpretation, Values } from "../types"; + +const parameters:Input[] = [ + { + id:"age", + name:"Age", + placeholder:"Enter the age", + type:"number", + required:true + }, + { + id:"hr", + name:"Heart Rate", + placeholder:"Enter the Heart Rate", + type:"number", + required:true, + defaultUnit:"beats/minute" + }, + { + id:"sbp", + name:"Systolic Blood Pressure", + placeholder:"Enter the Systolic Blood Pressure", + type:"number", + required:true, + defaultUnit:"mmHg" + }, + { + id:"cret", + name:"Serum Creatinine", + placeholder:"Enter the serum creatinine", + type:"number", + required:true, + defaultUnit:"mg/dL" + }, + { + id:"cardiacmarkers", + name:"Elevated Cardiac Markers", + placeholder:"Whether the patient had elevated cardiac markers", + type:"checkbox", + required:true + }, + { + id:"deviation", + name:"ST segment depression", + placeholder:"Whether the patient had ST segment depression", + type:"checkbox", + required:true + }, + { + id:"chf", + name:"Congestive Heart Failure", + placeholder:"Whether the patient has a history of Congestive Heart Failure", + type:"checkbox" + }, + { + id:"pci", + name:"Percutaneous Coronary Intervention", + placeholder:"Whether the patient had a PCI during hospital stay", + type:"checkbox" + }, + { + id:"mi", + name:"History of Myocardial Infarction", + placeholder:"Whether the patient has a history of Myocardial Infarction", + type:"checkbox" + } +] + +export const GRACE_Discharge : Calculator = { + id:"grace_discharge", + name:"GRACE 1.0 (Discharge)", + desc:"The GRACE (Global Registry for Acut Coronary Events) Score is a clinical tool to estimate the risk of death or myocardial infarction (MI) for 6 weeks in patients after discharge who have suffered Acute Coronary Syndrone (ACS)", + inputs:parameters, + calc_func:(values: Values):number => { + const age = values.age as number; + const hr = values.hr as number; + const sbp = values.sbp as number; + const cret = values.cret as number; + const chf = values.chf as boolean; + const pci = values.pci as boolean; + const deviation = values.deviation as boolean; + const mi = values.mi as boolean; + const cardiacmarkers = values.cardiacmarkers as boolean; + + var score = 0; + + if(age < 40) score = score + 0; + else if(age >=40 && age < 50) score = score + 18; + else if(age >= 50 && age < 60) score = score + 36; + else if(age >= 60 && age < 70) score = score + 55; + else if(age >= 70 && age < 80) score = score + 73 + else if(age >= 80 && age < 90) score = score + 91; + else score = score + 100; + + if (hr < 50) score += 0; + else if (hr <= 69) score += 3; + else if (hr <= 89) score += 9; + else if (hr <= 109) score += 14; + else if (hr <= 149) score += 23; + else if (hr <= 199) score += 35; + else score += 43; + + if (sbp < 80) score += 24; + else if (sbp <= 99) score += 22; + else if (sbp <= 119) score += 18; + else if (sbp <= 139) score += 14; + else if (sbp <= 159) score += 10; + else if (sbp <= 199) score += 4; + else score += 0; + + if (cret <= 0.39) score += 1; + else if (cret <= 0.79) score += 3; + else if (cret <= 1.19) score += 5; + else if (cret <= 1.59) score += 7; + else if (cret <= 1.99) score += 9; + else if (cret <= 3.99) score += 15; + else score += 20; + + if (chf) score += 24; + if (deviation) score += 11; + if(pci) score += 14; + if(mi) score += 12; + if(cardiacmarkers) score += 15; + return score; + }, + interpret_func:(score : number) : Interpretation => { + if(score <= 60) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 0.2%" + } + if(score <= 70 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 0.3%" + } + if(score <= 80 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 0.4%" + } + if(score <= 90 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 0.6%" + } + if(score <= 100 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 0.8%" + } + if(score <= 110 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 1.1%" + } + if(score <= 120 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 1.6%" + } + if(score <= 130 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 2.1%" + } + if(score <= 140 ) return { + level:"low", + message:"Probability of In Hospital Mortality is less than or equal to 2.9%" + } + if(score <= 150 ) return { + level:"moderate", + message:"Probability of In Hospital Mortality is less than or equal to 3.9%" + } + if(score <= 160 ) return { + level:"moderate", + message:"Probability of In Hospital Mortality is less than or equal to 5.4%" + } + if(score <= 170 ) return { + level:"moderate", + message:"Probability of In Hospital Mortality is less than or equal to 7.3%" + } + if(score <= 180 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 9.8%" + } + if(score <= 190 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 13%" + } + if(score <= 200 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 18%" + } + if(score <= 210 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 23%" + } + if(score <= 220 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 29%" + } + if(score <= 230 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 36%" + } + if(score <= 240 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 44%" + } + if(score < 250 ) return { + level:"severe", + message:"Probability of In Hospital Mortality is less than or equal to 44%" + } + if(score >= 250) return { + level:"severe", + message:"Probability of In Hospital Mortality is more than or equal to 52%" + } + return{ + level:"none", + message:"Invalid Value" + } + } +} \ No newline at end of file diff --git a/src/app/utils/calculators/registry.ts b/src/app/utils/calculators/registry.ts index 10dc41a..3659253 100644 --- a/src/app/utils/calculators/registry.ts +++ b/src/app/utils/calculators/registry.ts @@ -9,6 +9,8 @@ import { MELDNa } from "./Utilities/MELDNa"; import { GRACE_Inhosp } from "./Emergency/GRACE_Inhosp"; import { HEART_Score } from "./General Cardiology/HEART_Score"; import { HASBLED } from "./Arrhythmias and Anti-Coagulation/HAS-BLED"; +import { GRACE_Discharge } from "./General Cardiology/GRACE_Discharge"; +import { Adult_Drug_Calculator } from "./Drug Dose Calculator/Adult"; export const CalculatorRegistry : Record = { generalCardiology:{ @@ -17,7 +19,17 @@ export const CalculatorRegistry : Record = { textColor:"#ccc", svg:"", calculators:[ - MAP + MAP, + GRACE_Discharge + ] + }, + drugDoseCalculator:{ + id:"drugDosing", + displayName:"Drug Dose Calculator", + textColor:"#ccc", + svg:"", + calculators:[ + Adult_Drug_Calculator ] }, arrhythmias:{ diff --git a/src/app/utils/calculators/types.ts b/src/app/utils/calculators/types.ts index ab0359e..d82c93a 100644 --- a/src/app/utils/calculators/types.ts +++ b/src/app/utils/calculators/types.ts @@ -8,7 +8,7 @@ export interface Calculator { interpret_func:Function, customComponent?:React.FC } -interface inputOptions { +export interface inputOptions { label:string, value:string | number ; } @@ -52,3 +52,29 @@ export interface pastUsed { unit: string | undefined } export type Values = Record; + +export interface Drug { + id:string, + name:string, + adult_dosing:number | string, + pediatric_dosing?:number | string, + max_dose: number | string, + max_dose_pediatric?: number | string + isWeightBased:boolean + unit:string, + ckd_dosing?: + { + stage: "none" |"3A" | "3B" | "4" | "ESRD", + to_be_given:boolean + dosing?:number | string, + max_dose?:number | string + }[], + cld_dosing?: { + stage:"none" | "A" | "B" | "C", + to_be_given: boolean, + dosing?: number | string, + max_dose?:number | string + }[] +} + +export type Drugs = Drug[]; \ No newline at end of file