feat(MED-168): clean up types, show nested elements
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
@@ -64,8 +65,7 @@ export default async function AnalysisResultsPage({
|
||||
<Trans i18nKey="analysis-results:pageTitle" />
|
||||
</h4>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{analysisResponse?.elements &&
|
||||
analysisResponse.elements?.length > 0 ? (
|
||||
{orderedAnalysisElements.length > 0 ? (
|
||||
<Trans i18nKey="analysis-results:description" />
|
||||
) : (
|
||||
<Trans i18nKey="analysis-results:descriptionEmpty" />
|
||||
@@ -106,7 +106,16 @@ export default async function AnalysisResultsPage({
|
||||
<div className="flex flex-col gap-2">
|
||||
{orderedAnalysisElements ? (
|
||||
orderedAnalysisElements.map((element, index) => (
|
||||
<Analysis key={index} element={element} />
|
||||
<React.Fragment key={element.analysisIdOriginal}>
|
||||
<Analysis element={element} />
|
||||
{element.results?.nestedElements?.map((nestedElement, nestedIndex) => (
|
||||
<Analysis
|
||||
key={`nested-${nestedElement.analysisElementOriginalId}-${nestedIndex}`}
|
||||
nestedElement={nestedElement}
|
||||
isNestedElement
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
))
|
||||
) : (
|
||||
<div className="text-muted-foreground text-sm">
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
|
||||
import { ArrowDown } from 'lucide-react';
|
||||
|
||||
import { cn } from '@kit/ui/utils';
|
||||
import { AnalysisResultDetailsElementResults } from '@/packages/features/accounts/src/types/analysis-results';
|
||||
import type { AnalysisResultDetailsElementResults } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
|
||||
export enum AnalysisResultLevel {
|
||||
NORMAL = 0,
|
||||
@@ -11,6 +11,8 @@ export enum AnalysisResultLevel {
|
||||
CRITICAL = 2,
|
||||
}
|
||||
|
||||
type AnalysisResultLevelBarResults = Pick<AnalysisResultDetailsElementResults, 'normLower' | 'normUpper' | 'responseValue'>;
|
||||
|
||||
const Level = ({
|
||||
isActive = false,
|
||||
color,
|
||||
@@ -60,28 +62,19 @@ const Level = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const AnalysisLevelBarSkeleton = () => {
|
||||
return (
|
||||
<div className="mt-4 flex h-3 w-[60%] sm:w-[35%] max-w-[360px] gap-1 sm:mt-0">
|
||||
<Level color="gray-200" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AnalysisLevelBar = ({
|
||||
level,
|
||||
results,
|
||||
results: {
|
||||
normLower: lower,
|
||||
normUpper: upper,
|
||||
responseValue: value,
|
||||
},
|
||||
normRangeText,
|
||||
}: {
|
||||
level: AnalysisResultLevel;
|
||||
results: AnalysisResultDetailsElementResults;
|
||||
results: AnalysisResultLevelBarResults;
|
||||
normRangeText: string | null;
|
||||
}) => {
|
||||
|
||||
const { normLower: lower, normUpper: upper, responseValue: value, normStatus } = results;
|
||||
const normLowerIncluded = results?.normLowerIncluded || false;
|
||||
const normUpperIncluded = results?.normUpperIncluded || false;
|
||||
|
||||
// Calculate arrow position based on value within normal range
|
||||
const arrowLocation = useMemo(() => {
|
||||
// If no response value, center the arrow
|
||||
@@ -147,7 +140,6 @@ const AnalysisLevelBar = ({
|
||||
|
||||
// Show appropriate levels based on available norm bounds
|
||||
const hasLowerBound = lower !== null;
|
||||
const isLowerBoundZero = hasLowerBound && lower === 0;
|
||||
const hasUpperBound = upper !== null;
|
||||
|
||||
// Determine which section the value falls into
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { AnalysisResultDetailsElement } from '@/packages/features/accounts/src/types/analysis-results';
|
||||
import type {
|
||||
AnalysisResultDetailsElementResults,
|
||||
AnalysisResultDetailsElement,
|
||||
AnalysisResultsDetailsElementNested,
|
||||
} from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { format } from 'date-fns';
|
||||
import { Info } from 'lucide-react';
|
||||
|
||||
@@ -21,14 +25,45 @@ export enum AnalysisStatus {
|
||||
}
|
||||
|
||||
const Analysis = ({
|
||||
element,
|
||||
element: elementOriginal,
|
||||
nestedElement,
|
||||
isNestedElement = false,
|
||||
}: {
|
||||
element: AnalysisResultDetailsElement;
|
||||
element?: AnalysisResultDetailsElement;
|
||||
nestedElement?: AnalysisResultsDetailsElementNested;
|
||||
isNestedElement?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const element = (() => {
|
||||
if (isNestedElement) {
|
||||
return nestedElement!;
|
||||
}
|
||||
return elementOriginal!;
|
||||
})();
|
||||
const results: AnalysisResultDetailsElementResults = useMemo(() => {
|
||||
if (isNestedElement) {
|
||||
const nestedElement = element as AnalysisResultsDetailsElementNested;
|
||||
return {
|
||||
analysisElementOriginalId: nestedElement.analysisElementOriginalId,
|
||||
normLower: nestedElement.normLower,
|
||||
normUpper: nestedElement.normUpper,
|
||||
normStatus: nestedElement.normStatus,
|
||||
responseTime: nestedElement.responseTime,
|
||||
responseValue: nestedElement.responseValue,
|
||||
responseValueIsNegative: nestedElement.responseValueIsNegative,
|
||||
responseValueIsWithinNorm: nestedElement.responseValueIsWithinNorm,
|
||||
normLowerIncluded: nestedElement.normLowerIncluded,
|
||||
normUpperIncluded: nestedElement.normUpperIncluded,
|
||||
unit: nestedElement.unit,
|
||||
status: nestedElement.status,
|
||||
nestedElements: [],
|
||||
};
|
||||
}
|
||||
return (element as AnalysisResultDetailsElement).results;
|
||||
}, [element, isNestedElement]);
|
||||
|
||||
const name = element.analysisName || '';
|
||||
const results = element.results;
|
||||
|
||||
const hasIsWithinNorm = results?.responseValueIsWithinNorm !== null;
|
||||
const hasIsNegative = results?.responseValueIsNegative !== null;
|
||||
@@ -58,8 +93,8 @@ const Analysis = ({
|
||||
return responseValue;
|
||||
})();
|
||||
const unit = results?.unit || '';
|
||||
const normLower = results?.normLower;
|
||||
const normUpper = results?.normUpper;
|
||||
const normLower = results?.normLower ?? null;
|
||||
const normUpper = results?.normUpper ?? null;
|
||||
const normStatus = results?.normStatus ?? null;
|
||||
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
@@ -82,13 +117,18 @@ const Analysis = ({
|
||||
const isCancelled = Number(results?.status) === 5;
|
||||
const hasNestedElements = results?.nestedElements.length > 0;
|
||||
|
||||
const normRangeText = normLower !== null ? `${normLower} - ${normUpper || ''}` : null;
|
||||
const normRangeText = (() => {
|
||||
if (normLower === null && normUpper === null) {
|
||||
return null;
|
||||
}
|
||||
return `${normLower ?? '...'} - ${normUpper ?? '...'}`;
|
||||
})();
|
||||
const hasTextualResponse = hasIsNegative || hasIsWithinNorm;
|
||||
|
||||
return (
|
||||
<div className="border-border rounded-lg border px-5">
|
||||
<div className={cn("border-border rounded-lg border px-5", { 'ml-8': isNestedElement })}>
|
||||
<div className="flex flex-col items-center justify-between gap-2 pt-3 pb-6 sm:py-3 sm:h-[65px] sm:flex-row sm:gap-0">
|
||||
<div className="flex items-center gap-2 font-semibold">
|
||||
<div className={cn("flex items-center gap-2 font-semibold", { 'font-bold': isNestedElement })}>
|
||||
{name}
|
||||
{results?.responseTime && (
|
||||
<div
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AnalysisResultDetailsMapped } from "@/packages/features/accounts/src/types/analysis-results";
|
||||
import type { AnalysisResultDetailsMapped } from "@/packages/features/user-analyses/src/types/analysis-results";
|
||||
|
||||
type AnalysisTestResponse = Omit<AnalysisResultDetailsMapped, 'order' | 'orderedAnalysisElementIds' | 'summary' | 'elements'>;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { cache } from 'react';
|
||||
|
||||
import { AnalysisResultDetailsMapped } from '@kit/accounts/types/analysis-results';
|
||||
import type { AnalysisResultDetailsMapped } from '@/packages/features/user-analyses/src/types/analysis-results';
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user