Compare commits

...

2 Commits

Author SHA1 Message Date
victorAnumudu dd1430a350 confirm naira withdrawal added 2023-07-17 01:22:12 +01:00
victorAnumudu 0eca0c52ce withdraw page added 2023-07-17 01:15:16 +01:00
4 changed files with 566 additions and 1 deletions
@@ -0,0 +1,210 @@
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import RecentActivityTable from "./WalletComponent/RecentActivityTable";
import usersService from "../../services/UsersService";
function ConfirmNairaWithdraw({ payment, wallet }) {
const apiURL = new usersService();
const navigate = useNavigate();
let { state } = useLocation();
let [requestStatus, setRequestStatus] = useState({
message: "",
loading: false,
status: false,
});
let [pageLoading, setPageLoading] = useState(true);
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = () => {
setRequestStatus({ message: "", loading: true, status: false });
let reqData = {
amount: Number(state.amount),
Fee: Number(state.fee),
recipientid: Number(state.recipientID),
};
apiURL
.sendMoney(reqData)
.then((res) => {
if (res.data.internal_return < 0) {
setRequestStatus({
message: "Could not perform transaction",
loading: false,
status: false,
});
return;
}
setRequestStatus({
message: "transfer successful",
loading: false,
status: true,
});
toast.success("Transfer sucessful");
setTimeout(() => {
navigate("/my-wallet", { replace: true });
window.location.reload(true);
}, 1000);
})
.catch((error) => {
setRequestStatus({
message: "Opps! something went wrong! Try Again",
loading: false,
status: false,
});
});
};
useEffect(() => {
// what happens if not state redirect user
if (!state) {
navigate("/my-wallet/withdraw-naira", { replace: true });
} else {
setPageLoading(false);
}
}, []);
return (
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
{pageLoading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : (
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
<div className="add-fund w-full bg-white dark:bg-dark-white rounded-2xl shadow">
<div className="px-4 md:px-8 py-4">
{wallet.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : wallet.data.length ? (
<h2 className="my-4 text-slate-500 dark:text-white text-sm xl:text-xl font-medium">
{wallet.data.map((item) => {
if (item.description == "Naira") {
return `Withdraw from Naira Wallet : ${item.symbol}${(
item.amount * 0.01
).toFixed(2)}`;
}
})}
</h2>
) : wallet.error ? (
<h2 className="my-4 text-slate-500 dark:text-white text-sm xl:text-xl font-medium">
Opps! An Error Occured
</h2>
) : (
<h2 className="my-4 text-slate-500 dark:text-white text-sm xl:text-xl font-medium">
No Wallet Information Found!
</h2>
)}
</div>
<hr />
<div className="px-4 md:px-8 py-4 add-fund-info">
<h2 className="my-2 text-slate-900 dark:text-white text-sm xl:text-xl font-medium">
Confirm Withdraw to Account
</h2>
{/* AMOUNT */}
<div className="field w-full mb-3">
<InputCom
fieldClass="px-6"
label="Amount:"
type="text"
name="amount"
value={state?.amount || ""}
disable={true}
/>
</div>
{/* RECIPIENT ACC: */}
<div className="field w-full mb-3">
<InputCom
fieldClass="px-6"
label="Recipient Acc:"
type="text"
name="recipient"
value={state?.details.recipient || ""}
disable={true}
/>
</div>
{/* PROCESSING FEE: */}
<div className="field w-full mb-3">
<InputCom
fieldClass="px-6"
label="Processing Fee:"
type="text"
name="processingFee"
value={state?.fee || ""}
disable={true}
/>
</div>
{/* TOTAL */}
<div className="field w-full mb-3">
<InputCom
fieldClass="px-6"
label="Total"
type="text"
name="total"
value={state?.total || ""}
disable={true}
/>
</div>
{/* COMMENT/NOTE */}
<div className="field w-full mb-3">
<InputCom
fieldClass="px-6"
label="Comment/Note:"
type="text"
name="comment"
value={state?.comment || ""}
disable={true}
/>
</div>
</div>
<hr />
{requestStatus.message && (
<p
className={`text-base ${
requestStatus.status ? "text-green-500" : "text-red-500"
} px-4 md:px-8 py-4`}
>
{requestStatus.message}
</p>
)}
<div className="px-4 md:px-8 py-4 add-fund-btn flex justify-end items-center">
{requestStatus.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : (
<button
onClick={handleSubmit}
className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md"
>
Transfer
</button>
)}
</div>
</div>
</div>
)}
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
<div className="wallet w-full px-4 md:px-8 py-4 h-full max-h-[700px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
<h2 className="text-gray-900 dark:text-white text-xl lg:text-2xl font-medium">
Recent Activity
</h2>
{/* <p className='text-base text-gray-600 dark:text-white'>Activity Report</p> */}
{payment.loading ? (
<LoadingSpinner size="16" color="sky-blue" />
) : (
<RecentActivityTable payment={payment} />
)}
</div>
</div>
</div>
);
}
export default ConfirmNairaWithdraw;
+337
View File
@@ -0,0 +1,337 @@
import React, { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import RecentActivityTable from "./WalletComponent/RecentActivityTable";
import usersService from "../../services/UsersService";
import { Form, Formik } from "formik";
import * as Yup from "yup";
const validationSchema = Yup.object().shape({
amount: Yup.number()
.typeError("you must specify a number")
.min(1, "Amount must be greater than 0")
.required("Amount is required"),
recipientID: Yup.string()
.min(1, "Minimum 1 characters")
.max(50, "Maximum 50 characters")
.required("Recipient is required"),
});
const initialValues = {
amount: "",
recipientID: "",
comment: "",
};
function NairaWithdraw({ payment, wallet }) {
const apiCall = new usersService(); // API CLASS CALL
const navigate = useNavigate();
let [requestStatus, setRequestStatus] = useState(false);
let [recipients, setRecipients] = useState({
// FOR COUPON HISTORY
loading: true,
data: [],
error: false,
});
let [sendMoneyFee, setSendMoneyFee] = useState({
loading: false,
fee: 0,
total: 0,
}); // HOLD THE VALUE FOR SEND MONEY FEE
//FUNCTION TO GET RECIPIENT LIST
const getRecipients = () => {
apiCall
.getRecipient()
.then((res) => {
if (res.data.internal_return < 0) {
// success but no data
setRecipients((prev) => ({ ...prev, loading: false }));
return;
}
setRecipients((prev) => ({
...prev,
loading: false,
data: res.data.result_list,
}));
})
.catch((error) => {
setRecipients((prev) => ({ ...prev, loading: false, error: true }));
});
};
//FUNCTION TO GET SEND MONEY FEE
const getSendMoneyFee = ({ target: { value } }) => {
setSendMoneyFee({ loading: true, fee: 0, total: 0 });
let amount = value;
if (Number(amount) <= 0 || amount == "" || isNaN(amount)) {
setSendMoneyFee({ loading: false, fee: 0, total: 0 });
return;
}
apiCall
.getSendMoneyFee(Number(amount))
.then((res) => {
setSendMoneyFee({
loading: false,
fee: res.data.processing_fee,
total: res.data.total_amount,
});
})
.catch((error) => {
setSendMoneyFee({ loading: false, fee: 0, total: 0 });
});
};
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values, helpers) => {
if(!values?.amount && !values.recipientID) return
setRequestStatus(true);
let recipientDetails = recipients.data?.filter(
(item) => item.recipient_id == values.recipientID
);
let stateData = {
...values,
...sendMoneyFee,
details: { ...recipientDetails[0] },
};
setTimeout(() => {
setRequestStatus(false);
navigate("confirm-withdraw-naira", { state: stateData });
}, 1000);
};
useEffect(() => {
getRecipients();
}, []);
return (
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
<div className="add-fund w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props) => {
return (
<Form className="transfer-fund-info">
{wallet.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : wallet.data.length ? (
<h2 className="my-4 py-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
{wallet.data.map((item) => {
if (item.description == "Naira") {
return `Withdraw from Naira Wallet : ${item.symbol}${(
item.amount * 0.01
).toFixed(2)}`;
}
})}
</h2>
) : wallet.error ? (
<h2 className="my-4 py-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
Opps! An Error Occurred
</h2>
) : (
<h2 className="my-4 py-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
No Wallet Information Found!
</h2>
)}
<div className=" mb-6 gap-4 flex flex-col">
<div className="field w-full">
<InputCom
fieldClass="px-4"
parentClass="flex items-center gap-1 justify-between"
labelClass="flex-[0.2] mb-0"
inputClass="flex-[0.8] max-w-[12rem]"
label="Amount:"
type="number"
name="amount"
placeholder="0"
direction="rtl"
value={props.values.amount}
inputHandler={props.handleChange}
blurHandler={(e) => {
getSendMoneyFee(e);
}}
// props.handleBlur
// onMouseLeave={(e)=>{getSendMoneyFee(e)}}
/>
{props.errors.amount && props.touched.amount && (
<p className="sm:text-sm text-[12px] text-red-500 sm:text-left text-right sm:translate-y-0 translate-y-1">
{props.errors.amount}
</p>
)}
</div>
<div className="field w-full">
<InputCom
fieldClass="px-4 transfer-field"
parentClass="flex items-center gap-1 justify-between"
labelClass="flex-[0.2] mb-0"
inputClass="flex-[0.8] transfer-field max-w-[12rem]"
label="Fee:"
type="text"
name="fee"
direction="rtl"
value={
sendMoneyFee.loading ? "loading" : sendMoneyFee.fee
}
disable={true}
/>
</div>
<div className="field w-full mb-6">
<InputCom
fieldClass="px-4 transfer-field"
parentClass="flex items-center gap-1 justify-between"
labelClass="flex-[0.2] mb-0"
inputClass="flex-[0.8] transfer-field max-w-[12rem]"
label="Total:"
type="text"
name="total"
direction="rtl"
value={
sendMoneyFee.loading ? "loading" : sendMoneyFee.total
}
disable={true}
/>
</div>
</div>
<div className="w-full">
<div className="relative my-3 md:flex items-center">
<div className="transfer-input w-full flex items-start gap-1 justify-between">
<label className="text-[#181c32] dark:text-white text-base font-semibold block flex-[0.2] mb-0 mt-3">
Recipient:
</label>
<div className="flex flex-col gap-3 flex-[0.8] sm:items-start items-end">
<select
className="sm:w-full w-48 text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0 flex-[0.8]"
value={props.values.recipientID}
name="recipientID"
onChange={props.handleChange}
onBlur={props.handleBlur}
>
{recipients.loading ? (
<option
className="text-slate-500 text-lg"
value=""
>
Loading...
</option>
) : recipients.data.length ? (
<>
<option
className="text-slate-500 text-lg"
value=""
>
Select...
</option>
{recipients.data.map((item, index) => (
<option
key={index}
value={item.recipient_id}
className="text-slate-500 text-lg"
>
{item.recipient}
</option>
))}
</>
) : recipients.error ? (
<option
className="text-slate-500 text-lg"
value=""
>
Could'nt load, try again!
</option>
) : (
<option
className="text-slate-500 text-lg"
value=""
>
No Recipient Found!
</option>
)}
</select>
<div className="flex justify-end relative w-full">
{props.errors.recipientID &&
props.touched.recipientID && (
<p className="sm:text-sm text-[12px] text-red-500 absolute sm:top-1 -top-20 sm:left-0 left-[160px]">
{props.errors.recipientID}
</p>
)}
<Link
to="add-recipient"
className="mx-1 text-base text-white p-2 bg-[orange] rounded-md hover:opacity-80 max-w-[5rem]"
>
Add New
</Link>
</div>
</div>
</div>
</div>
</div>
<div className="field w-full mb-6 flex gap-1 justify-between">
<label className="text-[#181c32] dark:text-white text-base font-semibold flex flex-[0.2] mt-2.5">
Comment:
</label>
<textarea
style={{ resize: "none" }}
className="text-base px-4 py-2 rounded-md min-h-[100px] sm:max-w-[550px] max-w-[250px] text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none flex-[0.8]"
name="comment"
value={props.values.comment}
onChange={props.handleChange}
onBlur={props.handleBlur}
cols="30"
rows="2"
/>
</div>
<div className="transfer-fund-btn flex justify-end items-center py-4">
{requestStatus ? (
<LoadingSpinner size="8" color="sky-blue" />
) : (
<button
type="submit"
disabled={(props.isSubmitting || sendMoneyFee.loading) ? true : false}
className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md"
>
Continue
</button>
)}
</div>
</Form>
);
}}
</Formik>
</div>
</div>
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
<div className="wallet w-full md:p-8 p-4 h-full max-h-[650px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
<h2 className="text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
Recent Activity
</h2>
{/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */}
{payment.loading ? (
<LoadingSpinner size="16" color="sky-blue" />
) : (
<RecentActivityTable payment={payment} />
)}
</div>
</div>
</div>
);
}
export default NairaWithdraw;
+18
View File
@@ -15,6 +15,8 @@ import LoadingSpinner from "../Spinners/LoadingSpinner";
// const ConfirmAddFund = lazy(() => import("./ConfirmAddFund"));
// const TransferFund = lazy(() => import("./TransferFund"));
const WalletBox = lazy(() => import("./WalletBox"));
const NairaWithdraw = lazy(() => import("./NairaWithdraw"));
const ConfirmNairaWithdraw = lazy(() => import("./ConfirmNairaWithdraw"));
// const AddRecipient = lazy(() => import("./AddRecipient"));
// const ConfirmTransfer = lazy(() => import("./ConfirmTransfer"));
@@ -127,6 +129,22 @@ const WalletRoutes = () => {
</Suspense>
}
/>
<Route
path="withdraw-naira"
element={
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}>
<NairaWithdraw wallet={walletList} payment={paymentHistory} />
</Suspense>
}
/>
<Route
path="withdraw-naira/confirm-withdraw-naira"
element={
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}>
<ConfirmNairaWithdraw wallet={walletList} payment={paymentHistory} />
</Suspense>
}
/>
<Route path="*" element={<Navigate to="/" />} />
</Route>
</Routes>
+1 -1
View File
@@ -6,7 +6,7 @@ function WalletAction({walletItem, payment, openPopUp}) {
<div className="counters w-full flex justify-between gap-2">
<div className='w-1/2 flex justify-center items-center'>
<Link
to="transfer-fund"
to="withdraw-naira"
className={`${
walletItem.code != "NAIRA" && "invisible"
} px-4 h-10 flex justify-center items-center btn-gradient text-base rounded-full text-white`}