CreditCardVisual
DomainAnimated 3-D flip credit card. Front shows number, name, expiry; back shows CVV strip. Supports VISA, Mastercard, AMEX, Discover.
<%- include('modules/domain/common/payment/CreditCardVisual', {
brand: 'VISA', cardNumber: '4111111111111111',
cardholderName: 'JANE DOE', expiryMonth: '08', expiryYear: '28'
}) %>
<%- include('modules/domain/common/payment/CreditCardVisual', {
brand: 'AMEX', cardNumber: '378282246310005',
cardholderName: 'JANE DOE', expiryMonth: '03', expiryYear: '26',
cvv: '1234', flipped: true
}) %>
<%
var _brand = (locals.brand || 'UNKNOWN').toUpperCase();
var _number = locals.cardNumber || '';
var _name = locals.cardholderName || '';
var _month = locals.expiryMonth || 'MM';
var _year = locals.expiryYear || 'YY';
var _cvv = locals.cvv || '';
var _flipped = !!locals.flipped;
var brandStyle = {
VISA: { label: 'VISA', gradient: 'linear-gradient(135deg,#1A1F71,#0A0F3D)' },
MASTERCARD:{ label: 'Mastercard',gradient: 'linear-gradient(135deg,#EB001B,#F79E1B,#FF5F00)' },
AMEX: { label: 'AMEX', gradient: 'linear-gradient(135deg,#2E77BC,#006FCF)' },
DISCOVER: { label: 'Discover', gradient: 'linear-gradient(135deg,#F58220,#111827)' },
TROY: { label: 'TROY', gradient: 'linear-gradient(135deg,#00AEEF,#003B71,#111827)' },
MIR: { label: 'MIR', gradient: 'linear-gradient(135deg,#00A551,#0072BC,#111827)' },
UNIONPAY: { label: 'UnionPay', gradient: 'linear-gradient(135deg,#E21836,#00447C,#007A3D)' },
JCB: { label: 'JCB', gradient: 'linear-gradient(135deg,#0B5CAD,#D71920,#009A44)' },
UNKNOWN: { label: '', gradient: 'linear-gradient(135deg,#4B5563,#111827)' },
};
var bs = brandStyle[_brand] || brandStyle.UNKNOWN;
var digits = _number.replace(/\D/g, '');
var isAmex = _brand === 'AMEX';
var maxLen = isAmex ? 15 : 16;
var padded = digits.padEnd(maxLen, '•');
var masked;
if (isAmex) {
masked = padded.slice(0,4) + ' ' + padded.slice(4,10) + ' ' + padded.slice(10,15);
} else {
masked = padded.slice(0,4) + ' ' + padded.slice(4,8) + ' ' + padded.slice(8,12) + ' ' + padded.slice(12,16);
}
var cvvStars = _cvv ? '•'.repeat(_cvv.length) : '•••';
%>
<div class="w-72 h-44 select-none<%= locals.className ? ' ' + locals.className : '' %>"
data-credit-card-visual
data-flipped="<%= _flipped ? 'true' : 'false' %>"
style="perspective:1000px" aria-hidden="true">
<div class="relative w-full h-full transition-transform duration-500"
style="transform-style:preserve-3d;transform:<%= _flipped ? 'rotateY(180deg)' : 'rotateY(0deg)' %>">
<%# Front %>
<div class="absolute inset-0 rounded-2xl p-5 flex flex-col justify-between shadow-xl text-white"
style="background:<%= bs.gradient %>;backface-visibility:hidden">
<div class="flex justify-between items-start">
<div class="flex gap-1">
<div class="w-8 h-6 rounded" style="background:rgba(250,204,21,.8)"></div>
<div class="w-8 h-6 rounded -ml-3" style="background:rgba(253,224,71,.5)"></div>
</div>
<% if (bs.label) { %>
<span class="text-sm font-bold tracking-widest" style="opacity:.9"><%= bs.label %></span>
<% } %>
</div>
<p class="font-mono text-lg tracking-widest"><%= masked %></p>
<div class="flex justify-between items-end">
<div>
<p class="uppercase mb-0.5" style="font-size:9px;opacity:.6">Card Holder</p>
<p class="text-xs font-medium tracking-wide uppercase truncate" style="max-width:10rem">
<%= _name || '••••• •••••' %>
</p>
</div>
<div class="text-right">
<p class="uppercase mb-0.5" style="font-size:9px;opacity:.6">Expires</p>
<p class="text-xs font-medium font-mono"><%= _month %>/<%= _year %></p>
</div>
</div>
</div>
<%# Back %>
<div class="absolute inset-0 rounded-2xl shadow-xl overflow-hidden text-white"
style="background:<%= bs.gradient %>;backface-visibility:hidden;transform:rotateY(180deg)">
<div class="mt-7 h-10 w-full" style="background:rgba(0,0,0,.6)"></div>
<div class="px-5 mt-4 flex items-center justify-end gap-3">
<div class="flex-1 h-6 rounded" style="background:rgba(255,255,255,.2)"></div>
<div class="rounded px-3 py-1 text-right min-w-[3.5rem]" style="background:rgba(255,255,255,.9)">
<p class="text-gray-500 mb-0.5" style="font-size:9px">CVV</p>
<p class="font-mono text-sm text-gray-800 tracking-widest"><%= cvvStars %></p>
</div>
</div>
<% if (bs.label) { %>
<p class="absolute bottom-4 right-5 text-sm font-bold tracking-widest" style="opacity:.8"><%= bs.label %></p>
<% } %>
</div>
</div>
</div>