mirror of
https://github.com/temetro/temetro.git
synced 2026-09-03 06:17:55 +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,61 @@
|
||||
"use client";
|
||||
|
||||
import { useSpring } from "motion/react";
|
||||
import { useMemo, useRef } from "react";
|
||||
import { useChartConfig } from "./chart-config-context";
|
||||
import { useChartHover, useChartStable } from "./chart-context";
|
||||
import {
|
||||
computeSegmentBounds,
|
||||
INACTIVE_SEGMENT,
|
||||
} from "./highlight-segment-bounds";
|
||||
|
||||
// Hover-highlight band for `line.tsx` and `area.tsx`. Computes the segment
|
||||
// bounds and springs its x/width; `<HighlightSegment>` renders the clipped
|
||||
// re-stroke. Spring tuning comes from `ChartConfigProvider.highlightSpring`.
|
||||
// Stable + hover slices are read separately so callers can see the exact
|
||||
// subscription surface (anything calling this hook will re-render on hover).
|
||||
|
||||
export interface HighlightSegmentResult {
|
||||
xSpring: ReturnType<typeof useSpring>;
|
||||
widthSpring: ReturnType<typeof useSpring>;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enabled set false when there is no stroke to highlight (e.g. an area
|
||||
* with `showLine={false}`); defaults true.
|
||||
*/
|
||||
export function useHighlightSegment({
|
||||
enabled = true,
|
||||
}: {
|
||||
enabled?: boolean;
|
||||
} = {}): HighlightSegmentResult {
|
||||
const { data, xScale, xAccessor } = useChartStable();
|
||||
const { tooltipData, selection } = useChartHover();
|
||||
const { highlightSpring } = useChartConfig();
|
||||
|
||||
const bounds = useMemo(
|
||||
() =>
|
||||
enabled
|
||||
? computeSegmentBounds(data, xScale, xAccessor, tooltipData, selection)
|
||||
: INACTIVE_SEGMENT,
|
||||
[enabled, data, xScale, xAccessor, tooltipData, selection]
|
||||
);
|
||||
|
||||
const xSpring = useSpring(0, highlightSpring);
|
||||
const widthSpring = useSpring(0, highlightSpring);
|
||||
|
||||
// Jump on inactive→active so the band appears at the hovered point instead
|
||||
// of sliding in from x=0; ease on subsequent moves.
|
||||
const wasActive = useRef(false);
|
||||
if (bounds.isActive && !wasActive.current) {
|
||||
xSpring.jump(bounds.x);
|
||||
widthSpring.jump(bounds.width);
|
||||
} else {
|
||||
xSpring.set(bounds.x);
|
||||
widthSpring.set(bounds.width);
|
||||
}
|
||||
wasActive.current = bounds.isActive;
|
||||
|
||||
return { xSpring, widthSpring, isActive: bounds.isActive };
|
||||
}
|
||||
Reference in New Issue
Block a user