payment-method-icon
Paquete: @tiendana/ngx-core/ui
Componente para mostrar iconos de métodos de pago con soporte para tarjetas de crédito (franchises) y métodos personalizados.
Características
✅ Iconos para franchises de tarjetas (Visa, Mastercard, etc.)
✅ Logos personalizados desde CloudFront
✅ Máscara de tarjeta (últimos 4 dígitos)
✅ Posicionamiento configurable
✅ Tamaño small opcional
API
Inputs
| Input | Tipo | Default | Descripción |
|---|---|---|---|
data | PaymentMethod | undefined | null | - (requerido) | Datos del método de pago |
cardJson | any | undefined | JSON con datos de tarjeta (franchise, mask). Si tiene valor, se dibuja la tarjeta en lugar del logo |
position | 'center' | 'left' | 'right' | null | null | Alineación del contenido |
hasLabels | boolean | true | Muestra el número enmascarado de la tarjeta (solo con cardJson); el nombre del método se muestra siempre |
small | boolean | false | Versión pequeña |
Tipos
interface PaymentMethod {
name: string;
logo?: Attachment;
type: PaymentType;
}
// Forma esperada (el input es `any`, no es un tipo exportado)
interface CardJson {
franchise: string; // 'visa' | 'master' | 'amex'
mask: string; // '****1234'
}
Uso
Método de Pago Genérico
<payment-method-icon [data]="paymentMethod" />
Tarjeta con Franchise
<payment-method-icon
[data]="paymentMethod"
[cardJson]="{ franchise: 'visa', mask: '****4532' }"
/>
Sin Labels
<payment-method-icon
[data]="paymentMethod"
[cardJson]="{ franchise: 'visa', mask: '****4532' }"
[hasLabels]="false"
/>
Small Size
<payment-method-icon
[data]="paymentMethod"
[small]="true"
/>
Con Posicionamiento
<payment-method-icon
[data]="paymentMethod"
[position]="'center'"
/>
Template Interno
@if (hasValue(cardJson())) {
<!-- Tarjeta con franchise -->
<div class="icon tc" [ngClass]="cardJson()?.franchise!"></div>
@if (hasLabels()) {
<div>{{ cardJson()?.mask }}</div>
}
} @else {
<!-- Método personalizado -->
<img
[cfSrc]="data()?.logo"
defaultCfsrc="assets/icons/common/custom-payment.svg"
alt="Logo"
/>
<div>{{ data()?.name }}</div>
}
Franchises Soportadas
La clase .tc con [ngClass] aplica estilos para:
visamaster(Mastercard)amex
Cualquier otro valor de franchise agrega esa clase al icono, pero no trae imagen: el icono queda vacío.
Ejemplo Completo
@Component({
template: `
<h3>Métodos de Pago</h3>
@for (item of paymentMethods(); track item.method.id) {
<payment-method-icon
[data]="item.method"
[cardJson]="item.card"
[position]="'left'"
/>
}
`
})
export class PaymentMethodsComponent {
// Los datos de tarjeta van fuera de PaymentMethod
paymentMethods = signal<{ method: PaymentMethod; card?: { franchise: string; mask: string } }[]>([
{
method: visaMethod,
card: { franchise: 'visa', mask: '****1234' }
},
{
method: paypalMethod
}
]);
}
Host Classes
host: {
'[class.small]': 'small()',
'[class]': 'position()'
}
Aplica clases dinámicas:
<!-- Con small y position -->
<payment-method-icon class="small center">
<!-- Contenido -->
</payment-method-icon>
Default Fallback
Si no hay logo, usa icono default:
<img
[cfSrc]="data()?.logo"
defaultCfsrc="assets/icons/common/custom-payment.svg"
/>
Estilos
:host {
display: flex;
gap: 16px;
align-items: center;
justify-content: flex-end; // posición por defecto
img {
width: var(--icon-size, 40px);
height: var(--icon-size, 40px);
object-fit: contain;
}
&.small { --icon-size: 20px; }
&.center { justify-content: center; }
&.left { justify-content: flex-start; }
&.right { justify-content: flex-end; }
.icon.tc {
&.visa {
width: var(--icon-visa-width, 73px);
height: var(--icon-visa-height, 60px);
}
&.master {
width: var(--icon-master-width, 73px);
height: var(--icon-master-height, 60px);
}
&.amex {
width: var(--icon-amex-size, 50px);
height: var(--icon-amex-size, 50px);
}
}
}
Variables CSS que puedes sobrescribir: --icon-size (40px, 20px con small), --icon-visa-width, --icon-visa-height, --icon-master-width, --icon-master-height y --icon-amex-size. Las imágenes de las franquicias se cargan desde cdn-public.tiendana.com/assets/images/.
Casos de Uso
Lista de Métodos Guardados
<div class="saved-methods">
@for (method of userPaymentMethods(); track method.id) {
<div class="method-item">
<payment-method-icon
[data]="method"
[cardJson]="method.card"
[position]="'left'"
/>
<button (click)="selectMethod(method)">Usar</button>
</div>
}
</div>
Checkout Summary
<div class="checkout-summary">
<h4>Método de Pago</h4>
<payment-method-icon
[data]="selectedPayment()"
[cardJson]="selectedPayment()?.card"
[hasLabels]="true"
/>
</div>
Small Icons en Lista
<ul class="payment-options">
@for (option of options; track option.id) {
<li>
<payment-method-icon
[data]="option"
[small]="true"
[cardJson]="option.card"
[hasLabels]="false"
/>
</li>
}
</ul>
Validación de Datos
import { hasValue } from '@tiendana/utils';
// En template
@if (hasValue(cardJson())) {
<!-- Render tarjeta -->
}
Accesibilidad
- La imagen tiene
alt="Logo"por defecto - Considera agregar
altdescriptivo para cada método - Usa
aria-labelen elementos interactivos
<payment-method-icon
[data]="method"
role="img"
[attr.aria-label]="method.name + ' - ' + method.card?.mask"
/>