diff --git a/src/components/Helpers/Icons.jsx b/src/components/Helpers/Icons.jsx index a73d9a5..bb54399 100644 --- a/src/components/Helpers/Icons.jsx +++ b/src/components/Helpers/Icons.jsx @@ -504,11 +504,11 @@ export default function Icons({ name }) { > ) : name === "atm-card" ? ( - card + card ) : name === "visa-card" ? ( - card + card ) : name === "master-card" ? ( - card + card ) : name === "new-dashboard" ? ( dashboard ) : name === "new-family" ? ( diff --git a/src/components/Helpers/Inputs/InputCom/index.jsx b/src/components/Helpers/Inputs/InputCom/index.jsx index 83061e6..11c9cb8 100644 --- a/src/components/Helpers/Inputs/InputCom/index.jsx +++ b/src/components/Helpers/Inputs/InputCom/index.jsx @@ -21,6 +21,9 @@ export default function InputCom({ blurHandler, spanTag, inputBg, + onInput, + maxLength = 30, + minLength = 0, direction, error, }) { @@ -29,13 +32,13 @@ export default function InputCom({ // for Min Length: const minLengthValidation = () => { const inputConfig = inputConfigs[inputRef?.current?.name]?.minLength; - return inputConfig || 0; + return inputConfig || minLength; }; // for MaxLength const maxLengthValidation = () => { const inputConfig = inputConfigs[inputRef?.current?.name]?.maxLength; - return inputConfig || 30; + return inputConfig || maxLength; }; // for Patterns @@ -63,7 +66,9 @@ export default function InputCom({ )} {/* displays error is any */} - {error && {error}} + {error && ( + {error} + )} )} {forgotPassword && ( @@ -76,7 +81,11 @@ export default function InputCom({ )}
)} {passIcon && ( -
+
)} @@ -128,7 +135,8 @@ const inputConfigs = { amount: { minLength: 1, maxLength: 9, pattern: "[0-9]+" }, description: { minLength: 5, maxLength: 299 }, title: { minLength: 5, maxLength: 149 }, - job_detail: { minLength: 4, maxLength: 1440 } + job_detail: { minLength: 4, maxLength: 1440 }, + cardNum: { minLength: 4, maxLength: 19 }, }; /* Numbers Only: strictly numbers diff --git a/src/components/MyWallet/Popup/AddFundDollars.jsx b/src/components/MyWallet/Popup/AddFundDollars.jsx index f9bbfa1..b60c3ae 100644 --- a/src/components/MyWallet/Popup/AddFundDollars.jsx +++ b/src/components/MyWallet/Popup/AddFundDollars.jsx @@ -1,22 +1,31 @@ -import React, { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import { Form, Formik } from "formik"; +import { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import * as Yup from "yup"; import usersService from "../../../services/UsersService"; +import Icons from "../../Helpers/Icons"; import InputCom from "../../Helpers/Inputs/InputCom"; import LoadingSpinner from "../../Spinners/LoadingSpinner"; -import { Form, Formik } from "formik"; -import { useSelector } from "react-redux"; -import * as Yup from "yup"; -import Icons from "../../Helpers/Icons"; - const validationSchema = Yup.object().shape({ - name: Yup.string() - .min(3, "3 chars min.") - .max(50, "50 chars max.") - .required("required"), cardNum: Yup.string() - .min(3, "3 chars min.") - .max(25, "25 chars max.") + .min(6, "not a card number") + .max(19, "16 chars max.") //16 chars + 3 spaces + .test("luhn-validation", "Invalid Card Number", (value) => { + const sanitizedNumber = value?.replace(/\D/g, ""); + const digits = Array?.from(sanitizedNumber, Number); + + for (let i = digits.length - 2; i >= 0; i -= 2) { + digits[i] *= 2; + if (digits[i] > 9) { + digits[i] -= 9; + } + } + + const sum = digits.reduce((acc, digit) => acc + digit, 0); + + return sum % 10 === 0; + }) .required("required"), code: Yup.string() .min(3, "3 chars min.") @@ -45,7 +54,6 @@ const validationSchema = Yup.object().shape({ }); const initialValues = { - name: "", cardNum: "", code: "", state: "", @@ -56,25 +64,53 @@ const initialValues = { }; function AddFundDollars(props) { - const navigate = useNavigate(); const apiCall = new usersService(); let countryWallet = props.walletItem.country; const [tab, setTab] = useState("previous"); - const [loader, setLoader] = useState(false); const { userDetails } = useSelector((state) => state?.userDetails); - const { firstname, lastname } = userDetails; const [prevCardDetails, setPrevCardDetails] = useState({}); const [payListCards, setPayListCards] = useState({ loading: true, data: [] }); - let __awaitComponent = props.confirmCredit.show.awaitConfirm; - let __acceptComponent = props.confirmCredit.show.awaitConfirm; + const [cardIcons, setCardIcons] = useState("atm-card"); + + const { firstname, lastname } = userDetails; + + // Handling Card Icons + const handleCards = (event) => { + const { name, value } = event.target; + + if (name == "cardNum") { + // Check if the first character is 4 or 5 and set the card icon accordingly + const cardIcon = + value.length > 0 + ? value[0] === "4" + ? "visa-card" + : value[0] === "5" + ? "master-card" + : "atm-card" + : "atm-card"; + setCardIcons(cardIcon); + } + }; + + // Handling card change const handleInputChange = (event) => { const { name, value } = event.target; + setPrevCardDetails((prevState) => ({ ...prevState, [name]: value, })); }; + // Handling card number grouping + const handleCardNumberChange = (value) => { + return value + ?.replace(/\s/g, "") // Remove existing spaces + .match(/.{1,4}/g) // Group every four characters + ?.join(" "); + }; + + // card slicer const indexOfFirstItem = 0; const indexOfLastItem = indexOfFirstItem + Number(process.env.REACT_APP_ITEM_PER_PAGE); @@ -83,78 +119,70 @@ function AddFundDollars(props) { indexOfLastItem ); + // Submission for both prev and new cards const handleSubmit = async (values, helpers) => { props.setInputError(""); if (!props.input || props.input === "0") { props.setInputError("Please Enter Amount"); + setTimeout(() => props.setInputError(""), 5000); return; } if (isNaN(props.input)) { props.setInputError("Amount must be a Number"); + setTimeout(() => props.setInputError(""), 5000); return; } if (tab === "previous") { - if (!prevCardDetails) { + // To check if card is empty + if (Object.keys(prevCardDetails).length === 0) { return; } - - props.setConfirmCredit((prev) => ({ - ...prev, - show: { awaitConfirm: { loader: true } }, - })); - - let stateData = { - amount: Number(props.input) * 100, - currency: props.walletItem?.code, - }; - - try { - const res = await apiCall.getStartCredit(stateData); - if (res.data.internal_return < 0) { - props.setConfirmCredit((prev) => ({ - ...prev, - show: { awaitConfirm: { loader: false } }, - })); - props.setInputError("An Error Occurred"); - setTimeout(() => props.setInputError(""), 5000); - return; - } - - const _response = res.data; - stateData.amount = Number(props.input); - stateData.card = prevCardDetails["payment-card"]; - stateData.cardType = "prev"; - stateData = { ...stateData, ..._response }; - - setTimeout(() => { - props.setConfirmCredit({ - show: { - awaitConfirm: { loader: false, state: true }, - acceptConfirm: { loader: false, state: false }, - }, - data: stateData, - }); - }, 1500); - } catch (error) { - props.setConfirmCredit((prev) => ({ - ...prev, - show: { awaitConfirm: { loader: false } }, - })); - console.log(error); - } } - if (tab === "new") { - const stateData = { - amount: Number(props.input), - currency: props.currency, - ...values, - }; + props.setConfirmCredit((prev) => ({ + ...prev, + show: { awaitConfirm: { loader: true } }, + })); - // Rest of the code for tab "new" + let stateData = { + amount: Number(props.input) * 100, + currency: props.walletItem?.code, + }; + + try { + const res = await apiCall.getStartCredit(stateData); + if (res.data.internal_return < 0) { + props.setInputError("An Error Occurred"); + throw new Error("An Error Occurred"); + } + + const _response = res.data; + stateData.amount = Number(props.input); + stateData.card = + tab === "previous" ? prevCardDetails["payment-card"] : { ...values }; + stateData.cardType = tab === "previous" ? "prev" : "new"; + stateData = { ...stateData, ..._response }; + + setTimeout(() => { + props.setConfirmCredit({ + show: { + awaitConfirm: { loader: false, state: true }, + acceptConfirm: { loader: false, state: false }, + }, + data: stateData, + }); + }, 1500); + } catch (error) { + props.setInputError(error.message); + setTimeout(() => props.setInputError(""), 5000); + props.setConfirmCredit((prev) => ({ + ...prev, + show: { awaitConfirm: { loader: false } }, + })); + console.log(error); } }; @@ -221,7 +249,7 @@ function AddFundDollars(props) { {/* END OF switch button */} {/* previous tab */} - {tab === "previous" ? ( + {tab === "previous" && (
{payListCards.loading ? ( @@ -268,7 +296,9 @@ function AddFundDollars(props) {
)}
- ) : ( + )} + + {tab === "new" && (
+ {/* Expire Year, Year */}
@@ -357,6 +391,7 @@ function AddFundDollars(props) {
+
+ {/* Address and CVV */}
- {/* Address and CVV */}
)}
+ {tab == "previous" && (
diff --git a/src/components/MyWallet/Popup/ConfirmAddFund.jsx b/src/components/MyWallet/Popup/ConfirmAddFund.jsx index a157d87..4a4dd1a 100644 --- a/src/components/MyWallet/Popup/ConfirmAddFund.jsx +++ b/src/components/MyWallet/Popup/ConfirmAddFund.jsx @@ -1,11 +1,88 @@ import { FlutterWaveButton, closePaymentModal } from "flutterwave-react-v3"; import React, { useState } from "react"; -import { useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import usersService from "../../../services/UsersService"; import LoadingSpinner from "../../Spinners/LoadingSpinner"; +function ThePaymentText({ value, type }) { + const cardDetails = value; + value.description = + type === "new" + ? cardDetails.cardNum[0] === "4" + ? "Visa" + : value[0] === "5" + ? "Master" + : "ATM" + : value.description; + value.digits = type === "new" ? cardDetails.cardNum.slice(-4) : value.digits; + return ( +
+
+

+ {value.description} Card +

+

+ Bank **************{value.digits} +

+
+
+ ); +} + +function AmountSection({ currency, amount, country }) { + const formattedAmount = Number(amount).toFixed(2); + return ( +
+

+ Amount({currency}) +

+ + {formattedAmount} + +
+ ); +} + +function TransactionFeeSection({ currency, fee, country }) { + const formattedFee = Number(fee).toFixed(2); + return ( +
+

+ Transaction Fee +

+ + {formattedFee} + +
+ ); +} + +function TotalSection({ currency, amount, fee, country }) { + const total = Number(amount) + Number(fee); + const formattedTotal = total.toFixed(2); + return ( +
+

+ Total +

+ + {formattedTotal} + +
+ ); +} + function ConfirmAddFund({ confirmCredit, onClose, @@ -14,68 +91,25 @@ function ConfirmAddFund({ }) { const __confirmData = confirmCredit?.data; const __confirmCountry = walletItem?.country; - const __confirmCardDetails = __confirmData.card - ? JSON.parse(__confirmData.card) - : ""; - let { userDetails } = useSelector((state) => state.userDetails); // TO GET LOGGEDIN USER DETAILS - - let [requestStatus, setRequestStatus] = useState({ - message: "", - loading: false, - status: false, - }); // STATE FOR API REQUEST + const __confirmCardDetails = + __confirmData.cardType === "prev" + ? JSON.parse(__confirmData.card) + : __confirmData.card; const apiURL = new usersService(); const navigate = useNavigate(); - //FUNCTION TO HANDLE SUBMIT - const onSuccessPayment = () => { - setRequestStatus({ message: "", loading: true, status: false }); - let reqData = { amount: __confirmData?.account, currency: "NGN" }; - apiURL - .startTopUp(reqData) - .then((res) => { - if (res.data.internal_return < 0) { - setRequestStatus({ - message: "Could not finish transaction", - loading: false, - status: false, - }); - toast.success("Opps! something went wrong"); - } - // do something - setRequestStatus({ - message: "Topup successful", - loading: false, - status: true, - }); - toast.success("Account Topup was successful"); - setTimeout(() => { - navigate("/my-wallet", { replace: true }); - }, 1000); - }) - .catch((err) => { - // do something - setRequestStatus({ - message: "Opps! An Error Occured", - loading: false, - status: false, - }); - toast.success("Opps! something went wrong"); - }); - }; + const [requestStatus, setRequestStatus] = useState({ + message: "", + loading: false, + status: false, + }); const config = { public_key: process.env.REACT_APP_FLUTTERWAVE_APIKEY, tx_ref: Date.now(), - amount: __confirmData?.amount, currency: "NGN", payment_options: "card,mobilemoney,ussd", - customer: { - email: `${userDetails.email}`, - phone_number: userDetails.phone, - name: `${userDetails.lastname} ${userDetails.firstname}`, - }, customizations: { title: "WrenchBoard", description: "Topup Payment", @@ -88,12 +122,47 @@ function ConfirmAddFund({ text: "Proceed", callback: (response) => { onSuccessPayment(); - closePaymentModal(); // this will close the modal programmatically + closePaymentModal(); }, onClose: () => {}, }; - // Handling Previous Card + const onSuccessPayment = () => { + setRequestStatus({ message: "", loading: true, status: false }); + const reqData = { amount: __confirmData?.account, currency: "NGN" }; + + apiURL + .startTopUp(reqData) + .then((res) => { + if (res.data.internal_return < 0) { + setRequestStatus({ + message: "Could not finish transaction", + loading: false, + status: false, + }); + toast.success("Opps! something went wrong"); + } else { + setRequestStatus({ + message: "Topup successful", + loading: false, + status: true, + }); + toast.success("Account Topup was successful"); + setTimeout(() => { + navigate("/my-wallet", { replace: true }); + }, 1000); + } + }) + .catch((err) => { + setRequestStatus({ + message: "Opps! An Error Occured", + loading: false, + status: false, + }); + toast.success("Opps! something went wrong"); + }); + }; + const handlePrevCard = async () => { const { amount, credit_reference, currency } = __confirmData; const { card_uid } = __confirmCardDetails; @@ -124,18 +193,16 @@ function ConfirmAddFund({ return; } - return setTimeout( - () => - setConfirmCredit((prev) => ({ - ...prev, - show: { - awaitConfirm: { loader: false, state: false }, - acceptConfirm: { loader: false, state: true }, - }, - data: _response, - })), - 1500 - ); + setTimeout(() => { + setConfirmCredit((prev) => ({ + ...prev, + show: { + awaitConfirm: { loader: false, state: false }, + acceptConfirm: { loader: false, state: true }, + }, + data: _response, + })); + }, 1500); } catch (error) { setConfirmCredit((prev) => ({ ...prev, @@ -147,18 +214,67 @@ function ConfirmAddFund({ } }; - const ThePaymentText = ({ value }) => ( -
-
-

- {value.description} Card -

-

- Bank **************{value.digits} -

-
-
- ); + const handleNewCard = async () => { + const { amount, credit_reference, uid } = __confirmData; + const { address, cardNum, cvv, expirationMonth, expirationYear } = + __confirmCardDetails; + + const reqData = { + amount: amount * 100, + cardnumber: cardNum.replace(/\s/g, ""), + credit_reference, + cvc: cvv, + description: address, + exp_month: expirationMonth, + exp_year: expirationYear, + paymenttype: 100, + uid, + }; + + try { + setConfirmCredit((prev) => ({ + ...prev, + show: { + acceptConfirm: { loader: true }, + }, + })); + const res = await apiURL.getPaidNewCard(reqData); + const _response = res.data; + if (res.data.internal_return < 0) { + setConfirmCredit((prev) => ({ + ...prev, + show: { + awaitConfirm: { loader: false, state: false }, + acceptConfirm: { loader: false, state: true }, + }, + data: _response, + })); + return; + } + + setTimeout(() => { + setConfirmCredit((prev) => ({ + ...prev, + show: { + awaitConfirm: { loader: false, state: false }, + acceptConfirm: { loader: false, state: true }, + }, + data: _response, + })); + }, 1500); + } catch (error) { + setConfirmCredit((prev) => ({ + ...prev, + show: { + acceptConfirm: { loader: false }, + }, + })); + setTimeout(() => onClose, 10000) + console.log(error); + } + }; + + console.log(confirmCredit?.data); return (
@@ -166,76 +282,45 @@ function ConfirmAddFund({
- {confirmCredit?.show?.awaitConfirm?.state ? ( + {confirmCredit?.show?.awaitConfirm?.state && (
- {/* Amount */} -
-

- Amount({__confirmData?.currency}) -

- - {`${walletItem?.symbol} ${ - Number(__confirmData?.amount).toLocaleString() || "" - }`} - -
- {/* Transaction Fee */} -
-

- Transaction Fee -

- - {`${walletItem?.symbol} ${ - Number(__confirmData?.fee).toLocaleString() || "" - }`} - -
- {/* Total */} -
-

- Total -

- - {`${walletItem?.symbol} ${ - ( - Number(__confirmData?.amount) + - Number(__confirmData?.fee) - ).toLocaleString() || "" - }`} - -
- - {__confirmCountry == "US" && ( + + + + {__confirmCountry === "US" && (
- - {__confirmCardDetails ? ( - - ) : null} + +
)} -

@@ -246,13 +331,13 @@ function ConfirmAddFund({

- ) : null} + )}

@@ -263,13 +348,13 @@ function ConfirmAddFund({ > Cancel - {__confirmCountry == "US" && ( + {__confirmCountry === "US" && ( )} - {__confirmCountry == "NG" && ( + {__confirmCountry === "NG" && (