Wallet Card

Credit balance display card for available, pending, and refresh details. Install Wallet Card from the VLLNT UI registry with the shadcn CLI.

Report a bug

Credit balance display card for available, pending, and refresh details. Part of the content family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Wallet Card to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/wallet-card.json

Source

import * as React from "react"; import { cn } from "../../lib/utils"; import { Button } from "../button/button"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "../card/card"; import { CreditBadge, type CreditBadgeStatus, } from "../credit-badge/credit-badge"; export type WalletCardProps = React.ComponentPropsWithoutRef<typeof Card> & { availableLabel?: string; balanceLabel: string; note?: string; pendingLabel?: string; primaryActionLabel?: string; renewsLabel?: string; secondaryActionLabel?: string; status: CreditBadgeStatus; }; type WalletActionsProps = { primaryActionLabel?: string; secondaryActionLabel?: string; }; type WalletDetailsProps = { availableLabel?: string; balanceLabel: string; note?: string; pendingLabel?: string; renewsLabel?: string; }; function DetailRow({ label, value }: { label: string; value: string }) { return ( <div className="flex items-center justify-between gap-4 text-sm"> <span className="text-muted-foreground">{label}</span> <span className="text-right font-medium">{value}</span> </div> ); } function WalletDetails({ availableLabel, balanceLabel, note, pendingLabel, renewsLabel, }: WalletDetailsProps) { return ( <CardContent className="space-y-4"> <div className="rounded-lg border border-border/70 bg-background px-4 py-3"> <p className="text-xs uppercase tracking-[0.18em] text-muted-foreground"> Current balance </p> <p className="mt-2 text-3xl font-semibold tracking-tight"> {balanceLabel} </p> </div> <div className="space-y-3 rounded-lg border border-border/70 bg-muted/20 p-4"> {availableLabel ? ( <DetailRow label="Available now" value={availableLabel} /> ) : null} {pendingLabel ? ( <DetailRow label="Pending" value={pendingLabel} /> ) : null} {renewsLabel ? <DetailRow label="Refresh" value={renewsLabel} /> : null} </div> {note ? ( <p className="rounded-lg bg-muted px-4 py-3 text-sm text-muted-foreground"> {note} </p> ) : null} </CardContent> ); } function WalletActions({ primaryActionLabel, secondaryActionLabel, }: WalletActionsProps) { if (!primaryActionLabel && !secondaryActionLabel) { return null; } return ( <CardFooter className="flex flex-col gap-2 sm:flex-row sm:justify-end"> {secondaryActionLabel ? ( <Button className="w-full sm:w-auto" variant="outline"> {secondaryActionLabel} </Button> ) : null} {primaryActionLabel ? ( <Button className="w-full sm:w-auto">{primaryActionLabel}</Button> ) : null} </CardFooter> ); } export const WalletCard = ({ availableLabel, balanceLabel, className, note, pendingLabel, primaryActionLabel, ref: reference, renewsLabel, secondaryActionLabel, status, ...props }: WalletCardProps & { ref?: React.Ref<React.ComponentRef<typeof Card>> }) => { return ( <Card className={cn( "w-full max-w-md border-border/70 bg-card shadow-sm", className, )} ref={reference} {...props} > <CardHeader className="space-y-4 pb-4"> <div className="space-y-1"> <CardTitle className="text-lg">Wallet</CardTitle> <CardDescription> Track credits, pending top-ups, and replenishment timing. </CardDescription> </div> <div className="flex items-center justify-between gap-3 rounded-lg border border-border/70 bg-muted/30 px-4 py-3"> <div> <p className="text-sm font-medium">Available balance</p> <p className="text-xs text-muted-foreground"> {renewsLabel ?? "Credits refresh automatically when enabled."} </p> </div> <CreditBadge amount={balanceLabel} status={status} /> </div> </CardHeader> <WalletDetails availableLabel={availableLabel} balanceLabel={balanceLabel} note={note} pendingLabel={pendingLabel} renewsLabel={renewsLabel} /> <WalletActions primaryActionLabel={primaryActionLabel} secondaryActionLabel={secondaryActionLabel} /> </Card> ); }; WalletCard.displayName = "WalletCard";

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0