Menu

Change language

GitHub repo

Gift Card Balance Checker

blockcommerce

Customer storefront gift card balance lookup, live digital card passbook, quick fund reloading, and complete redemption audit history ledger.

Installation

$npx shadcn@latest add https://uipkge.dev/r/react/gift-card-balance-checker.json
Named registry:npx shadcn@latest add @uipkge-react/gift-card-balance-checkerInstalls to:components/blocks/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
classNamestring—optional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

TransactionRecord
interface TransactionRecord {
  id: string
  date: string
  reference: string
  title: string
  subtitle?: string
  type: 'activation' | 'redemption' | 'reload'
  amount: number
  balanceAfter: number
  status: 'Completed' | 'Pending'
}

Files installed (1)

  • components/blocks/GiftCardBalanceChecker.tsx29.4 kB
    'use client'
    
    import * as React from 'react'
    import { useMemo } from 'react'
    import {
      ArrowDownLeft,
      ArrowUpRight,
      Check,
      CheckCircle2,
      Copy,
      CreditCard,
      Gift,
      HelpCircle,
      Lock,
      Plus,
      RefreshCw,
      ShieldCheck,
      ShoppingBag,
      Wallet,
    } from 'lucide-react'
    import { cn } from '@/lib/utils'
    import { Badge } from '@/components/ui/badge'
    import { Button } from '@/components/ui/button'
    import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
    import { Input } from '@/components/ui/input'
    import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
    import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
    
    export interface GiftCardBalanceCheckerProps {
      className?: string
    }
    
    interface TransactionRecord {
      id: string
      date: string
      reference: string
      title: string
      subtitle?: string
      type: 'activation' | 'redemption' | 'reload'
      amount: number
      balanceAfter: number
      status: 'Completed' | 'Pending'
    }
    
    const initialTransactions: TransactionRecord[] = [
      {
        id: 'tx-1',
        date: 'Dec 19, 2024',
        reference: '#ORD-84112',
        title: 'Store Checkout Redemption',
        subtitle: 'Order #ORD-84112 · Leather Travel Wallet',
        type: 'redemption',
        amount: -15.0,
        balanceAfter: 150.0,
        status: 'Completed',
      },
      {
        id: 'tx-2',
        date: 'Nov 04, 2024',
        reference: '#ORD-84920',
        title: 'Store Checkout Redemption',
        subtitle: 'Order #ORD-84920 · Merino Knit Sweater',
        type: 'redemption',
        amount: -35.0,
        balanceAfter: 165.0,
        status: 'Completed',
      },
      {
        id: 'tx-3',
        date: 'Oct 12, 2024',
        reference: '#ACT-99014',
        title: 'Initial Activation & Fund Issue',
        subtitle: 'Digital Storefront Pass Issued',
        type: 'activation',
        amount: 200.0,
        balanceAfter: 200.0,
        status: 'Completed',
      },
    ]
    
    export function GiftCardBalanceChecker({ className }: GiftCardBalanceCheckerProps) {
      const [cardNumber, setCardNumber] = React.useState('7482 - 9104 - 6382 - 8492')
      const [securityPin, setSecurityPin] = React.useState('4829')
      const [isChecking, setIsChecking] = React.useState(false)
      const [isVerified, setIsVerified] = React.useState(true)
      const [copied, setCopied] = React.useState(false)
      const [applied, setApplied] = React.useState(false)
      const [feedbackMessage, setFeedbackMessage] = React.useState<string | null>(null)
      const [filterType, setFilterType] = React.useState<'all' | 'redemptions' | 'loads'>('all')
      const [transactions, setTransactions] = React.useState<TransactionRecord[]>(initialTransactions)
    
      function formatCardInput(raw: string): string {
        const digits = raw.replace(/\D/g, '').slice(0, 16)
        return digits.replace(/(.{4})(?=.)/g, '$1 - ')
      }
    
      function handleCardNumberChange(e: React.ChangeEvent<HTMLInputElement>) {
        const formatted = formatCardInput(e.target.value)
        setCardNumber(formatted)
      }
    
      function handlePinChange(e: React.ChangeEvent<HTMLInputElement>) {
        const digits = e.target.value.replace(/\D/g, '').slice(0, 4)
        setSecurityPin(digits)
      }
    
      const currentBalance = useMemo(() => {
        if (transactions.length === 0) return 0
        return transactions[0].balanceAfter
      }, [transactions])
    
      const totalLoaded = useMemo(() => {
        return transactions.filter((t) => t.amount > 0).reduce((sum, t) => sum + t.amount, 0)
      }, [transactions])
    
      const totalSpent = useMemo(() => {
        return Math.abs(transactions.filter((t) => t.amount < 0).reduce((sum, t) => sum + t.amount, 0))
      }, [transactions])
    
      const lastFourDigits = useMemo(() => {
        const digits = cardNumber.replace(/\D/g, '')
        return digits.length >= 4 ? digits.slice(-4) : '8492'
      }, [cardNumber])
    
      const filteredTransactions = useMemo(() => {
        if (filterType === 'redemptions') {
          return transactions.filter((t) => t.type === 'redemption')
        }
        if (filterType === 'loads') {
          return transactions.filter((t) => t.type === 'activation' || t.type === 'reload')
        }
        return transactions
      }, [transactions, filterType])
    
      function checkBalance() {
        setIsChecking(true)
        setFeedbackMessage(null)
        setTimeout(() => {
          setIsChecking(false)
          setIsVerified(true)
          setFeedbackMessage(`Gift card verified. Current active balance is $${currentBalance.toFixed(2)}.`)
          setTimeout(() => {
            setFeedbackMessage(null)
          }, 4000)
        }, 500)
      }
    
      function copyCardNumber() {
        const raw = cardNumber.replace(/\s+/g, '')
        if (typeof navigator !== 'undefined' && navigator.clipboard) {
          navigator.clipboard.writeText(raw)
        }
        setCopied(true)
        setTimeout(() => {
          setCopied(false)
        }, 2000)
      }
    
      function applyToOrder() {
        copyCardNumber()
        setApplied(true)
        setFeedbackMessage(`Card ending in ${lastFourDigits} copied and applied to your checkout session!`)
        setTimeout(() => {
          setApplied(false)
          setFeedbackMessage(null)
        }, 4000)
      }
    
      function reloadFunds(amount: number) {
        const newBalance = currentBalance + amount
        const newRecord: TransactionRecord = {
          id: `tx-${Date.now()}`,
          date: 'Today',
          reference: `#RLD-${Math.floor(10000 + Math.random() * 90000)}`,
          title: 'Manual Online Fund Reload',
          subtitle: `Instant Online Top-Up (+ $${amount.toFixed(2)})`,
          type: 'reload',
          amount: amount,
          balanceAfter: newBalance,
          status: 'Completed',
        }
        setTransactions((prev) => [newRecord, ...prev])
        setFeedbackMessage(`Successfully reloaded +$${amount.toFixed(2)}! New card balance: $${newBalance.toFixed(2)}.`)
        setTimeout(() => {
          setFeedbackMessage(null)
        }, 4000)
      }
    
      return (
        <div data-slot="gift-card-balance-checker" className={cn('w-full space-y-6', className)}>
          {/* Header Section */}
          <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
            <div className="space-y-1">
              <div className="flex items-center gap-2">
                <h2 className="text-foreground text-2xl font-bold tracking-tight">Check Gift Card Balance</h2>
                <Badge variant="outline" className="bg-primary/5 text-primary border-primary/20 gap-1">
                  <CheckCircle2 className="text-primary size-3" />
                  Storefront Pass
                </Badge>
              </div>
              <p className="text-muted-foreground text-sm">
                Check your remaining card balance, review past order redemptions, or reload funds.
              </p>
            </div>
    
            <div className="flex items-center gap-2">
              <TooltipProvider delayDuration={150}>
                <Tooltip>
                  <TooltipTrigger asChild>
                    <div className="border-border bg-card text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 rounded-md border px-3 py-1.5 text-xs shadow-xs">
                      <HelpCircle className="text-primary size-3.5" />
                      <span>PIN & Card Guide</span>
                    </div>
                  </TooltipTrigger>
                  <TooltipContent side="bottom" className="max-w-xs text-xs">
                    Locate the 16-digit card code on the back of your physical card or inside your digital gift email. The
                    4-digit security PIN is under the scratch-off foil.
                  </TooltipContent>
                </Tooltip>
              </TooltipProvider>
            </div>
          </div>
    
          {/* Feedback Banner if active */}
          {feedbackMessage && (
            <div className="border-success/20 bg-success/10 text-success flex items-center justify-between rounded-lg border px-4 py-2.5 text-sm">
              <div className="flex items-center gap-2">
                <CheckCircle2 className="text-success size-4 shrink-0" />
                <span>{feedbackMessage}</span>
              </div>
            </div>
          )}
    
          {/* 2-Column Storefront Layout */}
          <div className="grid grid-cols-1 gap-6 lg:grid-cols-12">
            {/* Left Column: Lookup Form & Digital Card Hero */}
            <div className="space-y-6 lg:col-span-5">
              {/* Lookup Card Form */}
              <Card className="border-border shadow-xs">
                <CardHeader className="pb-4">
                  <div className="flex items-center justify-between">
                    <CardTitle className="text-base font-semibold">Card Lookup</CardTitle>
                    {isVerified && (
                      <Badge variant="outline" className="border-success/30 bg-success/10 text-success gap-1 text-xs">
                        <Check className="size-3" />
                        Active Card
                      </Badge>
                    )}
                  </div>
                  <CardDescription className="text-xs">
                    Enter your gift card credentials to view live balance and activity.
                  </CardDescription>
                </CardHeader>
    
                <CardContent className="space-y-4 pb-4">
                  {/* 16-Digit Card Number Input */}
                  <div className="space-y-1.5">
                    <div className="flex items-center justify-between">
                      <label htmlFor="gc-number-input-react" className="text-foreground text-xs font-medium">
                        16-Digit Card Number
                      </label>
                      <TooltipProvider delayDuration={150}>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <button
                              type="button"
                              className="text-muted-foreground hover:text-foreground inline-flex items-center focus-visible:outline-none"
                              aria-label="Gift card number info"
                            >
                              <HelpCircle className="size-3.5" />
                            </button>
                          </TooltipTrigger>
                          <TooltipContent side="top" className="max-w-xs text-xs">
                            Enter the 16 digits on the back of your card or in your receipt email.
                          </TooltipContent>
                        </Tooltip>
                      </TooltipProvider>
                    </div>
    
                    <Input
                      id="gc-number-input-react"
                      value={cardNumber}
                      placeholder="XXXX - XXXX - XXXX - XXXX"
                      maxLength={25}
                      className="font-mono text-sm"
                      prefixIcon={<CreditCard className="size-4" />}
                      onChange={handleCardNumberChange}
                    />
                  </div>
    
                  {/* 4-Digit Security PIN Input */}
                  <div className="space-y-1.5">
                    <div className="flex items-center justify-between">
                      <label htmlFor="gc-pin-input-react" className="text-foreground text-xs font-medium">
                        Security PIN (4 digits)
                      </label>
                      <TooltipProvider delayDuration={150}>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <button
                              type="button"
                              className="text-muted-foreground hover:text-foreground inline-flex items-center focus-visible:outline-none"
                              aria-label="Security PIN info"
                            >
                              <HelpCircle className="size-3.5" />
                            </button>
                          </TooltipTrigger>
                          <TooltipContent side="top" className="max-w-xs text-xs">
                            The 4-digit PIN is revealed by scratching the silver foil or listed in your digital claim email.
                          </TooltipContent>
                        </Tooltip>
                      </TooltipProvider>
                    </div>
    
                    <Input
                      id="gc-pin-input-react"
                      value={securityPin}
                      type="password"
                      placeholder="••••"
                      maxLength={4}
                      showPasswordToggle
                      className="font-mono text-sm"
                      prefixIcon={<Lock className="size-4" />}
                      onChange={handlePinChange}
                    />
                  </div>
    
                  <Button type="button" className="w-full font-medium" disabled={isChecking} onClick={checkBalance}>
                    {isChecking ? (
                      <>
                        <RefreshCw className="mr-2 size-4 animate-spin" />
                        Verifying Balance...
                      </>
                    ) : (
                      <>
                        <ShieldCheck className="mr-2 size-4" />
                        Check Balance
                      </>
                    )}
                  </Button>
                </CardContent>
              </Card>
    
              {/* Stylized Digital Gift Card Hero Display */}
              <div className="relative overflow-hidden rounded-2xl border border-white/10 bg-gradient-to-br from-zinc-950 via-neutral-900 to-zinc-900 p-6 text-white shadow-lg">
                <div className="relative flex flex-col justify-between space-y-6">
                  {/* Card Top Bar: Brand & Pass Badge */}
                  <div className="flex items-start justify-between">
                    <div className="flex items-center gap-2.5">
                      <div className="flex size-9 items-center justify-center rounded-xl border border-white/10 bg-white/10 text-white shadow-inner backdrop-blur-md">
                        <Gift className="text-success size-5" />
                      </div>
                      <div>
                        <p className="text-xs font-bold tracking-wider text-neutral-200 uppercase">Lumen Store</p>
                        <p className="text-xs text-neutral-400">Digital Gift Pass</p>
                      </div>
                    </div>
    
                    <Badge
                      variant="outline"
                      className="gap-1.5 border-white/20 bg-white/10 px-2.5 py-0.5 text-xs text-white backdrop-blur-md"
                    >
                      <span className="bg-success size-1.5 animate-pulse rounded-full" />
                      Verified Active
                    </Badge>
                  </div>
    
                  {/* Card Center: Chip Icon & Balance Display */}
                  <div className="space-y-1 pt-1">
                    <div className="flex items-center justify-between">
                      <span className="text-xs font-medium tracking-wider text-neutral-400 uppercase">
                        Available Balance
                      </span>
                      {/* Chip graphic representation */}
                      <div className="flex items-center gap-1 opacity-70">
                        <div className="border-warning/20/40 h-5 w-7 rounded-sm border bg-gradient-to-tr from-amber-400/20 to-amber-200/40" />
                        <span className="font-mono text-xs tracking-tighter text-neutral-400">NFC</span>
                      </div>
                    </div>
    
                    <div className="flex items-baseline gap-2">
                      <span className="text-3xl font-bold tracking-tight text-white tabular-nums sm:text-4xl">
                        ${currentBalance.toFixed(2)}
                      </span>
                      <span className="text-success text-xs font-medium">USD</span>
                    </div>
                  </div>
    
                  {/* Card Footer: Card Number & Expiry terms */}
                  <div className="space-y-2 border-t border-white/10 pt-4">
                    <div className="flex items-center justify-between">
                      <div className="flex items-center gap-2">
                        <span className="font-mono text-sm tracking-widest text-neutral-200">
                          •••• •••• •••• {lastFourDigits}
                        </span>
                        <button
                          type="button"
                          className="rounded p-1 text-neutral-400 transition-colors hover:text-white focus-visible:ring-1 focus-visible:ring-white/40 focus-visible:outline-none"
                          aria-label="Copy card number"
                          onClick={copyCardNumber}
                        >
                          {copied ? <Check className="text-success size-3.5" /> : <Copy className="size-3.5" />}
                        </button>
                      </div>
                      {copied && <span className="animate-in fade-in text-success text-xs font-medium">Copied!</span>}
                    </div>
    
                    <div className="flex items-center justify-between text-xs text-neutral-400">
                      <span>Never Expires · No Inactivity Fees</span>
                      <span className="font-mono text-neutral-500">PIN: ••••</span>
                    </div>
                  </div>
                </div>
              </div>
    
              {/* Quick Action Buttons */}
              <div className="space-y-3">
                <Button variant="default" className="w-full font-medium" onClick={applyToOrder}>
                  {applied ? (
                    <>
                      <Check className="text-success mr-2 size-4" />
                      Applied to Checkout!
                    </>
                  ) : (
                    <>
                      <ShoppingBag className="mr-2 size-4" />
                      Apply to Next Order
                    </>
                  )}
                </Button>
    
                {/* Quick Reload Card */}
                <Card className="border-border shadow-xs">
                  <CardHeader className="p-4 pb-2">
                    <div className="flex items-center justify-between">
                      <CardTitle className="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
                        Quick Reload Funds
                      </CardTitle>
                      <Plus className="text-muted-foreground size-3.5" />
                    </div>
                  </CardHeader>
                  <CardContent className="p-4 pt-0">
                    <p className="text-muted-foreground mb-3 text-xs">
                      Top up your gift card instantly with a saved payment method.
                    </p>
                    <div className="grid grid-cols-3 gap-2">
                      <Button
                        variant="outline"
                        size="sm"
                        className="hover:bg-primary/5 hover:text-primary hover:border-primary/30 w-full font-medium tabular-nums"
                        onClick={() => reloadFunds(25)}
                      >
                        + $25.00
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        className="hover:bg-primary/5 hover:text-primary hover:border-primary/30 w-full font-medium tabular-nums"
                        onClick={() => reloadFunds(50)}
                      >
                        + $50.00
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        className="hover:bg-primary/5 hover:text-primary hover:border-primary/30 w-full font-medium tabular-nums"
                        onClick={() => reloadFunds(100)}
                      >
                        + $100.00
                      </Button>
                    </div>
                  </CardContent>
                </Card>
              </div>
            </div>
    
            {/* Right Column: Balance Stats & Redemption History Table */}
            <div className="space-y-6 lg:col-span-7">
              {/* Passbook Summary Metrics */}
              <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
                <div className="border-border bg-card rounded-xl border p-4 shadow-xs">
                  <div className="text-muted-foreground mb-1 flex items-center justify-between text-xs">
                    <span>Available Balance</span>
                    <Wallet className="text-primary size-3.5" />
                  </div>
                  <p className="text-foreground text-2xl font-bold tracking-tight tabular-nums">
                    ${currentBalance.toFixed(2)}
                  </p>
                  <p className="text-success mt-1 flex items-center gap-1 text-xs font-medium">
                    <Check className="size-3" />
                    Ready to spend
                  </p>
                </div>
    
                <div className="border-border bg-card rounded-xl border p-4 shadow-xs">
                  <div className="text-muted-foreground mb-1 flex items-center justify-between text-xs">
                    <span>Total Value Loaded</span>
                    <ArrowDownLeft className="text-success size-3.5" />
                  </div>
                  <p className="text-foreground text-2xl font-bold tracking-tight tabular-nums">
                    ${totalLoaded.toFixed(2)}
                  </p>
                  <p className="text-muted-foreground mt-1 text-xs">All top-ups & issue</p>
                </div>
    
                <div className="border-border bg-card rounded-xl border p-4 shadow-xs">
                  <div className="text-muted-foreground mb-1 flex items-center justify-between text-xs">
                    <span>Total Redeemed</span>
                    <ArrowUpRight className="text-muted-foreground size-3.5" />
                  </div>
                  <p className="text-foreground text-2xl font-bold tracking-tight tabular-nums">
                    -${totalSpent.toFixed(2)}
                  </p>
                  <p className="text-muted-foreground mt-1 text-xs">Past store orders</p>
                </div>
              </div>
    
              {/* Redemption & Activity History Card */}
              <Card className="border-border shadow-xs">
                <CardHeader className="pb-3">
                  <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                    <div>
                      <CardTitle className="text-base font-semibold">Redemption & Activity History</CardTitle>
                      <CardDescription className="text-xs">
                        Detailed ledger of card issuance, promotional top-ups, and store checkouts.
                      </CardDescription>
                    </div>
    
                    {/* Filter Pills */}
                    <div className="border-border bg-muted/40 flex items-center gap-1.5 rounded-lg border p-1 text-xs">
                      <button
                        type="button"
                        className={cn(
                          'rounded px-2.5 py-1 font-medium transition-colors',
                          filterType === 'all'
                            ? 'bg-background text-foreground shadow-xs'
                            : 'text-muted-foreground hover:text-foreground',
                        )}
                        onClick={() => setFilterType('all')}
                      >
                        All ({transactions.length})
                      </button>
                      <button
                        type="button"
                        className={cn(
                          'rounded px-2.5 py-1 font-medium transition-colors',
                          filterType === 'redemptions'
                            ? 'bg-background text-foreground shadow-xs'
                            : 'text-muted-foreground hover:text-foreground',
                        )}
                        onClick={() => setFilterType('redemptions')}
                      >
                        Redemptions
                      </button>
                      <button
                        type="button"
                        className={cn(
                          'rounded px-2.5 py-1 font-medium transition-colors',
                          filterType === 'loads'
                            ? 'bg-background text-foreground shadow-xs'
                            : 'text-muted-foreground hover:text-foreground',
                        )}
                        onClick={() => setFilterType('loads')}
                      >
                        Loads
                      </button>
                    </div>
                  </div>
                </CardHeader>
    
                <CardContent className="p-0">
                  <div className="overflow-x-auto">
                    <Table>
                      <TableHeader>
                        <TableRow>
                          <TableHead className="w-[110px]">Date</TableHead>
                          <TableHead>Activity & Reference</TableHead>
                          <TableHead className="w-[90px] text-center">Type</TableHead>
                          <TableHead className="w-[100px] text-right">Amount</TableHead>
                          <TableHead className="w-[110px] text-right">Resulting Balance</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {filteredTransactions.map((record) => (
                          <TableRow key={record.id}>
                            <TableCell className="text-muted-foreground text-xs font-medium">{record.date}</TableCell>
                            <TableCell>
                              <div className="space-y-0.5">
                                <p className="text-foreground text-sm leading-none font-medium">{record.title}</p>
                                {record.subtitle && <p className="text-muted-foreground text-xs">{record.subtitle}</p>}
                              </div>
                            </TableCell>
                            <TableCell className="text-center">
                              {record.type === 'activation' && (
                                <Badge
                                  variant="outline"
                                  className="border-success/30 bg-success/10 text-success px-2 py-0.5 text-xs font-normal"
                                >
                                  Activation
                                </Badge>
                              )}
                              {record.type === 'reload' && (
                                <Badge
                                  variant="outline"
                                  className="border-info/30 bg-info/10 text-info px-2 py-0.5 text-xs font-normal"
                                >
                                  Reload
                                </Badge>
                              )}
                              {record.type === 'redemption' && (
                                <Badge variant="secondary" className="px-2 py-0.5 text-xs font-normal">
                                  Redemption
                                </Badge>
                              )}
                            </TableCell>
                            <TableCell
                              className={cn(
                                'text-right text-sm font-medium tabular-nums',
                                record.amount > 0 ? 'text-success' : 'text-foreground',
                              )}
                            >
                              {record.amount > 0
                                ? `+$${record.amount.toFixed(2)}`
                                : `-$${Math.abs(record.amount).toFixed(2)}`}
                            </TableCell>
                            <TableCell className="text-muted-foreground text-right font-mono text-sm tabular-nums">
                              ${record.balanceAfter.toFixed(2)}
                            </TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </div>
                </CardContent>
    
                <CardFooter className="border-border text-muted-foreground flex flex-col gap-3 border-t p-4 text-xs sm:flex-row sm:items-center sm:justify-between">
                  <div className="flex items-center gap-1.5">
                    <ShieldCheck className="text-primary size-4 shrink-0" />
                    <span>Protected by 256-bit encryption · Zero liability policy</span>
                  </div>
                  <div className="flex items-center gap-3">
                    <button
                      type="button"
                      className="hover:text-foreground flex min-h-6 items-center gap-1 underline-offset-4 hover:underline"
                      onClick={checkBalance}
                    >
                      <RefreshCw className="size-3" />
                      Refresh Ledger
                    </button>
                  </div>
                </CardFooter>
              </Card>
    
              {/* Digital Passbook Barcode Card */}
              <Card className="border-border bg-muted/20 shadow-xs">
                <CardContent className="flex flex-col items-center justify-between gap-4 p-4 sm:flex-row sm:p-5">
                  <div className="space-y-1 text-center sm:text-left">
                    <h4 className="text-foreground flex items-center justify-center gap-2 text-sm font-semibold sm:justify-start">
                      <Wallet className="text-primary size-4" />
                      In-Store Digital Pass
                    </h4>
                    <p className="text-muted-foreground max-w-sm text-xs">
                      Present this barcode at checkout in any physical store location to scan and redeem card funds.
                    </p>
                  </div>
    
                  {/* Barcode Simulation */}
                  <div className="border-border bg-card flex flex-col items-center gap-1.5 rounded-lg border p-3 shadow-xs">
                    <div className="flex h-10 items-end gap-[3px] px-2" aria-hidden="true">
                      <div className="bg-foreground h-full w-[2px]" />
                      <div className="bg-foreground h-full w-[4px]" />
                      <div className="bg-foreground h-full w-[1px]" />
                      <div className="bg-foreground h-full w-[3px]" />
                      <div className="bg-foreground h-full w-[2px]" />
                      <div className="bg-foreground h-full w-[5px]" />
                      <div className="bg-foreground h-full w-[1px]" />
                      <div className="bg-foreground h-full w-[3px]" />
                      <div className="bg-foreground h-full w-[2px]" />
                      <div className="bg-foreground h-full w-[4px]" />
                      <div className="bg-foreground h-full w-[2px]" />
                      <div className="bg-foreground h-full w-[1px]" />
                      <div className="bg-foreground h-full w-[4px]" />
                      <div className="bg-foreground h-full w-[2px]" />
                      <div className="bg-foreground h-full w-[3px]" />
                    </div>
                    <span className="text-muted-foreground font-mono text-xs tracking-widest">{cardNumber}</span>
                  </div>
                </CardContent>
              </Card>
            </div>
          </div>
        </div>
      )
    }
    
    export default GiftCardBalanceChecker
    

Raw manifest:https://uipkge.dev/r/react/gift-card-balance-checker.json