Complete and working implementation of renderCalc.tsx | v1.0

This commit is contained in:
2026-03-30 23:29:24 +05:30
parent bb746ee8f6
commit 5a63ee26e6
8 changed files with 161 additions and 68 deletions

View File

@@ -1,29 +1,9 @@
import InputComponent from "@/app/utils/Input"; import RenderCalculator from "./renderCalc";
import Input from "@/app/utils/Input";
import { CalculatorRegistry } from "@/app/utils/calculators/registry";
export default async function Calculator({params} : {params:Promise<{section:string, id:string}>}){ export default async function Calculator({params} : {params:Promise<{section:string, id:string}>}){
const calcData : {section:string, id:string} = await params; const calcData : {section:string, id:string} = await params;
const calculator = CalculatorRegistry[calcData.section].calculators.find(e => e.id === calcData.id);
console.log(calculator);
return calculator ? (
<>
<div className="mb-6 mt-10">
<h1 className="text-2xl font-semibold">
{calculator?.name}
</h1>
<p className="text-gray-500 mt-1 max-w-xl">
{calculator?.desc}
</p>
<h1 className="text-1xl font-semibold">
Unit of the value:- {calculator?.unit}
</h1>
</div>
{calculator.inputs.map(e => {
return( return(
<InputComponent {...e}/> <RenderCalculator key={calcData.id} section={calcData.section} id={calcData.id}/>
); );
})}
</>
) : null;
} }

View File

@@ -0,0 +1,74 @@
"use client"
import InputComponent from "@/app/utils/Input";
import Input from "@/app/utils/Input";
import Result from "@/app/utils/Result";
import { CalculatorRegistry } from "@/app/utils/calculators/registry";
import { Interpretation } from "@/app/utils/calculators/types";
import { useState } from "react";
export default function RenderCalculator({section, id} : {section:string, id:string}){
const calculator = CalculatorRegistry[section].calculators.find(e => e.id === id);
const [form, setForm] = useState<Record<string, string | number>>({});
const [value, setValue] = useState<string | number>("");
function handleDataChange(key:string, value:string){
setForm(prev => {
return {
...prev,
[key]:value
}
});
}
const [showResult, setResultStatus] = useState<boolean>(false);
const [result, setResult] = useState<Interpretation>({
level:"none",
message:"none"
});
console.log(form);
return calculator ? (
<>
<div className="mb-6 mt-10">
<h1 className="text-2xl font-semibold">
{calculator?.name}
</h1>
<p className="text-gray-500 mt-1 max-w-xl">
{calculator?.desc}
</p>
<h1 className="text-1xl font-semibold">
Unit of the value:- {calculator?.unit}
</h1>
</div>
<div className="max-w-2xl">
<form onSubmit={(e: React.SubmitEvent) => {
e.preventDefault();
setResultStatus(true);
const calculatedValue = calculator.calc_func(form);
setValue(calculatedValue);
setResult(calculator.interpret_func(calculatedValue));
}}>
<div className="card max-w-auto bg-white bg-base-100 shadow-sm">
<div className="card-body">
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-4">
{calculator.inputs.map(e => {
return(
<InputComponent key={e.id} {...e} handleDataChange={handleDataChange}/>
);
})}
<button type={"submit"} className="btn md:col-span-2 w-full text-white border-none bg-[#ed1b24] hover:bg-[#c9161e]"
>Calculate</button>
</div>
</div>
</div>
{showResult ? <h3>
<Result
interpretation={result}
calculated_value={value}
unit={calculator.unit ?? ""}
/>
</h3> : null}
</form>
</div>
</>
) : null;
}

View File

