mirror of
https://github.com/temetro/temetro.git
synced 2026-08-31 21:08:38 +00:00
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>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
"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;
|
||||
Reference in New Issue
Block a user