Compare commits

...

10 Commits

21 changed files with 1220 additions and 12 deletions

5
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,5 @@
# Contributing to CalcForCardiac
By contributing, you agree that your contributions will be part of this project and remain under the project's license.
You may not reuse or redistribute this code outside this repository.

17
LICENSE.md Normal file
View File

@@ -0,0 +1,17 @@
Copyright (c) 2026 Saksham Vitwekar
All rights reserved.
You are allowed to:
* View the source code
* Fork the repository for personal or educational purposes
* Submit pull requests to this repository
You are NOT allowed to:
* Copy, reuse, or redistribute this code (in whole or in part)
* Use this code in your own projects (commercial or non-commercial)
* Host or deploy this code elsewhere
Permission may be granted upon explicit written approval from the author.

View File

@@ -1 +1,60 @@
COMING SOON
<p align="center">
<img src="/public/calcforcardiac_logo.png" />
</p>
<a href="https://calcforcardiac.online/" ><h1 align="center">CalcForCardiac</h1></a>
<h3 align="center">A minimal friction and zero login clinical calculator made especially for cardiologists!</h3>
## ✨ Features
- ⚡ Zero login, instant access
- 🫀 Multiple medical calculators all in one place
- 📱 Mobile-first responsive design
- 💾 Local storage support (stores past results and bookmarks)
- 🧠 Clinically relevant interpretations
## Preview
<p align="center">
<img src="./public/website_homepage.gif" width="800" />
<img src="./public/website_calculators.gif" width="800" />
</p>
## 📝 Section documentation
- [🫀 General Cardiology](#-general-cardiology)
- [🚨 Emergency](#-emergency)
- [🧬 Transplantation](#-transplantation)
- [🛠️ Utilities](#-utilities)
## 🧮 Calculators
All of the calculators are accessible in the website. The below list contains the documentation written by me of the calculators that have been made
### Note:- Documents of some of the calculators may be missing from the repository, they will be made soon
## 🫀 General Cardiology
<a id="risk"></a>
- [MAP](./docs/General%20Cardiology/MAP.md)
## 🚨 Emergency
<a id="emergency"></a>
- [TIMI Score](docs/Emergency/TIMI.md)
## 🧬 Transplantation
<a id="transplantation"></a>
- [IMPACT Score](docs/Transplantation/IMPACT.md)
## 🛠️ Utilities
<a id="utilities"></a>
- [Cockcroft gault Equation](docs/Utilities/cockcroft-gault-eq.md)
- [MELD Score](docs/Utilities/MELD.md)
## 🧠 Why CalcForCardiac?
Most existing clinical calculators:
- Require <b>login </b>
- Are <b>cluttered and slow</b>
CalcForCardiac is built to:
- ⚡ Provide <b>instant access</b>
- 🧼 Keep UI <b>minimal and fast</b>
- 🩺 Deliver <b>clinically meaningful</b> outputs

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

BIN
public/website_homepage.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

View File

@@ -59,7 +59,10 @@ export default function Home(){
</div>
</div>
</div>
<div className="max-w-6xl mx-auto px-4 mt-1">
<div className="flex gap-4 justify-center overflow-hidden">
<img src="./website_calculators.gif" width={800}/>
</div>
<div className="max-w-6xl mx-auto px-4 mt-20">
<h2 className="text-2xl sm:text-3xl font-bold text-center mb-2 tracking-tight text-white">
Start with What You Need
</h2>

View File

@@ -6,10 +6,15 @@ export default function InputComponent({id, type, inputOptions, min, max, requir
const [showError, setErrorStatus] = useState(false);
const [error, setError] = useState<string>();
const [option, setOption] = useState<string>("");
const [open, setOpen] = useState<boolean>(false);
const [search, setSearch] = useState<string>("");
const filteredOptions = inputOptions?.filter(e =>
e.label.toLowerCase().includes(search.toLowerCase())
);
if(type === "number"){
return(
<>
<fieldset className="fieldset">
<fieldset className="fieldset bg-white bg-base-100 border border-base-300 rounded-box w-full min-w-0 p-2 overflow-visible">
<legend className="fieldset-legend text-black">{ typeof info === "string" ?
<>
<div className="tooltip inline-block max-w-[140px] overflow-visible" data-tip={info}>
@@ -58,7 +63,7 @@ export default function InputComponent({id, type, inputOptions, min, max, requir
);
} else if(type === "select"){
return(
<fieldset className="fieldset">
<fieldset className="fieldset bg-white bg-base-100 border border-base-300 rounded-box w-full min-w-0 p-2 overflow-visible">
<legend className="fieldset-legend text-black"> { info ?
<>
<div className="tooltip inline-block" data-tip={info}>
@@ -124,5 +129,57 @@ export default function InputComponent({id, type, inputOptions, min, max, requir
</label>
</fieldset>
)
}else if(type === "search"){
return (
<fieldset className="fieldset">
<legend className="fieldset-legend text-black">
{name} {defaultUnit ? `(${defaultUnit})` : null}
</legend>
<div className="relative">
<input
type="text"
className="input bg-white text-black border-black"
placeholder={search !== "" ? search : placeholder}
value={search}
onChange={(e) => {
setSearch(e.target.value);
setOpen(true);
if(e.target.value === ""){
return;
}
handleDataChange !== undefined ? handleDataChange(id, e.target.value) : null;
}}
onFocus={() => setOpen(true)}
/>
{open && (
<div className="absolute left-0 top-full mt-0 z-50 w-full bg-white border border-black max-h-48 overflow-y-auto rounded shadow">
{filteredOptions?.length ? (
filteredOptions.map((e) => (
<div
key={e.value}
className="px-3 py-2 hover:bg-gray-200 cursor-pointer"
onClick={() => {
setSearch(e.label);
setOpen(false);
}}
onMouseDown={() => {
setSearch(e.label);
setOpen(false);
handleDataChange !== undefined ? handleDataChange(id, e.value) : null;
}}
>
{e.label}
</div>
))
) : (
<div className="px-3 py-2 text-gray-500">No results</div>
)}
</div>
)}
</div>
</fieldset>
);
}
}

View File

@@ -32,7 +32,7 @@ export default function Result({interpretation, calculated_value, unit, id, sect
<path d="M8.37032 11.0726L5.41421 14.0287C4.63317 14.8097 4.63316 16.076 5.41421 16.8571L6.95611 18.399C7.73715 19.18 9.00348 19.18 9.78453 18.399L12.7406 15.4429M11.0726 8.37032L14.0287 5.41421C14.8097 4.63317 16.076 4.63316 16.8571 5.41421L18.399 6.95611C19.18 7.73715 19.18 9.00348 18.399 9.78453L15.4429 12.7406M6.64883 6.64883L4.88296 4.88296M19.0992 19.0992L17.3333 17.3333M9.35119 5.87299V4M14.6488 20V18.127M5.87299 9.35119H4M20 14.6488H18.127" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
<h6 className="leading-none">{calc.name}</h6></Link> : null}
<h2 className="card-title self-center">Calculated Score/Value: {calculated_value} {unit}</h2>
<h2 className="card-title self-center">Calculated Score/Value: {String(calculated_value)} {unit}</h2>
<p>{message}</p>
{diagnosis ? <p>Diagnosis: {diagnosis}</p> : null}
{advice ? <p>Advice: {advice}</p> : null}

View File

@@ -17,7 +17,7 @@ const parameters:Input[] = [
},
{
id:"age",
name:"age",
name:"Age",
type:"number",
placeholder:"Enter the age",
required:true,

View File

@@ -0,0 +1,122 @@
import { Input, Calculator, Values, Interpretation } from "../types"
const parameters:Input[] = [
{
id:"sbp",
type:"number",
name:"Systolic Blood Pressure",
placeholder:"Enter the Systolic Blood Pressure",
min:0,
required:true
},
{
id:"rft",
type:"checkbox",
name:"Renal Function",
placeholder:"Whether the patient has/had abnormal renal function",
info:"Dialysis, Transplantation or Cr > 2.26 mg/dL"
},
{
id:"lft",
type:"checkbox",
name:"Liver Function",
placeholder:"Whether the patient has abnormal renal function",
info:"Cirrhosis or Bilirubin >2x normal or AST/ALT/AP > 3x normal",
},
{
id:"stroke",
type:"checkbox",
name:"History of stroke",
placeholder:"Whether the patient has a history of stroke",
},
{
id:"bleeding",
type:"checkbox",
name:"History of bleeding",
placeholder:"Whether the patient has a history of major bleeding or predeposition to Bleeding"
},
{
id:"inr",
type:"checkbox",
name:"INR",
placeholder:"Does the patient have Labile INR (Unstable/high INR)",
info:"Time in Therapeutic Range < 60%"
},
{
id:"age",
type:"number",
placeholder:"Enter the age",
name:"Age",
required:true
},
{
id:"alcohol",
name:"Prior alcohol usage",
type:"checkbox",
placeholder:"Whether the patient has a history of alcohol consumption",
info:">= 8 drinks/week",
required:true
},
{
id:"drugs",
name:"Prior drug usage",
type:"checkbox",
placeholder:"Whether the patient has a history of drug (Antiplatelet, NSAIDs) usage",
required:true
}
]
export const HASBLED : Calculator = {
id:"hasbled",
name:"HAS-BLED Score",
desc:"HAS-BLED is a scoring system developed to assess 1-year risk of major bleeding in people taking anticoagulants for AF (atrial fibrillation). Major bleeding is defined as being intracranial bleedings, hospitalization, hemoglobin decrease >2 g/dL, and/or transfusion.",
inputs:parameters,
calc_func:(values : Values):number => {
const sbp = values.sbp as number;
const rft = values.rft as boolean;
const lft = values.lft as boolean;
const stroke = values.stroke as boolean;
const bleeding = values.bleeding as boolean;
const inr = values.inr as boolean;
const age = values.age as number;
const alcohol = values.alcohol as boolean;
const drugs = values.drug as boolean;
let score = 0;
if(sbp > 160) score ++;
if(rft) score++;
if(lft) score++;
if(stroke) score++;
if(bleeding) score++;
if(inr) score++;
if(age > 65) score++;
if(alcohol) score++;
if(drugs) score++;
return score;
},
interpret_func:(score:number):Interpretation => {
if(score <= 1) return {
level:"low",
message:"There is a low (1-3.5%) risk of bleeding",
advice:"Anticoagulations may be considered"
}
if(score === 2) return {
level:"moderate",
message:"There is a moderate (4%) risk of bleeding",
advice:"Anticoagulations may be considered"
}
if(score <= 5) return {
level:"high",
message:"There is a high (5-9%) risk of bleeding",
advice:"Consider alternatives to anticoagulation"
}
if(score >= 6) return {
level:"severe",
message:"There is a very high (10+ %) risk of bleeding",
advice:"Consider alternatives to anticoagulations"
}
return {
level:"none",
message:"Invalid value"
};
}
}

View File

@@ -0,0 +1,155 @@
import { Calculator, Drug, Input, Interpretation, Values, inputOptions } from "../types"
import { DrugRegistry } from "./drugs/drug_registry"
function generateDrugList():inputOptions[] {
const drugs:inputOptions[] = DrugRegistry.map(e => {
const drug:inputOptions = {
label:e.name,
value:e.id
}
return drug;
});
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) return -1;
const dosingObj_CLD = drug.cld_dosing?.find(e => e.stage === cld);
const dosingObj_CKD = drug.ckd_dosing?.find(e => e.stage === ckd);
if(drug){
if(dosingObj_CLD && dosingObj_CKD && ckd !== "none" && cld !== "none"){
if(dosingObj_CLD.dosing === 0 || dosingObj_CKD.dosing === 0){
return 0;
}
if(drug.isWeightBased && typeof dosingObj_CLD.dosing === "number"){
return `${Math.floor(dosingObj_CLD.dosing * weight)} ${drug.unit}`
}else{
return `${dosingObj_CLD.dosing} ${drug.unit}`
}
}else if(dosingObj_CLD && cld !== "none"){
if(dosingObj_CLD.dosing === 0){
return 0;
}
if(drug.isWeightBased && typeof dosingObj_CLD.dosing === "number"){
return `${Math.floor(dosingObj_CLD.dosing * weight)} ${drug.unit}`
}else{
return `${dosingObj_CLD.dosing} ${drug.unit}`
}
}else if(dosingObj_CKD && ckd !== "none"){
if(dosingObj_CKD.dosing === 0){
return 0;
}
if(drug.isWeightBased && typeof dosingObj_CKD.dosing === "number"){
return `${Math.floor(dosingObj_CKD.dosing * weight)} ${drug.unit}`
}else{
return `${dosingObj_CKD.dosing} ${drug.unit}`
}
}else{
if(drug.isWeightBased && typeof drug.adult_dosing === "number"){
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}`
}
}
}
}

View File

@@ -0,0 +1,26 @@
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,
dosing:0,
max_dose:0
}
]
};

View File

@@ -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
}
]
}

View File

@@ -0,0 +1,8 @@
import { Drugs } from "../../types";
import { Atorvastatin } from "./Cardiology/atorvastatin";
import { metoprolol } from "./Cardiology/metoprolol";
export const DrugRegistry:Drugs = [
Atorvastatin,
metoprolol
];

View File

@@ -0,0 +1,233 @@
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:"killip",
name:"Killip Class",
type:"select",
placeholder:"Select the killip class",
required:true,
inputOptions:[
{
label:"Class I",
value:"I"
},
{
label:"Class II",
value:"II"
},
{
label:"Class III",
value:"III"
},
{
label:"Class IV",
value:"IV"
}
]
},
{
id:"cardiacarrest",
name:"Cardiac Arrest",
placeholder:"Whether the patient was in cardiac arrest at the time of admission",
type:"checkbox",
required:true
},
{
id:"cardiacmarkers",
name:"Elevated Cardiac Markers",
placeholder:"Whether the patient had elevated cardiac markers",
type:"checkbox",
required:true
},
{
id:"deviation",
name:"ST segment deviation",
placeholder:"Whether the patient had ST segment deviation",
type:"checkbox",
required:true
}
]
export const GRACE_Inhosp : Calculator = {
id:"grace_inhosp",
name:"GRACE 1.0 (In-Hospital)",
desc:"The GRACE (Global Registry for Acut Coronary Events) Score is a clinical tool to estimate the risk of death or myocardial infarction (MI) during In-Hospital Admission in patients 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 killip = values.killip as "I" | "II" | "III" | "IV";
const cardiacarrest = values.cardiacarrest as boolean;
const cardiacmarkers = values.cardiacmarkers as boolean;
const deviation = values.deviation as boolean;
var score = 0;
if(age >= 30 && age < 40) score = score + 8;
else if(age >=40 && age < 50) score = score + 25;
else if(age >= 50 && age < 60) score = score + 41;
else if(age >= 60 && age < 70) score = score + 58;
else if(age >= 70 && age < 80) score = score + 75
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 += 15;
else if (hr <= 149) score += 24;
else if (hr <= 199) score += 38;
else score += 46;
if (sbp < 80) score += 58;
else if (sbp <= 99) score += 53;
else if (sbp <= 119) score += 43;
else if (sbp <= 139) score += 34;
else if (sbp <= 159) score += 24;
else if (sbp <= 199) score += 10;
else score += 0;
if (cret <= 0.39) score += 1;
else if (cret <= 0.79) score += 4;
else if (cret <= 1.19) score += 7;
else if (cret <= 1.59) score += 10;
else if (cret <= 1.99) score += 13;
else if (cret <= 3.99) score += 21;
else score += 28;
if (killip === "I") score += 0;
else if (killip === "II") score += 20;
else if (killip === "III") score += 39;
else if (killip === "IV") score += 59;
if (cardiacarrest) score += 39;
if (cardiacmarkers) score += 14;
if (deviation) score += 28;
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"
}
}
}

View File

@@ -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"
}
}
}

View File

@@ -0,0 +1,146 @@
import { Calculator, Input, Interpretation, Values } from "../types";
const parameters : Input[] = [
{
id:"history",
name:"History",
placeholder:"Select the suspicion level based on history",
type:"select",
inputOptions:[
{
label:"Highly suspicious",
value:"high"
},
{
label:"Moderately suspicious",
value:"moderate",
},
{
label:"Slightly suspicious",
value:"none"
}
],
required:true
},
{
id:"ecg",
name:"ECG Interpretation",
placeholder:"Select the interpretation of ECG",
type:"select",
inputOptions:[
{
label:"Significant ST-Depression",
value:"stdepression"
},
{
label:"Nonspecific Repolarization",
value:"repolarization"
},
{
label:"Normal",
value:"normal"
}
],
required:true
},
{
id:"age",
name:"Age",
type:"number",
placeholder:"Enter the age",
required:true
},
{
id:"risk",
name:"Risk factors",
type:"select",
placeholder:"Select the number of risk factors found",
inputOptions:[
{
label:"3 or more than 3 Risk Factors or history of CAD",
value:"high"
},
{
label:"1 or 2 Risk Factors",
value:"moderate"
},
{
label:"No risk factors",
value:"none"
}
],
required:true
},
{
id:"trop",
name:"Troponin Levels",
placeholder:"Select the amount of Troponin",
type:"select",
inputOptions:[
{
label:"more than 3 times the normal limit",
value:"high"
},
{
label:"1 to 3 times the normal limit",
value:"moderate"
},
{
label:"within normal limits",
value:"none"
}
]
}
]
export const HEART_Score : Calculator = {
id:"heart-score",
name:"HEART Score",
desc:"HEART (History, ECG, Age, Risk factors, Troponin) Score is a risk scoring which predicts 6-week risk of major cardiac events in patients with chest pain",
inputs:parameters,
calc_func:(values : Values):number => {
const history = values.history as "high" | "moderate" | "none";
const ecg = values.ecg as "stdepression" | "repolarization" | "normal";
const age = values.age as number;
const risk = values.risk as "high" | "moderate" | "none";
const trop = values.trop as "high" | "moderate" | "none";
var score = 0;
if(history === "high") score = score + 2;
else if(history === "moderate") score++;
if(ecg === "stdepression") score = score + 2;
else if(ecg === "repolarization") score++;
if(age >= 65) score = score + 2;
else if(age > 45 && age < 65) score++;
if(risk === "high") score = score + 2;
else if(risk === "moderate") score++;
if(trop === "high") score = score + 2;
else if(trop === "moderate") score++;
return score;
},
interpret_func:(score:number):Interpretation => {
if(score >= 0 && score < 4){
return {
level:"low",
message:"There is a chance of 2.5% of Major Adverse Cardiac Event",
advice:"Discharge home"
}
}else if(score >= 4 && score < 7){
return {
level:"moderate",
message:"There is a chance of 20.3% of Major Adverse Cardiac Event",
advice:"Admit for Clinical Observation"
}
}else{
return {
level:"severe",
message:"There is a chance of 72.7% of Major Adverse Cardiac Event",
advice:"Consider early invasive strategies"
}
}
}
}

View File

@@ -0,0 +1,92 @@
import { Calculator, Input, Interpretation, Values } from "../types";
import { MELD } from "./MELD";
const parameters : Input[] = [
{
id:"sbilirubin",
type:"number",
name:"Serum (Total) Bilirubin",
defaultUnit:"mg/dL",
placeholder:"Enter serum bilirubin levels in mg/dL",
required:true,
min:0,
},
{
id:"screatinine",
type:"number",
name:"Serum Creatinine",
defaultUnit:"mg/dL",
placeholder:"Enter Serum Creatinine levels in mg/dL",
required:true,
min:0.2
},
{
id:'inr',
name:"International Normalized Ratio",
type:'number',
placeholder:"Enter INR values",
required:true,
min:0
},
{
id:"na",
name:"Sodium levels",
type:"number",
placeholder:"Enter the sodium value",
required:true,
min:127,
max:137,
defaultUnit:"mmol/L"
}
];
export const MELDNa:Calculator = {
id:"meldna-score",
name:"Model For End-stage Liver Disease sodium (MELD-Na) score",
desc:"MELD-Na (Model for End-stage Liver Disease sodium) score is a numerical scale ranging from 6 to 40 that estimates the 3-month mortality risk for patients with CLD (Chronic Liver Disease) which also takes in account of sodium levels",
inputs:parameters,
calc_func:(values : Values):number => {
const meldscore:number = MELD.calc_func(values);
const na = values.na as number;
const score:number = meldscore
+ 1.32
* (137 - na)
+ (0.033 * meldscore * (137 - na));
return Math.floor(score);
},
interpret_func:(score : number):Interpretation => {
if(score <= 9){
return {
level:"none",
message:"The mortality prediction percent for the patient is 1.9%",
advice:"Patient is a great candidate for TIPS procedure"
}
}else if(score >= 10 && score < 20){
if(score < 14){
return{
level:"low",
message:"The mortality risk percent for the patient is less than 6.0%",
advice:"Patient is a great candidate for TIPS procedure"
};
}
return{
level:"low",
message:"The mortality risk percent for the patient is from 6.0% to 19.6%",
};
}else if (score >=20 && score < 30){
return {
level:"moderate",
message:"The mortality risk percent for the patient is from 19.6% to 52.6%"
};
}else if(score >= 30 && score < 40){
return {
level:"high",
message:"The mortality risk percent for the patient is from 52.6% to 71.3%"
}
}else{
return {
level:"severe",
message:"The mortality risk percent for the patient is more than 71.3%"
}
}
}
}

View File

@@ -5,6 +5,12 @@ import { MELD } from "./Utilities/MELD";
import { MAP } from "./General Cardiology/MAP";
import { TIMI } from "./Emergency/TIMI_score";
import { cha2ds2 } from "./Arrhythmias and Anti-Coagulation/CHA2DS2-VASc-score";
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<string, Section> = {
generalCardiology:{
@@ -13,7 +19,17 @@ export const CalculatorRegistry : Record<string, Section> = {
textColor:"#ccc",
svg:"",
calculators:[
MAP
MAP,
GRACE_Discharge
]
},
drugDoseCalculator:{
id:"drugDosing",
displayName:"Drug Dose Calculator",
textColor:"#ccc",
svg:"",
calculators:[
Adult_Drug_Calculator
]
},
arrhythmias:{
@@ -22,7 +38,8 @@ export const CalculatorRegistry : Record<string, Section> = {
textColor:"#ccc",
svg:"",
calculators:[
cha2ds2
cha2ds2,
HASBLED
]
},
emergency:{
@@ -31,7 +48,9 @@ export const CalculatorRegistry : Record<string, Section> = {
textColor:"#ccc",
svg:"",
calculators:[
TIMI
TIMI,
GRACE_Inhosp,
HEART_Score
]
},
transplantation:{
@@ -50,7 +69,8 @@ export const CalculatorRegistry : Record<string, Section> = {
svg:"",
calculators:[
cockcroftGault,
MELD
MELD,
MELDNa
]
}
}

View File

@@ -8,7 +8,7 @@ export interface Calculator {
interpret_func:Function,
customComponent?:React.FC
}
interface inputOptions {
export interface inputOptions {
label:string,
value:string | number ;
}
@@ -16,7 +16,7 @@ export interface Input{
id:string,
name:string,
placeholder?:string,
type: "number" | "text" | "select" | "checkbox",
type: "number" | "text" | "select" | "checkbox" | "search",
inputOptions?:inputOptions[],
min?:number,
max?:number,
@@ -52,3 +52,29 @@ export interface pastUsed {
unit: string | undefined
}
export type Values = Record<string, string | number | boolean >;
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[];