Vector Motion
Finance

Dividend Calendar Card - Dividend Tracking

Monitor dividend payments and schedules. Track dividend history and investor returns.

Finance Dividend Calendar Card

The Finance Dividend Calendar Card displays upcoming dividend payment dates and amounts, helping investors manage their dividend income.

Preview

Installation

npx shadcn@latest add https://vectormotion.vercel.app/registry/finance-dividend-calendar-card.json
Finance Dividend Calendar Card
'use client'import React from 'react';import { Calendar, CheckCircle2, Clock } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, BarChart, Bar, XAxis, Tooltip, Cell } from 'recharts';function cn(...inputs: ClassValue[]) {  return twMerge(clsx(inputs))}interface DividendDate {  id: number;  symbol: string;  amount: string;  payDate: string;  status: string;}interface ChartData {  name: string;  value: number;}interface DividendCalendarCardProps {  isInteractive?: boolean;  className?: string;  title?: string;  totalPayout?: string;  payoutLabel?: string;  dividends?: DividendDate[];  chartData?: ChartData[];}const DEFAULT_TITLE = "Dividends";const DEFAULT_TOTAL_PAYOUT = "$145.2";const DEFAULT_PAYOUT_LABEL = "Est. Payout";const DEFAULT_DIVIDENDS: DividendDate[] = [  { id: 1, symbol: 'AAPL', amount: '$0.24', payDate: 'Nov 16', status: 'confirmed' },  { id: 2, symbol: 'MSFT', amount: '$0.68', payDate: 'Dec 08', status: 'confirmed' },  { id: 3, symbol: 'KO', amount: '$0.46', payDate: 'Dec 15', status: 'pending' },];const DEFAULT_CHART_DATA: ChartData[] = [  { name: 'Nov', value: 45 },  { name: 'Dec', value: 68 },  { name: 'Jan', value: 52 },  { name: 'Feb', value: 38 },];const container = {  hidden: { opacity: 0 },  show: {    opacity: 1,    transition: { staggerChildren: 0.1 }  }};const item = {  hidden: { x: -10, opacity: 0 },  show: { x: 0, opacity: 1 }};export const DividendCalendarCard: React.FC<DividendCalendarCardProps> = ({  isInteractive = true,  className = "",  title = DEFAULT_TITLE,  totalPayout = DEFAULT_TOTAL_PAYOUT,  payoutLabel = DEFAULT_PAYOUT_LABEL,  dividends = DEFAULT_DIVIDENDS,  chartData = DEFAULT_CHART_DATA,}) => {  const index = 19;  return (    <motion.div      layoutId={isInteractive ? `card-${index}-${title}` : undefined}      transition={{ duration: 0.4, ease: "easeOut" }}      className={cn(        "relative overflow-hidden rounded-xl border border-border bg-card text-card-foreground p-5 shadow-sm transition-all flex flex-col h-full group",        isInteractive ? "cursor-pointer hover:border-primary/50 hover:shadow-md" : "",        className      )}    >      <div className="mb-2 flex items-start justify-between relative z-10">        <div>          <h3 className="font-semibold text-lg text-foreground">            {title}          </h3>          <div className="flex items-center gap-2 mt-1">            <span className="text-2xl font-bold text-foreground">{totalPayout}</span>            <span className="text-xs text-muted-foreground">{payoutLabel}</span>          </div>        </div>        <div className="rounded-lg bg-emerald-500/10 p-2 text-emerald-500">          <Calendar className="h-5 w-5" />        </div>      </div>      <div className="relative z-0 h-16 w-full mb-2">        <ResponsiveContainer width="100%" height="100%">          <BarChart data={chartData}>            <Tooltip cursor={{ fill: 'transparent' }} contentStyle={{ borderRadius: '8px', border: 'none', backgroundColor: 'var(--tooltip-bg)', color: 'var(--tooltip-text)' }} />            <Bar dataKey="value" radius={[4, 4, 0, 0]} barSize={32}>              {chartData.map((entry, index) => (                <Cell key={`cell-${index}`} fill={index === 1 ? '#10b981' : '#e4e4e7'} className={index === 1 ? "fill-emerald-500" : "fill-zinc-200 dark:fill-zinc-700"} />              ))}            </Bar>          </BarChart>        </ResponsiveContainer>      </div>      <div className="relative z-10 flex-1">        <motion.div          className="space-y-2"          variants={container}          initial="hidden"          animate="show"        >          {dividends.map((div) => (            <motion.div              key={div.id}              variants={item}              whileHover={{ x: 4 }}              className="flex items-center justify-between p-1.5 rounded-lg hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors"            >              <div className="flex items-center gap-3">                <div className="h-7 w-7 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center font-bold text-[10px] text-foreground">                  {div.symbol[0]}                </div>                <div>                  <p className="text-xs font-bold text-foreground">{div.symbol}</p>                  <p className="text-[10px] text-muted-foreground flex items-center gap-1">                    {div.status === 'confirmed' ? <CheckCircle2 className="h-2.5 w-2.5 text-emerald-500" /> : <Clock className="h-2.5 w-2.5 text-amber-500" />}                    {div.payDate}                  </p>                </div>              </div>              <div className="text-right">                <p className="text-xs font-medium text-foreground">{div.amount}</p>              </div>            </motion.div>          ))}        </motion.div>      </div>    </motion.div>  );};

Props

Prop

Type