Vector Motion
E-Commerce

Loyalty Program Card - Customer Rewards

Track loyalty program membership and reward redemptions. Monitor customer loyalty engagement and retention.

Loyalty Program Card

The Loyalty Program Card Track rewards program participation and redemption.

Preview

Installation

ash npx shadcn@latest add https://vectormotion.vercel.app/registry/loyalty-program-card.json

Loyalty Program Card
'use client';import React from "react";import { Gift, Star } 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 Tier {  tier: string;  members: number;  points: number;  color: string;  [key: string]: any;}interface LoyaltyProgramCardProps {  className?: string;  title?: string;  description?: string;  tiers?: Tier[];}const DEFAULT_TITLE = "Loyalty Program";const DEFAULT_DESCRIPTION = "Rewards Tracking";const DEFAULT_TIERS: Tier[] = [  { tier: "Platinum", members: 245, points: 125000, color: "bg-purple-500" },  { tier: "Gold", members: 680, points: 89000, color: "bg-amber-500" },  { tier: "Silver", members: 1200, points: 45000, color: "bg-zinc-400" },];export const LoyaltyProgramCard: React.FC<LoyaltyProgramCardProps> = ({  className = "",  title = DEFAULT_TITLE,  description = DEFAULT_DESCRIPTION,  tiers = DEFAULT_TIERS,}) => {  const isInteractive = true;  const index = 29;  const totalMembers = tiers.reduce((sum, t) => sum + t.members, 0);  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-6 shadow-sm transition-all flex flex-col group",        isInteractive          ? "cursor-pointer hover:border-zinc-300 dark:hover:border-zinc-700"          : "",        className,      )}    >      <div className="mb-4 flex items-start justify-between relative z-10">        <div>          <h3 className="font-semibold text-lg tracking-tight text-foreground">            {title}          </h3>          {description && (            <p className="text-sm text-muted-foreground mt-1">{description}</p>          )}        </div>        <div className="rounded-full bg-zinc-100 dark:bg-zinc-800 p-2 text-foreground flex items-center justify-center">          <Gift className="h-5 w-5 text-purple-500" />        </div>      </div>      <div className="relative z-10 flex-1">        <div className="flex items-baseline gap-2 mb-2">          <div className="text-3xl font-bold text-foreground">            {totalMembers.toLocaleString()}          </div>          <Star className="h-5 w-5 text-amber-500 fill-amber-500" />        </div>        <p className="text-sm text-muted-foreground mb-4">Active members</p>        <div className="space-y-3">          {tiers.map((tier, idx) => {            const percentage = Math.round((tier.members / totalMembers) * 100);            return (              <motion.div                key={idx}                initial={{ opacity: 0, scale: 0.95 }}                animate={{ opacity: 1, scale: 1 }}                transition={{ duration: 0.4, delay: idx * 0.1 }}                className="bg-muted rounded-lg p-3"              >                <div className="flex justify-between items-center mb-2">                  <div className="flex items-center gap-2">                    <div className={`w-3 h-3 rounded-full ${tier.color}`} />                    <span className="text-sm font-medium text-foreground">                      {tier.tier}                    </span>                  </div>                  <span className="text-sm font-bold text-foreground">                    {tier.members}                  </span>                </div>                <div className="flex justify-between text-xs text-muted-foreground">                  <span>{percentage}% of members</span>                  <span>{(tier.points / 1000).toFixed(0)}K points</span>                </div>              </motion.div>            );          })}        </div>      </div>    </motion.div>  );};

Usage

This component is a data-rich dashboard card displaying e-commerce metrics with animated visualizations and dark mode support. Perfect for dashboards, landing pages, and analytics interfaces.

Prop

Type