Files
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

59 lines
1.7 KiB
TypeScript

import type { Transition } from "motion/react";
import { DEFAULT_CHART_ENTER_TRANSITION } from "./animation";
export function transitionWithDelay(
transition: Transition | undefined,
delaySeconds: number,
fallback: Transition = DEFAULT_CHART_ENTER_TRANSITION
): Transition {
const base = transition ?? fallback;
return { ...base, delay: delaySeconds };
}
export interface SpringOptions {
stiffness: number;
damping: number;
mass?: number;
}
export function springOptionsFromTransition(
transition?: Transition,
fallback: SpringOptions = { stiffness: 60, damping: 20 }
): SpringOptions {
if (!transition) {
return fallback;
}
if (transition.type === "spring") {
const bounce =
typeof transition.bounce === "number" ? transition.bounce : undefined;
const baseStiffness =
typeof transition.stiffness === "number"
? transition.stiffness
: fallback.stiffness;
const baseDamping =
typeof transition.damping === "number"
? transition.damping
: fallback.damping;
return {
stiffness:
bounce == null
? baseStiffness
: Math.min(400, Math.max(80, baseStiffness * (1 + bounce * 0.35))),
damping:
bounce == null
? baseDamping
: Math.max(8, baseDamping * (1 - bounce * 0.25)),
mass:
typeof transition.mass === "number" ? transition.mass : fallback.mass,
};
}
const duration =
"duration" in transition && typeof transition.duration === "number"
? transition.duration
: 0.8;
return {
stiffness: Math.min(500, Math.max(40, 280 / duration)),
damping: Math.min(40, Math.max(12, 18 + duration * 4)),
};
}