Paying using new card

This commit is contained in:
2023-07-17 11:04:31 +01:00
parent fb7913c563
commit 78145eee77
6 changed files with 244 additions and 110 deletions
+3 -3
View File
@@ -504,11 +504,11 @@ export default function Icons({ name }) {
></path>
</svg>
) : name === "atm-card" ? (
<img className="w-[20px]" src={ATMCard} alt="card" />
<img className="w-[30px]" src={ATMCard} alt="card" />
) : name === "visa-card" ? (
<img className="w-[20px]" src={VisaCard} alt="card" />
<img className="w-[30px]" src={VisaCard} alt="card" />
) : name === "master-card" ? (
<img className="w-[20px]" src={MasterCard} alt="card" />
<img className="w-[30px]" src={MasterCard} alt="card" />
) : name === "new-dashboard" ? (
<img className="w-[17px] h-[17px]" src={localImgLoad('images/icons/dashboard.svg')} alt="dashboard" />
) : name === "new-family" ? (
@@ -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({
</span>
)}
{/* displays error is any */}
{error && <span className="text-[12px] text-red-500 italic">{error}</span>}
{error && (
<span className="text-[12px] text-red-500 italic">{error}</span>
)}
</label>
)}
{forgotPassword && (
@@ -76,7 +81,11 @@ export default function InputCom({
)}
</div>
<div
className={`input-wrapper w-full rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-base ${inputClass ? inputClass : "text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] border"}`}
className={`input-wrapper w-full rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-base ${
inputClass
? inputClass
: "text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] border"
}`}
>
<input
placeholder={placeholder}
@@ -88,6 +97,7 @@ export default function InputCom({
type={type}
id={name}
name={name}
onInput={onInput}
minLength={minLengthValidation()}
maxLength={maxLengthValidation()}
// pattern={inputPatterns()}
@@ -104,10 +114,7 @@ export default function InputCom({
</div>
)}
{passIcon && (
<div
className="absolute right-6 bottom-3 z-10"
onClick={onClick}
>
<div className="absolute right-6 bottom-3 z-10" onClick={onClick}>
<Icons name={passIcon} />
</div>
)}
@@ -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: <input type="text" pattern="[0-9]*" /> strictly numbers
+121 -83
View File
@@ -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,24 +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: [] });
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);
@@ -82,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");
return;
}
if (!prevCardDetails["payment-card"]?.card_uid) {
setTimeout(() => props.setInputError(""), 5000);
return;
}
if (tab === "previous") {
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);
// To check if card is empty
if (Object.keys(prevCardDetails).length === 0) {
return;
}
}
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);
}
};
@@ -171,8 +200,6 @@ function AddFundDollars(props) {
const handleClose = props.onClose;
console.log(prevCardDetails)
return (
<>
<div className="w-full">
@@ -222,7 +249,7 @@ function AddFundDollars(props) {
{/* END OF switch button */}
{/* previous tab */}
{tab === "previous" ? (
{tab === "previous" && (
<div className="p-4 previous-details w-full min-h-[16rem] flex flex-col justify-between items-center">
{payListCards.loading ? (
<LoadingSpinner size="10" color="sky-blue" />
@@ -269,7 +296,9 @@ function AddFundDollars(props) {
</div>
)}
</div>
) : (
)}
{tab === "new" && (
<div className="new-details w-full max-h-[23rem]">
<div className="w-full flex flex-col justify-between">
<Formik
@@ -298,17 +327,21 @@ function AddFundDollars(props) {
<InputCom
fieldClass="px-6"
spanTag="*"
iconName="master-card visa-card atm-card"
iconName={cardIcons}
label="Card Number"
type="text"
name="cardNum"
onInput={handleCards}
placeholder="Enter Card Number"
value={props.values.cardNum}
value={handleCardNumberChange(
props.values.cardNum
)}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={props.errors.cardNum}
/>
</div>
{/* Expire Year, Year */}
<div className="sm:grid gap-5 grid-cols-2 flex-[0.4]">
<div className="field w-full mb-6 xl:mb-0 col-span-1">
@@ -358,6 +391,7 @@ function AddFundDollars(props) {
</div>
</div>
</div>
<div className="field w-full mb-6 xl:mb-0 col-span-1">
<div className="select-option">
<div
@@ -405,17 +439,18 @@ function AddFundDollars(props) {
</div>
</div>
{/* Address and CVV */}
<div className="flex items-center flex-1 gap-3 my-2">
{/* Address and CVV */}
<div className="field w-full col-span-1 flex-[0.4]">
<InputCom
fieldClass="px-6"
spanTag="*"
iconName="atm-card"
iconName={cardIcons}
label="CVV"
type="text"
type="number"
name="cvv"
placeholder="CVV"
maxLength={3}
value={props.values.cvv}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
@@ -449,6 +484,7 @@ function AddFundDollars(props) {
name="code"
placeholder="Postal Code"
value={props.values.code}
maxLength={6}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={props.errors.code}
@@ -482,9 +518,9 @@ function AddFundDollars(props) {
</button>
<button
type="submit"
className="px-4 py-1 h-11 max-w-[100px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
className="px-4 py-1 h-11 max-w-[115px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{loader ? (
{props.confirmCredit?.show?.awaitConfirm?.loader ? (
<LoadingSpinner size="6" color="sky-blue" />
) : (
<>
@@ -502,6 +538,7 @@ function AddFundDollars(props) {
</div>
)}
</div>
{tab == "previous" && (
<div className="md:py-8 px-[38px] add-fund-btn flex justify-end items-center gap-4 py-4">
<button
@@ -512,8 +549,9 @@ function AddFundDollars(props) {
</button>
<button
onClick={handleSubmit}
name="previous"
type="button"
className="px-4 py-1 h-11 max-w-[100px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
className="px-4 py-1 h-11 max-w-[115px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{props.confirmCredit?.show?.awaitConfirm?.loader ? (
<LoadingSpinner size="6" color="sky-blue" />
@@ -53,7 +53,7 @@ function CompleteConfirmCredit({ onClose, confirmCredit }) {
<h1 className="text-xl font-semibold text-dark-gray dark:text-white tracking-tighter my-1">
{data?.result == "Charge success"
? "Credit was Successful!"
: "Credit was Unsuccessful"}
: data?.result}
</h1>
</div>
@@ -5,11 +5,21 @@ import { toast } from "react-toastify";
import usersService from "../../../services/UsersService";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
function ThePaymentText({ value }) {
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 (
<div className="my-2 flex items-center gap-5">
<div className="card-details flex items-center gap-3">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1 space-x-1">
{value.description} Card
</h1>
<p className="text-base font-bold text-dark-gray dark:text-white tracking-wide">
@@ -21,7 +31,7 @@ function ThePaymentText({ value }) {
}
function AmountSection({ currency, amount, country }) {
const formattedAmount = (Number(amount) / 100).toFixed(2);
const formattedAmount = Number(amount).toFixed(2);
return (
<div
className={`flex items-center ${country == "US" ? "gap-14" : "gap-4"}`}
@@ -37,7 +47,7 @@ function AmountSection({ currency, amount, country }) {
}
function TransactionFeeSection({ currency, fee, country }) {
const formattedFee = (Number(fee) / 100).toFixed(2);
const formattedFee = Number(fee).toFixed(2);
return (
<div
className={`flex items-center border-b border-gray-600 ${
@@ -55,7 +65,7 @@ function TransactionFeeSection({ currency, fee, country }) {
}
function TotalSection({ currency, amount, fee, country }) {
const total = (Number(amount) + Number(fee)) / 100;
const total = Number(amount) + Number(fee);
const formattedTotal = total.toFixed(2);
return (
<div
@@ -81,9 +91,10 @@ function ConfirmAddFund({
}) {
const __confirmData = confirmCredit?.data;
const __confirmCountry = walletItem?.country;
const __confirmCardDetails = __confirmData.card
? JSON.parse(__confirmData.card)
: "";
const __confirmCardDetails =
__confirmData.cardType === "prev"
? JSON.parse(__confirmData.card)
: __confirmData.card;
const apiURL = new usersService();
const navigate = useNavigate();
@@ -203,6 +214,68 @@ function ConfirmAddFund({
}
};
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 (
<div className="content-wrapper w-full h-[32rem]">
<div className="w-full mb-10">
@@ -236,9 +309,10 @@ function ConfirmAddFund({
Payment Method
</label>
<span className="text-[#181c32] dark:text-white">
{__confirmCardDetails ? (
<ThePaymentText value={__confirmCardDetails} />
) : null}
<ThePaymentText
value={__confirmCardDetails}
type={__confirmData?.cardType}
/>
</span>
</div>
)}
@@ -246,7 +320,7 @@ function ConfirmAddFund({
className={`${
__confirmCountry === "US"
? "gap-[3.7rem]"
: "gap-[9.81rem]"
: "gap-[1.81rem]"
} flex items-center`}
>
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
@@ -263,7 +337,7 @@ function ConfirmAddFund({
<div
className={
__confirmCountry === "US" ? "min-h-[96px]" : "min-h-[200px]"
__confirmCountry === "US" ? "min-h-[96px]" : "min-h-[157px]"
}
></div>
<hr />
@@ -280,7 +354,7 @@ function ConfirmAddFund({
onClick={
__confirmData?.cardType === "prev"
? handlePrevCard
: () => console.log("Test me")
: handleNewCard
}
>
{confirmCredit?.show?.acceptConfirm?.loader ? (
+14
View File
@@ -216,6 +216,7 @@ class usersService {
return this.postAuxEnd("/sendmoneyfee", postData);
}
// Start Credit for Cards
getStartCredit(value) {
var postData = {
uid: localStorage.getItem("uid"),
@@ -227,6 +228,7 @@ class usersService {
return this.postAuxEnd("/startcredit", postData);
}
// Paying using Previous Cards
getPaidPrevCard(value) {
var postData = {
uid: localStorage.getItem("uid"),
@@ -238,6 +240,18 @@ class usersService {
return this.postAuxEnd("/payprevcard", postData);
}
// Paying using New Card
getPaidNewCard(value) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11054,
...value,
};
return this.postAuxEnd("/paynewcard", postData);
}
getFamilySampleTasks() {
var postData = {
uid: localStorage.getItem("uid"),