MED-105: create analysis results page

This commit is contained in:
Danel Kungla
2025-07-15 17:12:52 +03:00
parent 0af3823148
commit 87dfcf55e6
19 changed files with 6213 additions and 25 deletions

View File

@@ -0,0 +1,89 @@
import React from 'react';
import { ArrowDown } from 'lucide-react';
import { cn } from '@kit/ui/utils';
export enum AnalysisResultLevel {
VERY_LOW = 0,
LOW = 1,
NORMAL = 2,
HIGH = 3,
VERY_HIGH = 4,
}
const Level = ({
isActive = false,
color,
isFirst = false,
isLast = false,
}: {
isActive?: boolean;
color: 'destructive' | 'success' | 'warning';
isFirst?: boolean;
isLast?: boolean;
}) => {
return (
<div
className={cn(`bg-${color} relative h-3 flex-1`, {
'opacity-20': !isActive,
'rounded-l-lg': isFirst,
'rounded-r-lg': isLast,
})}
>
{isActive && (
<div className="absolute top-[-14px] left-1/2 -translate-x-1/2 rounded-[10px] bg-white p-[2px]">
<ArrowDown strokeWidth={2} />
</div>
)}
</div>
);
};
const AnalysisLevelBar = ({
normLowerIncluded = true,
normUpperIncluded = true,
level,
}: {
normLowerIncluded?: boolean;
normUpperIncluded?: boolean;
level: AnalysisResultLevel;
}) => {
return (
<div className="flex h-3 w-full max-w-[360px] gap-1">
{normLowerIncluded && (
<>
<Level
isActive={level === AnalysisResultLevel.VERY_LOW}
color="destructive"
isFirst
/>
<Level isActive={level === AnalysisResultLevel.LOW} color="warning" />
</>
)}
<Level
isFirst={!normLowerIncluded}
isLast={!normUpperIncluded}
isActive={level === AnalysisResultLevel.NORMAL}
color="success"
/>
{normUpperIncluded && (
<>
<Level
isActive={level === AnalysisResultLevel.HIGH}
color="warning"
/>
<Level
isActive={level === AnalysisResultLevel.VERY_HIGH}
color="destructive"
isLast
/>
</>
)}
</div>
);
};
export default AnalysisLevelBar;

View File

@@ -0,0 +1,84 @@
import React from 'react';
import { Info } from 'lucide-react';
import AnalysisLevelBar, { AnalysisResultLevel } from './analysis-level-bar';
export enum AnalysisStatus {
NORMAL = 0,
MEDIUM = 1,
HIGH = 2,
}
const Analysis = ({
analysis: {
name,
status,
unit,
value,
normLowerIncluded,
normUpperIncluded,
normLower,
normUpper,
},
}: {
analysis: {
name: string;
status: AnalysisStatus;
unit: string;
value: number;
normLowerIncluded: boolean;
normUpperIncluded: boolean;
normLower: number;
normUpper: number;
};
}) => {
const isUnderNorm = value < normLower;
const getAnalysisResultLevel = () => {
if (isUnderNorm) {
switch (status) {
case AnalysisStatus.MEDIUM:
return AnalysisResultLevel.LOW;
default:
return AnalysisResultLevel.VERY_LOW;
}
}
switch (status) {
case AnalysisStatus.MEDIUM:
return AnalysisResultLevel.HIGH;
case AnalysisStatus.HIGH:
return AnalysisResultLevel.VERY_HIGH;
default:
return AnalysisResultLevel.NORMAL;
}
};
return (
<div className="border-border flex items-center justify-between rounded-lg border px-5 py-3">
<div className="flex items-center gap-2 font-semibold">
{name}
<div className="group/tooltip relative">
<Info className="hover" />{' '}
<div className="absolute bottom-full left-1/2 z-10 mb-2 hidden -translate-x-1/2 rounded bg-gray-800 px-2 py-1 text-sm whitespace-nowrap text-white group-hover/tooltip:block">
This text changes when you hover the box above.
</div>
</div>
</div>
<div className="flex items-center gap-3">
<div className="font-semibold">{value}</div>
<div className="text-muted-foreground text-sm">{unit}</div>
</div>
<div className="text-muted-foreground text-center text-sm">
{normLower} - {normUpper}
<div>Normaalne vahemik</div>
</div>
<AnalysisLevelBar
normLowerIncluded={normLowerIncluded}
normUpperIncluded={normUpperIncluded}
level={getAnalysisResultLevel()}
/>
</div>
);
};
export default Analysis;