Medical
Staff Availability Card - Staffing Management
Monitor staff availability and scheduling. Track shift coverage and staffing adequacy.
Staff Availability Card
The Staff Availability Card Monitor healthcare staff availability and scheduling.
Preview
Installation
ash npx shadcn@latest add https://vectormotion.vercel.app/registry/staff-availability-card.json
Staff Availability Card
'use client'import React from 'react';import { UserCheck, Stethoscope, Syringe, Clipboard as ClipboardNurse, LucideIcon } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs));}interface StaffData { role: string; label: string; percent: number; status: string; icon: LucideIcon; barColor: string; statusColor: string;}interface StaffAvailabilityCardProps { className?: string; title?: string; subtitle?: string; extraStaffCount?: number; data?: StaffData[];}const DEFAULT_DATA: StaffData[] = [ { role: 'ICU Nursing', label: 'ICU Ratio', percent: 100, status: '100% Covered', icon: ClipboardNurse, barColor: 'bg-emerald-500', statusColor: 'text-emerald-500' }, { role: 'ER Physicians', label: 'ER Docs', percent: 80, status: '80% Covered', icon: Stethoscope, barColor: 'bg-blue-500', statusColor: 'text-foreground' }, { role: 'Anesthesiology', label: 'Surgeons', percent: 60, status: 'Searching (1)', icon: Syringe, barColor: 'bg-amber-500', statusColor: 'text-amber-500' },];const DEFAULT_TITLE = "Staffing";const DEFAULT_SUBTITLE = "On-Call Status";const DEFAULT_EXTRA_STAFF_COUNT = 12;export const StaffAvailabilityCard: React.FC<StaffAvailabilityCardProps> = ({ className = "", title = DEFAULT_TITLE, subtitle = DEFAULT_SUBTITLE, extraStaffCount = DEFAULT_EXTRA_STAFF_COUNT, data = DEFAULT_DATA,}) => { const isInteractive = true; const index = 17; return ( <motion.div layoutId={isInteractive ? `card-${index}-${title}` : undefined} transition={{ duration: 0.4, ease: "easeOut" }} className={cn( "relative overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-sm transition-all flex flex-col h-full", isInteractive ? "hover:border-primary/50 hover:shadow-md" : "", className )} > <div className="p-5 flex flex-col h-full relative z-10"> <div className="mb-4 flex items-start justify-between"> <div> <h3 className="font-bold text-lg text-foreground"> {title} </h3> <div className="flex items-center gap-1.5 mt-1"> <span className="relative flex h-2 w-2"> <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span> </span> <p className="text-sm text-muted-foreground font-medium"> {subtitle} </p> </div> </div> <div className="rounded-xl bg-emerald-500/10 p-2.5 text-emerald-500 flex items-center justify-center ring-1 ring-emerald-100 dark:ring-emerald-800"> <UserCheck className="h-5 w-5" /> </div> </div> <div className="flex-1 space-y-4"> {/* Avatars / Key Personnel */} <div className="flex items-center justify-between"> <div className="flex -space-x-2"> {[1, 2, 3, 4].map((i) => ( <div key={i} className="h-8 w-8 rounded-full border-2 border-white dark:border-zinc-900 bg-zinc-200 dark:bg-zinc-800 flex items-center justify-center text-[10px] text-muted-foreground font-bold overflow-hidden"> <img src={`https://i.pravatar.cc/150?u=${i + 20}`} alt="Staff" className="h-full w-full object-cover" /> </div> ))} <div className="h-8 w-8 rounded-full border-2 border-white dark:border-zinc-900 bg-emerald-500/10 text-emerald-500 flex items-center justify-center text-[10px] font-bold"> +{extraStaffCount} </div> </div> <button className="text-[10px] font-semibold text-emerald-600 bg-emerald-500/10 px-2.5 py-1.5 rounded-lg active:scale-95 transition-transform"> View Schedule </button> </div> {/* Coverage Bars */} <div className="space-y-3"> {data?.map((item, i) => ( <div key={i} className="space-y-1"> <div className="flex justify-between text-xs font-medium text-muted-foreground"> <span className="flex items-center gap-1.5"><item.icon className="h-3 w-3" /> {item.role}</span> <span className={item.statusColor}>{item.status}</span> </div> <div className="h-1.5 w-full bg-zinc-100 dark:bg-zinc-800 rounded-full overflow-hidden"> <motion.div initial={{ width: 0 }} animate={{ width: `${item.percent}%` }} className={cn("h-full rounded-full", item.barColor)} /> </div> </div> ))} </div> </div> </div> </motion.div> );};Usage
This component is a demo card displaying medical metrics with animated visualizations and dark mode support.
Prop
Type