Saltar al contenido principal

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​

InputTipoDefaultDescripción
dataPaymentMethod | undefined | null- (requerido)Datos del método de pago
cardJsonanyundefinedJSON con datos de tarjeta (franchise, mask). Si tiene valor, se dibuja la tarjeta en lugar del logo
position'center' | 'left' | 'right' | nullnullAlineación del contenido
hasLabelsbooleantrueMuestra el número enmascarado de la tarjeta (solo con cardJson); el nombre del método se muestra siempre
smallbooleanfalseVersió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:

  • visa
  • master (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 alt descriptivo para cada método
  • Usa aria-label en elementos interactivos
<payment-method-icon 
[data]="method"
role="img"
[attr.aria-label]="method.name + ' - ' + method.card?.mask"
/>