Concorde
BETA

WalletBalanceCard

Tarjeta «Billetera» (375×221). Compone CardTitle y ProfileButton. El cuerpo (SubasCoins / Saldo + CTA) se irá montando encima.

BILLETERA

SubasCoins:>S< 0
Saldo:US$ 0
<WalletBalanceCard />

Instalación

$ npx github:AaronCoorahua/ConcordeV2#cli add walletbalancecard

Uso

import WalletBalanceCard from "@/src/components/WalletBalanceCard";

<WalletBalanceCard onTransactions={() => {}} />

Ejemplos

Por defecto

Header con título «BILLETERA» (CardTitle) y acceso «Transacciones» (ProfileButton).

BILLETERA

SubasCoins:>S< 0
Saldo:US$ 0
<WalletBalanceCard />

API

PropTipoDefault
title
Título de la tarjeta (CardTitle con brackets).
string"BILLETERA"
onTransactions
Click del acceso «Transacciones».
MouseEventHandler
transactionsHref
Si se pasa, «Transacciones» se renderiza como enlace.
string
className
Clases extra sobre la tarjeta.
string

Código del componente

Ver WalletBalanceCard.tsx completo
WalletBalanceCard.tsx
"use client";

/**
 * WalletBalanceCard — Generado por Concorde
 * Fuente: Figma VOYAGER · "WalletBalanceCard" (nodo 2020:13635)
 *
 * Tarjeta «Billetera» 375×221 (blanca, radius 16, drop shadow suave):
 *   · Header: CardTitle «BILLETERA» (brackets) + ProfileButton «Transacciones ›»
 *   · Divisor #E1E3E2
 *   · Filas SubasCoins / Saldo (label morado + valor morado bold)
 *   · CTA «Adquiere SubasCoins» (Button sm-guest, círculo + texto, centrado)
 */

import type { JSX, MouseEventHandler } from "react";
import CardTitle from "@/src/components/CardTitle";
import ProfileButton from "@/src/components/ProfileButton";

// ─── Types ────────────────────────────────────────────────────────────────────

export interface WalletBalanceCardProps {
  /** Título de la tarjeta (default "BILLETERA"). */
  title?: string;
  /** Valor de SubasCoins (default ">S< 0"). */
  subasCoins?: string;
  /** Valor de Saldo (default "US$ 0"). */
  saldo?: string;
  /** Acción / enlace del acceso «Transacciones». */
  onTransactions?: MouseEventHandler<HTMLElement>;
  transactionsHref?: string;
  /** Click del CTA «Adquiere SubasCoins». */
  onAcquire?: MouseEventHandler<HTMLButtonElement>;
  className?: string;
}

// ─── Self-contained CSS ───────────────────────────────────────────────────────

const STYLE_ID = "concorde-walletbalancecard-styles";

const STYLES = `
.wbc {
  box-sizing: border-box;
  width: 375px;
  height: 221px;
  border-radius: 16px;
  background: #ffffff;
  box-shadow: 0 0 8px 4px rgba(0,0,0,0.08);
  padding: 16px;
  display: flex;
  flex-direction: column;
  font-family: var(--vmc-font-display, "Plus Jakarta Sans", -apple-system, sans-serif);
}
.wbc__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.wbc__divider {
  height: 1px;
  background: #E1E3E2;
  margin-top: 8px;
}
.wbc__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding-top: 18px;
}
.wbc__rows {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0 4px;
}
.wbc__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.wbc__row-label { font-size: 15px; font-weight: 500; color: #3B1782; }
.wbc__row-value { font-size: 15px; font-weight: 700; color: #3B1782; }
.wbc__cta {
  margin-top: auto;
  display: flex;
  justify-content: center;
  padding-bottom: 4px;
}
/* Botón CTA autónomo — mismo look que sm-guest, texto realmente centrado */
.wbc__acquire {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 250px;
  height: 40px;
  padding: 0 16px;
  border-radius: 9999px;
  border: 2px solid transparent;
  cursor: pointer;
  overflow: hidden;
  font-family: var(--vmc-font-display, "Plus Jakarta Sans", sans-serif);
  font-size: 14px;
  font-weight: 600;
  color: #ffffff;
  text-shadow: rgba(0,0,0,0.2) 0 1px 2px;
  background-image:
    linear-gradient(135deg, #ED8936 0%, #ED8936 40%, #8460e5 100%),
    linear-gradient(135deg, #ffffff 0%, #fbc47d 25%, #ae8eff 75%, #ffffff 100%);
  background-origin: padding-box, border-box;
  background-clip: padding-box, border-box;
  box-shadow: rgba(255,255,255,0.25) 0 1px 0 2px inset, rgba(237,137,54,0.25) 0 2px 6px;
  transition: transform 0.2s cubic-bezier(0.25,0.8,0.25,1), box-shadow 0.25s;
}
.wbc__acquire::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 9999px;
  background: linear-gradient(rgba(255,255,255,0.15) 0%, transparent 55%);
  pointer-events: none;
}
.wbc__acquire-circle {
  position: absolute;
  left: 4px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255,255,255,0.2);
}
.wbc__acquire:hover {
  transform: translateY(-1px) scale(1.02);
  box-shadow: rgba(255,255,255,0.2) 0 1px 0 2px inset, rgba(132,96,229,0.3) 0 6px 18px, rgba(237,137,54,0.35) 0 3px 8px;
}
.wbc__acquire:active {
  transform: scale(0.97) translateY(1px);
  box-shadow: rgba(0,0,0,0.22) 0 2px 4px 2px inset;
}
@media (prefers-reduced-motion: reduce) { .wbc__acquire { transition: none; } }
`;

let _stylesInjected = false;

// ─── Component ────────────────────────────────────────────────────────────────

export default function WalletBalanceCard({
  title = "BILLETERA",
  subasCoins = ">S< 0",
  saldo = "US$ 0",
  onTransactions,
  transactionsHref,
  onAcquire,
  className = "",
}: WalletBalanceCardProps): JSX.Element {
  if (typeof document !== "undefined" && !_stylesInjected) {
    if (!document.getElementById(STYLE_ID)) {
      const el = document.createElement("style");
      el.id = STYLE_ID;
      el.textContent = STYLES;
      document.head.appendChild(el);
    }
    _stylesInjected = true;
  }

  return (
    <>
      <style id={`${STYLE_ID}-ssr`} suppressHydrationWarning dangerouslySetInnerHTML={{ __html: STYLES }} />
      <section className={["wbc", className].filter(Boolean).join(" ")} data-component="wallet-balance-card">
        {/* Header: título + acceso a transacciones */}
        <div className="wbc__header">
          <CardTitle title={title} subtitle="" titleSize={14} />
          <ProfileButton href={transactionsHref} onClick={onTransactions} aria-label="Transacciones">
            Transacciones
          </ProfileButton>
        </div>

        <div className="wbc__divider" />

        {/* Cuerpo: SubasCoins / Saldo + CTA */}
        <div className="wbc__body">
          <div className="wbc__rows">
            <div className="wbc__row">
              <span className="wbc__row-label">SubasCoins:</span>
              <span className="wbc__row-value">{subasCoins}</span>
            </div>
            <div className="wbc__row">
              <span className="wbc__row-label">Saldo:</span>
              <span className="wbc__row-value">{saldo}</span>
            </div>
          </div>

          <div className="wbc__cta">
            <button className="wbc__acquire" type="button" onClick={onAcquire}>
              <span className="wbc__acquire-circle" aria-hidden="true" />
              Adquiere SubasCoins
            </button>
          </div>
        </div>
      </section>
    </>
  );
}