Merge branch 'add-family-acc' of WrenchBoard/Users-Wrench into master
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png"
|
||||
import React, { useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
import usersService from "../../../services/UsersService";
|
||||
|
||||
export default function ForgotPassword() {
|
||||
const [checked, setValue] = useState(false);
|
||||
const [resetLoading, setResetLoading] = useState(false)
|
||||
const [resetLoading, setResetLoading] = useState(false);
|
||||
// email
|
||||
const [email, setMail] = useState("");
|
||||
const [msgError, setMsgError] = useState('');
|
||||
const [msgSuccess, setMsgSuccess] = useState(false)
|
||||
const [msgError, setMsgError] = useState("");
|
||||
const [msgSuccess, setMsgSuccess] = useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const userApi = new usersService();
|
||||
@@ -21,52 +21,54 @@ export default function ForgotPassword() {
|
||||
};
|
||||
|
||||
const humanChecker = () => {
|
||||
setValue(!checked)
|
||||
}
|
||||
setValue(!checked);
|
||||
};
|
||||
|
||||
const resetHandler = async () => {
|
||||
if (email == '') {
|
||||
setMsgError('An email is required')
|
||||
if (email == "") {
|
||||
setMsgError("An email is required");
|
||||
} else if (!checked) {
|
||||
setMsgError('Check if you are human')
|
||||
setMsgError("Check if you are human");
|
||||
}
|
||||
|
||||
if (email !== '' && checked) {
|
||||
const reqData = { email }
|
||||
setResetLoading(true)
|
||||
if (email !== "" && checked) {
|
||||
const reqData = { email };
|
||||
setResetLoading(true);
|
||||
try {
|
||||
const res = await userApi.StartResetPassword(reqData)
|
||||
const res = await userApi.StartResetPassword(reqData);
|
||||
if (res.status === 200) {
|
||||
setMsgSuccess(true)
|
||||
setMail("")
|
||||
setValue(false)
|
||||
setResetLoading(false)
|
||||
setMsgSuccess(true);
|
||||
setMail("");
|
||||
setValue(false);
|
||||
setResetLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setResetLoading(false)
|
||||
setMail("")
|
||||
setMsgError('An error occurred')
|
||||
throw new Error(error)
|
||||
setResetLoading(false);
|
||||
setMail("");
|
||||
setMsgError("An error occurred");
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setMsgError(null)
|
||||
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT)
|
||||
setMsgError(null);
|
||||
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
setMsgError(null)
|
||||
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT)
|
||||
}
|
||||
setMsgError(null);
|
||||
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthLayout
|
||||
slogan="Welcome to WrenchBoard"
|
||||
>
|
||||
<AuthLayout slogan="Welcome to WrenchBoard">
|
||||
<div className="w-full">
|
||||
<div className='mb-12'>
|
||||
<Link to='#'>
|
||||
<img src={WrenchBoard} alt="wrenchboard" className="h-10 mx-auto" />
|
||||
<div className="mb-12">
|
||||
<Link to="#">
|
||||
<img
|
||||
src={WrenchBoard}
|
||||
alt="wrenchboard"
|
||||
className="h-10 mx-auto"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5">
|
||||
@@ -75,11 +77,14 @@ export default function ForgotPassword() {
|
||||
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
|
||||
Forget Password
|
||||
</h1>
|
||||
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">Enter your email to reset your password.</span>
|
||||
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
|
||||
Enter your email to reset your password.
|
||||
</span>
|
||||
</div>
|
||||
<div className="input-area">
|
||||
<div className="input-item mb-10">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="Your Username/Email"
|
||||
label="Email"
|
||||
name="email"
|
||||
@@ -98,7 +103,14 @@ export default function ForgotPassword() {
|
||||
<div className="relative table top-0 h-full">
|
||||
<div className="table-cell align-middle">
|
||||
<div className="relative w-[30px] h-[30px] mx-[15px]">
|
||||
<input type="checkbox" name="human-checkbox" id="human-checkbox" className="w-[28px] h-[28px] border-[1px] rounded border-gray-400 checked:bg-white" checked={checked} onChange={humanChecker} />
|
||||
<input
|
||||
type="checkbox"
|
||||
name="human-checkbox"
|
||||
id="human-checkbox"
|
||||
className="w-[28px] h-[28px] border-[1px] rounded border-gray-400 checked:bg-white"
|
||||
checked={checked}
|
||||
onChange={humanChecker}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,7 +118,10 @@ export default function ForgotPassword() {
|
||||
<div className="h-full relative inline-block w-[170px]">
|
||||
<label className="relative table top-0 h-full">
|
||||
<label className="table-cell align-middle">
|
||||
<label className="text-800 text-sm" htmlFor="human-checkbox">
|
||||
<label
|
||||
className="text-800 text-sm"
|
||||
htmlFor="human-checkbox"
|
||||
>
|
||||
I am human
|
||||
</label>
|
||||
</label>
|
||||
@@ -116,8 +131,24 @@ export default function ForgotPassword() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{msgError && <div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">{msgError}</div>}
|
||||
{msgSuccess && <div className="relative p-4 text-[#44228c] bg-[#e3d7fb] border-[#d5c4f9] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">If we find your email, you will receive a link to reset your password. Please use or <Link to='/contact' className="text-[#4687ba] hover:text-[#009ef7]">contact form</Link> if you did not get our message after few minutes.</div>}
|
||||
{msgError && (
|
||||
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">
|
||||
{msgError}
|
||||
</div>
|
||||
)}
|
||||
{msgSuccess && (
|
||||
<div className="relative p-4 text-[#44228c] bg-[#e3d7fb] border-[#d5c4f9] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">
|
||||
If we find your email, you will receive a link to reset your
|
||||
password. Please use or{" "}
|
||||
<Link
|
||||
to="/contact"
|
||||
className="text-[#4687ba] hover:text-[#009ef7]"
|
||||
>
|
||||
contact form
|
||||
</Link>{" "}
|
||||
if you did not get our message after few minutes.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="signin-area mb-3.5">
|
||||
<div className="flex justify-center items-center gap-2">
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate, Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import googleLogo from "../../../assets/images/google-logo.svg";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import appleLogo from "../../../assets/images/apple-black.svg";
|
||||
import facebookLogo from "../../../assets/images/facebook-4.svg";
|
||||
import googleLogo from "../../../assets/images/google-logo.svg";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateUserDetails } from "../../../store/UserDetails";
|
||||
|
||||
export default function Login() {
|
||||
@@ -73,7 +72,7 @@ export default function Login() {
|
||||
setLoginError(true);
|
||||
}
|
||||
} else {
|
||||
setMsgError("Please fill in fields");
|
||||
setMsgError("Please fill in the fields");
|
||||
}
|
||||
} catch (error) {
|
||||
setMsgError("An error occurred");
|
||||
@@ -117,6 +116,7 @@ export default function Login() {
|
||||
<div className="input-area">
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={email}
|
||||
inputHandler={handleEmail}
|
||||
placeholder="support@mermsemr.com"
|
||||
@@ -129,6 +129,7 @@ export default function Login() {
|
||||
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={password}
|
||||
inputHandler={handlePassword}
|
||||
placeholder="● ● ● ● ● ●"
|
||||
@@ -139,39 +140,6 @@ export default function Login() {
|
||||
forgotPassword
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="forgot-password-area flex justify-between items-center mb-7">
|
||||
<div className="remember-checkbox flex items-center space-x-2.5">
|
||||
<button
|
||||
onClick={rememberMe}
|
||||
type="button"
|
||||
className="w-5 h-5 text-dark-gray dark:text-white flex justify-center items-center border border-light-gray"
|
||||
>
|
||||
{checked && (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
<span
|
||||
onClick={rememberMe}
|
||||
className="text-base text-dark-gray dark:text-white"
|
||||
>
|
||||
Remember Me
|
||||
</span>
|
||||
</div>
|
||||
<a href="/forgot-password" className="text-base text-purple">
|
||||
Forgot Password
|
||||
</a>
|
||||
</div> */}
|
||||
{loginError && (
|
||||
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-thin leading-[19.5px] text-[13px]">
|
||||
Invalid username or password- Please{" "}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useNavigate, Link } from "react-router-dom";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import facebookLogo from "../../../assets/images/facebook-4.svg";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png";
|
||||
import usersService from "../../../services/UsersService";
|
||||
@@ -171,6 +171,7 @@ export default function SignUp() {
|
||||
<div className="input-fl-name mb-5 sm:flex w-full sm:space-x-6 ">
|
||||
<div className="input-item sm:w-1/2 w-full mb-5 sm:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="Firstname"
|
||||
label="First Name"
|
||||
name="first_name"
|
||||
@@ -181,6 +182,7 @@ export default function SignUp() {
|
||||
</div>
|
||||
<div className="input-item flex-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="Lastname"
|
||||
label="Last Name"
|
||||
name="last_name"
|
||||
@@ -192,6 +194,7 @@ export default function SignUp() {
|
||||
</div>
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="support@mermsemr.com"
|
||||
label="Email"
|
||||
name="email"
|
||||
@@ -202,6 +205,7 @@ export default function SignUp() {
|
||||
</div>
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="● ● ● ● ● ●"
|
||||
label="Password"
|
||||
name="password"
|
||||
|
||||
@@ -16,9 +16,7 @@ export default function UpdatePassword() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthLayout
|
||||
slogan="Welcome to myFit"
|
||||
>
|
||||
<AuthLayout slogan="Welcome to myFit">
|
||||
{updated === false ? (
|
||||
<div className="content-wrapper update-password-section xl:bg-white dark:bg-dark-white w-full 2xl:h-[818px] xl:h-[600px] sm:w-auto sm:px-[70px] px-5 2xl:px-[100px] rounded-xl flex flex-col justify-center">
|
||||
<div>
|
||||
@@ -34,6 +32,7 @@ export default function UpdatePassword() {
|
||||
<div className="input-area">
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="*********"
|
||||
label="Old Password"
|
||||
name="password"
|
||||
@@ -43,6 +42,7 @@ export default function UpdatePassword() {
|
||||
</div>
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="*********"
|
||||
label="New Password"
|
||||
name="password"
|
||||
@@ -52,6 +52,7 @@ export default function UpdatePassword() {
|
||||
</div>
|
||||
<div className="input-item mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
placeholder="*********"
|
||||
label="Re-enter Password"
|
||||
name="password"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useLocation, Link, useNavigate } from "react-router-dom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png";
|
||||
import debounce from "../../../hooks/debounce";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
|
||||
export default function VerifyLink() {
|
||||
const [email, setEmail] = useState("");
|
||||
@@ -173,6 +173,7 @@ const SuccessfulComponent = ({
|
||||
{/* INPUT */}
|
||||
<div className="mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={email}
|
||||
inputHandler={handleEmail}
|
||||
placeholder="support@mermsemr.com"
|
||||
@@ -184,6 +185,7 @@ const SuccessfulComponent = ({
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={password}
|
||||
inputHandler={handlePassword}
|
||||
placeholder="● ● ● ● ● ●"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useLocation, Link, useNavigate } from "react-router-dom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import { useState } from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard.png";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
|
||||
const VerifyPassword = () => {
|
||||
const [password, setPassword] = useState("");
|
||||
@@ -158,6 +158,7 @@ const SuccessfulComponent = ({
|
||||
{/* INPUT */}
|
||||
<div className="mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={password}
|
||||
inputHandler={handlePassword}
|
||||
placeholder="● ● ● ● ● ●"
|
||||
@@ -165,13 +166,12 @@ const SuccessfulComponent = ({
|
||||
name="password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
onClick={onClick}
|
||||
passIcon={
|
||||
showPassword ? "show-password" : "hide-password"
|
||||
}
|
||||
passIcon={showPassword ? "show-password" : "hide-password"}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
value={confirmPassword}
|
||||
inputHandler={handlePassword}
|
||||
placeholder="● ● ● ● ● ●"
|
||||
|
||||
@@ -1,80 +1,71 @@
|
||||
import React, { useState } from "react";
|
||||
import dataImage1 from "../../assets/images/data-table-user-1.png";
|
||||
import dataImage2 from "../../assets/images/data-table-user-2.png";
|
||||
import dataImage3 from "../../assets/images/data-table-user-3.png";
|
||||
import dataImage4 from "../../assets/images/data-table-user-4.png";
|
||||
import SelectBox from "../Helpers/SelectBox";
|
||||
|
||||
export default function FamilyTable({ className }) {
|
||||
const filterCategories = ["All Categories", "Explore", "Featured"];
|
||||
const [selectedCategory, setCategory] = useState(filterCategories[0]);
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
const filterCategories = ["All Categories", "Explore", "Featured"];
|
||||
const [selectedCategory, setCategory] = useState(filterCategories[0]);
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
<tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom ">
|
||||
<td className="py-4">Name</td>
|
||||
<td className="py-4 text-center">Last Login</td>
|
||||
<td className="py-4 text-center">No of Tasks</td>
|
||||
<td className="py-4 text-right">Status</td>
|
||||
</tr>
|
||||
<tr className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
|
||||
<img
|
||||
src={dataImage1}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
Firstname Lastname (age)
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Added <span className="text-purple">10-10-2029</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
10-10-2019
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
100
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
<tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom ">
|
||||
<td className="py-4">Name</td>
|
||||
<td className="py-4 text-center">Last Login</td>
|
||||
<td className="py-4 text-center">No of Tasks</td>
|
||||
<td className="py-4 text-right">Status</td>
|
||||
</tr>
|
||||
<tr className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
|
||||
<img
|
||||
src={dataImage1}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
Firstname Lastname (age)
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Added <span className="text-purple">10-10-2029</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
10-10-2019
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
100
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2">
|
||||
<button
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<td className="text-right py-4 px-2">
|
||||
<button
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,212 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import React, { useId, useMemo, useState } from "react";
|
||||
import CustomPopUp from "../Helpers/CustomPopUp";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
import FamilyTable from "./FamilyTable";
|
||||
import SiteService from "../../services/SiteService";
|
||||
|
||||
export default function FamilyAcc() {
|
||||
const [selectTab, setValue] = useState("today");
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
return (
|
||||
<Layout>
|
||||
{/*<CommonHead />*/}
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
const [selectTab, setValue] = useState("today");
|
||||
const [selectedAge, setSelectedAge] = useState(undefined);
|
||||
const [loader, setLoader] = useState(false);
|
||||
const [msgErr, setMsgErr] = useState("");
|
||||
const [formData, setFormData] = useState({
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
});
|
||||
|
||||
const apiCall = useMemo(() => new SiteService(), []);
|
||||
|
||||
// tab handler
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
let id = useId();
|
||||
// For the age drop down
|
||||
let startAge = 16;
|
||||
let endAge = 70;
|
||||
// creates an array of age values ranging from 16 to 70
|
||||
const ageRange = Array.from(
|
||||
{ length: endAge - startAge + 1 },
|
||||
(_, index) => startAge + index
|
||||
);
|
||||
// age handler
|
||||
const handleAgeSelect = (event) => {
|
||||
setSelectedAge(parseInt(event.target.value));
|
||||
};
|
||||
// Input handler
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event?.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
};
|
||||
|
||||
const addMember = async () => {
|
||||
let { first_name, last_name } = formData;
|
||||
setLoader(true);
|
||||
try {
|
||||
if (first_name !== "" && last_name !== "") {
|
||||
const reqData = {
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
uid: localStorage.getItem("uid"),
|
||||
session_id: localStorage.getItem("session_token"),
|
||||
firstname: first_name,
|
||||
lastname: last_name,
|
||||
age: selectedAge,
|
||||
};
|
||||
const res = await apiCall.addFamily(reqData);
|
||||
const { data } = res;
|
||||
if (data.internal_return > 0 && data.status == "OK") {
|
||||
setLoader(false);
|
||||
console.log(data);
|
||||
}
|
||||
} else {
|
||||
setLoader(false);
|
||||
setMsgErr("Please fill in the fields");
|
||||
}
|
||||
} catch (error) {
|
||||
setLoader(false);
|
||||
setMsgErr("An error occurred");
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setMsgErr(null);
|
||||
}, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
{/*<CommonHead />*/}
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-2 text-dark-gray dark:text-white">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Family Accounts
|
||||
</span>
|
||||
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div onClick={() => filterHandler("today")} className="relative">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FamilyTable />
|
||||
</div>
|
||||
<CustomPopUp
|
||||
name="(Add)"
|
||||
btn_class="text-purple"
|
||||
key={id}
|
||||
title="Add members"
|
||||
>
|
||||
<FamilyForm
|
||||
value={formData}
|
||||
ageHandler={handleAgeSelect}
|
||||
ageRange={ageRange}
|
||||
ageValue={selectedAge}
|
||||
inputHandler={handleInputChange}
|
||||
msgErr={msgErr}
|
||||
onClick={addMember}
|
||||
loader={loader}
|
||||
/>
|
||||
</CustomPopUp>
|
||||
</h1>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<FamilyTable />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
const FamilyForm = ({
|
||||
value: { first_name, last_name },
|
||||
ageValue,
|
||||
inputHandler,
|
||||
ageHandler,
|
||||
ageRange,
|
||||
msgErr,
|
||||
loader,
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<div className="w-full relative block ">
|
||||
<form className="flex flex-col gap-4">
|
||||
<InputCom
|
||||
placeholder="Firstname"
|
||||
label="First Name:"
|
||||
name="first_name"
|
||||
type="text"
|
||||
parentClass="flex items-center gap-1"
|
||||
labelClass="flex-[0.2] mb-0"
|
||||
inputClass="flex-[0.8]"
|
||||
fieldClass="px-2"
|
||||
value={first_name}
|
||||
inputHandler={inputHandler}
|
||||
/>
|
||||
<InputCom
|
||||
placeholder="Lastname"
|
||||
label="Last Name:"
|
||||
name="last_name"
|
||||
type="text"
|
||||
parentClass="flex items-center gap-1"
|
||||
labelClass="flex-[0.2] mb-0"
|
||||
inputClass="flex-[0.8]"
|
||||
fieldClass="px-2"
|
||||
value={last_name}
|
||||
inputHandler={inputHandler}
|
||||
/>
|
||||
<div className="input-com mb-7 flex gap-1 items-center">
|
||||
{/* Age dropdown */}
|
||||
<div className="flex items-center justify-between flex-[0.3]">
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
|
||||
htmlFor="age-selection"
|
||||
>
|
||||
Select your age:
|
||||
</label>
|
||||
</div>
|
||||
<div className=" flex-[0.7]">
|
||||
<select
|
||||
name="age-selection"
|
||||
id="age-selection"
|
||||
className="input-wrapper border border-[#f5f8fa]] dark:border-[#5e6278] w-full rounded-[0.475rem] h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] text-base focus-visible:border-transparent focus-visible:outline-0 focus-visible:ring-transparent px-2"
|
||||
onChange={ageHandler}
|
||||
value={ageValue}
|
||||
>
|
||||
<option value={""}>Select your age</option>
|
||||
{ageRange?.length > 0 &&
|
||||
ageRange?.map((age) => (
|
||||
<option value={age} key={age}>
|
||||
{age}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{msgErr && (
|
||||
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px]">
|
||||
{msgErr}
|
||||
</div>
|
||||
)}
|
||||
<div className="signin-area">
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={`rounded-[0.475rem] text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center h-[42px] py-[0.8875rem] px-[1.81rem] text-[14.95px] btn-login`}
|
||||
>
|
||||
{loader ? (
|
||||
<div className="signup btn-loader"></div>
|
||||
) : (
|
||||
<span>Add</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const CustomPopUp = ({ name, btn_class, title, children }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const handleOpen = () => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={handleOpen} className={btn_class}>
|
||||
{name}
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className={`fixed inset-0 bg-gray-800 bg-opacity-75 flex items-center justify-center z-50 transition-opacity ${isOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}>
|
||||
<div className="bg-white rounded-md p-6 shadow-lg transform transition-all duration-300 ease-in-out lg:max-w-[400px] lg:min-h-[300px] max-w-[300px] min-h-[200px] w-full">
|
||||
<div className="w-full flex justify-end">
|
||||
<button onClick={handleClose}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
{title && <h2 className="text-xl font-bold mb-2">{title}</h2>}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomPopUp;
|
||||
|
||||
const CloseIcon = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -12,76 +12,153 @@ export default function InputCom({
|
||||
inputHandler,
|
||||
value,
|
||||
forgotPassword,
|
||||
parentClass,
|
||||
labelClass,
|
||||
inputClass,
|
||||
fieldClass,
|
||||
onClick,
|
||||
disable,
|
||||
blurHandler
|
||||
blurHandler,
|
||||
}) {
|
||||
const inputRef = useRef(null)
|
||||
const inputRef = useRef(null);
|
||||
// Entry Validation
|
||||
// for Min Length:
|
||||
const minLengthValidation = () => {
|
||||
if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') {
|
||||
return 7
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') {
|
||||
return 3
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') {
|
||||
return 3
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') {
|
||||
return 5
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') {
|
||||
return 8
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') {
|
||||
return 3
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') {
|
||||
return 3
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') {
|
||||
return 3
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') {
|
||||
return 1
|
||||
if (inputRef && inputRef?.current && inputRef?.current?.name === "email") {
|
||||
return 7;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "first_name"
|
||||
) {
|
||||
return 3;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "last_name"
|
||||
) {
|
||||
return 3;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "address"
|
||||
) {
|
||||
return 5;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "password"
|
||||
) {
|
||||
return 8;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "state"
|
||||
) {
|
||||
return 3;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "province"
|
||||
) {
|
||||
return 3;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "city"
|
||||
) {
|
||||
return 3;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "amount"
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// for MaxLength
|
||||
const maxLengthValidation = () => {
|
||||
if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') {
|
||||
return 35
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') {
|
||||
return 25
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') {
|
||||
return 25
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') {
|
||||
return 49
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') {
|
||||
return 15
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') {
|
||||
return 25
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') {
|
||||
return 25
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') {
|
||||
return 25
|
||||
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') {
|
||||
return 9
|
||||
if (inputRef && inputRef?.current && inputRef?.current?.name === "email") {
|
||||
return 35;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "first_name"
|
||||
) {
|
||||
return 25;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "last_name"
|
||||
) {
|
||||
return 25;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "address"
|
||||
) {
|
||||
return 49;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "password"
|
||||
) {
|
||||
return 15;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "state"
|
||||
) {
|
||||
return 25;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "province"
|
||||
) {
|
||||
return 25;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "city"
|
||||
) {
|
||||
return 25;
|
||||
} else if (
|
||||
inputRef &&
|
||||
inputRef?.current &&
|
||||
inputRef?.current?.name === "amount"
|
||||
) {
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="input-com">
|
||||
<div className="flex items-center justify-between">
|
||||
{label && (
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block mb-2.5"
|
||||
htmlFor={name}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{forgotPassword && <Link to="/forgot-password" className="text-[13.975px] leading-[20.9625px] text-[#019ef7] hover:text-[#009ef7]">Forgot Password?</Link>}
|
||||
<div className={`input-com ${parentClass}`}>
|
||||
<div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
|
||||
{label && (
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
|
||||
htmlFor={name}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{forgotPassword && (
|
||||
<Link
|
||||
to="/forgot-password"
|
||||
className="text-[13.975px] leading-[20.9625px] text-[#019ef7] hover:text-[#009ef7]"
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="input-wrapper border border-[#f5f8fa]] dark:border-[#5e6278] w-full rounded-[0.475rem] h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] text-base ">
|
||||
<div
|
||||
className={`input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-full rounded-[0.475rem] h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] text-base ${inputClass}`}
|
||||
>
|
||||
<input
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={inputHandler}
|
||||
className="input-field placeholder:text-base px-6 text-dark-gray dark:text-white w-full h-full bg-[#FAFAFA] dark:bg-[#11131F] focus:ring-0 focus:outline-none"
|
||||
className={`input-field placeholder:text-base text-dark-gray dark:text-white w-full h-full bg-[#FAFAFA] dark:bg-[#11131F] focus:ring-0 focus:outline-none ${fieldClass}`}
|
||||
type={type}
|
||||
id={name}
|
||||
name={name}
|
||||
@@ -97,7 +174,10 @@ export default function InputCom({
|
||||
</div>
|
||||
)}
|
||||
{passIcon && (
|
||||
<div className="absolute right-6 bottom-[10px] z-10" onClick={onClick}>
|
||||
<div
|
||||
className="absolute right-6 bottom-[10px] z-10"
|
||||
onClick={onClick}
|
||||
>
|
||||
<Icons name={passIcon} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,370 +1,499 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import Icons from '../Helpers/Icons'
|
||||
import usersService from '../../services/UsersService'
|
||||
import InputCom from '../Helpers/Inputs/InputCom'
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import usersService from "../../services/UsersService";
|
||||
import Icons from "../Helpers/Icons";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner'
|
||||
import {toast} from 'react-toastify'
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { toast } from "react-toastify";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
firstname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Firstname is required'),
|
||||
lastname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Lastname is required'),
|
||||
country: Yup.string()
|
||||
.min(1, 'Minimum 1 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Country is required'),
|
||||
bank: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Bank name is required'),
|
||||
accountNumber: Yup.string()
|
||||
firstname: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Firstname is required"),
|
||||
lastname: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Lastname is required"),
|
||||
country: Yup.string()
|
||||
.min(1, "Minimum 1 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Country is required"),
|
||||
bank: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Bank name is required"),
|
||||
accountNumber: Yup.string()
|
||||
.matches(/\d/, "must be a number")
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Account Number is required'),
|
||||
repeatAccountNumber: Yup.string()
|
||||
.required('Repeat Account Number is required')
|
||||
.oneOf([Yup.ref('accountNumber'), null], 'Must match Account Number'),
|
||||
accountType: Yup.string()
|
||||
.min(1, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Account Type is required'),
|
||||
city: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('City is required'),
|
||||
state: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('State is required'),
|
||||
})
|
||||
|
||||
const initialValues = {
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
country: '',
|
||||
bank: '',
|
||||
accountNumber: '',
|
||||
repeatAccountNumber: '',
|
||||
accountType: '',
|
||||
state: '',
|
||||
city: ''
|
||||
}
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Account Number is required"),
|
||||
repeatAccountNumber: Yup.string()
|
||||
.required("Repeat Account Number is required")
|
||||
.oneOf([Yup.ref("accountNumber"), null], "Must match Account Number"),
|
||||
accountType: Yup.string()
|
||||
.min(1, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Account Type is required"),
|
||||
city: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("City is required"),
|
||||
state: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("State is required"),
|
||||
});
|
||||
|
||||
const initialValues = {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
country: "",
|
||||
bank: "",
|
||||
accountNumber: "",
|
||||
repeatAccountNumber: "",
|
||||
accountType: "",
|
||||
state: "",
|
||||
city: "",
|
||||
};
|
||||
|
||||
function AddRecipient() {
|
||||
const apiURL = new usersService();
|
||||
|
||||
const apiURL = new usersService()
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigate = useNavigate()
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
message: "",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false})
|
||||
let [allCountries, setAllCountries] = useState({
|
||||
// STATE TO HOLD LIST OF COUNTRIES
|
||||
loading: true,
|
||||
data: [],
|
||||
});
|
||||
|
||||
let [allCountries, setAllCountries] = useState({ // STATE TO HOLD LIST OF COUNTRIES
|
||||
loading: true,
|
||||
data: []
|
||||
})
|
||||
let [bankName, setBankName] = useState({
|
||||
// STATE TO HOLD LIST OF BANK NAME
|
||||
loading: true,
|
||||
data: [],
|
||||
});
|
||||
|
||||
let [bankName, setBankName] = useState({ // STATE TO HOLD LIST OF BANK NAME
|
||||
loading: true,
|
||||
data: []
|
||||
})
|
||||
let [accType, setAccType] = useState({
|
||||
// STATE TO HOLD LIST ACCOUNT TYPE
|
||||
loading: true,
|
||||
data: [],
|
||||
});
|
||||
|
||||
let [accType, setAccType] = useState({ // STATE TO HOLD LIST ACCOUNT TYPE
|
||||
loading: true,
|
||||
data: []
|
||||
})
|
||||
//FUNCTION TO HANDLE ADD RECIPIENT SUBMIT
|
||||
const handleSubmit = (values, helpers) => {
|
||||
setRequestStatus({ message: "", loading: true, status: false });
|
||||
|
||||
//FUNCTION TO HANDLE ADD RECIPIENT SUBMIT
|
||||
const handleSubmit = (values, helpers) => {
|
||||
setRequestStatus({message: '', loading: true, status: false})
|
||||
let reqData = {
|
||||
//REQUEST DATA FOR API CALL
|
||||
firstname: values.firstname,
|
||||
lastname: values.lastname,
|
||||
bank_code: values.bank,
|
||||
account_no: values.accountNumber,
|
||||
account_type: values.accountType,
|
||||
country: values.country,
|
||||
state: values.state,
|
||||
city: values.city,
|
||||
};
|
||||
|
||||
let reqData = { //REQUEST DATA FOR API CALL
|
||||
firstname: values.firstname,
|
||||
lastname: values.lastname,
|
||||
bank_code: values.bank,
|
||||
account_no: values.accountNumber,
|
||||
account_type: values.accountType,
|
||||
country: values.country,
|
||||
state: values.state,
|
||||
city: values.city
|
||||
//CALL TO ADD RECIPIENT API
|
||||
apiURL
|
||||
.addRecipient(reqData)
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setRequestStatus({
|
||||
message: "could not add recipient, try again!",
|
||||
loading: false,
|
||||
status: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// setRequestStatus({message: 'Recipient Added Successfully!', loading: false, status: true})
|
||||
toast.success("Recipient Added Successfully!");
|
||||
setTimeout(() => {
|
||||
navigate("/my-wallet/transfer-fund", { replace: true });
|
||||
}, 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
setRequestStatus({
|
||||
message: "Opps! an error occured! Try again later",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//CALL TO ADD RECIPIENT API
|
||||
apiURL.addRecipient(reqData).then((res)=>{
|
||||
if(res.data.internal_return < 0){
|
||||
setRequestStatus({message: 'could not add recipient, try again!', loading: false, status: true})
|
||||
return
|
||||
}
|
||||
// setRequestStatus({message: 'Recipient Added Successfully!', loading: false, status: true})
|
||||
toast.success("Recipient Added Successfully!");
|
||||
setTimeout(()=>{navigate('/my-wallet/transfer-fund',{replace:true})},1000)
|
||||
}).catch((error)=>{
|
||||
setRequestStatus({message: 'Opps! an error occured! Try again later', loading: false, status: false})
|
||||
})
|
||||
}
|
||||
// FUNCTION TO GET COUNTRIES
|
||||
const getCountry = () => {
|
||||
apiURL
|
||||
.getSignupCountryData()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setAllCountries((prev) => ({ loading: false, data: [] }));
|
||||
return;
|
||||
}
|
||||
setAllCountries((prev) => ({
|
||||
loading: false,
|
||||
data: res.data.signup_country,
|
||||
}));
|
||||
})
|
||||
.catch((error) => {
|
||||
setAllCountries((prev) => ({ loading: false, data: [] }));
|
||||
});
|
||||
};
|
||||
// END OF FUNCTION TO GET COUNTRIES
|
||||
|
||||
// FUNCTION TO GET COUNTRY BANK
|
||||
const getCountryBank = () => {
|
||||
apiURL
|
||||
.getCountryBank()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setBankName((prev) => ({ loading: false, data: [] }));
|
||||
return;
|
||||
}
|
||||
setBankName((prev) => ({ loading: false, data: res.data.result_list }));
|
||||
})
|
||||
.catch((error) => {
|
||||
setBankName((prev) => ({ loading: false, data: [] }));
|
||||
});
|
||||
};
|
||||
// END OF FUNCTION TO GET COUNTRY BANK
|
||||
|
||||
// FUNCTION TO GET COUNTRIES
|
||||
const getCountry = ()=> {
|
||||
apiURL.getSignupCountryData().then((res)=>{
|
||||
if(res.data.internal_return < 0){
|
||||
setAllCountries(prev => ({loading: false, data: []}))
|
||||
return
|
||||
}
|
||||
setAllCountries(prev => ({loading: false, data:res.data.signup_country}))
|
||||
}).catch((error)=>{
|
||||
setAllCountries(prev => ({loading: false, data: []}))
|
||||
})
|
||||
}
|
||||
// END OF FUNCTION TO GET COUNTRIES
|
||||
// FUNCTION TO GET ACCOUNT TYPES
|
||||
const getAccountTypes = () => {
|
||||
apiURL
|
||||
.getAccountTypes()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setAccType((prev) => ({ loading: false, data: [] }));
|
||||
return;
|
||||
}
|
||||
setAccType((prev) => ({ loading: false, data: res.data.result_list }));
|
||||
})
|
||||
.catch((error) => {
|
||||
setAccType((prev) => ({ loading: false, data: [] }));
|
||||
});
|
||||
};
|
||||
// END OF FUNCTION TO GET ACCOUNT TYPES
|
||||
|
||||
// FUNCTION TO GET COUNTRY BANK
|
||||
const getCountryBank = ()=> {
|
||||
apiURL.getCountryBank().then((res)=>{
|
||||
if(res.data.internal_return < 0){
|
||||
setBankName(prev => ({loading: false, data: []}))
|
||||
return
|
||||
}
|
||||
setBankName(prev => ({loading: false, data:res.data.result_list}))
|
||||
}).catch((error)=>{
|
||||
setBankName(prev => ({loading: false, data: []}))
|
||||
})
|
||||
}
|
||||
// END OF FUNCTION TO GET COUNTRY BANK
|
||||
useEffect(() => {
|
||||
getCountry(); // TO LOAD LIST COUNTRY
|
||||
getCountryBank(); // TO LOAD LIST COUNTRY BANK
|
||||
getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
|
||||
}, []);
|
||||
|
||||
// FUNCTION TO GET ACCOUNT TYPES
|
||||
const getAccountTypes = ()=> {
|
||||
apiURL.getAccountTypes().then((res)=>{
|
||||
if(res.data.internal_return < 0){
|
||||
setAccType(prev => ({loading: false, data: []}))
|
||||
return
|
||||
}
|
||||
setAccType(prev => ({loading: false, data:res.data.result_list}))
|
||||
}).catch((error)=>{
|
||||
setAccType(prev => ({loading: false, data: []}))
|
||||
})
|
||||
}
|
||||
// END OF FUNCTION TO GET ACCOUNT TYPES
|
||||
return (
|
||||
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
|
||||
<div className="w-full mb-10 lg:mb-0">
|
||||
<div className="w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow">
|
||||
<h2 className="my-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-semibold">
|
||||
ADD BANK ACCOUNT
|
||||
</h2>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => (
|
||||
<Form className="add-recipient-info px-1 md:px-[50px] lg:px-[100px]">
|
||||
{/* inputs starts here */}
|
||||
{/* firstname */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Firstname"
|
||||
type="text"
|
||||
name="firstname"
|
||||
placeholder="Account Firstname"
|
||||
value={props.values.firstname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.firstname && props.touched.firstname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.firstname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
useEffect(()=>{
|
||||
getCountry() // TO LOAD LIST COUNTRY
|
||||
getCountryBank() // TO LOAD LIST COUNTRY BANK
|
||||
getAccountTypes() // TO LOAD LIST ACCOUNT TYPES
|
||||
},[])
|
||||
|
||||
return (
|
||||
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
|
||||
<div className="w-full mb-10 lg:mb-0">
|
||||
<div className="w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow">
|
||||
<h2 className='my-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-semibold'>ADD BANK ACCOUNT</h2>
|
||||
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}>
|
||||
{(props)=>(
|
||||
<Form className='add-recipient-info px-1 md:px-[50px] lg:px-[100px]'>
|
||||
|
||||
{/* inputs starts here */}
|
||||
{/* firstname */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
label="Firstname"
|
||||
type="text"
|
||||
name="firstname"
|
||||
placeholder="Account Firstname"
|
||||
value={props.values.firstname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.firstname && props.touched.firstname) && <p className="text-sm text-red-500">{props.errors.firstname}</p>}
|
||||
</div>
|
||||
|
||||
{/* lastname */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
label="Lastname"
|
||||
type="text"
|
||||
name="lastname"
|
||||
placeholder="Account Lastname"
|
||||
value={props.values.lastname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.lastname && props.touched.lastname) && <p className="text-sm text-red-500">{props.errors.lastname}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
{/* country */}
|
||||
<div className='add-recipient w-full mb-6 xl:mb-0'>
|
||||
<label className='input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Country <span className='text-red-500'>*</span></label>
|
||||
<select className='w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0' name='country'
|
||||
value={props.values.country}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{allCountries.loading ?
|
||||
<option className='text-slate-500 text-lg' value="">Loading...</option>
|
||||
:
|
||||
allCountries.data.length ?
|
||||
<>
|
||||
<option className='text-slate-500 text-lg' value="">Select...</option>
|
||||
{allCountries.data.map((item, index)=>(
|
||||
<option key={index} className='text-slate-500 text-lg' value={item[0]}>{item[1]}</option>
|
||||
))}
|
||||
</>
|
||||
:
|
||||
<option className='text-slate-500 text-lg' value="">No Options Found! Try Again</option>
|
||||
}
|
||||
</select>
|
||||
{(props.errors.country && props.touched.country) && <p className="text-sm text-red-500">{props.errors.country}</p>}
|
||||
</div>
|
||||
|
||||
{/* bank name */}
|
||||
<div className='add-recipient w-full'>
|
||||
<label className='input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Bank Name <span className='text-red-500'>*</span></label>
|
||||
<select className='w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0' name='bank'
|
||||
value={props.values.bank}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{bankName.loading ?
|
||||
<option className='text-slate-500 text-lg' value="">Loading...</option>
|
||||
:
|
||||
bankName.data.length ?
|
||||
<>
|
||||
<option className='text-slate-500 text-lg' value="">Select...</option>
|
||||
{bankName.data.map((item, index)=>(
|
||||
<option key={index} className='text-slate-500 text-lg' value={item.code}>{item.name}</option>
|
||||
))}
|
||||
</>
|
||||
:
|
||||
<option className='text-slate-500 text-lg' value="">No Options Found! Try Again</option>
|
||||
}
|
||||
</select>
|
||||
{(props.errors.bank && props.touched.bank) && <p className="text-sm text-red-500">{props.errors.bank}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ACCOUNT NUMBER */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
label="Account Number"
|
||||
type="text"
|
||||
name="accountNumber"
|
||||
placeholder="Account No"
|
||||
value={props.values.accountNumber}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.accountNumber && props.touched.accountNumber) && <p className="text-sm text-red-500">{props.errors.accountNumber}</p>}
|
||||
</div>
|
||||
|
||||
{/* REPEAT ACCT. NUMBER */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
label="Repeat Account Number"
|
||||
type="text"
|
||||
name="repeatAccountNumber"
|
||||
placeholder="Repeat Account Number"
|
||||
value={props.values.repeatAccountNumber}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.repeatAccountNumber && props.touched.repeatAccountNumber) && <p className="text-sm text-red-500">{props.errors.repeatAccountNumber}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
{/* Account Type */}
|
||||
<div className='add-recipient w-full'>
|
||||
<label className='input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Account Type <span className='text-red-500'>*</span></label>
|
||||
<select className='w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0' name='accountType'
|
||||
value={props.values.accountType}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{accType.loading ?
|
||||
<option className='text-slate-500 text-lg' value="">Loading...</option>
|
||||
:
|
||||
accType.data.length ?
|
||||
<>
|
||||
<option className='text-slate-500 text-lg' value="">Select...</option>
|
||||
{accType.data.map((item, index)=>(
|
||||
<option key={index} className='text-slate-500 text-lg' value={item.value}>{item.name}</option>
|
||||
))}
|
||||
</>
|
||||
:
|
||||
<option className='text-slate-500 text-lg' value="">No Options Found! Try Again</option>
|
||||
}
|
||||
</select>
|
||||
{(props.errors.accountType && props.touched.accountType) && <p className="text-sm text-red-500">{props.errors.accountType}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* state */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
label="State"
|
||||
type="text"
|
||||
name="state"
|
||||
placeholder="State/Province"
|
||||
value={props.values.state}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.state && props.touched.state) && <p className="text-sm text-red-500">{props.errors.state}</p>}
|
||||
</div>
|
||||
|
||||
{/* city */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
label="City"
|
||||
type="text"
|
||||
name="city"
|
||||
placeholder="City"
|
||||
value={props.values.city}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.city && props.touched.city) && <p className="text-sm text-red-500">{props.errors.city}</p>}
|
||||
</div>
|
||||
</div>
|
||||
{/* end of inputs starts here */}
|
||||
|
||||
{/* REQUEST ERROR DISPLAY */}
|
||||
{requestStatus.message && <p className='text-sm text-red-500'>{requestStatus.message}</p>}
|
||||
|
||||
<div className='add-recipient-btn flex justify-end items-center py-4'>
|
||||
{requestStatus.loading ?
|
||||
<LoadingSpinner size={6} color='sky-blue' />
|
||||
:
|
||||
<button type='submit' className='text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md flex items-center space-x-1'>
|
||||
<span className='pr-2'>ADD RECIPIENT</span>
|
||||
<Icons name="arrows" />
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
{/* lastname */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Lastname"
|
||||
type="text"
|
||||
name="lastname"
|
||||
placeholder="Account Lastname"
|
||||
value={props.values.lastname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.lastname && props.touched.lastname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.lastname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
{/* country */}
|
||||
<div className="add-recipient w-full mb-6 xl:mb-0">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
|
||||
Country <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
className="w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0"
|
||||
name="country"
|
||||
value={props.values.country}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{allCountries.loading ? (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Loading...
|
||||
</option>
|
||||
) : allCountries.data.length ? (
|
||||
<>
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Select...
|
||||
</option>
|
||||
{allCountries.data.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item[0]}
|
||||
>
|
||||
{item[1]}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
No Options Found! Try Again
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{props.errors.country && props.touched.country && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.country}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* bank name */}
|
||||
<div className="add-recipient w-full">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
|
||||
Bank Name <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
className="w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0"
|
||||
name="bank"
|
||||
value={props.values.bank}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{bankName.loading ? (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Loading...
|
||||
</option>
|
||||
) : bankName.data.length ? (
|
||||
<>
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Select...
|
||||
</option>
|
||||
{bankName.data.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.code}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
No Options Found! Try Again
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{props.errors.bank && props.touched.bank && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.bank}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ACCOUNT NUMBER */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Account Number"
|
||||
type="text"
|
||||
name="accountNumber"
|
||||
placeholder="Account No"
|
||||
value={props.values.accountNumber}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.accountNumber &&
|
||||
props.touched.accountNumber && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.accountNumber}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* REPEAT ACCT. NUMBER */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Repeat Account Number"
|
||||
type="text"
|
||||
name="repeatAccountNumber"
|
||||
placeholder="Repeat Account Number"
|
||||
value={props.values.repeatAccountNumber}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.repeatAccountNumber &&
|
||||
props.touched.repeatAccountNumber && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.repeatAccountNumber}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
{/* Account Type */}
|
||||
<div className="add-recipient w-full">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
|
||||
Account Type <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
className="w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0"
|
||||
name="accountType"
|
||||
value={props.values.accountType}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{accType.loading ? (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Loading...
|
||||
</option>
|
||||
) : accType.data.length ? (
|
||||
<>
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Select...
|
||||
</option>
|
||||
{accType.data.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.value}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
No Options Found! Try Again
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{props.errors.accountType && props.touched.accountType && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.accountType}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* state */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="State"
|
||||
type="text"
|
||||
name="state"
|
||||
placeholder="State/Province"
|
||||
value={props.values.state}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.state && props.touched.state && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.state}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* city */}
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="City"
|
||||
type="text"
|
||||
name="city"
|
||||
placeholder="City"
|
||||
value={props.values.city}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.city && props.touched.city && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.city}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* end of inputs starts here */}
|
||||
|
||||
{/* REQUEST ERROR DISPLAY */}
|
||||
{requestStatus.message && (
|
||||
<p className="text-sm text-red-500">
|
||||
{requestStatus.message}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="add-recipient-btn flex justify-end items-center py-4">
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size={6} color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md flex items-center space-x-1"
|
||||
>
|
||||
<span className="pr-2">ADD RECIPIENT</span>
|
||||
<Icons name="arrows" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddRecipient
|
||||
export default AddRecipient;
|
||||
|
||||
@@ -1,132 +1,156 @@
|
||||
import React, {useState, useEffect} from 'react'
|
||||
import RecentActivityTable from './WalletComponent/RecentActivityTable'
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner'
|
||||
import InputCom from '../Helpers/Inputs/InputCom'
|
||||
import {toast} from 'react-toastify'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
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'
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
import { FlutterWaveButton, closePaymentModal } from 'flutterwave-react-v3'
|
||||
import { FlutterWaveButton, closePaymentModal } from "flutterwave-react-v3";
|
||||
|
||||
function ConfirmAddFund({ payment }) {
|
||||
let { userDetails } = useSelector((state) => state.userDetails); // TO GET LOGGEDIN USER DETAILS
|
||||
|
||||
function ConfirmAddFund({payment}) {
|
||||
let [pageLoading, setPageLoading] = useState(true);
|
||||
|
||||
let {userDetails} = useSelector(state => state.userDetails) // TO GET LOGGEDIN USER DETAILS
|
||||
|
||||
let [pageLoading, setPageLoading] = useState(true)
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
message: "",
|
||||
loading: false,
|
||||
status: false,
|
||||
}); // STATE FOR API REQUEST
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false}) // STATE FOR API REQUEST
|
||||
const apiURL = new usersService();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const apiURL = new usersService()
|
||||
const navigate = useNavigate()
|
||||
let { state } = useLocation();
|
||||
|
||||
let {state} = useLocation()
|
||||
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const onSuccessPayment = () => {
|
||||
setRequestStatus({message: '', loading: true, status: false})
|
||||
let reqData = {amount: state?.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 sucessful')
|
||||
setTimeout(()=>{
|
||||
navigate('/my-wallet', {replace: true})
|
||||
window.location.reload(true)
|
||||
}, 1000)
|
||||
}).catch(err => {
|
||||
// do something
|
||||
setRequestStatus({message: 'Opps! An Error Occured', loading: false, status: false})
|
||||
toast.success('Opps! something went wrong')
|
||||
})
|
||||
}
|
||||
|
||||
const config = {
|
||||
public_key: process.env.REACT_APP_FLUTTERWAVE_APIKEY,
|
||||
tx_ref: Date.now(),
|
||||
amount: state?.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',
|
||||
logo: 'https://st2.depositphotos.com/4403291/7418/v/450/depositphotos_74189661-stock-illustration-online-shop-log.jpg',
|
||||
},
|
||||
};
|
||||
|
||||
const fwConfig = {
|
||||
...config,
|
||||
text: 'Proceed',
|
||||
callback: (response) => {
|
||||
onSuccessPayment()
|
||||
closePaymentModal() // this will close the modal programmatically
|
||||
},
|
||||
onClose: () => {},
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
// what happens if not state redirect user
|
||||
if(!state){
|
||||
navigate('/my-wallet/add-fund',{replace: true})
|
||||
}else{
|
||||
setPageLoading(false)
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const onSuccessPayment = () => {
|
||||
setRequestStatus({ message: "", loading: true, status: false });
|
||||
let reqData = { amount: state?.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 sucessful");
|
||||
setTimeout(() => {
|
||||
navigate("/my-wallet", { replace: true });
|
||||
window.location.reload(true);
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
// do something
|
||||
setRequestStatus({
|
||||
message: "Opps! An Error Occured",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
toast.success("Opps! something went wrong");
|
||||
});
|
||||
};
|
||||
|
||||
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">
|
||||
<h2 className='md:p-8 p-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium'>Confirm Add Fund To Account</h2>
|
||||
<hr />
|
||||
<div className='px-4 md:px-8 py-4 add-fund-info'>
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
label="Amount (Naira):"
|
||||
type="text"
|
||||
name="amount"
|
||||
value={state.amount || ''}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
const config = {
|
||||
public_key: process.env.REACT_APP_FLUTTERWAVE_APIKEY,
|
||||
tx_ref: Date.now(),
|
||||
amount: state?.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",
|
||||
logo: "https://st2.depositphotos.com/4403291/7418/v/450/depositphotos_74189661-stock-illustration-online-shop-log.jpg",
|
||||
},
|
||||
};
|
||||
|
||||
<hr />
|
||||
<div className='md:p-8 p-4 add-fund-btn flex justify-end items-center py-4'>
|
||||
<FlutterWaveButton {...fwConfig} className='text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md' />
|
||||
</div>
|
||||
</div>
|
||||
const fwConfig = {
|
||||
...config,
|
||||
text: "Proceed",
|
||||
callback: (response) => {
|
||||
onSuccessPayment();
|
||||
closePaymentModal(); // this will close the modal programmatically
|
||||
},
|
||||
onClose: () => {},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// what happens if not state redirect user
|
||||
if (!state) {
|
||||
navigate("/my-wallet/add-fund", { 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">
|
||||
<h2 className="md:p-8 p-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
|
||||
Confirm Add Fund To Account
|
||||
</h2>
|
||||
<hr />
|
||||
<div className="px-4 md:px-8 py-4 add-fund-info">
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Amount (Naira):"
|
||||
type="text"
|
||||
name="amount"
|
||||
value={state.amount || ""}
|
||||
disable={true}
|
||||
/>
|
||||
</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-[600px] 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>
|
||||
|
||||
<hr />
|
||||
<div className="md:p-8 p-4 add-fund-btn flex justify-end items-center py-4">
|
||||
<FlutterWaveButton
|
||||
{...fwConfig}
|
||||
className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</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-[600px] 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 ConfirmAddFund
|
||||
export default ConfirmAddFund;
|
||||
|
||||
@@ -1,168 +1,210 @@
|
||||
import React, {useState, useEffect} from 'react'
|
||||
import {useLocation, useNavigate} from 'react-router-dom'
|
||||
import RecentActivityTable from './WalletComponent/RecentActivityTable'
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner'
|
||||
import InputCom from '../Helpers/Inputs/InputCom'
|
||||
import {toast} from 'react-toastify'
|
||||
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'
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
function ConfirmTransfer({payment, wallet}) {
|
||||
const apiURL = new usersService()
|
||||
function ConfirmTransfer({ payment, wallet }) {
|
||||
const apiURL = new usersService();
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
let {state} = useLocation()
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false})
|
||||
let [pageLoading, setPageLoading] = useState(true)
|
||||
let { state } = useLocation();
|
||||
|
||||
//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)
|
||||
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;
|
||||
}
|
||||
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})
|
||||
})
|
||||
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/transfer-fund", { replace: true });
|
||||
} else {
|
||||
setPageLoading(false);
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
// what happens if not state redirect user
|
||||
if(!state){
|
||||
navigate('/my-wallet/transfer-fund',{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
|
||||
label="Amount:"
|
||||
type="text"
|
||||
name="amount"
|
||||
value={state?.amount || ''}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* RECIPIENT ACC: */}
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
label="Recipient Acc:"
|
||||
type="text"
|
||||
name="recipient"
|
||||
value={state?.details.recipient || ''}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* PROCESSING FEE: */}
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
label="Processing Fee:"
|
||||
type="text"
|
||||
name="processingFee"
|
||||
value={state?.fee || ''}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* TOTAL */}
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
label="Total"
|
||||
type="text"
|
||||
name="total"
|
||||
value={state?.total || ''}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* COMMENT/NOTE */}
|
||||
<div className="field w-full mb-3">
|
||||
<InputCom
|
||||
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}/>
|
||||
}, []);
|
||||
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)}`;
|
||||
}
|
||||
</div>
|
||||
})}
|
||||
</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 ConfirmTransfer
|
||||
export default ConfirmTransfer;
|
||||
|
||||
@@ -1,240 +1,326 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import RecentActivityTable from './WalletComponent/RecentActivityTable'
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner'
|
||||
import InputCom from '../Helpers/Inputs/InputCom'
|
||||
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 usersService from "../../services/UsersService";
|
||||
|
||||
import {toast} from 'react-toastify'
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
amount: Yup.number()
|
||||
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: '',
|
||||
}
|
||||
.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"),
|
||||
});
|
||||
|
||||
function TransferFund({payment, wallet}) {
|
||||
const apiCall = new usersService() // API CLASS CALL
|
||||
const initialValues = {
|
||||
amount: "",
|
||||
recipientID: "",
|
||||
comment: "",
|
||||
};
|
||||
|
||||
const navigate = useNavigate()
|
||||
function TransferFund({ payment, wallet }) {
|
||||
const apiCall = new usersService(); // API CLASS CALL
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState(false)
|
||||
const navigate = useNavigate();
|
||||
|
||||
let [recipients, setRecipients] = useState({ // FOR COUPON HISTORY
|
||||
loading: true,
|
||||
data: [],
|
||||
error: false
|
||||
})
|
||||
let [requestStatus, setRequestStatus] = useState(false);
|
||||
|
||||
let [sendMoneyFee, setSendMoneyFee] = useState({loading: false, fee: 0, total: 0}) // HOLD THE VALUE FOR SEND MONEY FEE
|
||||
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
|
||||
//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;
|
||||
}
|
||||
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})
|
||||
})
|
||||
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) => {
|
||||
setRequestStatus(true);
|
||||
let recipientDetails = recipients.data?.filter(
|
||||
(item) => item.recipient_id == values.recipientID
|
||||
);
|
||||
let stateData = {
|
||||
...values,
|
||||
...sendMoneyFee,
|
||||
details: { ...recipientDetails[0] },
|
||||
};
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values, helpers) => {
|
||||
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-transfer", { state: stateData });
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
setTimeout(()=>{
|
||||
setRequestStatus(false)
|
||||
navigate('confirm-transfer', {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 Occured
|
||||
</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="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Amount"
|
||||
type="text"
|
||||
name="amount"
|
||||
placeholder="0"
|
||||
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="text-sm text-red-500">
|
||||
{props.errors.amount}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
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 Occured</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="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Fee"
|
||||
type="text"
|
||||
name="fee"
|
||||
value={
|
||||
sendMoneyFee.loading ? "loading" : sendMoneyFee.fee
|
||||
}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
label="Amount"
|
||||
type="text"
|
||||
name="amount"
|
||||
placeholder='0'
|
||||
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="text-sm text-red-500">{props.errors.amount}</p>}
|
||||
</div>
|
||||
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
label="Fee"
|
||||
type="text"
|
||||
name="fee"
|
||||
value={sendMoneyFee.loading ? 'loading' : sendMoneyFee.fee}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:flex items-center justify-end">
|
||||
<div className="field w-full lg:w-1/2 mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Total"
|
||||
type="text"
|
||||
name="total"
|
||||
value={
|
||||
sendMoneyFee.loading ? "loading" : sendMoneyFee.total
|
||||
}
|
||||
disable={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='md:flex items-center justify-end'>
|
||||
<div className="field w-full lg:w-1/2 mb-6">
|
||||
<InputCom
|
||||
label="Total"
|
||||
type="text"
|
||||
name="total"
|
||||
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'>
|
||||
<div className='flex items-center justify-start py-2'>
|
||||
<label className='text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Recipient
|
||||
<span className='text-red-500 mx-2'>*</span>
|
||||
<span title='Transfer Recipient' className={`text-white text-sm bg-slate-500 w-1 h-1 rounded-full px-3 py-1 cursor-pointer`}>!</span>
|
||||
</label>
|
||||
<Link to='add-recipient' className='mx-1 text-base text-white p-2 bg-[orange] rounded-md hover:opacity-80'>Add New</Link>
|
||||
</div>
|
||||
<select className='w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0' 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! Click Add to Add</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{(props.errors.recipientID && props.touched.recipientID) && <p className="text-sm text-red-500">{props.errors.recipientID}</p>}
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="relative my-3 md:flex items-center">
|
||||
<div className="transfer-input w-full">
|
||||
<div className="flex items-center justify-start py-2">
|
||||
<label className="text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
|
||||
Recipient
|
||||
<span className="text-red-500 mx-2">*</span>
|
||||
<span
|
||||
title="Transfer Recipient"
|
||||
className={`text-white text-sm bg-slate-500 w-1 h-1 rounded-full px-3 py-1 cursor-pointer`}
|
||||
>
|
||||
!
|
||||
</span>
|
||||
</label>
|
||||
<Link
|
||||
to="add-recipient"
|
||||
className="mx-1 text-base text-white p-2 bg-[orange] rounded-md hover:opacity-80"
|
||||
>
|
||||
Add New
|
||||
</Link>
|
||||
</div>
|
||||
<select
|
||||
className="w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0"
|
||||
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! Click Add to Add
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{props.errors.recipientID && props.touched.recipientID && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.recipientID}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6">
|
||||
{/* <InputCom
|
||||
<div className="field w-full mb-6">
|
||||
{/* <InputCom fieldClass="px-6"
|
||||
label="Comment"
|
||||
type="text"
|
||||
name="comment"
|
||||
value={inputs.comment}
|
||||
inputHandler={handleChange}
|
||||
/> */}
|
||||
<label className='text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Comment</label>
|
||||
<textarea style={{resize: 'none'}}
|
||||
className='text-base px-6 text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none'
|
||||
name="comment"
|
||||
value={props.values.comment}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
cols="30"
|
||||
rows="2"
|
||||
/>
|
||||
</div>
|
||||
<label className="text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
|
||||
Comment
|
||||
</label>
|
||||
<textarea
|
||||
style={{ resize: "none" }}
|
||||
className="text-base px-6 text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none"
|
||||
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' 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 className="transfer-fund-btn flex justify-end items-center py-4">
|
||||
{requestStatus ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
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 TransferFund
|
||||
export default TransferFund;
|
||||
|
||||
@@ -1,182 +1,224 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import usersService from '../../services/UsersService';
|
||||
import InputCom from '../Helpers/Inputs/InputCom';
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner';
|
||||
import usersService from "../../services/UsersService";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import ReferralTable from '../MyWallet/WalletComponent/ReferralTable';
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import ReferralTable from "../MyWallet/WalletComponent/ReferralTable";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email('Wrong email format')
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(50, 'Maximum 50 characters')
|
||||
.required('Email is required'),
|
||||
firstname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Firstname is required'),
|
||||
lastname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Lastname is required'),
|
||||
})
|
||||
|
||||
const initialValues = {
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
email: ''
|
||||
}
|
||||
email: Yup.string()
|
||||
.email("Wrong email format")
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(50, "Maximum 50 characters")
|
||||
.required("Email is required"),
|
||||
firstname: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Firstname is required"),
|
||||
lastname: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Lastname is required"),
|
||||
});
|
||||
|
||||
const initialValues = {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
email: "",
|
||||
};
|
||||
|
||||
function ReferralDisplay() {
|
||||
const apiCall = new usersService() // GET API CALL
|
||||
const navigate = useNavigate()
|
||||
const apiCall = new usersService(); // GET API CALL
|
||||
const navigate = useNavigate();
|
||||
|
||||
let [refHistoryReload, setRefHistoryReload] = useState(false) // Determines when referral history reloads
|
||||
let [refHistoryReload, setRefHistoryReload] = useState(false); // Determines when referral history reloads
|
||||
|
||||
// STATE TO HOLD REFERRAL HISTORY
|
||||
let [referralList, setReferralList] = useState({
|
||||
loading: true,
|
||||
error: false,
|
||||
data: []
|
||||
})
|
||||
// STATE TO HOLD REFERRAL HISTORY
|
||||
let [referralList, setReferralList] = useState({
|
||||
loading: true,
|
||||
error: false,
|
||||
data: [],
|
||||
});
|
||||
|
||||
let [error, setError] = useState({message: '', loading: false, status: false}) // for displaying error message on the page
|
||||
let [error, setError] = useState({
|
||||
message: "",
|
||||
loading: false,
|
||||
status: false,
|
||||
}); // for displaying error message on the page
|
||||
|
||||
//function to call referral history API
|
||||
const allReferrals = () => {
|
||||
setReferralList({
|
||||
loading: true,
|
||||
error: false,
|
||||
data: []
|
||||
})
|
||||
apiCall.getReferralHx().then((res)=>{
|
||||
setReferralList((prev)=>{
|
||||
return {...prev, loading: false, data:[...res.data.result_list]}
|
||||
})
|
||||
}).catch((error)=>{
|
||||
setReferralList(prev => ({...prev, loading: false, error: true}))
|
||||
})
|
||||
}
|
||||
//function to call referral history API
|
||||
const allReferrals = () => {
|
||||
setReferralList({
|
||||
loading: true,
|
||||
error: false,
|
||||
data: [],
|
||||
});
|
||||
apiCall
|
||||
.getReferralHx()
|
||||
.then((res) => {
|
||||
setReferralList((prev) => {
|
||||
return { ...prev, loading: false, data: [...res.data.result_list] };
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
setReferralList((prev) => ({ ...prev, loading: false, error: true }));
|
||||
});
|
||||
};
|
||||
|
||||
//FUNCTION TO SEND REFERRAL MESSAGE
|
||||
const sendReferralMsg = (postData) => {
|
||||
apiCall.sendReferralMsg(postData).then((res)=>{
|
||||
if(res.data.internal_return < 0){
|
||||
setError({message:'Email already referred', loading: false, status: false})
|
||||
return
|
||||
}else{
|
||||
toast.success("Message Sent");
|
||||
setError({message:'', loading: false, status: true})
|
||||
setRefHistoryReload(prev => !prev)
|
||||
}
|
||||
}).catch((error)=>{
|
||||
setError({message:'Opps! an error occured, try again later', loading: false, status: false})
|
||||
})
|
||||
}
|
||||
//FUNCTION TO SEND REFERRAL MESSAGE
|
||||
const sendReferralMsg = (postData) => {
|
||||
apiCall
|
||||
.sendReferralMsg(postData)
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setError({
|
||||
message: "Email already referred",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
toast.success("Message Sent");
|
||||
setError({ message: "", loading: false, status: true });
|
||||
setRefHistoryReload((prev) => !prev);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setError({
|
||||
message: "Opps! an error occured, try again later",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values, helpers) => {
|
||||
setError({message: '', loading: true, status: false})
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values, helpers) => {
|
||||
setError({ message: "", loading: true, status: false });
|
||||
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
action: 11032,
|
||||
...values
|
||||
};
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
action: 11032,
|
||||
...values,
|
||||
};
|
||||
|
||||
sendReferralMsg(postData) // FUNCTION TO SEND REFERRAL MESSAGE
|
||||
}
|
||||
sendReferralMsg(postData); // FUNCTION TO SEND REFERRAL MESSAGE
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
allReferrals()
|
||||
}, [refHistoryReload])
|
||||
useEffect(() => {
|
||||
allReferrals();
|
||||
}, [refHistoryReload]);
|
||||
|
||||
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="referral w-full md:p-8 p-4 h-full bg-white dark:bg-dark-white rounded-2xl shadow">
|
||||
<h2 className='text-slate-900 dark:text-white text-xl lg:text-2xl font-medium'>Send Referral</h2>
|
||||
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}>
|
||||
{(props)=>(
|
||||
<Form className='referral-info'>
|
||||
{/* Firstname */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
label="Firstname"
|
||||
type="text"
|
||||
name="firstname"
|
||||
placeholder="Firstname"
|
||||
value={props.values.firstname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.firstname && props.touched.firstname) && <p className="text-sm text-red-500">{props.errors.firstname}</p>}
|
||||
</div>
|
||||
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
|
||||
<div className="referral w-full md:p-8 p-4 h-full bg-white dark:bg-dark-white rounded-2xl shadow">
|
||||
<h2 className="text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
|
||||
Send Referral
|
||||
</h2>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => (
|
||||
<Form className="referral-info">
|
||||
{/* Firstname */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Firstname"
|
||||
type="text"
|
||||
name="firstname"
|
||||
placeholder="Firstname"
|
||||
value={props.values.firstname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.firstname && props.touched.firstname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.firstname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Lastname */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
label="Lastname"
|
||||
type="text"
|
||||
name="lastname"
|
||||
placeholder="Lastname"
|
||||
value={props.values.lastname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.lastname && props.touched.lastname) && <p className="text-sm text-red-500">{props.errors.lastname}</p>}
|
||||
</div>
|
||||
{/* Lastname */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Lastname"
|
||||
type="text"
|
||||
name="lastname"
|
||||
placeholder="Lastname"
|
||||
value={props.values.lastname}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.lastname && props.touched.lastname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.lastname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
label="Email"
|
||||
type="text"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
value={props.values.email}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.email && props.touched.email) && <p className="text-sm text-red-500">{props.errors.email}</p>}
|
||||
</div>
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Email"
|
||||
type="text"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
value={props.values.email}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{props.errors.email && props.touched.email && (
|
||||
<p className="text-sm text-red-500">{props.errors.email}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
{error.message != '' && <p className='text-base text-red-500 py-2'>{error.message}</p>}
|
||||
<div className='referral-btn flex justify-end items-center py-4 border-b-4'>
|
||||
{error.loading ?
|
||||
<LoadingSpinner size='6' color='sky-blue' />
|
||||
:
|
||||
<button type='submit' className='text-lg text-white bg-sky-blue p-2 hover:opacity-90 rounded-md'>Send Message</button>
|
||||
}
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
<hr />
|
||||
{error.message != "" && (
|
||||
<p className="text-base text-red-500 py-2">{error.message}</p>
|
||||
)}
|
||||
<div className="referral-btn flex justify-end items-center py-4 border-b-4">
|
||||
{error.loading ? (
|
||||
<LoadingSpinner size="6" color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
className="text-lg text-white bg-sky-blue p-2 hover:opacity-90 rounded-md"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
|
||||
<div className="referral w-full md:p-8 p-4 h-full max-h-[700px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
|
||||
<h2 className='mb-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium'>Referral List</h2>
|
||||
{referralList.loading ?
|
||||
(
|
||||
<LoadingSpinner size='32' color='sky-blue' />
|
||||
)
|
||||
:
|
||||
(
|
||||
<ReferralTable history={referralList} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
|
||||
<div className="referral w-full md:p-8 p-4 h-full max-h-[700px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
|
||||
<h2 className="mb-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
|
||||
Referral List
|
||||
</h2>
|
||||
{referralList.loading ? (
|
||||
<LoadingSpinner size="32" color="sky-blue" />
|
||||
) : (
|
||||
<ReferralTable history={referralList} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferralDisplay
|
||||
export default ReferralDisplay;
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import Icons from "../../Helpers/Icons";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import {Link, useNavigate} from 'react-router-dom'
|
||||
import usersService from "../../../services/UsersService";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import {toast} from 'react-toastify'
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email('Wrong email format')
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(50, 'Maximum 50 characters')
|
||||
.required('Email is required'),
|
||||
.email("Wrong email format")
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(50, "Maximum 50 characters")
|
||||
.required("Email is required"),
|
||||
firstname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Firstname is required'),
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Firstname is required"),
|
||||
lastname: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('Lastname is required'),
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Lastname is required"),
|
||||
city: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('City is required'),
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("City is required"),
|
||||
state: Yup.string()
|
||||
.min(3, 'Minimum 3 characters')
|
||||
.max(25, 'Maximum 25 characters')
|
||||
.required('State is required'),
|
||||
})
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("State is required"),
|
||||
});
|
||||
|
||||
export default function PersonalInfoTab({
|
||||
datas,
|
||||
@@ -49,72 +49,86 @@ export default function PersonalInfoTab({
|
||||
browseCoverImg,
|
||||
coverImgChangHandler,
|
||||
}) {
|
||||
let { userDetails } = useSelector((state) => state.userDetails);
|
||||
|
||||
let {userDetails} = useSelector((state) => state.userDetails)
|
||||
|
||||
const apiCall = new usersService()
|
||||
const apiCall = new usersService();
|
||||
|
||||
let navigate = useNavigate()
|
||||
let navigate = useNavigate();
|
||||
|
||||
let [togglePromotion, setTogglePromotion] = useState(false)
|
||||
let [togglePromotion, setTogglePromotion] = useState(false);
|
||||
|
||||
const initialValues = {
|
||||
firstname: userDetails?.firstname,
|
||||
lastname: userDetails?.lastname,
|
||||
state: userDetails?.state,
|
||||
city: userDetails?.city,
|
||||
email: userDetails?.email
|
||||
}
|
||||
email: userDetails?.email,
|
||||
};
|
||||
|
||||
let [profile, setProfile] = useState({ // state for requesting from load profile API
|
||||
let [profile, setProfile] = useState({
|
||||
// state for requesting from load profile API
|
||||
loading: true,
|
||||
status: false
|
||||
})
|
||||
status: false,
|
||||
});
|
||||
|
||||
let [requestStatus, setRequestState] = useState({ // state for requesting from update api
|
||||
message: '',
|
||||
let [requestStatus, setRequestState] = useState({
|
||||
// state for requesting from update api
|
||||
message: "",
|
||||
loading: false,
|
||||
status: false
|
||||
})
|
||||
status: false,
|
||||
});
|
||||
|
||||
const handleUpdateUser = (values, helpers)=> {
|
||||
setRequestState({message: '', loading: true, status: false})
|
||||
|
||||
apiCall.updateProfile(values).then((res)=>{ // API CALL TO UPDATE USER DETAILS
|
||||
if(res.data.internal_return < 0){
|
||||
setRequestState({message: 'Profile Was unable to update', loading: false, status: false})
|
||||
return
|
||||
}
|
||||
// setRequestState({message: 'Profile update successfully', loading: false, status: true})
|
||||
toast.success("Update Successful");
|
||||
setTimeout(()=>{
|
||||
navigate('/',{replace:true})
|
||||
window.location.reload(true)
|
||||
},1000)
|
||||
}).catch(error => {
|
||||
setRequestState({message: 'Opps! an error occurred. Try Agian', loading: false, status: false})
|
||||
})
|
||||
}
|
||||
const handleUpdateUser = (values, helpers) => {
|
||||
setRequestState({ message: "", loading: true, status: false });
|
||||
|
||||
useEffect(()=>{
|
||||
setProfile({loading: false, status: true})
|
||||
},[])
|
||||
apiCall
|
||||
.updateProfile(values)
|
||||
.then((res) => {
|
||||
// API CALL TO UPDATE USER DETAILS
|
||||
if (res.data.internal_return < 0) {
|
||||
setRequestState({
|
||||
message: "Profile Was unable to update",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// setRequestState({message: 'Profile update successfully', loading: false, status: true})
|
||||
toast.success("Update Successful");
|
||||
setTimeout(() => {
|
||||
navigate("/", { replace: true });
|
||||
window.location.reload(true);
|
||||
}, 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
setRequestState({
|
||||
message: "Opps! an error occurred. Try Agian",
|
||||
loading: false,
|
||||
status: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
useEffect(() => {
|
||||
setProfile({ loading: false, status: true });
|
||||
}, []);
|
||||
|
||||
profile.loading ?
|
||||
<div className="personal-info-tab w-full flex flex-col justify-between">
|
||||
<div className="p-3">
|
||||
<LoadingSpinner size='32' color='sky-blue' />
|
||||
</div>
|
||||
return profile.loading ? (
|
||||
<div className="personal-info-tab w-full flex flex-col justify-between">
|
||||
<div className="p-3">
|
||||
<LoadingSpinner size="32" color="sky-blue" />
|
||||
</div>
|
||||
:
|
||||
<div className="personal-info-tab w-full flex flex-col justify-between">
|
||||
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleUpdateUser}>
|
||||
{(props => {
|
||||
return (
|
||||
</div>
|
||||
) : (
|
||||
<div className="personal-info-tab w-full flex flex-col justify-between">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleUpdateUser}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form>
|
||||
|
||||
<div className="flex flex-col-reverse sm:flex-row">
|
||||
<div className="flex-1 sm:mr-10">
|
||||
<div className="fields w-full">
|
||||
@@ -122,6 +136,7 @@ export default function PersonalInfoTab({
|
||||
{/* username */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="User Name"
|
||||
type="text"
|
||||
name="username"
|
||||
@@ -134,6 +149,7 @@ export default function PersonalInfoTab({
|
||||
{/* Email */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Email"
|
||||
type="text"
|
||||
name="email"
|
||||
@@ -142,12 +158,17 @@ export default function PersonalInfoTab({
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.email && props.touched.email) && <p className="text-sm text-red-500">{props.errors.email}</p>}
|
||||
{props.errors.email && props.touched.email && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.email}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{/* first name and last name */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="First Name"
|
||||
type="text"
|
||||
name="firstname"
|
||||
@@ -156,10 +177,15 @@ export default function PersonalInfoTab({
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.firstname && props.touched.firstname) && <p className="text-sm text-red-500">{props.errors.firstname}</p>}
|
||||
{props.errors.firstname && props.touched.firstname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.firstname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="field w-full">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Last Name"
|
||||
type="text"
|
||||
name="lastname"
|
||||
@@ -168,13 +194,18 @@ export default function PersonalInfoTab({
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.lastname && props.touched.lastname) && <p className="text-sm text-red-500">{props.errors.lastname}</p>}
|
||||
{props.errors.lastname && props.touched.lastname && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.lastname}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Country */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Country"
|
||||
type="text"
|
||||
name="country"
|
||||
@@ -186,6 +217,7 @@ export default function PersonalInfoTab({
|
||||
{/* State/Province */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="State/Province"
|
||||
type="text"
|
||||
name="state"
|
||||
@@ -194,12 +226,17 @@ export default function PersonalInfoTab({
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.state && props.touched.state) && <p className="text-sm text-red-500">{props.errors.state}</p>}
|
||||
{props.errors.state && props.touched.state && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.state}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* City */}
|
||||
<div className="field w-full mb-6">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="City"
|
||||
type="text"
|
||||
name="city"
|
||||
@@ -208,34 +245,65 @@ export default function PersonalInfoTab({
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
{(props.errors.city && props.touched.city) && <p className="text-sm text-red-500">{props.errors.city}</p>}
|
||||
{props.errors.city && props.touched.city && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.city}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Preferred Communication*/}
|
||||
<div className='field w-full mb-6 md:flex items-center space-x-4'>
|
||||
<label className='input-label text-[#181c32] dark:text-white text-base font-semibold'>Pref. Communication</label>
|
||||
<div className="check-box">
|
||||
<div className="flex items-center justify-start">
|
||||
<div className="check-input flex items-center mr-1">
|
||||
<input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm1" id="" />
|
||||
<span className="mx-2 text-base text-dark-gray dark:text-white">Email</span>
|
||||
</div>
|
||||
<div className="check-input flex items-center">
|
||||
<input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm2" id="" />
|
||||
<span className="mx-2 text-base text-dark-gray dark:text-white">Phone</span>
|
||||
</div>
|
||||
<div className="field w-full mb-6 md:flex items-center space-x-4">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-base font-semibold">
|
||||
Pref. Communication
|
||||
</label>
|
||||
<div className="check-box">
|
||||
<div className="flex items-center justify-start">
|
||||
<div className="check-input flex items-center mr-1">
|
||||
<input
|
||||
className="w-4 h-4 cursor-pointer"
|
||||
type="checkbox"
|
||||
name="prefcomm1"
|
||||
id=""
|
||||
/>
|
||||
<span className="mx-2 text-base text-dark-gray dark:text-white">
|
||||
Email
|
||||
</span>
|
||||
</div>
|
||||
<div className="check-input flex items-center">
|
||||
<input
|
||||
className="w-4 h-4 cursor-pointer"
|
||||
type="checkbox"
|
||||
name="prefcomm2"
|
||||
id=""
|
||||
/>
|
||||
<span className="mx-2 text-base text-dark-gray dark:text-white">
|
||||
Phone
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Allow Promotions */}
|
||||
<div className='field w-full mb-6 flex items-center space-x-4'>
|
||||
<label className='input-label text-[#181c32] dark:text-white text-base font-semibold'>Allow Promotions</label>
|
||||
<div className="cursor-pointer flex items-center" onClick={()=>setTogglePromotion(prev => !prev)}>
|
||||
<div className={`h-6 w-8 mr-1 p-1 ${togglePromotion ? 'bg-sky-blue flex justify-end items-center': 'bg-slate-200'} rounded-full transition`}>
|
||||
<div className="w-4 h-full bg-white rounded-full"></div>
|
||||
</div>
|
||||
<div className="field w-full mb-6 flex items-center space-x-4">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-base font-semibold">
|
||||
Allow Promotions
|
||||
</label>
|
||||
<div
|
||||
className="cursor-pointer flex items-center"
|
||||
onClick={() => setTogglePromotion((prev) => !prev)}
|
||||
>
|
||||
<div
|
||||
className={`h-6 w-8 mr-1 p-1 ${
|
||||
togglePromotion
|
||||
? "bg-sky-blue flex justify-end items-center"
|
||||
: "bg-slate-200"
|
||||
} rounded-full transition`}
|
||||
>
|
||||
<div className="w-4 h-full bg-white rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* inputs ends here */}
|
||||
</div>
|
||||
@@ -300,11 +368,19 @@ export default function PersonalInfoTab({
|
||||
</div>
|
||||
|
||||
<div className="content-footer w-full">
|
||||
{requestStatus.message != '' && <p className={`text-center text-base ${requestStatus.status ? 'text-green-800' : 'text-red-600'}`}>{requestStatus.message}</p>}
|
||||
{requestStatus.message != "" && (
|
||||
<p
|
||||
className={`text-center text-base ${
|
||||
requestStatus.status ? "text-green-800" : "text-red-600"
|
||||
}`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</p>
|
||||
)}
|
||||
<div className="w-full h-[120px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
||||
<div className="flex items-center space-x-4 mr-9">
|
||||
<Link
|
||||
to='/'
|
||||
to="/"
|
||||
className="text-18 text-light-red tracking-wide "
|
||||
>
|
||||
<span className="border-b dark:border-[#5356fb29] border-light-red">
|
||||
@@ -313,23 +389,23 @@ export default function PersonalInfoTab({
|
||||
</span>
|
||||
</Link>
|
||||
|
||||
{requestStatus.loading ?
|
||||
<LoadingSpinner size='8' color='sky-blue' />
|
||||
:
|
||||
<button
|
||||
type="submit"
|
||||
className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Update Profile
|
||||
</button>
|
||||
}
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Update Profile
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
})}
|
||||
</Formik>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ export default function ProductUploadField({
|
||||
<h1 className="field-title">Item Name </h1>
|
||||
<div className="input-field mt-2">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="RaidParty Fighters"
|
||||
@@ -164,6 +165,7 @@ export default function ProductUploadField({
|
||||
<h1 className="field-title">Exter link </h1>
|
||||
<div className="input-field mt-2">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
type="text"
|
||||
name="link"
|
||||
inputHandler={linkh}
|
||||
@@ -200,7 +202,9 @@ export default function ProductUploadField({
|
||||
<div className="w-[1px] h-[33px] bg-light-purple dark:bg-dark-light-purple "></div>
|
||||
<div className="flex-1 flex h-full justify-center items-center bg-[#FAFAFA] dark:bg-[#11131F] ">
|
||||
<div className="flex space-x-1 items-center">
|
||||
<span className="text-dark-gray dark:text-white text-base">ETH</span>
|
||||
<span className="text-dark-gray dark:text-white text-base">
|
||||
ETH
|
||||
</span>
|
||||
<span>
|
||||
<svg
|
||||
width="13"
|
||||
@@ -235,6 +239,7 @@ export default function ProductUploadField({
|
||||
<div className="input-field my-2">
|
||||
<div className="mb-2">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
type="text"
|
||||
name="link"
|
||||
inputHandler={roltsHndlr}
|
||||
@@ -260,6 +265,7 @@ export default function ProductUploadField({
|
||||
<div className="sm:flex sm:space-x-8">
|
||||
<div className="sm:w-1/2 w-full mb-2 sm:mb-0">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
type="text"
|
||||
name="link"
|
||||
inputHandler={keyHndlr}
|
||||
@@ -269,6 +275,7 @@ export default function ProductUploadField({
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
type="text"
|
||||
name="link"
|
||||
inputHandler={valueHndlr}
|
||||
|
||||
@@ -28,6 +28,10 @@ class SiteService {
|
||||
return this.getAuxEnd("/pricing", null);
|
||||
}
|
||||
|
||||
addFamily(reqData) {
|
||||
return this.postAuxEnd('/familyadd', reqData)
|
||||
}
|
||||
|
||||
//---------------------------------------- -----
|
||||
//---------------------------------------- -----
|
||||
// Unified call below
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
import React, { useContext,useState, useEffect } from "react";
|
||||
import usersService from "../services/UsersService";
|
||||
import FamilyAcc from "../components/FamilyAcc";
|
||||
|
||||
export default function FamilyAccPage() {
|
||||
|
||||
const [MyActiveJobList, setMyActiveJobList] = useState([]);
|
||||
const api = new usersService();
|
||||
|
||||
const getMyActiveJobList = async () => {
|
||||
try {
|
||||
const res = await api.getMyActiveJobList();
|
||||
setMyActiveJobList(res.data);
|
||||
} catch (error) {
|
||||
console.log("Error getting mode");
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
getMyActiveJobList();
|
||||
}, []);
|
||||
|
||||
//debugger;
|
||||
return (
|
||||
<>
|
||||
<FamilyAcc ActiveJobList={MyActiveJobList}/>
|
||||
<FamilyAcc />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user