I am trying to integrate the react-payment-inputs
hook with my custom credit card component but after doing that, it messes with the styles of my component and its looking really messed up.
import React, { useState } from 'react';
import { PaymentInputsWrapper, usePaymentInputs } from 'react-payment-inputs';
import images from 'react-payment-inputs/images';
import CardChip from '../../assets/card-chip.png';
import ContactlessOutlinedIcon from "@mui/icons-material/ContactlessOutlined";
import styled from 'styled-components';
const CardContainer = styled.div`
perspective: 1000px;
`;
const CardWrapper = styled.div<{ isFlipped: boolean }>`
width: 350px;
height: 200px;
background: #117922;
color: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
transform-style: preserve-3d;
transition: transform 0.8s ease;
cursor: pointer;
transform: ${({ isFlipped }) => (isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)')};
`;
const CardFace = styled.div`
position: absolute;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
border-radius: 20px;
`;
const FrontCard = styled(CardFace)`
background-color: #117922;
`;
const BackCard = styled(CardFace)`
background-color: #333;
transform: rotateY(180deg);
`;
const MagneticStrip = styled.div`
height: 40px;
background: #000;
margin-top: 20px;
border-radius: 5px;
`;
const Signature = styled.div`
margin-top: 20px;
height: 40px;
background: #eee;
border-radius: 5px;
padding: 10px;
color: #333;
font-size: 13px;
`;
const CardNumber = styled.div`
font-size: 21px;
letter-spacing: 3px;
text-shadow: 0px 2px #333;
`;
const CardHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
const CardHolder = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;
const CardHolderName = styled.div`
text-transform: uppercase;
font-size: 15px;
text-shadow: 0px 2px #333;
`;
const ExpiryDate = styled.div`
font-size: 16px;
text-shadow: 0px 2px #333;
`;
const Cvv = styled.div`
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
text-align: right;
font-weight: 500;
`;
const CardInputWrapper = styled.div`
margin-top: 30px;
display: flex;
flex-direction: column;
gap: 15px;
width: 350px;
`;
const Input = styled.input`
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 8px;
width: 100%;
box-sizing: border-box;
&:focus {
outline: none;
border-color: #4e54c8;
}
`;
export const CreditCard:React.FC = ()=> {
const {
wrapperProps,
getCardImageProps,
getCardNumberProps,
getExpiryDateProps,
getCVCProps,
} = usePaymentInputs();
const [cardNumber, setCardNumber] = useState<string>("#### #### #### ####");
const [cardHolder, setCardHolder] = useState<string>("John Doe");
const [expiryDate, setExpiryDate] = useState<string>("MM/YY");
const [cvv, setCvv] = useState<string>("***");
const [isFlipped, setIsFlipped] = useState<boolean>(false);
const handlecvvFocus = ()=> {
setIsFlipped(true);
}
const handlecvvBlur = ()=> {
setIsFlipped(false);
}
const handleExpiryDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let input = e.target.value.replace(/D/g, '');
if (input.length <= 4) {
if (input.length >= 3) {
input = `${input.slice(0, 2)}/${input.slice(2, 4)}`;
}
setExpiryDate(input);
}
};
const handleCardNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let input = e.target.value.replace(/D/g, "");
if (input.length <= 16) {
input = input.replace(/(.{4})/g, "$1 ").trim();
setCardNumber(input);
}
};
const handleCardCvvChange = (e: React.ChangeEvent<HTMLInputElement>)=> {
const input = e.target.value.replace(/D/g, "");
if(input.length <= 3) {
setCvv(input);
}
}
return (
<div>
<PaymentInputsWrapper {...wrapperProps}>
<CardContainer onClick={()=> setIsFlipped(!isFlipped)}>
<CardWrapper isFlipped={isFlipped}>
{/* Front of the card */}
<FrontCard>
<CardHeader>
<img src={CardChip} />
<ContactlessOutlinedIcon />
</CardHeader>
<CardNumber>
{cardNumber}
</CardNumber>
<CardHolder>
<CardHolderName>
<div className='text-[10px] tracking-wide text-white mb-1 text-uppercase'>card holder</div>
{cardHolder}
</CardHolderName>
<ExpiryDate>{expiryDate}</ExpiryDate>
</CardHolder>
</FrontCard>
{/* Back of the card */}
<BackCard>
<MagneticStrip />
<Signature>Signature</Signature>
<Cvv>Cvv: {cvv}</Cvv>
</BackCard>
</CardWrapper>
</CardContainer>
<CardInputWrapper>
<svg {...getCardImageProps({ images })} />
<Input
{...getCardNumberProps()}
type="text"
placeholder="Card Number"
maxLength={16}
onChange={handleCardNumberChange}
/>
<Input
type="text"
placeholder="Card Holder"
value={cardHolder}
onChange={(e)=> setCardHolder(e.target.value)}
/>
<Input
{...getExpiryDateProps()}
type="text"
placeholder="Expiry Date (MM/YY)"
value={expiryDate}
maxLength={5}
onChange={handleExpiryDateChange}
/>
<Input
{...getCVCProps()}
type="password"
placeholder="CVV"
value={cvv}
maxLength={3}
onChange={handleCardCvvChange}
onFocus={handlecvvFocus}
onBlur={handlecvvBlur}
/>
</CardInputWrapper>
</PaymentInputsWrapper>
</div>
);
}
I have tried using inline-css to solve the problem, even tried chat-gpt but I am really stuck.
New contributor
Abdulmalik Abdulrahman is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1