Spaces:
Runtime error
Runtime error
| import type { GestationalAgeResponse } from '../lib/api'; | |
| interface GAResultsCardProps { | |
| results: GestationalAgeResponse | null; | |
| isLoading: boolean; | |
| } | |
| // Map view/biometry key to display label | |
| const BIOMETRY_LABELS: Record<string, string> = { | |
| head_circumference: 'Head Circumference', | |
| abdominal_circumference: 'Abdominal Circumference', | |
| femur_length: 'Femur Length', | |
| }; | |
| export function GAResultsCard({ results, isLoading }: GAResultsCardProps) { | |
| if (isLoading) { | |
| return ( | |
| <div className="space-y-3"> | |
| <div className="bg-white border border-dark-border rounded-xl p-4 shadow-card"> | |
| <div className="h-3 w-24 shimmer-premium rounded mb-2" /> | |
| <div className="h-8 w-40 shimmer-premium rounded" /> | |
| </div> | |
| <div className="bg-white border border-dark-border rounded-xl p-4 shadow-card"> | |
| <div className="h-3 w-40 shimmer-premium rounded mb-3" /> | |
| <div className="grid grid-cols-3 gap-2"> | |
| {[...Array(3)].map((_, i) => ( | |
| <div key={i} className="h-16 shimmer-premium rounded-lg" style={{ animationDelay: `${i * 100}ms` }} /> | |
| ))} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| if (!results) { | |
| return ( | |
| <div className="bg-white border border-dark-border rounded-xl p-8 text-center shadow-card"> | |
| <p className="text-text-muted text-sm"> | |
| Upload a fetal ultrasound and click "Estimate Age" | |
| </p> | |
| </div> | |
| ); | |
| } | |
| const { gestational_age } = results; | |
| // Get biometry data dynamically based on what the backend returned | |
| const biometryData = results.head_circumference | |
| || results.abdominal_circumference | |
| || results.femur_length; | |
| // Determine which biometry type we have | |
| let biometryLabel = 'Biometry'; | |
| if (results.head_circumference) biometryLabel = BIOMETRY_LABELS.head_circumference; | |
| else if (results.abdominal_circumference) biometryLabel = BIOMETRY_LABELS.abdominal_circumference; | |
| else if (results.femur_length) biometryLabel = BIOMETRY_LABELS.femur_length; | |
| return ( | |
| <div className="space-y-3 animate-scale-in"> | |
| {/* Gestational Age */} | |
| <div className="bg-gradient-to-r from-nvidia-green/10 to-nvidia-green/5 border border-nvidia-green/20 rounded-xl p-4 shadow-card"> | |
| <p className="text-[10px] uppercase tracking-wider text-text-muted mb-1"> | |
| Gestational Age | |
| </p> | |
| <div className="text-2xl font-bold text-nvidia-green"> | |
| {gestational_age.weeks} weeks, {gestational_age.days} days | |
| </div> | |
| <p className="text-text-muted text-xs mt-1"> | |
| Total: {gestational_age.total_days} days | |
| </p> | |
| </div> | |
| {/* Biometry Percentiles - Dynamic based on view */} | |
| {biometryData && ( | |
| <div className="bg-white border border-dark-border rounded-xl p-4 shadow-card card-interactive"> | |
| <p className="text-[10px] uppercase tracking-wider text-text-muted mb-3"> | |
| {biometryLabel} Percentiles | |
| </p> | |
| <div className="grid grid-cols-3 gap-3"> | |
| <div className="bg-dark-input rounded-xl p-3 text-center"> | |
| <p className="text-[10px] text-text-muted mb-1">2.5th</p> | |
| <p className="text-base font-semibold text-text-primary"> | |
| {biometryData.p2_5} mm | |
| </p> | |
| </div> | |
| <div className="bg-nvidia-green/10 rounded-xl p-3 text-center border-2 border-nvidia-green"> | |
| <p className="text-[10px] text-nvidia-green mb-1 font-medium">50th</p> | |
| <p className="text-base font-bold text-nvidia-green"> | |
| {biometryData.p50} mm | |
| </p> | |
| </div> | |
| <div className="bg-dark-input rounded-xl p-3 text-center"> | |
| <p className="text-[10px] text-text-muted mb-1">97.5th</p> | |
| <p className="text-base font-semibold text-text-primary"> | |
| {biometryData.p97_5} mm | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |