import { useMemo } from 'react';
import { ArrowDown } from 'lucide-react';
import { cn } from '@kit/ui/utils';
import { AnalysisResultForDisplay } from './analysis-doctor';
export enum AnalysisResultLevel {
NORMAL = 'NORMAL',
WARNING = 'WARNING',
CRITICAL = 'CRITICAL',
}
const Level = ({
isActive = false,
color,
isFirst = false,
isLast = false,
arrowLocation,
normRangeText,
}: {
isActive?: boolean;
color: 'destructive' | 'success' | 'warning' | 'gray-200';
isFirst?: boolean;
isLast?: boolean;
arrowLocation?: number;
normRangeText?: string | null;
}) => {
return (
{isActive && (
92.5 && { left: '92.5%' }),
...(arrowLocation < 7.5 && { left: '7.5%' }),
},
}
: {})}
>
)}
{color === 'success' && typeof normRangeText === 'string' && (
{normRangeText}
)}
);
};
export const AnalysisLevelBarSkeleton = () => {
return (
);
};
const AnalysisLevelBar = ({
level,
results,
normRangeText,
}: {
level: AnalysisResultLevel | null;
results: AnalysisResultForDisplay;
normRangeText: string | null;
}) => {
const {
norm_lower: lower,
norm_upper: upper,
response_value: value,
} = results;
// Calculate arrow position based on value within normal range
const arrowLocation = useMemo(() => {
// If no response value, center the arrow
if (value === null || value === undefined) {
return 50;
}
// If no normal ranges defined, center the arrow
if (lower === null && upper === null) {
return 50;
}
// If only upper bound exists
if (lower === null && upper !== null) {
if (value <= upper!) {
return Math.min(75, (value / upper!) * 75); // Show in left 75% of normal range
}
return 100; // Beyond upper bound
}
// If only lower bound exists
if (upper === null && lower !== null) {
if (value >= lower!) {
// Value is in normal range (above lower bound)
// Position proportionally in the normal range section
const normalizedPosition = Math.min(
(value - lower!) / (lower! * 0.5),
1,
); // Use 50% of lower as scale
return normalizedPosition * 100;
}
// Value is below lower bound - position in the "below normal" section
const belowPosition = Math.max(0, Math.min(1, value / lower!));
return belowPosition * 100;
}
// Both bounds exist
if (lower !== null && upper !== null) {
if (value < lower!) {
return 0; // Below normal range
}
if (value > upper!) {
return 100; // Above normal range
}
// Within normal range
return ((value - lower!) / (upper! - lower!)) * 100;
}
return 50; // Fallback
}, [value, upper, lower]);
// Determine level states based on normStatus
const isNormal = level === AnalysisResultLevel.NORMAL;
const isWarning = level === AnalysisResultLevel.WARNING;
const isCritical = level === AnalysisResultLevel.CRITICAL;
const isPending = level === null;
// Show appropriate levels based on available norm bounds
const hasLowerBound = lower !== null;
// Calculate level configuration (must be called before any returns)
const [first, second, third] = useMemo(() => {
const [warning, normal, critical] = [
{
isActive: isWarning,
color: 'warning',
...(isWarning ? { arrowLocation } : {}),
},
{
isActive: isNormal,
color: 'success',
normRangeText,
...(isNormal ? { arrowLocation } : {}),
},
{
isActive: isCritical,
color: 'destructive',
isLast: true,
...(isCritical ? { arrowLocation } : {}),
},
] as const;
if (!hasLowerBound) {
return [{ ...normal, isFirst: true }, warning, critical] as const;
}
return [
{ ...warning, isFirst: true },
normal,
{ ...critical, isLast: true },
] as const;
}, [
arrowLocation,
normRangeText,
isNormal,
isWarning,
isCritical,
hasLowerBound,
]);
// If pending results, show gray bar
if (isPending) {
return (
);
}
return (
);
};
export default AnalysisLevelBar;