Merge branch 'add-family-acc' of WrenchBoard/Users-Wrench into master

This commit is contained in:
2023-05-09 11:25:42 +00:00
committed by Gogs
19 changed files with 2056 additions and 1362 deletions
@@ -1,17 +1,17 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from "react-router-dom";
import WrenchBoard from "../../../assets/images/wrenchboard.png" import WrenchBoard from "../../../assets/images/wrenchboard.png";
import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import usersService from "../../../services/UsersService";
export default function ForgotPassword() { export default function ForgotPassword() {
const [checked, setValue] = useState(false); const [checked, setValue] = useState(false);
const [resetLoading, setResetLoading] = useState(false) const [resetLoading, setResetLoading] = useState(false);
// email // email
const [email, setMail] = useState(""); const [email, setMail] = useState("");
const [msgError, setMsgError] = useState(''); const [msgError, setMsgError] = useState("");
const [msgSuccess, setMsgSuccess] = useState(false) const [msgSuccess, setMsgSuccess] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const userApi = new usersService(); const userApi = new usersService();
@@ -21,52 +21,54 @@ export default function ForgotPassword() {
}; };
const humanChecker = () => { const humanChecker = () => {
setValue(!checked) setValue(!checked);
} };
const resetHandler = async () => { const resetHandler = async () => {
if (email == '') { if (email == "") {
setMsgError('An email is required') setMsgError("An email is required");
} else if (!checked) { } else if (!checked) {
setMsgError('Check if you are human') setMsgError("Check if you are human");
} }
if (email !== '' && checked) { if (email !== "" && checked) {
const reqData = { email } const reqData = { email };
setResetLoading(true) setResetLoading(true);
try { try {
const res = await userApi.StartResetPassword(reqData) const res = await userApi.StartResetPassword(reqData);
if (res.status === 200) { if (res.status === 200) {
setMsgSuccess(true) setMsgSuccess(true);
setMail("") setMail("");
setValue(false) setValue(false);
setResetLoading(false) setResetLoading(false);
} }
} catch (error) { } catch (error) {
setResetLoading(false) setResetLoading(false);
setMail("") setMail("");
setMsgError('An error occurred') setMsgError("An error occurred");
throw new Error(error) throw new Error(error);
} finally { } finally {
setTimeout(() => { setTimeout(() => {
setMsgError(null) setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT) }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
} }
} }
setTimeout(() => { setTimeout(() => {
setMsgError(null) setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT) }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
} };
return ( return (
<> <>
<AuthLayout <AuthLayout slogan="Welcome to WrenchBoard">
slogan="Welcome to WrenchBoard"
>
<div className="w-full"> <div className="w-full">
<div className='mb-12'> <div className="mb-12">
<Link to='#'> <Link to="#">
<img src={WrenchBoard} alt="wrenchboard" className="h-10 mx-auto" /> <img
src={WrenchBoard}
alt="wrenchboard"
className="h-10 mx-auto"
/>
</Link> </Link>
</div> </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"> <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]"> <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Forget Password Forget Password
</h1> </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>
<div className="input-area"> <div className="input-area">
<div className="input-item mb-10"> <div className="input-item mb-10">
<InputCom <InputCom
fieldClass="px-6"
placeholder="Your Username/Email" placeholder="Your Username/Email"
label="Email" label="Email"
name="email" name="email"
@@ -98,7 +103,14 @@ export default function ForgotPassword() {
<div className="relative table top-0 h-full"> <div className="relative table top-0 h-full">
<div className="table-cell align-middle"> <div className="table-cell align-middle">
<div className="relative w-[30px] h-[30px] mx-[15px]"> <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> </div>
</div> </div>
@@ -106,7 +118,10 @@ export default function ForgotPassword() {
<div className="h-full relative inline-block w-[170px]"> <div className="h-full relative inline-block w-[170px]">
<label className="relative table top-0 h-full"> <label className="relative table top-0 h-full">
<label className="table-cell align-middle"> <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 I am human
</label> </label>
</label> </label>
@@ -116,8 +131,24 @@ export default function ForgotPassword() {
</div> </div>
</div> </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>} {msgError && (
{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="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="signin-area mb-3.5">
<div className="flex justify-center items-center gap-2"> <div className="flex justify-center items-center gap-2">
+6 -38
View File
@@ -1,15 +1,14 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useNavigate, Link } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import googleLogo from "../../../assets/images/google-logo.svg";
import appleLogo from "../../../assets/images/apple-black.svg"; import appleLogo from "../../../assets/images/apple-black.svg";
import facebookLogo from "../../../assets/images/facebook-4.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 WrenchBoard from "../../../assets/images/wrenchboard.png";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch } from "react-redux";
import { updateUserDetails } from "../../../store/UserDetails"; import { updateUserDetails } from "../../../store/UserDetails";
export default function Login() { export default function Login() {
@@ -73,7 +72,7 @@ export default function Login() {
setLoginError(true); setLoginError(true);
} }
} else { } else {
setMsgError("Please fill in fields"); setMsgError("Please fill in the fields");
} }
} catch (error) { } catch (error) {
setMsgError("An error occurred"); setMsgError("An error occurred");
@@ -117,6 +116,7 @@ export default function Login() {
<div className="input-area"> <div className="input-area">
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={email} value={email}
inputHandler={handleEmail} inputHandler={handleEmail}
placeholder="support@mermsemr.com" placeholder="support@mermsemr.com"
@@ -129,6 +129,7 @@ export default function Login() {
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={password} value={password}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
@@ -139,39 +140,6 @@ export default function Login() {
forgotPassword forgotPassword
/> />
</div> </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 && ( {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]"> <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{" "} Invalid username or password- Please{" "}
+5 -1
View File
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from "react"; 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 facebookLogo from "../../../assets/images/facebook-4.svg";
import WrenchBoard from "../../../assets/images/wrenchboard.png"; import WrenchBoard from "../../../assets/images/wrenchboard.png";
import usersService from "../../../services/UsersService"; 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-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"> <div className="input-item sm:w-1/2 w-full mb-5 sm:mb-0">
<InputCom <InputCom
fieldClass="px-6"
placeholder="Firstname" placeholder="Firstname"
label="First Name" label="First Name"
name="first_name" name="first_name"
@@ -181,6 +182,7 @@ export default function SignUp() {
</div> </div>
<div className="input-item flex-1"> <div className="input-item flex-1">
<InputCom <InputCom
fieldClass="px-6"
placeholder="Lastname" placeholder="Lastname"
label="Last Name" label="Last Name"
name="last_name" name="last_name"
@@ -192,6 +194,7 @@ export default function SignUp() {
</div> </div>
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
placeholder="support@mermsemr.com" placeholder="support@mermsemr.com"
label="Email" label="Email"
name="email" name="email"
@@ -202,6 +205,7 @@ export default function SignUp() {
</div> </div>
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
label="Password" label="Password"
name="password" name="password"
@@ -16,9 +16,7 @@ export default function UpdatePassword() {
return ( return (
<> <>
<AuthLayout <AuthLayout slogan="Welcome to myFit">
slogan="Welcome to myFit"
>
{updated === false ? ( {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 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> <div>
@@ -34,6 +32,7 @@ export default function UpdatePassword() {
<div className="input-area"> <div className="input-area">
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
placeholder="*********" placeholder="*********"
label="Old Password" label="Old Password"
name="password" name="password"
@@ -43,6 +42,7 @@ export default function UpdatePassword() {
</div> </div>
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
placeholder="*********" placeholder="*********"
label="New Password" label="New Password"
name="password" name="password"
@@ -52,6 +52,7 @@ export default function UpdatePassword() {
</div> </div>
<div className="input-item mb-5"> <div className="input-item mb-5">
<InputCom <InputCom
fieldClass="px-6"
placeholder="*********" placeholder="*********"
label="Re-enter Password" label="Re-enter Password"
name="password" name="password"
@@ -1,10 +1,10 @@
import { useState, useEffect, useCallback } from "react"; import { useCallback, useEffect, useState } from "react";
import { useLocation, Link, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import AuthLayout from "../AuthLayout";
import InputCom from "../../Helpers/Inputs/InputCom";
import usersService from "../../../services/UsersService";
import WrenchBoard from "../../../assets/images/wrenchboard.png"; import WrenchBoard from "../../../assets/images/wrenchboard.png";
import debounce from "../../../hooks/debounce"; import debounce from "../../../hooks/debounce";
import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout";
export default function VerifyLink() { export default function VerifyLink() {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@@ -173,6 +173,7 @@ const SuccessfulComponent = ({
{/* INPUT */} {/* INPUT */}
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={email} value={email}
inputHandler={handleEmail} inputHandler={handleEmail}
placeholder="support@mermsemr.com" placeholder="support@mermsemr.com"
@@ -184,6 +185,7 @@ const SuccessfulComponent = ({
</div> </div>
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={password} value={password}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
@@ -1,9 +1,9 @@
import { useState, useEffect, useCallback } from "react"; import { useState } from "react";
import { useLocation, Link, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import AuthLayout from "../AuthLayout";
import InputCom from "../../Helpers/Inputs/InputCom";
import usersService from "../../../services/UsersService";
import WrenchBoard from "../../../assets/images/wrenchboard.png"; 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 VerifyPassword = () => {
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
@@ -158,6 +158,7 @@ const SuccessfulComponent = ({
{/* INPUT */} {/* INPUT */}
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={password} value={password}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
@@ -165,13 +166,12 @@ const SuccessfulComponent = ({
name="password" name="password"
type={showPassword ? "text" : "password"} type={showPassword ? "text" : "password"}
onClick={onClick} onClick={onClick}
passIcon={ passIcon={showPassword ? "show-password" : "hide-password"}
showPassword ? "show-password" : "hide-password"
}
/> />
</div> </div>
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="px-6"
value={confirmPassword} value={confirmPassword}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
+65 -74
View File
@@ -1,80 +1,71 @@
import React, { useState } from "react"; import React, { useState } from "react";
import dataImage1 from "../../assets/images/data-table-user-1.png"; 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 }) { export default function FamilyTable({ className }) {
const filterCategories = ["All Categories", "Explore", "Featured"]; const filterCategories = ["All Categories", "Explore", "Featured"];
const [selectedCategory, setCategory] = useState(filterCategories[0]); const [selectedCategory, setCategory] = useState(filterCategories[0]);
return ( return (
<div <div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${ className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
className || "" 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"> <td className="text-right py-4 px-2">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400"> <button
<tbody> type="button"
<tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom "> className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
<td className="py-4">Name</td> >
<td className="py-4 text-center">Last Login</td> Manage
<td className="py-4 text-center">No of Tasks</td> </button>
<td className="py-4 text-right">Status</td> </td>
</tr> </tr>
<tr className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"> </tbody>
<td className=" py-4"> </table>
<div className="flex space-x-2 items-center"> </div>
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center"> </div>
<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>
);
} }
+202 -30
View File
@@ -1,40 +1,212 @@
import React, { useState } from "react"; import React, { useId, useMemo, useState } from "react";
import { Link } from "react-router-dom"; import CustomPopUp from "../Helpers/CustomPopUp";
import InputCom from "../Helpers/Inputs/InputCom";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
import CommonHead from "../UserHeader/CommonHead";
import FamilyTable from "./FamilyTable"; import FamilyTable from "./FamilyTable";
import SiteService from "../../services/SiteService";
export default function FamilyAcc() { export default function FamilyAcc() {
const [selectTab, setValue] = useState("today"); const [selectTab, setValue] = useState("today");
const filterHandler = (value) => { const [selectedAge, setSelectedAge] = useState(undefined);
setValue(value); const [loader, setLoader] = useState(false);
}; const [msgErr, setMsgErr] = useState("");
return ( const [formData, setFormData] = useState({
<Layout> first_name: "",
{/*<CommonHead />*/} last_name: "",
<div className="notification-page w-full mb-10"> });
<div className="notification-wrapper w-full">
{/* heading */} const apiCall = useMemo(() => new SiteService(), []);
<div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0"> // tab handler
<h1 className="text-26 font-bold text-dark-gray dark:text-white"> 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 <span
className={`${selectTab === "today" ? "block" : "hidden"}`} className={`${selectTab === "today" ? "block" : "hidden"}`}
> >
Family Accounts Family Accounts
</span> </span>
<CustomPopUp
</h1> name="(Add)"
</div> btn_class="text-purple"
<div className="slider-btns flex space-x-4"> key={id}
<div onClick={() => filterHandler("today")} className="relative"> title="Add members"
>
</div> <FamilyForm
</div> value={formData}
</div> ageHandler={handleAgeSelect}
<FamilyTable /> ageRange={ageRange}
</div> ageValue={selectedAge}
inputHandler={handleInputChange}
msgErr={msgErr}
onClick={addMember}
loader={loader}
/>
</CustomPopUp>
</h1>
</div> </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>
);
+134 -54
View File
@@ -12,76 +12,153 @@ export default function InputCom({
inputHandler, inputHandler,
value, value,
forgotPassword, forgotPassword,
parentClass,
labelClass,
inputClass,
fieldClass,
onClick, onClick,
disable, disable,
blurHandler blurHandler,
}) { }) {
const inputRef = useRef(null) const inputRef = useRef(null);
// Entry Validation // Entry Validation
// for Min Length: // for Min Length:
const minLengthValidation = () => { const minLengthValidation = () => {
if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') { if (inputRef && inputRef?.current && inputRef?.current?.name === "email") {
return 7 return 7;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') { } else if (
return 3 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') { inputRef?.current &&
return 3 inputRef?.current?.name === "first_name"
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') { ) {
return 5 return 3;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') { } else if (
return 8 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') { inputRef?.current &&
return 3 inputRef?.current?.name === "last_name"
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') { ) {
return 3 return 3;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') { } else if (
return 3 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') { inputRef?.current &&
return 1 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 // for MaxLength
const maxLengthValidation = () => { const maxLengthValidation = () => {
if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') { if (inputRef && inputRef?.current && inputRef?.current?.name === "email") {
return 35 return 35;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') { } else if (
return 25 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') { inputRef?.current &&
return 25 inputRef?.current?.name === "first_name"
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') { ) {
return 49 return 25;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') { } else if (
return 15 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') { inputRef?.current &&
return 25 inputRef?.current?.name === "last_name"
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') { ) {
return 25 return 25;
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') { } else if (
return 25 inputRef &&
} else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') { inputRef?.current &&
return 9 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 ( return (
<div className="input-com"> <div className={`input-com ${parentClass}`}>
<div className="flex items-center justify-between"> <div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
{label && ( {label && (
<label <label
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block mb-2.5" className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
htmlFor={name} htmlFor={name}
> >
{label} {label}
</label> </label>
)} )}
{forgotPassword && <Link to="/forgot-password" className="text-[13.975px] leading-[20.9625px] text-[#019ef7] hover:text-[#009ef7]">Forgot Password?</Link>} {forgotPassword && (
<Link
to="/forgot-password"
className="text-[13.975px] leading-[20.9625px] text-[#019ef7] hover:text-[#009ef7]"
>
Forgot Password?
</Link>
)}
</div> </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 <input
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
onChange={inputHandler} 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} type={type}
id={name} id={name}
name={name} name={name}
@@ -97,7 +174,10 @@ export default function InputCom({
</div> </div>
)} )}
{passIcon && ( {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} /> <Icons name={passIcon} />
</div> </div>
)} )}
+472 -343
View File
@@ -1,370 +1,499 @@
import React, {useEffect, useState} from 'react' import React, { useEffect, useState } from "react";
import { Link, useNavigate } from 'react-router-dom' import { useNavigate } from "react-router-dom";
import Icons from '../Helpers/Icons' import usersService from "../../services/UsersService";
import usersService from '../../services/UsersService' import Icons from "../Helpers/Icons";
import InputCom from '../Helpers/Inputs/InputCom' import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from '../Spinners/LoadingSpinner' import { toast } from "react-toastify";
import {toast} from 'react-toastify' import LoadingSpinner from "../Spinners/LoadingSpinner";
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({ const validationSchema = Yup.object().shape({
firstname: Yup.string() firstname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Firstname is required'), .required("Firstname is required"),
lastname: Yup.string() lastname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Lastname is required'), .required("Lastname is required"),
country: Yup.string() country: Yup.string()
.min(1, 'Minimum 1 characters') .min(1, "Minimum 1 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Country is required'), .required("Country is required"),
bank: Yup.string() bank: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Bank name is required'), .required("Bank name is required"),
accountNumber: Yup.string() accountNumber: Yup.string()
.matches(/\d/, "must be a number") .matches(/\d/, "must be a number")
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Account Number is required'), .required("Account Number is required"),
repeatAccountNumber: Yup.string() repeatAccountNumber: Yup.string()
.required('Repeat Account Number is required') .required("Repeat Account Number is required")
.oneOf([Yup.ref('accountNumber'), null], 'Must match Account Number'), .oneOf([Yup.ref("accountNumber"), null], "Must match Account Number"),
accountType: Yup.string() accountType: Yup.string()
.min(1, 'Minimum 3 characters') .min(1, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Account Type is required'), .required("Account Type is required"),
city: Yup.string() city: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('City is required'), .required("City is required"),
state: Yup.string() state: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('State is required'), .required("State is required"),
}) });
const initialValues = { const initialValues = {
firstname: '', firstname: "",
lastname: '', lastname: "",
country: '', country: "",
bank: '', bank: "",
accountNumber: '', accountNumber: "",
repeatAccountNumber: '', repeatAccountNumber: "",
accountType: '', accountType: "",
state: '', state: "",
city: '' city: "",
} };
function AddRecipient() { 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 let [bankName, setBankName] = useState({
loading: true, // STATE TO HOLD LIST OF BANK NAME
data: [] loading: true,
}) data: [],
});
let [bankName, setBankName] = useState({ // STATE TO HOLD LIST OF BANK NAME let [accType, setAccType] = useState({
loading: true, // STATE TO HOLD LIST ACCOUNT TYPE
data: [] loading: true,
}) data: [],
});
let [accType, setAccType] = useState({ // STATE TO HOLD LIST ACCOUNT TYPE //FUNCTION TO HANDLE ADD RECIPIENT SUBMIT
loading: true, const handleSubmit = (values, helpers) => {
data: [] setRequestStatus({ message: "", loading: true, status: false });
})
//FUNCTION TO HANDLE ADD RECIPIENT SUBMIT let reqData = {
const handleSubmit = (values, helpers) => { //REQUEST DATA FOR API CALL
setRequestStatus({message: '', loading: true, status: false}) 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 //CALL TO ADD RECIPIENT API
firstname: values.firstname, apiURL
lastname: values.lastname, .addRecipient(reqData)
bank_code: values.bank, .then((res) => {
account_no: values.accountNumber, if (res.data.internal_return < 0) {
account_type: values.accountType, setRequestStatus({
country: values.country, message: "could not add recipient, try again!",
state: values.state, loading: false,
city: values.city 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 // FUNCTION TO GET COUNTRIES
apiURL.addRecipient(reqData).then((res)=>{ const getCountry = () => {
if(res.data.internal_return < 0){ apiURL
setRequestStatus({message: 'could not add recipient, try again!', loading: false, status: true}) .getSignupCountryData()
return .then((res) => {
} if (res.data.internal_return < 0) {
// setRequestStatus({message: 'Recipient Added Successfully!', loading: false, status: true}) setAllCountries((prev) => ({ loading: false, data: [] }));
toast.success("Recipient Added Successfully!"); return;
setTimeout(()=>{navigate('/my-wallet/transfer-fund',{replace:true})},1000) }
}).catch((error)=>{ setAllCountries((prev) => ({
setRequestStatus({message: 'Opps! an error occured! Try again later', loading: false, status: false}) 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 // FUNCTION TO GET ACCOUNT TYPES
const getCountry = ()=> { const getAccountTypes = () => {
apiURL.getSignupCountryData().then((res)=>{ apiURL
if(res.data.internal_return < 0){ .getAccountTypes()
setAllCountries(prev => ({loading: false, data: []})) .then((res) => {
return if (res.data.internal_return < 0) {
} setAccType((prev) => ({ loading: false, data: [] }));
setAllCountries(prev => ({loading: false, data:res.data.signup_country})) return;
}).catch((error)=>{ }
setAllCountries(prev => ({loading: false, data: []})) setAccType((prev) => ({ loading: false, data: res.data.result_list }));
}) })
} .catch((error) => {
// END OF FUNCTION TO GET COUNTRIES setAccType((prev) => ({ loading: false, data: [] }));
});
};
// END OF FUNCTION TO GET ACCOUNT TYPES
// FUNCTION TO GET COUNTRY BANK useEffect(() => {
const getCountryBank = ()=> { getCountry(); // TO LOAD LIST COUNTRY
apiURL.getCountryBank().then((res)=>{ getCountryBank(); // TO LOAD LIST COUNTRY BANK
if(res.data.internal_return < 0){ getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
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 ACCOUNT TYPES return (
const getAccountTypes = ()=> { <div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
apiURL.getAccountTypes().then((res)=>{ <div className="w-full mb-10 lg:mb-0">
if(res.data.internal_return < 0){ <div className="w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow">
setAccType(prev => ({loading: false, data: []})) <h2 className="my-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-semibold">
return ADD BANK ACCOUNT
} </h2>
setAccType(prev => ({loading: false, data:res.data.result_list})) <Formik
}).catch((error)=>{ initialValues={initialValues}
setAccType(prev => ({loading: false, data: []})) validationSchema={validationSchema}
}) onSubmit={handleSubmit}
} >
// END OF FUNCTION TO GET ACCOUNT TYPES {(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(()=>{ {/* lastname */}
getCountry() // TO LOAD LIST COUNTRY <div className="field w-full">
getCountryBank() // TO LOAD LIST COUNTRY BANK <InputCom
getAccountTypes() // TO LOAD LIST ACCOUNT TYPES fieldClass="px-6"
},[]) label="Lastname"
type="text"
return ( name="lastname"
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin"> placeholder="Account Lastname"
<div className="w-full mb-10 lg:mb-0"> value={props.values.lastname}
<div className="w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow"> inputHandler={props.handleChange}
<h2 className='my-4 text-slate-900 dark:text-white text-xl lg:text-2xl font-semibold'>ADD BANK ACCOUNT</h2> blurHandler={props.handleBlur}
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}> />
{(props)=>( {props.errors.lastname && props.touched.lastname && (
<Form className='add-recipient-info px-1 md:px-[50px] lg:px-[100px]'> <p className="text-sm text-red-500">
{props.errors.lastname}
{/* inputs starts here */} </p>
{/* firstname */} )}
<div className="xl:flex xl:space-x-7 mb-6"> </div>
<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>
</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>
</div>
);
} }
export default AddRecipient export default AddRecipient;
+140 -116
View File
@@ -1,132 +1,156 @@
import React, {useState, useEffect} from 'react' import React, { useEffect, useState } from "react";
import RecentActivityTable from './WalletComponent/RecentActivityTable' import { useSelector } from "react-redux";
import LoadingSpinner from '../Spinners/LoadingSpinner' import { useLocation, useNavigate } from "react-router-dom";
import InputCom from '../Helpers/Inputs/InputCom' import { toast } from "react-toastify";
import {toast} from 'react-toastify' import InputCom from "../Helpers/Inputs/InputCom";
import { useLocation, useNavigate } from 'react-router-dom' import LoadingSpinner from "../Spinners/LoadingSpinner";
import { useSelector } from 'react-redux' 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 [requestStatus, setRequestStatus] = useState({
message: "",
let [pageLoading, setPageLoading] = useState(true) 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() let { state } = useLocation();
const navigate = useNavigate()
let {state} = useLocation() //FUNCTION TO HANDLE SUBMIT
const onSuccessPayment = () => {
setRequestStatus({ message: "", loading: true, status: false });
//FUNCTION TO HANDLE SUBMIT let reqData = { amount: state?.account, currency: "NGN" };
const onSuccessPayment = () => { apiURL
setRequestStatus({message: '', loading: true, status: false}) .startTopUp(reqData)
let reqData = {amount: state?.account, currency: 'NGN'} .then((res) => {
apiURL.startTopUp(reqData).then((res)=>{ if (res.data.internal_return < 0) {
if(res.data.internal_return < 0){ setRequestStatus({
setRequestStatus({message: 'Could not finish transaction', loading: false, status: false}) message: "Could not finish transaction",
toast.success('Opps! something went wrong') loading: false,
} status: false,
// do something });
setRequestStatus({message: 'Topup successful', loading: false, status: true}) toast.success("Opps! something went wrong");
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)
} }
},[]) // 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 ( const config = {
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin"> public_key: process.env.REACT_APP_FLUTTERWAVE_APIKEY,
{pageLoading ? tx_ref: Date.now(),
<LoadingSpinner size='8' color='sky-blue' /> amount: state?.amount,
: currency: "NGN",
<div className="lg:w-1/2 w-full mb-10 lg:mb-0"> payment_options: "card,mobilemoney,ussd",
<div className="add-fund w-full bg-white dark:bg-dark-white rounded-2xl shadow"> customer: {
<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> email: `${userDetails.email}`,
<hr /> phone_number: userDetails.phone,
<div className='px-4 md:px-8 py-4 add-fund-info'> name: `${userDetails.lastname} ${userDetails.firstname}`,
<div className="field w-full mb-3"> },
<InputCom customizations: {
label="Amount (Naira):" title: "WrenchBoard",
type="text" description: "Topup Payment",
name="amount" logo: "https://st2.depositphotos.com/4403291/7418/v/450/depositphotos_74189661-stock-illustration-online-shop-log.jpg",
value={state.amount || ''} },
disable={true} };
/>
</div>
</div>
<hr /> const fwConfig = {
<div className='md:p-8 p-4 add-fund-btn flex justify-end items-center py-4'> ...config,
<FlutterWaveButton {...fwConfig} className='text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md' /> text: "Proceed",
</div> callback: (response) => {
</div> 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>
}
<hr />
<div className="lg:w-1/2 w-full mb-10 lg:mb-0"> <div className="md:p-8 p-4 add-fund-btn flex justify-end items-center py-4">
<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"> <FlutterWaveButton
<h2 className='text-gray-900 dark:text-white text-xl lg:text-2xl font-medium'>Recent Activity</h2> {...fwConfig}
{/* <p className='text-base text-gray-600 dark:text-white'>Activity Report</p> */} className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md"
{payment.loading ? />
<LoadingSpinner size='16' color='sky-blue' />
:
<RecentActivityTable payment={payment}/>
}
</div>
</div> </div>
</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;
+198 -156
View File
@@ -1,168 +1,210 @@
import React, {useState, useEffect} from 'react' import React, { useEffect, useState } from "react";
import {useLocation, useNavigate} from 'react-router-dom' import { useLocation, useNavigate } from "react-router-dom";
import RecentActivityTable from './WalletComponent/RecentActivityTable' import { toast } from "react-toastify";
import LoadingSpinner from '../Spinners/LoadingSpinner' import InputCom from "../Helpers/Inputs/InputCom";
import InputCom from '../Helpers/Inputs/InputCom' import LoadingSpinner from "../Spinners/LoadingSpinner";
import {toast} from 'react-toastify' import RecentActivityTable from "./WalletComponent/RecentActivityTable";
import usersService from '../../services/UsersService' import usersService from "../../services/UsersService";
function ConfirmTransfer({payment, wallet}) { function ConfirmTransfer({ payment, wallet }) {
const apiURL = new usersService() const apiURL = new usersService();
const navigate = useNavigate() const navigate = useNavigate();
let {state} = useLocation()
let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false}) let { state } = useLocation();
let [pageLoading, setPageLoading] = useState(true)
//FUNCTION TO HANDLE SUBMIT let [requestStatus, setRequestStatus] = useState({
const handleSubmit = () => { message: "",
setRequestStatus({message: '', loading: true, status: false}) loading: false,
let reqData = { status: false,
amount: Number(state.amount), });
Fee: Number(state.fee), let [pageLoading, setPageLoading] = useState(true);
recipientid: Number(state.recipientID)
//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)=>{ setRequestStatus({
if(res.data.internal_return < 0){ message: "transfer successful",
setRequestStatus({message: 'Could not perform transaction', loading: false, status: false}) loading: false,
return status: true,
} });
setRequestStatus({message: 'transfer successful', loading: false, status: true}) toast.success("Transfer sucessful");
toast.success('Transfer sucessful') setTimeout(() => {
setTimeout(()=>{ navigate("/my-wallet", { replace: true });
navigate('/my-wallet', {replace: true}) window.location.reload(true);
window.location.reload(true) }, 1000);
}, 1000) })
}).catch(error=>{ .catch((error) => {
setRequestStatus({message: 'Opps! something went wrong! Try Again', loading: false, status: false}) 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(()=>{ return (
// what happens if not state redirect user <div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin">
if(!state){ {pageLoading ? (
navigate('/my-wallet/transfer-fund',{replace: true}) <LoadingSpinner size="8" color="sky-blue" />
}else{ ) : (
setPageLoading(false) <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">
return ( {wallet.loading ? (
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin"> <LoadingSpinner size="8" color="sky-blue" />
{pageLoading ? ) : wallet.data.length ? (
<LoadingSpinner size='8' color='sky-blue' /> <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") {
<div className="lg:w-1/2 w-full mb-10 lg:mb-0"> return `Withdraw from Naira Wallet : ${item.symbol}${(
<div className="add-fund w-full bg-white dark:bg-dark-white rounded-2xl shadow"> item.amount * 0.01
<div className='px-4 md:px-8 py-4'> ).toFixed(2)}`;
{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}/>
} }
</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> </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>
) )}
<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;
+295 -209
View File
@@ -1,240 +1,326 @@
import React, {useEffect, useState} from 'react' import React, { useEffect, useState } from "react";
import { Link, useNavigate } from 'react-router-dom' import { Link, useNavigate } from "react-router-dom";
import RecentActivityTable from './WalletComponent/RecentActivityTable' import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from '../Spinners/LoadingSpinner' import LoadingSpinner from "../Spinners/LoadingSpinner";
import InputCom from '../Helpers/Inputs/InputCom' import RecentActivityTable from "./WalletComponent/RecentActivityTable";
import usersService from '../../services/UsersService' import usersService from "../../services/UsersService";
import {toast} from 'react-toastify' import { Form, Formik } from "formik";
import * as Yup from "yup";
import {Formik, Form} from 'formik'
import * as Yup from 'yup'
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
amount: Yup.number() amount: Yup.number()
.typeError("you must specify a number") .typeError("you must specify a number")
.min(1, 'Amount must be greater than 0') .min(1, "Amount must be greater than 0")
.required('Amount is required'), .required("Amount is required"),
recipientID: Yup.string() recipientID: Yup.string()
.min(1, 'Minimum 1 characters') .min(1, "Minimum 1 characters")
.max(50, 'Maximum 50 characters') .max(50, "Maximum 50 characters")
.required('Recipient is required'), .required("Recipient is required"),
}) });
const initialValues = {
amount: '',
recipientID: '',
comment: '',
}
function TransferFund({payment, wallet}) { const initialValues = {
const apiCall = new usersService() // API CLASS CALL 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 let [requestStatus, setRequestStatus] = useState(false);
loading: true,
data: [],
error: 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 //FUNCTION TO GET RECIPIENT LIST
const getRecipients = ()=>{ const getRecipients = () => {
apiCall.getRecipient().then((res)=>{ apiCall
if(res.data.internal_return < 0){ // success but no data .getRecipient()
setRecipients(prev => ({...prev, loading: false})) .then((res) => {
return if (res.data.internal_return < 0) {
} // success but no data
setRecipients(prev => ({...prev, loading: false, data: res.data.result_list})) setRecipients((prev) => ({ ...prev, loading: false }));
}).catch((error)=>{ return;
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)=>{ setRecipients((prev) => ({
setSendMoneyFee({loading: false, fee: res.data.processing_fee, total: res.data.total_amount}) ...prev,
}).catch((error)=>{ loading: false,
setSendMoneyFee({loading: false, fee: 0, total: 0}) 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 setTimeout(() => {
const handleSubmit = (values, helpers) => { setRequestStatus(false);
setRequestStatus(true) navigate("confirm-transfer", { state: stateData });
let recipientDetails = recipients.data?.filter(item => item.recipient_id == values.recipientID) }, 1000);
let stateData = {...values, ...sendMoneyFee, details:{...recipientDetails[0]}} };
setTimeout(()=>{ useEffect(() => {
setRequestStatus(false) getRecipients();
navigate('confirm-transfer', {state: stateData}) }, []);
}, 1000) 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(()=>{ <div className="field w-full">
getRecipients() <InputCom
},[]) fieldClass="px-6"
return ( label="Fee"
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin"> type="text"
<div className="lg:w-1/2 w-full mb-10 lg:mb-0"> name="fee"
<div className="add-fund w-full md:p-8 p-4 bg-white dark:bg-dark-white rounded-2xl shadow"> value={
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}> sendMoneyFee.loading ? "loading" : sendMoneyFee.fee
{(props)=>{ }
return ( disable={true}
<Form className='transfer-fund-info'> />
{wallet.loading ? </div>
<LoadingSpinner size='8' color='sky-blue' /> </div>
:
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"> <div className="md:flex items-center justify-end">
<InputCom <div className="field w-full lg:w-1/2 mb-6">
label="Amount" <InputCom
type="text" fieldClass="px-6"
name="amount" label="Total"
placeholder='0' type="text"
value={props.values.amount} name="total"
inputHandler={props.handleChange} value={
blurHandler={(e)=>{ sendMoneyFee.loading ? "loading" : sendMoneyFee.total
getSendMoneyFee(e) }
}} disable={true}
// props.handleBlur />
// onMouseLeave={(e)=>{getSendMoneyFee(e)}} </div>
/> </div>
{(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="w-full">
<div className="field w-full lg:w-1/2 mb-6"> <div className="relative my-3 md:flex items-center">
<InputCom <div className="transfer-input w-full">
label="Total" <div className="flex items-center justify-start py-2">
type="text" <label className="text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
name="total" Recipient
value={sendMoneyFee.loading ? 'loading' : sendMoneyFee.total} <span className="text-red-500 mx-2">*</span>
disable={true} <span
/> title="Transfer Recipient"
</div> className={`text-white text-sm bg-slate-500 w-1 h-1 rounded-full px-3 py-1 cursor-pointer`}
</div> >
!
<div className='w-full'> </span>
<div className='relative my-3 md:flex items-center'> </label>
<div className='transfer-input w-full'> <Link
<div className='flex items-center justify-start py-2'> to="add-recipient"
<label className='text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Recipient className="mx-1 text-base text-white p-2 bg-[orange] rounded-md hover:opacity-80"
<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> Add New
</label> </Link>
<Link to='add-recipient' className='mx-1 text-base text-white p-2 bg-[orange] rounded-md hover:opacity-80'>Add New</Link> </div>
</div> <select
<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}> className="w-full text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0"
{recipients.loading ? value={props.values.recipientID}
<option className='text-slate-500 text-lg' value="">Loading...</option> name="recipientID"
: onChange={props.handleChange}
recipients.data.length ? onBlur={props.handleBlur}
<> >
<option className='text-slate-500 text-lg' value="">Select...</option> {recipients.loading ? (
{recipients.data.map((item, index)=>( <option className="text-slate-500 text-lg" value="">
<option key={index} value={item.recipient_id} className='text-slate-500 text-lg'>{item.recipient}</option> Loading...
))} </option>
</> ) : recipients.data.length ? (
: <>
recipients.error ? <option
<option className='text-slate-500 text-lg' value="">Could'nt Load, try again!</option> className="text-slate-500 text-lg"
: value=""
<option className='text-slate-500 text-lg' value="">No Recipient Found! Click Add to Add</option> >
} Select...
</select> </option>
</div> {recipients.data.map((item, index) => (
</div> <option
{(props.errors.recipientID && props.touched.recipientID) && <p className="text-sm text-red-500">{props.errors.recipientID}</p>} key={index}
</div> 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"> <div className="field w-full mb-6">
{/* <InputCom {/* <InputCom fieldClass="px-6"
label="Comment" label="Comment"
type="text" type="text"
name="comment" name="comment"
value={inputs.comment} value={inputs.comment}
inputHandler={handleChange} inputHandler={handleChange}
/> */} /> */}
<label className='text-[#181c32] dark:text-white text-base font-semibold block mb-2.5'>Comment</label> <label className="text-[#181c32] dark:text-white text-base font-semibold block mb-2.5">
<textarea style={{resize: 'none'}} Comment
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' </label>
name="comment" <textarea
value={props.values.comment} style={{ resize: "none" }}
onChange={props.handleChange} 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"
onBlur={props.handleBlur} name="comment"
cols="30" value={props.values.comment}
rows="2" onChange={props.handleChange}
/> onBlur={props.handleBlur}
</div> cols="30"
rows="2"
/>
</div>
<div className='transfer-fund-btn flex justify-end items-center py-4'> <div className="transfer-fund-btn flex justify-end items-center py-4">
{requestStatus ? {requestStatus ? (
<LoadingSpinner size='8' color='sky-blue' /> <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> <button
} type="submit"
</div> className="text-lg text-white bg-sky-blue px-4 py-2 hover:opacity-90 rounded-md"
</Form> >
) Continue
}} </button>
</Formik> )}
</div> </div>
</div> </Form>
);
<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"> </Formik>
<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> </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;
+197 -155
View File
@@ -1,182 +1,224 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import usersService from '../../services/UsersService'; import usersService from "../../services/UsersService";
import InputCom from '../Helpers/Inputs/InputCom'; import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from '../Spinners/LoadingSpinner'; import LoadingSpinner from "../Spinners/LoadingSpinner";
import {Formik, Form} from 'formik' import { Form, Formik } from "formik";
import * as Yup from 'yup' import * as Yup from "yup";
import ReferralTable from '../MyWallet/WalletComponent/ReferralTable'; import ReferralTable from "../MyWallet/WalletComponent/ReferralTable";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
email: Yup.string() email: Yup.string()
.email('Wrong email format') .email("Wrong email format")
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(50, 'Maximum 50 characters') .max(50, "Maximum 50 characters")
.required('Email is required'), .required("Email is required"),
firstname: Yup.string() firstname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Firstname is required'), .required("Firstname is required"),
lastname: Yup.string() lastname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Lastname is required'), .required("Lastname is required"),
}) });
const initialValues = { const initialValues = {
firstname: '', firstname: "",
lastname: '', lastname: "",
email: '' email: "",
} };
function ReferralDisplay() { function ReferralDisplay() {
const apiCall = new usersService() // GET API CALL const apiCall = new usersService(); // GET API CALL
const navigate = useNavigate() 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 // STATE TO HOLD REFERRAL HISTORY
let [referralList, setReferralList] = useState({ let [referralList, setReferralList] = useState({
loading: true, loading: true,
error: false, error: false,
data: [] 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 //function to call referral history API
const allReferrals = () => { const allReferrals = () => {
setReferralList({ setReferralList({
loading: true, loading: true,
error: false, error: false,
data: [] data: [],
}) });
apiCall.getReferralHx().then((res)=>{ apiCall
setReferralList((prev)=>{ .getReferralHx()
return {...prev, loading: false, data:[...res.data.result_list]} .then((res) => {
}) setReferralList((prev) => {
}).catch((error)=>{ return { ...prev, loading: false, data: [...res.data.result_list] };
setReferralList(prev => ({...prev, loading: false, error: true})) });
}) })
} .catch((error) => {
setReferralList((prev) => ({ ...prev, loading: false, error: true }));
});
};
//FUNCTION TO SEND REFERRAL MESSAGE //FUNCTION TO SEND REFERRAL MESSAGE
const sendReferralMsg = (postData) => { const sendReferralMsg = (postData) => {
apiCall.sendReferralMsg(postData).then((res)=>{ apiCall
if(res.data.internal_return < 0){ .sendReferralMsg(postData)
setError({message:'Email already referred', loading: false, status: false}) .then((res) => {
return if (res.data.internal_return < 0) {
}else{ setError({
toast.success("Message Sent"); message: "Email already referred",
setError({message:'', loading: false, status: true}) loading: false,
setRefHistoryReload(prev => !prev) status: false,
} });
}).catch((error)=>{ return;
setError({message:'Opps! an error occured, try again later', loading: false, status: false}) } 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 //FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values, helpers) => { const handleSubmit = (values, helpers) => {
setError({message: '', loading: true, status: false}) setError({ message: "", loading: true, status: false });
var postData = { var postData = {
uid: localStorage.getItem("uid"), uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"), member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"), sessionid: localStorage.getItem("session_token"),
action: 11032, action: 11032,
...values ...values,
}; };
sendReferralMsg(postData) // FUNCTION TO SEND REFERRAL MESSAGE sendReferralMsg(postData); // FUNCTION TO SEND REFERRAL MESSAGE
} };
useEffect(()=>{ useEffect(() => {
allReferrals() allReferrals();
}, [refHistoryReload]) }, [refHistoryReload]);
return ( return (
<div className="content-wrapper w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin"> <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="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"> <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> <h2 className="text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}> Send Referral
{(props)=>( </h2>
<Form className='referral-info'> <Formik
{/* Firstname */} initialValues={initialValues}
<div className="field w-full mb-6"> validationSchema={validationSchema}
<InputCom onSubmit={handleSubmit}
label="Firstname" >
type="text" {(props) => (
name="firstname" <Form className="referral-info">
placeholder="Firstname" {/* Firstname */}
value={props.values.firstname} <div className="field w-full mb-6">
inputHandler={props.handleChange} <InputCom
blurHandler={props.handleBlur} fieldClass="px-6"
/> label="Firstname"
{(props.errors.firstname && props.touched.firstname) && <p className="text-sm text-red-500">{props.errors.firstname}</p>} type="text"
</div> 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 */} {/* Lastname */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
label="Lastname" fieldClass="px-6"
type="text" label="Lastname"
name="lastname" type="text"
placeholder="Lastname" name="lastname"
value={props.values.lastname} placeholder="Lastname"
inputHandler={props.handleChange} value={props.values.lastname}
blurHandler={props.handleBlur} inputHandler={props.handleChange}
/> blurHandler={props.handleBlur}
{(props.errors.lastname && props.touched.lastname) && <p className="text-sm text-red-500">{props.errors.lastname}</p>} />
</div> {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"> <div className="field w-full mb-6">
<InputCom <InputCom
label="Email" fieldClass="px-6"
type="text" label="Email"
name="email" type="text"
placeholder="Email" name="email"
value={props.values.email} placeholder="Email"
inputHandler={props.handleChange} value={props.values.email}
blurHandler={props.handleBlur} inputHandler={props.handleChange}
/> blurHandler={props.handleBlur}
{(props.errors.email && props.touched.email) && <p className="text-sm text-red-500">{props.errors.email}</p>} />
</div> {props.errors.email && props.touched.email && (
<p className="text-sm text-red-500">{props.errors.email}</p>
)}
</div>
<hr /> <hr />
{error.message != '' && <p className='text-base text-red-500 py-2'>{error.message}</p>} {error.message != "" && (
<div className='referral-btn flex justify-end items-center py-4 border-b-4'> <p className="text-base text-red-500 py-2">{error.message}</p>
{error.loading ? )}
<LoadingSpinner size='6' color='sky-blue' /> <div className="referral-btn flex justify-end items-center py-4 border-b-4">
: {error.loading ? (
<button type='submit' className='text-lg text-white bg-sky-blue p-2 hover:opacity-90 rounded-md'>Send Message</button> <LoadingSpinner size="6" color="sky-blue" />
} ) : (
</div> <button
</Form> type="submit"
)} className="text-lg text-white bg-sky-blue p-2 hover:opacity-90 rounded-md"
</Formik> >
</div> Send Message
</button>
)}
</div>
</Form>
)}
</Formik>
</div> </div>
</div>
<div className="lg:w-1/2 w-full mb-10 lg:mb-0"> <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"> <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> <h2 className="mb-2 text-slate-900 dark:text-white text-xl lg:text-2xl font-medium">
{referralList.loading ? Referral List
( </h2>
<LoadingSpinner size='32' color='sky-blue' /> {referralList.loading ? (
) <LoadingSpinner size="32" color="sky-blue" />
: ) : (
( <ReferralTable history={referralList} />
<ReferralTable history={referralList} /> )}
)
}
</div>
</div> </div>
</div>
</div> </div>
) );
} }
export default ReferralDisplay export default ReferralDisplay;
+185 -109
View File
@@ -1,39 +1,39 @@
import React, { useEffect, useState } from "react"; 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 Icons from "../../Helpers/Icons";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import {Link, useNavigate} from 'react-router-dom'
import usersService from "../../../services/UsersService";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; 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 { Form, Formik } from "formik";
import * as Yup from 'yup' import * as Yup from "yup";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
email: Yup.string() email: Yup.string()
.email('Wrong email format') .email("Wrong email format")
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(50, 'Maximum 50 characters') .max(50, "Maximum 50 characters")
.required('Email is required'), .required("Email is required"),
firstname: Yup.string() firstname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Firstname is required'), .required("Firstname is required"),
lastname: Yup.string() lastname: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('Lastname is required'), .required("Lastname is required"),
city: Yup.string() city: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('City is required'), .required("City is required"),
state: Yup.string() state: Yup.string()
.min(3, 'Minimum 3 characters') .min(3, "Minimum 3 characters")
.max(25, 'Maximum 25 characters') .max(25, "Maximum 25 characters")
.required('State is required'), .required("State is required"),
}) });
export default function PersonalInfoTab({ export default function PersonalInfoTab({
datas, datas,
@@ -49,72 +49,86 @@ export default function PersonalInfoTab({
browseCoverImg, browseCoverImg,
coverImgChangHandler, 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 = { const initialValues = {
firstname: userDetails?.firstname, firstname: userDetails?.firstname,
lastname: userDetails?.lastname, lastname: userDetails?.lastname,
state: userDetails?.state, state: userDetails?.state,
city: userDetails?.city, 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, loading: true,
status: false status: false,
}) });
let [requestStatus, setRequestState] = useState({ // state for requesting from update api let [requestStatus, setRequestState] = useState({
message: '', // state for requesting from update api
message: "",
loading: false, loading: false,
status: false status: false,
}) });
const handleUpdateUser = (values, helpers)=> { const handleUpdateUser = (values, helpers) => {
setRequestState({message: '', loading: true, status: false}) 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})
})
}
useEffect(()=>{ apiCall
setProfile({loading: false, status: true}) .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 ? return profile.loading ? (
<div className="personal-info-tab w-full flex flex-col justify-between"> <div className="personal-info-tab w-full flex flex-col justify-between">
<div className="p-3"> <div className="p-3">
<LoadingSpinner size='32' color='sky-blue' /> <LoadingSpinner size="32" color="sky-blue" />
</div>
</div> </div>
: </div>
<div className="personal-info-tab w-full flex flex-col justify-between"> ) : (
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleUpdateUser}> <div className="personal-info-tab w-full flex flex-col justify-between">
{(props => { <Formik
return ( initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleUpdateUser}
>
{(props) => {
return (
<Form> <Form>
<div className="flex flex-col-reverse sm:flex-row"> <div className="flex flex-col-reverse sm:flex-row">
<div className="flex-1 sm:mr-10"> <div className="flex-1 sm:mr-10">
<div className="fields w-full"> <div className="fields w-full">
@@ -122,6 +136,7 @@ export default function PersonalInfoTab({
{/* username */} {/* username */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
fieldClass="px-6"
label="User Name" label="User Name"
type="text" type="text"
name="username" name="username"
@@ -134,6 +149,7 @@ export default function PersonalInfoTab({
{/* Email */} {/* Email */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
fieldClass="px-6"
label="Email" label="Email"
type="text" type="text"
name="email" name="email"
@@ -142,12 +158,17 @@ export default function PersonalInfoTab({
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} 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> </div>
{/* first name and last name */} {/* first name and last name */}
<div className="xl:flex xl:space-x-7 mb-6"> <div className="xl:flex xl:space-x-7 mb-6">
<div className="field w-full mb-6 xl:mb-0"> <div className="field w-full mb-6 xl:mb-0">
<InputCom <InputCom
fieldClass="px-6"
label="First Name" label="First Name"
type="text" type="text"
name="firstname" name="firstname"
@@ -156,10 +177,15 @@ export default function PersonalInfoTab({
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} 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>
<div className="field w-full"> <div className="field w-full">
<InputCom <InputCom
fieldClass="px-6"
label="Last Name" label="Last Name"
type="text" type="text"
name="lastname" name="lastname"
@@ -168,13 +194,18 @@ export default function PersonalInfoTab({
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} 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>
</div> </div>
{/* Country */} {/* Country */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
fieldClass="px-6"
label="Country" label="Country"
type="text" type="text"
name="country" name="country"
@@ -186,6 +217,7 @@ export default function PersonalInfoTab({
{/* State/Province */} {/* State/Province */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
fieldClass="px-6"
label="State/Province" label="State/Province"
type="text" type="text"
name="state" name="state"
@@ -194,12 +226,17 @@ export default function PersonalInfoTab({
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} 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> </div>
{/* City */} {/* City */}
<div className="field w-full mb-6"> <div className="field w-full mb-6">
<InputCom <InputCom
fieldClass="px-6"
label="City" label="City"
type="text" type="text"
name="city" name="city"
@@ -208,34 +245,65 @@ export default function PersonalInfoTab({
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} 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> </div>
{/* Preferred Communication*/} {/* Preferred Communication*/}
<div className='field w-full mb-6 md:flex items-center space-x-4'> <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> <label className="input-label text-[#181c32] dark:text-white text-base font-semibold">
<div className="check-box"> Pref. Communication
<div className="flex items-center justify-start"> </label>
<div className="check-input flex items-center mr-1"> <div className="check-box">
<input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm1" id="" /> <div className="flex items-center justify-start">
<span className="mx-2 text-base text-dark-gray dark:text-white">Email</span> <div className="check-input flex items-center mr-1">
</div> <input
<div className="check-input flex items-center"> className="w-4 h-4 cursor-pointer"
<input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm2" id="" /> type="checkbox"
<span className="mx-2 text-base text-dark-gray dark:text-white">Phone</span> name="prefcomm1"
</div> 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>
</div>
</div> </div>
{/* Allow Promotions */} {/* Allow Promotions */}
<div className='field w-full mb-6 flex items-center space-x-4'> <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> <label className="input-label text-[#181c32] dark:text-white text-base font-semibold">
<div className="cursor-pointer flex items-center" onClick={()=>setTogglePromotion(prev => !prev)}> Allow Promotions
<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`}> </label>
<div className="w-4 h-full bg-white rounded-full"></div> <div
</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>
</div> </div>
{/* inputs ends here */} {/* inputs ends here */}
</div> </div>
@@ -300,11 +368,19 @@ export default function PersonalInfoTab({
</div> </div>
<div className="content-footer w-full"> <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="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"> <div className="flex items-center space-x-4 mr-9">
<Link <Link
to='/' to="/"
className="text-18 text-light-red tracking-wide " className="text-18 text-light-red tracking-wide "
> >
<span className="border-b dark:border-[#5356fb29] border-light-red"> <span className="border-b dark:border-[#5356fb29] border-light-red">
@@ -313,23 +389,23 @@ export default function PersonalInfoTab({
</span> </span>
</Link> </Link>
{requestStatus.loading ? {requestStatus.loading ? (
<LoadingSpinner size='8' color='sky-blue' /> <LoadingSpinner size="8" color="sky-blue" />
: ) : (
<button <button
type="submit" type="submit"
className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white" className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
> >
Update Profile Update Profile
</button> </button>
} )}
</div> </div>
</div> </div>
</div> </div>
</Form> </Form>
) );
})} }}
</Formik> </Formik>
</div> </div>
); );
} }
@@ -152,6 +152,7 @@ export default function ProductUploadField({
<h1 className="field-title">Item Name </h1> <h1 className="field-title">Item Name </h1>
<div className="input-field mt-2"> <div className="input-field mt-2">
<InputCom <InputCom
fieldClass="px-6"
type="text" type="text"
name="name" name="name"
placeholder="RaidParty Fighters" placeholder="RaidParty Fighters"
@@ -164,6 +165,7 @@ export default function ProductUploadField({
<h1 className="field-title">Exter link </h1> <h1 className="field-title">Exter link </h1>
<div className="input-field mt-2"> <div className="input-field mt-2">
<InputCom <InputCom
fieldClass="px-6"
type="text" type="text"
name="link" name="link"
inputHandler={linkh} 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="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-1 flex h-full justify-center items-center bg-[#FAFAFA] dark:bg-[#11131F] ">
<div className="flex space-x-1 items-center"> <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> <span>
<svg <svg
width="13" width="13"
@@ -235,6 +239,7 @@ export default function ProductUploadField({
<div className="input-field my-2"> <div className="input-field my-2">
<div className="mb-2"> <div className="mb-2">
<InputCom <InputCom
fieldClass="px-6"
type="text" type="text"
name="link" name="link"
inputHandler={roltsHndlr} inputHandler={roltsHndlr}
@@ -260,6 +265,7 @@ export default function ProductUploadField({
<div className="sm:flex sm:space-x-8"> <div className="sm:flex sm:space-x-8">
<div className="sm:w-1/2 w-full mb-2 sm:mb-0"> <div className="sm:w-1/2 w-full mb-2 sm:mb-0">
<InputCom <InputCom
fieldClass="px-6"
type="text" type="text"
name="link" name="link"
inputHandler={keyHndlr} inputHandler={keyHndlr}
@@ -269,6 +275,7 @@ export default function ProductUploadField({
</div> </div>
<div className="flex-1"> <div className="flex-1">
<InputCom <InputCom
fieldClass="px-6"
type="text" type="text"
name="link" name="link"
inputHandler={valueHndlr} inputHandler={valueHndlr}
+4
View File
@@ -28,6 +28,10 @@ class SiteService {
return this.getAuxEnd("/pricing", null); return this.getAuxEnd("/pricing", null);
} }
addFamily(reqData) {
return this.postAuxEnd('/familyadd', reqData)
}
//---------------------------------------- ----- //---------------------------------------- -----
//---------------------------------------- ----- //---------------------------------------- -----
// Unified call below // Unified call below
+1 -20
View File
@@ -1,28 +1,9 @@
import React, { useContext,useState, useEffect } from "react";
import usersService from "../services/UsersService";
import FamilyAcc from "../components/FamilyAcc"; import FamilyAcc from "../components/FamilyAcc";
export default function FamilyAccPage() { 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 ( return (
<> <>
<FamilyAcc ActiveJobList={MyActiveJobList}/> <FamilyAcc />
</> </>
); );
} }