@@ -7,12 +7,14 @@ const font = Roboto({});
export default function LayoutClient({children} : {children:React.ReactNode}){ export default function LayoutClient({children} : {children:React.ReactNode}){
const [navbar, setNavbar] = useState<boolean>(false); const [navbar, setNavbar] = useState<boolean>(false);
return( return(
<div className={`grid grid-cols-[300px_1fr] grid-rows-[60px_1fr_40px] overflow-hidden calculators-container ${font.className}`}> <div className={`grid grid-cols-[300px_1fr] grid-rows-[60px_1fr_40px] calculators-container ${font.className}`}>
<Navbar navbarToggle={setNavbar}/> <Navbar navbarToggle={setNavbar}/>
<Sidemenu isNavOpen={navbar}/> <Sidemenu isNavOpen={navbar}/>
<div className="content"> <div className="content w-full flex justify-center px-4 pb-6">
<div className="w-full max-w-2xl">
{children} {children}
</div> </div>
</div>
<div className="footer"></div> <div className="footer"></div>
</div> </div>
); );

View File

@@ -2,23 +2,22 @@
import { useState } from "react"; import { useState } from "react";
import { Input } from "./calculators/types"; import { Input } from "./calculators/types";
export default function InputComponent({id, type, inputOptions, min, max, required, defaultUnit, unitOptions, name, placeholder} : Input){ export default function InputComponent({id, type, inputOptions, min, max, required, defaultUnit, unitOptions, name, placeholder, handleDataChange} : Input){
const [showError, setErrorStatus] = useState(false); const [showError, setErrorStatus] = useState(false);
const [error, setError] = useState<string>(); const [error, setError] = useState<string>();
const [option, setOption] = useState<string>(""); const [option, setOption] = useState<string>("");
console.log(id);
if(type === "number"){ if(type === "number"){
console.log(min);
return( return(
<> <>
<fieldset className="fieldset"> <fieldset className="fieldset">
<legend className="fieldset-legend text-black">{name}</legend> <legend className="fieldset-legend text-black">{name}</legend>
<input type="number" <input type="number"
id={id} id={id}
className="input bg-white" className="input bg-white border-solid border-black"
placeholder={placeholder} placeholder={placeholder}
min={min} min={min}
max={max} max={max}
step={0.1}
required={required} required={required}
onChange={(e) => { onChange={(e) => {
if(e.target.value === ""){ if(e.target.value === ""){
@@ -34,6 +33,7 @@ export default function InputComponent({id, type, inputOptions, min, max, requir
}else{ }else{
setError(""); setError("");
setErrorStatus(false); setErrorStatus(false);
handleDataChange !== undefined ? handleDataChange(id, e.target.value) : null;
} }
}} }}
/> />
@@ -46,11 +46,14 @@ export default function InputComponent({id, type, inputOptions, min, max, requir
<fieldset className="fieldset"> <fieldset className="fieldset">
<legend className="fieldset-legend text-black">{name}</legend> <legend className="fieldset-legend text-black">{name}</legend>
<select value={option} <select value={option}
className="select bg-white" className="select bg-white border-solid border-black"
onChange={(e) => { onChange={(e) => {
setOption(e.target.value); setOption(e.target.value);
}}> handleDataChange !== undefined ? handleDataChange(id, e.target.value) : null;
<option value="" disabled selected hidden>{placeholder}</option> }}
required={required}
>
<option value="" disabled hidden>{placeholder}</option>
{inputOptions?.map(e => { {inputOptions?.map(e => {
return( return(
<option key={e.label} value={e.value}>{e.value}</option> <option key={e.label} value={e.value}>{e.value}</option>

29
src/app/utils/Result.tsx Normal file
View File

@@ -0,0 +1,29 @@
import { Interpretation } from "./calculators/types";
export default function Result({interpretation, calculated_value, unit} : {interpretation:Interpretation, calculated_value:string | number, unit:string
}){
var {level, message, diagnosis, advice} = interpretation;
var levelClass = "";
if(level === "none" || level === "low"){
levelClass = "bg-success";
}else if(level === "moderate"){
levelClass = "bg-orange-600";
}else if(level === "high" || level === "severe"){
levelClass = "bg-red-500";
}else{
levelClass = "bg-white";
}
console.log(levelClass);
return(
<div className={`card max-w-auto ${levelClass} bg-base-100 shadow-sm mt-5 ${levelClass}`}>
<div className="card-body">
<h2 className="card-title self-center">Calculated Score/Value: {calculated_value} {unit}</h2>
<p>{message}</p>
{diagnosis ? <p>Diagnosis: {diagnosis}</p> : null}
{advice ? <p>Advice: {advice}</p> : null}
<div className="card-actions justify-end">
</div>
</div>
</div>
);
}

View File

@@ -8,7 +8,11 @@ export default function Section({sectionName, Calculators, id} : {sectionName:st
<ul> <ul>
{Calculators.map((e) => { {Calculators.map((e) => {
return( return(
<li><a key={e.id} href={`/calculate/${id}/${e.id}`}>{e.name}</a></li> <li key={e.id}>
<a href={`/calculate/${id}/${e.id}`}>
{e.name}
</a>
</li>
) )
})} })}
</ul> </ul>

View File

@@ -4,7 +4,7 @@ const parameters:Input[] = [
{ {
id:"gender", id:"gender",
name:"Gender", name:"Gender",
placeholder:"Enter your gender", placeholder:"Select gender",
type:"select", type:"select",
inputOptions:[ inputOptions:[
{ {
@@ -22,7 +22,7 @@ const parameters:Input[] = [
id:"age", id:"age",
type:"number", type:"number",
name:"Age", name:"Age",
placeholder:"Enter your age", placeholder:"Enter age",
min:18, min:18,
max:95, max:95,
required:true required:true
@@ -31,7 +31,7 @@ const parameters:Input[] = [
id:"creatinine", id:"creatinine",
type:"number", type:"number",
name:"Creatinine", name:"Creatinine",
placeholder:"Enter your serum creatinine values", placeholder:"Enter serum creatinine values in mg/dL",
min:0.2, min:0.2,
max:20, max:20,
required:true required:true
@@ -40,7 +40,7 @@ const parameters:Input[] = [
id:"weight", id:"weight",
type:"number", type:"number",
name:"Weight", name:"Weight",
placeholder:"Enter your weight in kilograms", placeholder:"Enter weight in kilograms",
min:10, min:10,
max:100 , max:100 ,
required:true required:true
@@ -52,8 +52,8 @@ function calc_func(values : Values):number{
const weight = values.weight as number; const weight = values.weight as number;
const creatinine = values.creatinine as number; const creatinine = values.creatinine as number;
return gender === "male" return gender === "male"
? ((140 - age) * weight)/(72 * creatinine) ? Math.floor(((140 - age) * weight)/(72 * creatinine))
: (((140 - age) * weight)/(72 * creatinine)) * 0.85; : Math.floor((((140 - age) * weight)/(72 * creatinine)) * 0.85);
} }
function interpret_func(gfr:number):Interpretation{ function interpret_func(gfr:number):Interpretation{
if(gfr >= 90){ if(gfr >= 90){

View File

@@ -22,11 +22,12 @@ export interface Input{
max?:number, max?:number,
required?:boolean, required?:boolean,
defaultUnit?:string, defaultUnit?:string,
unitOptions?:string[] unitOptions?:string[],
handleDataChange?:Function
} }
export interface Interpretation{ export interface Interpretation{
level?: "none" | "low" | "moderate" | "high" | "severe", level: "none" | "low" | "moderate" | "high" | "severe",
diagnosis?:string, diagnosis?:string,
message:string, message:string,
advice?:string advice?:string