Vector Motion
Medical

No-Show Rate Card - Appointment Analytics

Monitor patient no-show rates and appointment compliance. Track missed appointments and scheduling efficiency.

No Show Rate Card

The No Show Rate Card Monitor patient appointment no-show rates and trends.

Preview

Installation

ash npx shadcn@latest add https://vectormotion.vercel.app/registry/no-show-rate-card.json

No Show Rate Card
'use client'import React from 'react';import { UserX, TrendingDown, ArrowDownRight } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';function cn(...inputs: ClassValue[]) {   return twMerge(clsx(inputs));}interface ReasonData {   name: string;   value: number;   color: string;   [key: string]: any;}interface NoShowRateCardProps {   className?: string;   title?: string;   subtitle?: string;   currentRate?: string;   trendValue?: string;   trendLabel?: string;   primaryReasonLabel?: string;   primaryReasonValue?: string;   data?: ReasonData[];}const DEFAULT_DATA: ReasonData[] = [   { name: 'Transport', value: 45, color: '#f87171' }, // red-400   { name: 'Forgot', value: 30, color: '#fb923c' },    // orange-400   { name: 'Cost', value: 15, color: '#facc15' },      // yellow-400   { name: 'Other', value: 10, color: '#9ca3af' },     // zinc-400];const DEFAULT_TITLE = "No-Shows";const DEFAULT_SUBTITLE = "Missed Rate";const DEFAULT_CURRENT_RATE = "12%";const DEFAULT_TREND_VALUE = "2%";const DEFAULT_TREND_LABEL = "vs Last Month";const DEFAULT_PRIMARY_REASON_LABEL = "Primary Reason";const DEFAULT_PRIMARY_REASON_VALUE = "Transportation Issues (45%)";export const NoShowRateCard: React.FC<NoShowRateCardProps> = ({   className = "",   title = DEFAULT_TITLE,   subtitle = DEFAULT_SUBTITLE,   currentRate = DEFAULT_CURRENT_RATE,   trendValue = DEFAULT_TREND_VALUE,   trendLabel = DEFAULT_TREND_LABEL,   primaryReasonLabel = DEFAULT_PRIMARY_REASON_LABEL,   primaryReasonValue = DEFAULT_PRIMARY_REASON_VALUE,   data = DEFAULT_DATA,}) => {   const isInteractive = true;   const index = 43;   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-red-300 dark:hover:border-red-700 hover:shadow-md" : "",            className         )}      >         <div className="p-5 flex flex-col h-full relative z-10">            <div className="mb-2 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-red-500"></span>                     </span>                     <p className="text-sm text-muted-foreground font-medium">                        {subtitle}                     </p>                  </div>               </div>               <div className="rounded-xl bg-red-50 dark:bg-red-900/20 p-2.5 text-red-600 dark:text-red-400 flex items-center justify-center ring-1 ring-red-100 dark:ring-red-800">                  <UserX className="h-5 w-5" />               </div>            </div>            <div className="flex-1 flex gap-4 items-center">               <div className="flex-1">                  <div className="flex items-end gap-2 mb-2">                     <span className="text-3xl font-bold text-foreground">{currentRate}</span>                     <div className="flex items-center text-emerald-500 bg-emerald-500/10 px-1.5 py-0.5 rounded text-[10px] font-bold mb-1">                        <ArrowDownRight className="h-3 w-3 mr-0.5" /> {trendValue}                     </div>                  </div>                  <p className="text-xs text-muted-foreground mb-4">{trendLabel}</p>                  <div className="space-y-1">                     <p className="text-[10px] font-bold text-muted-foreground uppercase">{primaryReasonLabel}</p>                     <p className="text-xs font-semibold text-zinc-800 dark:text-zinc-200">{primaryReasonValue}</p>                  </div>               </div>               <div className="relative h-24 w-24 flex-shrink-0">                  <ResponsiveContainer width="100%" height="100%">                     <PieChart>                        <Pie                           data={data}                           innerRadius={25}                           outerRadius={40}                           paddingAngle={2}                           dataKey="value"                           stroke="none"                        >                           {data.map((entry, index) => (                              <Cell key={`cell-${index}`} fill={entry.color} />                           ))}                        </Pie>                        <Tooltip                           contentStyle={{ borderRadius: '8px', border: 'none', boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)', padding: '4px 8px', fontSize: '10px' }}                           itemStyle={{ padding: 0 }}                        />                     </PieChart>                  </ResponsiveContainer>               </div>            </div>         </div>      </motion.div>   );};

Usage

This component is a demo card displaying medical metrics with animated visualizations and dark mode support.

Prop

Type