Files
temetro/frontend/components/charts/area-chart-loading.tsx
T
Khalid Abdi 321a6298a4 frontend: pharmacy inventory, lab add-result & analysis charts
- Pharmacy: the sidebar entry now expands into Pharmacy + a new Inventory page
  (searchable medication stock with derived in-stock/low/out availability,
  backed by /api/inventory). Fix the dispensing-queue "Expiring" badge so it
  only flags courses ending within the next 7 days, not ones already elapsed.
- Lab "Add analysis result": the patient picker no longer lists patients until
  you type and supports arrow-key + Enter selection; the test field offers a
  catalog of common analyses with an Advanced option (custom analysis + ref
  range); submitted results now show immediately in a Recent results feed.
- Analysis: add a Live panel (real-time line chart) and replace the flat trend
  sparklines with bklit-ui area + bar charts (installed from the @bklit shadcn
  registry; chart CSS variables wired into the theme for light and dark).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:22:07 +03:00

111 lines
3.2 KiB
TypeScript

"use client";
import { curveNatural } from "@visx/curve";
import { useMemo } from "react";
import { Area } from "./area";
import { AreaChart } from "./area-chart";
import type { Margin } from "./chart-context";
import {
DEFAULT_SKELETON_DATA_KEY,
DEFAULT_SKELETON_POINT_COUNT,
generateChartSkeletonData,
} from "./generate-chart-skeleton-data";
import { Grid } from "./grid";
const LOADING_DATA_KEY = DEFAULT_SKELETON_DATA_KEY;
const DEFAULT_LOADING_STROKE = "var(--foreground)";
const DEFAULT_LOADING_GRID_STROKE =
"color-mix(in oklch, var(--chart-grid) 50%, transparent)";
const DEFAULT_LOADING_GRID_SHIMMER_STROKE =
"color-mix(in oklch, var(--foreground) 68%, transparent)";
const DEFAULT_LOADING_STROKE_OPACITY = 0.5;
export interface AreaChartLoadingProps {
/** Chart margins */
margin?: Partial<Margin>;
/** Stroke color for the animated loading segment. */
stroke?: string;
/** Stroke opacity for the animated loading segment. Default: 0.5 */
strokeOpacity?: number;
/** Grid line stroke (color and opacity via color-mix or oklch alpha). */
gridStroke?: string;
/** Shimmer band stroke (color and opacity via color-mix or oklch alpha). */
gridShimmerStroke?: string;
/** Animate a shimmer band across grid lines. Default: true */
gridShimmer?: boolean;
/** Shimmer band width in pixels. Default: 140 */
gridShimmerLength?: number;
/** Shimmer speed multiplier (higher = faster). Default: 1 */
gridShimmerSpeed?: number;
/** Match shimmer loop to the loading line pulse (cycle + inter-loop pause). */
gridShimmerSync?: boolean;
/** Centered shimmer label text. Default: "Loading" */
label?: string;
/** Aspect ratio as "width / height". Default: "2 / 1" */
aspectRatio?: string;
/** Additional class name for the container */
className?: string;
}
export function AreaChartLoading({
margin,
stroke = DEFAULT_LOADING_STROKE,
strokeOpacity = DEFAULT_LOADING_STROKE_OPACITY,
gridStroke = DEFAULT_LOADING_GRID_STROKE,
gridShimmerStroke = DEFAULT_LOADING_GRID_SHIMMER_STROKE,
gridShimmer = true,
gridShimmerLength,
gridShimmerSpeed,
gridShimmerSync = false,
label = "Loading",
aspectRatio = "2 / 1",
className = "",
}: AreaChartLoadingProps) {
const data = useMemo(
() =>
generateChartSkeletonData({
dataKey: DEFAULT_SKELETON_DATA_KEY,
pointCount: DEFAULT_SKELETON_POINT_COUNT,
}),
[]
);
return (
<AreaChart
animationDuration={0}
aspectRatio={aspectRatio}
className={className}
data={data}
loadingLabel={label}
margin={margin}
status="loading"
>
<Grid
horizontal
shimmer={gridShimmer}
shimmerLength={gridShimmerLength}
shimmerSpeed={gridShimmerSpeed}
shimmerStroke={gridShimmerStroke}
shimmerSync={gridShimmerSync}
stroke={gridStroke}
/>
<Area
curve={curveNatural}
dataKey={LOADING_DATA_KEY}
fadeEdges={false}
fill="transparent"
fillOpacity={0}
loading
loadingStroke={stroke}
loadingStrokeOpacity={strokeOpacity}
showHighlight={false}
showLine
stroke="transparent"
strokeWidth={2}
/>
</AreaChart>
);
}
export default AreaChartLoading;