An elegant black and gold credit card checkout component with interactive 3D card visualization Long description A premium credit card checkout component featuring a stunning black and gold design with real-time card visualization. The component includes a 3D flipping card that updates as users enter their information, automatic card type detection, input formatting, and form validation. The luxurious design includes gold accents, patterns, and elegant typography, making it perfect for high-end e-commerce sites and premium services.
"use client"
import type React from "react"
import { useState, useEffect } from "react"
import { motion } from "framer-motion"
import { CreditCard, Check, Lock } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils"
export default function CreditCardCheckout() {
const [flipped, setFlipped] = useState(false)
const [cardDetails, setCardDetails] = useState({
number: "",
name: "",
expiry: "",
cvc: "",
})
const [isComplete, setIsComplete] = useState(false)
// Format card number with spaces
const formatCardNumber = (value: string) => {
const v = value.replace(/\s+/g, "").replace(/[^0-9]/gi, "")
const matches = v.match(/\d{4,16}/g)
const match = (matches && matches[0]) || ""
const parts = []
for (let i = 0, len = match.length; i < len; i += 4) {
parts.push(match.substring(i, i + 4))
}
if (parts.length) {
return parts.join(" ")
} else {
return value
}
}
// Format expiry date
const formatExpiry = (value: string) => {
const v = value.replace(/\s+/g, "").replace(/[^0-9]/gi, "")
if (v.length >= 3) {
return `${v.substring(0, 2)}/${v.substring(2, 4)}`
}
return value
}
// Handle input changes
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target
if (name === "number") {
setCardDetails({
...cardDetails,
[name]: formatCardNumber(value),
})
} else if (name === "expiry") {
setCardDetails({
...cardDetails,
[name]: formatExpiry(value),
})
} else {
setCardDetails({
...cardDetails,
[name]: value,
})
}
}
// Focus on CVC field
const handleCVCFocus = () => {
setFlipped(true)
}
// Blur from CVC field
const handleCVCBlur = () => {
setFlipped(false)
}
// Check if form is complete
useEffect(() => {
if (
cardDetails.number.replace(/\s/g, "").length === 16 &&
cardDetails.name.length > 3 &&
cardDetails.expiry.length === 5 &&
cardDetails.cvc.length === 3
) {
setIsComplete(true)
} else {
setIsComplete(false)
}
}, [cardDetails])
// Handle form submission
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (isComplete) {
alert("Payment successful!")
}
}
// Get card type based on first digits
const getCardType = () => {
const number = cardDetails.number.replace(/\s+/g, "")
if (number.startsWith("4")) {
return "visa"
} else if (/^5[1-5]/.test(number)) {
return "mastercard"
} else if (/^3[47]/.test(number)) {
return "amex"
} else if (/^6(?:011|5)/.test(number)) {
return "discover"
}
return "unknown"
}
const cardType = getCardType()
return (
<div className="w-full max-w-4xl mx-auto p-6 bg-gradient-to-br from-slate-900 to-slate-800 rounded-xl shadow-lg">
<div className="flex flex-col lg:flex-row gap-8">
<div className="w-full lg:w-1/2 flex flex-col justify-center items-center">
<h2 className="text-2xl font-bold mb-6 text-yellow-400">Secure Checkout</h2>
{/* Credit Card Visualization */}
<div className="relative w-full max-w-sm h-56 perspective">
<motion.div
className={cn(
"absolute w-full h-full transition-all duration-500 preserve-3d",
flipped ? "rotate-y-180" : "",
)}
initial={false}
animate={{ rotateY: flipped ? 180 : 0 }}
transition={{ duration: 0.6 }}
>
{/* Front of card */}
<div className="absolute w-full h-full backface-hidden rounded-xl p-6 shadow-md bg-gradient-to-br from-black to-slate-900 overflow-hidden">
{/* Gold pattern overlay */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-[radial-gradient(#FFD700_1px,transparent_1px)] bg-[size:10px_10px]"></div>
</div>
{/* Gold accent line */}
<div className="absolute top-0 right-0 h-full w-1 bg-gradient-to-b from-yellow-400 to-yellow-600"></div>
<div className="flex justify-between items-start relative z-10">
<div className="w-12 h-12 rounded-full bg-gradient-to-r from-yellow-300 to-yellow-500 flex items-center justify-center shadow-lg">
<CreditCard className="text-black" size={24} />
</div>
<div className="text-yellow-400 font-bold uppercase tracking-wider">
{cardType !== "unknown" ? cardType : "Card"}
</div>
</div>
<div className="mt-6 relative z-10">
<div className="h-8 w-12 bg-gradient-to-br from-yellow-300 to-yellow-600 rounded-md mb-6 shadow-md"></div>
<div className="text-xl font-mono tracking-wider text-yellow-400 font-semibold">
{cardDetails.number || "•••• •••• •••• ••••"}
</div>
</div>
<div className="mt-6 flex justify-between relative z-10">
<div>
<div className="text-xs text-yellow-500/70 uppercase font-semibold">Card Holder</div>
<div className="text-yellow-400 font-medium truncate max-w-[150px]">
{cardDetails.name || "YOUR NAME"}
</div>
</div>
<div>
<div className="text-xs text-yellow-500/70 uppercase font-semibold">Expires</div>
<div className="text-yellow-400 font-medium">{cardDetails.expiry || "MM/YY"}</div>
</div>
</div>
{/* Gold corner accent */}
<div className="absolute bottom-0 right-0 w-24 h-24 bg-gradient-to-tl from-yellow-400/20 to-transparent rounded-tl-full"></div>
</div>
{/* Back of card */}
<div className="absolute w-full h-full backface-hidden rounded-xl shadow-md bg-gradient-to-br from-black to-slate-900 rotate-y-180 overflow-hidden">
{/* Gold pattern overlay */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-[radial-gradient(#FFD700_1px,transparent_1px)] bg-[size:10px_10px]"></div>
</div>
{/* Gold accent line */}
<div className="absolute top-0 left-0 h-full w-1 bg-gradient-to-b from-yellow-400 to-yellow-600"></div>
<div className="w-full h-12 bg-gradient-to-r from-yellow-500 to-yellow-700 mt-6"></div>
<div className="px-6 mt-6 relative z-10">
<div className="flex justify-end items-center">
<div className="bg-slate-800 h-10 w-full max-w-[80%] rounded-md flex items-center px-4 justify-end border border-yellow-500/30">
<div className="font-mono text-yellow-400">{cardDetails.cvc || "•••"}</div>
</div>
</div>
<div className="mt-6 text-xs text-yellow-500/70 text-right font-semibold">CVC security code</div>
</div>
{/* Gold corner accent */}
<div className="absolute bottom-0 left-0 w-24 h-24 bg-gradient-to-tr from-yellow-400/20 to-transparent rounded-tr-full"></div>
</div>
</motion.div>
</div>
</div>
<div className="w-full lg:w-1/2">
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-2">
<Label htmlFor="number">Card Number</Label>
<div className="relative">
<Input
id="number"
name="number"
placeholder="1234 5678 9012 3456"
value={cardDetails.number}
onChange={handleInputChange}
maxLength={19}
className="pl-10"
required
/>
<CreditCard className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400" size={16} />
</div>
</div>
<div className="space-y-2">
<Label htmlFor="name">Cardholder Name</Label>
<Input
id="name"
name="name"
placeholder="John Doe"
value={cardDetails.name}
onChange={handleInputChange}
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="expiry">Expiry Date</Label>
<Input
id="expiry"
name="expiry"
placeholder="MM/YY"
value={cardDetails.expiry}
onChange={handleInputChange}
maxLength={5}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="cvc">CVC</Label>
<Input
id="cvc"
name="cvc"
placeholder="123"
value={cardDetails.cvc}
onChange={handleInputChange}
maxLength={3}
onFocus={handleCVCFocus}
onBlur={handleCVCBlur}
required
/>
</div>
</div>
<div className="pt-4">
<Button
type="submit"
className={cn(
"w-full transition-all duration-300",
isComplete
? "bg-gradient-to-r from-yellow-600 to-yellow-500 hover:from-yellow-700 hover:to-yellow-600 text-black"
: "bg-slate-800 hover:bg-slate-900 text-yellow-500",
)}
disabled={!isComplete}
>
{isComplete ? (
<span className="flex items-center">
<Check className="mr-2" size={18} />
Complete Payment
</span>
) : (
<span className="flex items-center">
<Lock className="mr-2" size={18} />
Complete Payment
</span>
)}
</Button>
</div>
<div className="text-xs text-center text-slate-500 flex items-center justify-center">
<Lock size={12} className="mr-1" />
Your payment information is secure and encrypted
</div>
</form>
</div>
</div>
</div>
)
}npx shadcn@latest add @react-market/credit-card-checkoutimport { CreditCardCheckout } from "@/components/credit-card-checkout"<CreditCardCheckout />