UNPKG

react-paysofter

Version:

This is a ReactJS package for integrating Paysofter payment gateway into your ReactJS application.

311 lines (287 loc) 9.53 kB
// CardPayment.js import React, { useState, useEffect, useCallback } from "react"; import { Form, Button, Row, Col } from "react-bootstrap"; import "bootstrap/dist/css/bootstrap.min.css"; import Select from "react-select"; import { MONTH_CHOICES, YEAR_CHOICES } from "./payment-constants"; import Message from "./Message"; import MessageFixed from "./MessageFixed"; import Loader from "./Loader"; import { formatAmount } from "./FormatAmount"; import { PAYSOFTER_API_URL } from "./config/apiConfig"; import axios from "axios"; import SuccessScreen from "./SuccessScreen"; function CardPayment({ amount, currency, email, paysofterPublicKey, onSuccess, onClose, qty, productName, referenceId, buyerName, buyerPhoneNumber, }) { const [showSuccessMessage, setShowSuccessMessage] = useState(false); const [hasHandledSuccess, setHasHandledSuccess] = useState(false); const [monthChoices, setMonthChoices] = useState([]); const [yearChoices, setYearChoices] = useState([]); const [showSuccessScreen, setShowSuccessScreen] = useState(false); const [paymentSuccess, setPaymentSuccess] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); useEffect(() => { setMonthChoices(MONTH_CHOICES); setYearChoices(YEAR_CHOICES); }, []); const [cardType, setCardType] = useState(""); const [paymentDetails, setPaymentDetails] = useState({ cardNumber: "", expirationMonth: null, expirationYear: null, cvv: "", }); const [cvvVisible, setCvvVisible] = useState(false); const toggleCvvVisibility = () => setCvvVisible(!cvvVisible); const formatCard = (value) => { return value .replace(/\s?/g, "") .replace(/(\d{4})/g, "$1 ") .trim(); }; const handlePaymentDetailsChange = (name, value) => { if (name === "cardNumber") { value = formatCard(value); let detectedCardType = ""; if (/^4/.test(value)) { detectedCardType = "Visa"; } else if (/^5[1-5]/.test(value)) { detectedCardType = "Mastercard"; } setCardType(detectedCardType); } setPaymentDetails({ ...paymentDetails, [name]: value }); }; const isFormValid = () => { return ( paymentDetails.cardNumber && paymentDetails.expirationMonth && paymentDetails.expirationYear && paymentDetails.cvv ); }; const createdAt = new Date().toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: true, timeZoneName: "short", }); const paymentMethod = "Debit Card"; const submitHandler = async (e) => { e.preventDefault(); setLoading(true); setError(""); const paysofterPaymentData = { buyer_email: email, buyer_name: buyerName, buyer_phone: buyerPhoneNumber, qty: qty, product_name: productName, reference_id: referenceId, currency: currency, amount: amount, public_api_key: paysofterPublicKey, created_at: createdAt, payment_method: paymentMethod, card_number: paymentDetails.cardNumber, expiration_month: paymentDetails.expirationMonth, expiration_year: paymentDetails.expirationYear, cvv: paymentDetails.cvv, }; try { const { data } = await axios.post( `${PAYSOFTER_API_URL}/api/initiate-transaction/`, paysofterPaymentData ); console.log(data); setPaymentSuccess(true); handleOnSuccess(); setShowSuccessMessage(true); setTimeout(() => { // handleOnClose(); setShowSuccessMessage(false); setShowSuccessScreen(true); }, 3000); } catch (error) { setError( error.response && error.response.data.detail ? error.response.data.detail : error.message ); } finally { setLoading(false); } }; const handleOnSuccess = useCallback(() => { onSuccess(); }, [onSuccess]); // const handleOnClose = useCallback(() => { // onClose(); // }, [onClose]); useEffect(() => { if (paymentSuccess && !hasHandledSuccess) { setHasHandledSuccess(true); setShowSuccessMessage(true); // handleOnSuccess(); setTimeout(() => { setShowSuccessMessage(false); setShowSuccessScreen(true); }, 3000); } }, [paymentSuccess, hasHandledSuccess]); return ( <div> {showSuccessScreen ? ( <SuccessScreen /> ) : ( <div> <h2 className="py-2 text-center">Debit Card</h2> {showSuccessMessage && ( <Message variant="success">Payment made successfully.</Message> )} {error && <Message variant="danger">{error}</Message>} {loading && <Loader />} <Form onSubmit={submitHandler}> <Form.Group> <Form.Label>Card Number</Form.Label> <Form.Control type="text" name="cardNumber" value={paymentDetails.cardNumber} onChange={(e) => handlePaymentDetailsChange("cardNumber", e.target.value) } required placeholder="1234 5678 9012 3456" maxLength="19" /> </Form.Group> {cardType && ( <p> Detected Card Type: {cardType} {cardType === "Visa " && <i className="fab fa-cc-visa"></i>} {cardType === "Mastercard " && ( <i className="fab fa-cc-mastercard"></i> )} </p> )} <i className="fab fa-cc-mastercard"></i>{" "} <i className="fab fa-cc-visa"></i> <Row> <Col> <Form.Group> <Form.Label>Expiration Month</Form.Label> <Select options={monthChoices?.map(([value, label]) => ({ value, label, }))} onChange={(selectedOption) => handlePaymentDetailsChange( "expirationMonth", selectedOption.value ) } value={{ value: paymentDetails.expirationMonth, label: paymentDetails.expirationMonth, }} placeholder="Select Month" /> </Form.Group> </Col> <Col> <Form.Group> <Form.Label>Expiration Year</Form.Label> <Select options={yearChoices?.map(([value, label]) => ({ value, label, }))} value={{ value: paymentDetails.expirationYear, label: paymentDetails.expirationYear, }} onChange={(selectedOption) => handlePaymentDetailsChange( "expirationYear", selectedOption.value ) } placeholder="Select Year" /> </Form.Group> </Col> </Row> <Form.Group> <Form.Label>CVV</Form.Label> <Form.Control type={cvvVisible ? "text" : "password"} name="cvv" value={paymentDetails.cvv} onChange={(e) => handlePaymentDetailsChange("cvv", e.target.value) } required maxLength="3" placeholder="123" /> </Form.Group> <span className="d-flex justify-content-end"> <Button variant="outline" className="rounded" size="sm" onClick={toggleCvvVisibility} > {cvvVisible ? ( <span> <i className="fa fa-eye-slash"></i> Hide </span> ) : ( <span> <i className="fa fa-eye"></i> Show </span> )} </Button> </span> <div className="text-center w-100 mt-3 py-2"> <Button className="w-100 rounded" variant="primary" type="submit" disabled={!isFormValid() || loading} > Pay{" "} <span> ({formatAmount(amount)} {currency}) </span> </Button> </div> <div className="py-2 d-flex justify-content-center"> {error && <MessageFixed variant="danger">{error}</MessageFixed>} </div> </Form> </div> )} </div> ); } export default CardPayment;