UNPKG

react-native-credit-card-input-plus

Version:
265 lines (245 loc) 5.89 kB
import React, { useMemo, useEffect, useRef, useState } from "react"; import PropTypes from "prop-types"; import { View, ImageBackground, Image, Text, StyleSheet, Platform, } from "react-native"; import defaultIcons from "./Icons"; import CardFlip from "./CardFlip"; const BASE_SIZE = { width: 300, height: 190 }; const s = StyleSheet.create({ cardContainer: {}, cardFace: {}, icon: { position: "absolute", top: 15, right: 15, width: 60, height: 40, resizeMode: "contain", }, baseText: { color: "rgba(255, 255, 255, 0.8)", backgroundColor: "transparent", }, placeholder: { color: "rgba(255, 255, 255, 0.5)", }, focused: { fontWeight: "bold", color: "rgba(255, 255, 255, 1)", }, number: { fontSize: 21, position: "absolute", top: 95, left: 28, }, name: { fontSize: 16, position: "absolute", bottom: 20, left: 25, right: 100, }, expiryLabel: { fontSize: 9, position: "absolute", bottom: 40, left: 218, }, expiry: { fontSize: 16, position: "absolute", bottom: 20, left: 220, }, amexCVC: { fontSize: 16, position: "absolute", top: 73, right: 30, }, cvc: { fontSize: 16, position: "absolute", top: 80, right: 30, }, }); const CardView = ({ focused, brand, name, number, expiry, cvc, customIcons, placeholder, imageFront, imageBack, scale, fontFamily, }) => { const Icons = { ...defaultIcons, ...customIcons }; const containerSize = { ...BASE_SIZE, height: BASE_SIZE.height * scale }; const transform = { transform: [ { scale }, { translateY: (BASE_SIZE.height * (scale - 1)) / 2 }, ], }; /** * Ref */ const cardFlipRef = useRef(null); /** * States */ const [sideFlip, setSideFlip] = useState("FRONT"); /** * Check if is amex card */ const isAmex = useMemo(() => brand === "american-express", [brand]); /** * Check if can flip card */ const shouldFlip = useMemo( () => !isAmex && focused === "cvc", [isAmex, focused] ); const onFlipCard = (side) => { if (!cardFlipRef.current) { return; } setSideFlip(side); cardFlipRef.current.flip(); }; /** * Manage state of the flip */ useEffect(() => { if (shouldFlip && sideFlip === "FRONT") { onFlipCard("BACK"); } else if (sideFlip === "BACK") { onFlipCard("FRONT"); } }, [shouldFlip]); return ( <View style={[s.cardContainer, containerSize]}> <CardFlip ref={cardFlipRef} perspective={2000} flipZoom={0.02}> <ImageBackground style={[BASE_SIZE, s.cardFace, transform]} source={imageFront} > <Image style={[s.icon]} source={Icons[brand]} /> <Text style={[ s.baseText, { fontFamily }, s.number, !number && s.placeholder, focused === "number" && s.focused, ]} > {!number ? placeholder.number : number} </Text> <Text style={[ s.baseText, { fontFamily }, s.name, !name && s.placeholder, focused === "name" && s.focused, ]} numberOfLines={1} > {!name ? placeholder.name : name.toUpperCase()} </Text> <Text style={[ s.baseText, { fontFamily }, s.expiryLabel, s.placeholder, focused === "expiry" && s.focused, ]} > MONTH/YEAR </Text> <Text style={[ s.baseText, { fontFamily }, s.expiry, !expiry && s.placeholder, focused === "expiry" && s.focused, ]} > {!expiry ? placeholder.expiry : expiry} </Text> {isAmex && ( <Text style={[ s.baseText, { fontFamily }, s.amexCVC, !cvc && s.placeholder, focused === "cvc" && s.focused, ]} > {!cvc ? placeholder.cvc : cvc} </Text> )} </ImageBackground> <ImageBackground style={[BASE_SIZE, s.cardFace, transform]} source={imageBack} > <Text style={[ s.baseText, s.cvc, !cvc && s.placeholder, focused === "cvc" && s.focused, ]} > {!cvc ? placeholder.cvc : cvc} </Text> </ImageBackground> </CardFlip> </View> ); }; CardView.propTypes = { focused: PropTypes.string, brand: PropTypes.string, name: PropTypes.string, number: PropTypes.string, expiry: PropTypes.string, cvc: PropTypes.string, placeholder: PropTypes.object, scale: PropTypes.number, fontFamily: PropTypes.string, imageFront: PropTypes.number, imageBack: PropTypes.number, customIcons: PropTypes.object, }; CardView.defaultProps = { name: "", placeholder: { number: "•••• •••• •••• ••••", name: "FULL NAME", expiry: "••/••", cvc: "•••", }, scale: 1, fontFamily: Platform.select({ ios: "Courier", android: "monospace" }), imageFront: require("../images/card-front.png"), imageBack: require("../images/card-back.png"), }; export default CardView;