diff --git a/src/components/AuthPages/ForgotPassword/index.jsx b/src/components/AuthPages/ForgotPassword/index.jsx index 65bdbe7..c7712c6 100644 --- a/src/components/AuthPages/ForgotPassword/index.jsx +++ b/src/components/AuthPages/ForgotPassword/index.jsx @@ -1,17 +1,17 @@ -import React, { useEffect, useState } from "react"; -import { Link, useNavigate } from 'react-router-dom'; -import WrenchBoard from "../../../assets/images/wrenchboard.png" +import React, { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import WrenchBoard from "../../../assets/images/wrenchboard.png"; +import usersService from "../../../services/UsersService"; import InputCom from "../../Helpers/Inputs/InputCom"; import AuthLayout from "../AuthLayout"; -import usersService from "../../../services/UsersService"; export default function ForgotPassword() { const [checked, setValue] = useState(false); - const [resetLoading, setResetLoading] = useState(false) + const [resetLoading, setResetLoading] = useState(false); // email const [email, setMail] = useState(""); - const [msgError, setMsgError] = useState(''); - const [msgSuccess, setMsgSuccess] = useState(false) + const [msgError, setMsgError] = useState(""); + const [msgSuccess, setMsgSuccess] = useState(false); const navigate = useNavigate(); const userApi = new usersService(); @@ -21,52 +21,54 @@ export default function ForgotPassword() { }; const humanChecker = () => { - setValue(!checked) - } + setValue(!checked); + }; const resetHandler = async () => { - if (email == '') { - setMsgError('An email is required') + if (email == "") { + setMsgError("An email is required"); } else if (!checked) { - setMsgError('Check if you are human') + setMsgError("Check if you are human"); } - if (email !== '' && checked) { - const reqData = { email } - setResetLoading(true) + if (email !== "" && checked) { + const reqData = { email }; + setResetLoading(true); try { - const res = await userApi.StartResetPassword(reqData) + const res = await userApi.StartResetPassword(reqData); if (res.status === 200) { - setMsgSuccess(true) - setMail("") - setValue(false) - setResetLoading(false) + setMsgSuccess(true); + setMail(""); + setValue(false); + setResetLoading(false); } } catch (error) { - setResetLoading(false) - setMail("") - setMsgError('An error occurred') - throw new Error(error) + setResetLoading(false); + setMail(""); + setMsgError("An error occurred"); + throw new Error(error); } finally { setTimeout(() => { - setMsgError(null) - }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT) + setMsgError(null); + }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT); } } setTimeout(() => { - setMsgError(null) - }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT) - } + setMsgError(null); + }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT); + }; return ( <> - +
-
- - wrenchboard +
+ + wrenchboard
@@ -75,11 +77,14 @@ export default function ForgotPassword() {

Forget Password

- Enter your email to reset your password. + + Enter your email to reset your password. +
- +
@@ -106,7 +118,10 @@ export default function ForgotPassword() {
- {msgError &&
{msgError}
} - {msgSuccess &&
If we find your email, you will receive a link to reset your password. Please use or contact form if you did not get our message after few minutes.
} + {msgError && ( +
+ {msgError} +
+ )} + {msgSuccess && ( +
+ If we find your email, you will receive a link to reset your + password. Please use or{" "} + + contact form + {" "} + if you did not get our message after few minutes. +
+ )}
diff --git a/src/components/AuthPages/Login/index.jsx b/src/components/AuthPages/Login/index.jsx index 3907df8..efd6b14 100644 --- a/src/components/AuthPages/Login/index.jsx +++ b/src/components/AuthPages/Login/index.jsx @@ -1,15 +1,14 @@ import React, { useState } from "react"; -import { useNavigate, Link } from "react-router-dom"; -import { toast } from "react-toastify"; -import googleLogo from "../../../assets/images/google-logo.svg"; +import { Link, useNavigate } from "react-router-dom"; import appleLogo from "../../../assets/images/apple-black.svg"; import facebookLogo from "../../../assets/images/facebook-4.svg"; +import googleLogo from "../../../assets/images/google-logo.svg"; import WrenchBoard from "../../../assets/images/wrenchboard.png"; import usersService from "../../../services/UsersService"; import InputCom from "../../Helpers/Inputs/InputCom"; import AuthLayout from "../AuthLayout"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; import { updateUserDetails } from "../../../store/UserDetails"; export default function Login() { @@ -73,7 +72,7 @@ export default function Login() { setLoginError(true); } } else { - setMsgError("Please fill in fields"); + setMsgError("Please fill in the fields"); } } catch (error) { setMsgError("An error occurred"); @@ -117,6 +116,7 @@ export default function Login() {
- {/*
-
- - - Remember Me - -
- - Forgot Password - -
*/} {loginError && (
Invalid username or password- Please{" "} diff --git a/src/components/AuthPages/SignUp/index.jsx b/src/components/AuthPages/SignUp/index.jsx index 47f2584..d10040b 100644 --- a/src/components/AuthPages/SignUp/index.jsx +++ b/src/components/AuthPages/SignUp/index.jsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from "react"; -import { useNavigate, Link } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import facebookLogo from "../../../assets/images/facebook-4.svg"; import WrenchBoard from "../../../assets/images/wrenchboard.png"; import usersService from "../../../services/UsersService"; @@ -171,6 +171,7 @@ export default function SignUp() {
- + {updated === false ? (
@@ -34,6 +32,7 @@ export default function UpdatePassword() {
{ const [password, setPassword] = useState(""); @@ -158,6 +158,7 @@ const SuccessfulComponent = ({ {/* INPUT */}
+ const filterCategories = ["All Categories", "Explore", "Featured"]; + const [selectedCategory, setCategory] = useState(filterCategories[0]); + return ( +
+
+ + + + + + + + + + + + -
-
NameLast LoginNo of TasksStatus
+
+
+ data +
+
+

+ Firstname Lastname (age) +

+ + Added 10-10-2029 + +
+
+
+
+ + 10-10-2019 + +
+
+
+ + 100 + +
+
- - - - - - - - - - - - - - - - - -
NameLast LoginNo of TasksStatus
-
-
- data -
-
-

- Firstname Lastname (age) -

- - Added 10-10-2029 - -
-
-
-
- - - 10-10-2019 - -
-
-
- - - 100 - -
-
- -
-
-
- ); + + + + + + +
+
+ ); } diff --git a/src/components/FamilyAcc/index.jsx b/src/components/FamilyAcc/index.jsx index 1b2b9ac..5d3e384 100644 --- a/src/components/FamilyAcc/index.jsx +++ b/src/components/FamilyAcc/index.jsx @@ -1,40 +1,212 @@ -import React, { useState } from "react"; -import { Link } from "react-router-dom"; +import React, { useId, useMemo, useState } from "react"; +import CustomPopUp from "../Helpers/CustomPopUp"; +import InputCom from "../Helpers/Inputs/InputCom"; import Layout from "../Partials/Layout"; -import CommonHead from "../UserHeader/CommonHead"; import FamilyTable from "./FamilyTable"; +import SiteService from "../../services/SiteService"; export default function FamilyAcc() { - const [selectTab, setValue] = useState("today"); - const filterHandler = (value) => { - setValue(value); - }; - return ( - - {/**/} -
-
- {/* heading */} -
-
-

+ const [selectTab, setValue] = useState("today"); + const [selectedAge, setSelectedAge] = useState(undefined); + const [loader, setLoader] = useState(false); + const [msgErr, setMsgErr] = useState(""); + const [formData, setFormData] = useState({ + first_name: "", + last_name: "", + }); + + const apiCall = useMemo(() => new SiteService(), []); + + // tab handler + const filterHandler = (value) => { + setValue(value); + }; + + let id = useId(); + // For the age drop down + let startAge = 16; + let endAge = 70; + // creates an array of age values ranging from 16 to 70 + const ageRange = Array.from( + { length: endAge - startAge + 1 }, + (_, index) => startAge + index + ); + // age handler + const handleAgeSelect = (event) => { + setSelectedAge(parseInt(event.target.value)); + }; + // Input handler + const handleInputChange = (event) => { + const { name, value } = event?.target; + setFormData({ ...formData, [name]: value }); + }; + + const addMember = async () => { + let { first_name, last_name } = formData; + setLoader(true); + try { + if (first_name !== "" && last_name !== "") { + const reqData = { + member_id: localStorage.getItem("member_id"), + uid: localStorage.getItem("uid"), + session_id: localStorage.getItem("session_token"), + firstname: first_name, + lastname: last_name, + age: selectedAge, + }; + const res = await apiCall.addFamily(reqData); + const { data } = res; + if (data.internal_return > 0 && data.status == "OK") { + setLoader(false); + console.log(data); + } + } else { + setLoader(false); + setMsgErr("Please fill in the fields"); + } + } catch (error) { + setLoader(false); + setMsgErr("An error occurred"); + } finally { + setTimeout(() => { + setMsgErr(null); + }, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT)); + } + }; + + return ( + + {/**/} +
+
+ {/* heading */} +
+
+

Family Accounts - -

-
-
-
filterHandler("today")} className="relative"> - -
-
-
- -
+ + + +

- - ); +
+
filterHandler("today")} + className="relative" + >
+
+
+ +
+
+
+ ); } + +const FamilyForm = ({ + value: { first_name, last_name }, + ageValue, + inputHandler, + ageHandler, + ageRange, + msgErr, + loader, + onClick, +}) => { + return ( +
+
+ + +
+ {/* Age dropdown */} +
+ +
+
+ +
+
+ {msgErr && ( +
+ {msgErr} +
+ )} +
+
+ +
+
+ +
+ ); +}; diff --git a/src/components/Helpers/CustomPopUp/index.jsx b/src/components/Helpers/CustomPopUp/index.jsx new file mode 100644 index 0000000..bcfdd04 --- /dev/null +++ b/src/components/Helpers/CustomPopUp/index.jsx @@ -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 ( + <> + + + {isOpen && ( +
+
+
+ +
+ {title &&

{title}

} + {children} +
+
+ )} + + ); +}; + +export default CustomPopUp; + +const CloseIcon = () => ( + + + +); diff --git a/src/components/Helpers/Inputs/InputCom/index.jsx b/src/components/Helpers/Inputs/InputCom/index.jsx index 9839068..eec3eb3 100644 --- a/src/components/Helpers/Inputs/InputCom/index.jsx +++ b/src/components/Helpers/Inputs/InputCom/index.jsx @@ -12,76 +12,153 @@ export default function InputCom({ inputHandler, value, forgotPassword, + parentClass, + labelClass, + inputClass, + fieldClass, onClick, disable, - blurHandler + blurHandler, }) { - const inputRef = useRef(null) + const inputRef = useRef(null); // Entry Validation // for Min Length: const minLengthValidation = () => { - if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') { - return 7 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') { - return 3 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') { - return 3 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') { - return 5 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') { - return 8 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') { - return 3 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') { - return 3 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') { - return 3 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') { - return 1 + if (inputRef && inputRef?.current && inputRef?.current?.name === "email") { + return 7; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "first_name" + ) { + return 3; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "last_name" + ) { + return 3; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "address" + ) { + return 5; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "password" + ) { + return 8; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "state" + ) { + return 3; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "province" + ) { + return 3; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "city" + ) { + return 3; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "amount" + ) { + return 1; } - } + }; // for MaxLength const maxLengthValidation = () => { - if (inputRef && inputRef?.current && inputRef?.current?.name === 'email') { - return 35 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'first_name') { - return 25 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'last_name') { - return 25 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'address') { - return 49 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'password') { - return 15 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'state') { - return 25 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'province') { - return 25 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'city') { - return 25 - } else if (inputRef && inputRef?.current && inputRef?.current?.name === 'amount') { - return 9 + if (inputRef && inputRef?.current && inputRef?.current?.name === "email") { + return 35; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "first_name" + ) { + return 25; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "last_name" + ) { + return 25; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "address" + ) { + return 49; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "password" + ) { + return 15; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "state" + ) { + return 25; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "province" + ) { + return 25; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "city" + ) { + return 25; + } else if ( + inputRef && + inputRef?.current && + inputRef?.current?.name === "amount" + ) { + return 9; } - } + }; return ( -
-
- {label && ( - - )} - {forgotPassword && Forgot Password?} +
+
+ {label && ( + + )} + {forgotPassword && ( + + Forgot Password? + + )}
-
+
)} {passIcon && ( -
+
)} diff --git a/src/components/MyWallet/AddRecipient.jsx b/src/components/MyWallet/AddRecipient.jsx index bf0965c..d12bcc9 100644 --- a/src/components/MyWallet/AddRecipient.jsx +++ b/src/components/MyWallet/AddRecipient.jsx @@ -1,370 +1,499 @@ -import React, {useEffect, useState} from 'react' -import { Link, useNavigate } from 'react-router-dom' -import Icons from '../Helpers/Icons' -import usersService from '../../services/UsersService' -import InputCom from '../Helpers/Inputs/InputCom' +import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import usersService from "../../services/UsersService"; +import Icons from "../Helpers/Icons"; +import InputCom from "../Helpers/Inputs/InputCom"; -import LoadingSpinner from '../Spinners/LoadingSpinner' -import {toast} from 'react-toastify' - -import {Formik, Form} from 'formik' -import * as Yup from 'yup' +import { toast } from "react-toastify"; +import LoadingSpinner from "../Spinners/LoadingSpinner"; +import { Form, Formik } from "formik"; +import * as Yup from "yup"; const validationSchema = Yup.object().shape({ - firstname: Yup.string() - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('Firstname is required'), - lastname: Yup.string() - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('Lastname is required'), - country: Yup.string() - .min(1, 'Minimum 1 characters') - .max(25, 'Maximum 25 characters') - .required('Country is required'), - bank: Yup.string() - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('Bank name is required'), - accountNumber: Yup.string() + firstname: Yup.string() + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("Firstname is required"), + lastname: Yup.string() + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("Lastname is required"), + country: Yup.string() + .min(1, "Minimum 1 characters") + .max(25, "Maximum 25 characters") + .required("Country is required"), + bank: Yup.string() + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("Bank name is required"), + accountNumber: Yup.string() .matches(/\d/, "must be a number") - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('Account Number is required'), - repeatAccountNumber: Yup.string() - .required('Repeat Account Number is required') - .oneOf([Yup.ref('accountNumber'), null], 'Must match Account Number'), - accountType: Yup.string() - .min(1, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('Account Type is required'), - city: Yup.string() - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('City is required'), - state: Yup.string() - .min(3, 'Minimum 3 characters') - .max(25, 'Maximum 25 characters') - .required('State is required'), - }) - - const initialValues = { - firstname: '', - lastname: '', - country: '', - bank: '', - accountNumber: '', - repeatAccountNumber: '', - accountType: '', - state: '', - city: '' - } + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("Account Number is required"), + repeatAccountNumber: Yup.string() + .required("Repeat Account Number is required") + .oneOf([Yup.ref("accountNumber"), null], "Must match Account Number"), + accountType: Yup.string() + .min(1, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("Account Type is required"), + city: Yup.string() + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("City is required"), + state: Yup.string() + .min(3, "Minimum 3 characters") + .max(25, "Maximum 25 characters") + .required("State is required"), +}); + +const initialValues = { + firstname: "", + lastname: "", + country: "", + bank: "", + accountNumber: "", + repeatAccountNumber: "", + accountType: "", + state: "", + city: "", +}; function AddRecipient() { + const apiURL = new usersService(); - const apiURL = new usersService() + const navigate = useNavigate(); - const navigate = useNavigate() + let [requestStatus, setRequestStatus] = useState({ + message: "", + loading: false, + status: false, + }); - let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false}) + let [allCountries, setAllCountries] = useState({ + // STATE TO HOLD LIST OF COUNTRIES + loading: true, + data: [], + }); - let [allCountries, setAllCountries] = useState({ // STATE TO HOLD LIST OF COUNTRIES - loading: true, - data: [] - }) + let [bankName, setBankName] = useState({ + // STATE TO HOLD LIST OF BANK NAME + loading: true, + data: [], + }); - let [bankName, setBankName] = useState({ // STATE TO HOLD LIST OF BANK NAME - loading: true, - data: [] - }) + let [accType, setAccType] = useState({ + // STATE TO HOLD LIST ACCOUNT TYPE + loading: true, + data: [], + }); - let [accType, setAccType] = useState({ // STATE TO HOLD LIST ACCOUNT TYPE - loading: true, - data: [] - }) + //FUNCTION TO HANDLE ADD RECIPIENT SUBMIT + const handleSubmit = (values, helpers) => { + setRequestStatus({ message: "", loading: true, status: false }); - //FUNCTION TO HANDLE ADD RECIPIENT SUBMIT - const handleSubmit = (values, helpers) => { - setRequestStatus({message: '', loading: true, status: false}) + let reqData = { + //REQUEST DATA FOR API CALL + firstname: values.firstname, + lastname: values.lastname, + bank_code: values.bank, + account_no: values.accountNumber, + account_type: values.accountType, + country: values.country, + state: values.state, + city: values.city, + }; - let reqData = { //REQUEST DATA FOR API CALL - firstname: values.firstname, - lastname: values.lastname, - bank_code: values.bank, - account_no: values.accountNumber, - account_type: values.accountType, - country: values.country, - state: values.state, - city: values.city + //CALL TO ADD RECIPIENT API + apiURL + .addRecipient(reqData) + .then((res) => { + if (res.data.internal_return < 0) { + setRequestStatus({ + message: "could not add recipient, try again!", + loading: false, + status: true, + }); + return; } + // setRequestStatus({message: 'Recipient Added Successfully!', loading: false, status: true}) + toast.success("Recipient Added Successfully!"); + setTimeout(() => { + navigate("/my-wallet/transfer-fund", { replace: true }); + }, 1000); + }) + .catch((error) => { + setRequestStatus({ + message: "Opps! an error occured! Try again later", + loading: false, + status: false, + }); + }); + }; - //CALL TO ADD RECIPIENT API - apiURL.addRecipient(reqData).then((res)=>{ - if(res.data.internal_return < 0){ - setRequestStatus({message: 'could not add recipient, try again!', loading: false, status: true}) - return - } - // setRequestStatus({message: 'Recipient Added Successfully!', loading: false, status: true}) - toast.success("Recipient Added Successfully!"); - setTimeout(()=>{navigate('/my-wallet/transfer-fund',{replace:true})},1000) - }).catch((error)=>{ - setRequestStatus({message: 'Opps! an error occured! Try again later', loading: false, status: false}) - }) - } + // FUNCTION TO GET COUNTRIES + const getCountry = () => { + apiURL + .getSignupCountryData() + .then((res) => { + if (res.data.internal_return < 0) { + setAllCountries((prev) => ({ loading: false, data: [] })); + return; + } + setAllCountries((prev) => ({ + loading: false, + data: res.data.signup_country, + })); + }) + .catch((error) => { + setAllCountries((prev) => ({ loading: false, data: [] })); + }); + }; + // END OF FUNCTION TO GET COUNTRIES + // FUNCTION TO GET COUNTRY BANK + const getCountryBank = () => { + apiURL + .getCountryBank() + .then((res) => { + if (res.data.internal_return < 0) { + setBankName((prev) => ({ loading: false, data: [] })); + return; + } + setBankName((prev) => ({ loading: false, data: res.data.result_list })); + }) + .catch((error) => { + setBankName((prev) => ({ loading: false, data: [] })); + }); + }; + // END OF FUNCTION TO GET COUNTRY BANK - // FUNCTION TO GET COUNTRIES - const getCountry = ()=> { - apiURL.getSignupCountryData().then((res)=>{ - if(res.data.internal_return < 0){ - setAllCountries(prev => ({loading: false, data: []})) - return - } - setAllCountries(prev => ({loading: false, data:res.data.signup_country})) - }).catch((error)=>{ - setAllCountries(prev => ({loading: false, data: []})) - }) - } - // END OF FUNCTION TO GET COUNTRIES + // FUNCTION TO GET ACCOUNT TYPES + const getAccountTypes = () => { + apiURL + .getAccountTypes() + .then((res) => { + if (res.data.internal_return < 0) { + setAccType((prev) => ({ loading: false, data: [] })); + return; + } + setAccType((prev) => ({ loading: false, data: res.data.result_list })); + }) + .catch((error) => { + setAccType((prev) => ({ loading: false, data: [] })); + }); + }; + // END OF FUNCTION TO GET ACCOUNT TYPES - // FUNCTION TO GET COUNTRY BANK - const getCountryBank = ()=> { - apiURL.getCountryBank().then((res)=>{ - if(res.data.internal_return < 0){ - setBankName(prev => ({loading: false, data: []})) - return - } - setBankName(prev => ({loading: false, data:res.data.result_list})) - }).catch((error)=>{ - setBankName(prev => ({loading: false, data: []})) - }) - } - // END OF FUNCTION TO GET COUNTRY BANK + useEffect(() => { + getCountry(); // TO LOAD LIST COUNTRY + getCountryBank(); // TO LOAD LIST COUNTRY BANK + getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES + }, []); - // FUNCTION TO GET ACCOUNT TYPES - const getAccountTypes = ()=> { - apiURL.getAccountTypes().then((res)=>{ - if(res.data.internal_return < 0){ - setAccType(prev => ({loading: false, data: []})) - return - } - setAccType(prev => ({loading: false, data:res.data.result_list})) - }).catch((error)=>{ - setAccType(prev => ({loading: false, data: []})) - }) - } - // END OF FUNCTION TO GET ACCOUNT TYPES + return ( +
+
+
+

+ ADD BANK ACCOUNT +

+ + {(props) => ( +
+ {/* inputs starts here */} + {/* firstname */} +
+
+ + {props.errors.firstname && props.touched.firstname && ( +

+ {props.errors.firstname} +

+ )} +
- useEffect(()=>{ - getCountry() // TO LOAD LIST COUNTRY - getCountryBank() // TO LOAD LIST COUNTRY BANK - getAccountTypes() // TO LOAD LIST ACCOUNT TYPES - },[]) - - return ( -
-
-
-

ADD BANK ACCOUNT

- - {(props)=>( - - - {/* inputs starts here */} - {/* firstname */} -
-
- - {(props.errors.firstname && props.touched.firstname) &&

{props.errors.firstname}

} -
- - {/* lastname */} -
- - {(props.errors.lastname && props.touched.lastname) &&

{props.errors.lastname}

} -
-
- - -
- {/* country */} -
- - - {(props.errors.country && props.touched.country) &&

{props.errors.country}

} -
- - {/* bank name */} -
- - - {(props.errors.bank && props.touched.bank) &&

{props.errors.bank}

} -
-
- - {/* ACCOUNT NUMBER */} -
-
- - {(props.errors.accountNumber && props.touched.accountNumber) &&

{props.errors.accountNumber}

} -
- - {/* REPEAT ACCT. NUMBER */} -
- - {(props.errors.repeatAccountNumber && props.touched.repeatAccountNumber) &&

{props.errors.repeatAccountNumber}

} -
-
- -
- {/* Account Type */} -
- - - {(props.errors.accountType && props.touched.accountType) &&

{props.errors.accountType}

} -
-
- - {/* state */} -
-
- - {(props.errors.state && props.touched.state) &&

{props.errors.state}

} -
- - {/* city */} -
- - {(props.errors.city && props.touched.city) &&

{props.errors.city}

} -
-
- {/* end of inputs starts here */} - - {/* REQUEST ERROR DISPLAY */} - {requestStatus.message &&

{requestStatus.message}

} - -
- {requestStatus.loading ? - - : - - } -
- - )} -
+ {/* lastname */} +
+ + {props.errors.lastname && props.touched.lastname && ( +

+ {props.errors.lastname} +

+ )} +
-
+
+ {/* country */} +
+ + + {props.errors.country && props.touched.country && ( +

+ {props.errors.country} +

+ )} +
+ + {/* bank name */} +
+ + + {props.errors.bank && props.touched.bank && ( +

+ {props.errors.bank} +

+ )} +
+
+ + {/* ACCOUNT NUMBER */} +
+
+ + {props.errors.accountNumber && + props.touched.accountNumber && ( +

+ {props.errors.accountNumber} +

+ )} +
+ + {/* REPEAT ACCT. NUMBER */} +
+ + {props.errors.repeatAccountNumber && + props.touched.repeatAccountNumber && ( +

+ {props.errors.repeatAccountNumber} +

+ )} +
+
+ +
+ {/* Account Type */} +
+ + + {props.errors.accountType && props.touched.accountType && ( +

+ {props.errors.accountType} +

+ )} +
+
+ + {/* state */} +
+
+ + {props.errors.state && props.touched.state && ( +

+ {props.errors.state} +

+ )} +
+ + {/* city */} +
+ + {props.errors.city && props.touched.city && ( +

+ {props.errors.city} +

+ )} +
+
+ {/* end of inputs starts here */} + + {/* REQUEST ERROR DISPLAY */} + {requestStatus.message && ( +

+ {requestStatus.message} +

+ )} + +
+ {requestStatus.loading ? ( + + ) : ( + + )} +
+ + )} +
- ) +
+
+ ); } -export default AddRecipient \ No newline at end of file +export default AddRecipient; diff --git a/src/components/MyWallet/ConfirmAddFund.jsx b/src/components/MyWallet/ConfirmAddFund.jsx index a34e675..00b0eee 100644 --- a/src/components/MyWallet/ConfirmAddFund.jsx +++ b/src/components/MyWallet/ConfirmAddFund.jsx @@ -1,132 +1,156 @@ -import React, {useState, useEffect} from 'react' -import RecentActivityTable from './WalletComponent/RecentActivityTable' -import LoadingSpinner from '../Spinners/LoadingSpinner' -import InputCom from '../Helpers/Inputs/InputCom' -import {toast} from 'react-toastify' -import { useLocation, useNavigate } from 'react-router-dom' -import { useSelector } from 'react-redux' +import React, { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import { useLocation, useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import InputCom from "../Helpers/Inputs/InputCom"; +import LoadingSpinner from "../Spinners/LoadingSpinner"; +import RecentActivityTable from "./WalletComponent/RecentActivityTable"; -import usersService from '../../services/UsersService' +import usersService from "../../services/UsersService"; -import { FlutterWaveButton, closePaymentModal } from 'flutterwave-react-v3' +import { FlutterWaveButton, closePaymentModal } from "flutterwave-react-v3"; +function ConfirmAddFund({ payment }) { + let { userDetails } = useSelector((state) => state.userDetails); // TO GET LOGGEDIN USER DETAILS -function ConfirmAddFund({payment}) { + let [pageLoading, setPageLoading] = useState(true); - let {userDetails} = useSelector(state => state.userDetails) // TO GET LOGGEDIN USER DETAILS - - let [pageLoading, setPageLoading] = useState(true) + let [requestStatus, setRequestStatus] = useState({ + message: "", + loading: false, + status: false, + }); // STATE FOR API REQUEST - let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false}) // STATE FOR API REQUEST + const apiURL = new usersService(); + const navigate = useNavigate(); - const apiURL = new usersService() - const navigate = useNavigate() + let { state } = useLocation(); - let {state} = useLocation() - - - //FUNCTION TO HANDLE SUBMIT - const onSuccessPayment = () => { - setRequestStatus({message: '', loading: true, status: false}) - let reqData = {amount: state?.account, currency: 'NGN'} - apiURL.startTopUp(reqData).then((res)=>{ - if(res.data.internal_return < 0){ - setRequestStatus({message: 'Could not finish transaction', loading: false, status: false}) - toast.success('Opps! something went wrong') - } - // do something - setRequestStatus({message: 'Topup successful', loading: false, status: true}) - toast.success('Account Topup was sucessful') - setTimeout(()=>{ - navigate('/my-wallet', {replace: true}) - window.location.reload(true) - }, 1000) - }).catch(err => { - // do something - setRequestStatus({message: 'Opps! An Error Occured', loading: false, status: false}) - toast.success('Opps! something went wrong') - }) - } - - const config = { - public_key: process.env.REACT_APP_FLUTTERWAVE_APIKEY, - tx_ref: Date.now(), - amount: state?.amount, - currency: 'NGN', - payment_options: 'card,mobilemoney,ussd', - customer: { - email: `${userDetails.email}`, - phone_number: userDetails.phone, - name: `${userDetails.lastname} ${userDetails.firstname}` - }, - customizations: { - title: 'WrenchBoard', - description: 'Topup Payment', - logo: 'https://st2.depositphotos.com/4403291/7418/v/450/depositphotos_74189661-stock-illustration-online-shop-log.jpg', - }, - }; - - const fwConfig = { - ...config, - text: 'Proceed', - callback: (response) => { - onSuccessPayment() - closePaymentModal() // this will close the modal programmatically - }, - onClose: () => {}, - }; - - useEffect(()=>{ - // what happens if not state redirect user - if(!state){ - navigate('/my-wallet/add-fund',{replace: true}) - }else{ - setPageLoading(false) + //FUNCTION TO HANDLE SUBMIT + const onSuccessPayment = () => { + setRequestStatus({ message: "", loading: true, status: false }); + let reqData = { amount: state?.account, currency: "NGN" }; + apiURL + .startTopUp(reqData) + .then((res) => { + if (res.data.internal_return < 0) { + setRequestStatus({ + message: "Could not finish transaction", + loading: false, + status: false, + }); + toast.success("Opps! something went wrong"); } - },[]) + // do something + setRequestStatus({ + message: "Topup successful", + loading: false, + status: true, + }); + toast.success("Account Topup was sucessful"); + setTimeout(() => { + navigate("/my-wallet", { replace: true }); + window.location.reload(true); + }, 1000); + }) + .catch((err) => { + // do something + setRequestStatus({ + message: "Opps! An Error Occured", + loading: false, + status: false, + }); + toast.success("Opps! something went wrong"); + }); + }; - return ( -
- {pageLoading ? - - : -
-
-

Confirm Add Fund To Account

-
-
-
- -
-
+ 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); + } + }, []); + + return ( +
+ {pageLoading ? ( + + ) : ( +
+
+

+ Confirm Add Fund To Account +

+
+
+
+ +
- } - -
-
-

Recent Activity

- {/*

Activity Report

*/} - {payment.loading ? - - : - - } -
+ +
+
+
+
- ) + )} + +
+
+

+ Recent Activity +

+ {/*

Activity Report

*/} + {payment.loading ? ( + + ) : ( + + )} +
+
+
+ ); } -export default ConfirmAddFund \ No newline at end of file +export default ConfirmAddFund; diff --git a/src/components/MyWallet/ConfirmTransfer.jsx b/src/components/MyWallet/ConfirmTransfer.jsx index 3e1f5d5..2aa8d4d 100644 --- a/src/components/MyWallet/ConfirmTransfer.jsx +++ b/src/components/MyWallet/ConfirmTransfer.jsx @@ -1,168 +1,210 @@ -import React, {useState, useEffect} from 'react' -import {useLocation, useNavigate} from 'react-router-dom' -import RecentActivityTable from './WalletComponent/RecentActivityTable' -import LoadingSpinner from '../Spinners/LoadingSpinner' -import InputCom from '../Helpers/Inputs/InputCom' -import {toast} from 'react-toastify' +import React, { useEffect, useState } from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import InputCom from "../Helpers/Inputs/InputCom"; +import LoadingSpinner from "../Spinners/LoadingSpinner"; +import RecentActivityTable from "./WalletComponent/RecentActivityTable"; -import usersService from '../../services/UsersService' +import usersService from "../../services/UsersService"; -function ConfirmTransfer({payment, wallet}) { - const apiURL = new usersService() +function ConfirmTransfer({ payment, wallet }) { + const apiURL = new usersService(); - const navigate = useNavigate() - - let {state} = useLocation() - + const navigate = useNavigate(); - let [requestStatus, setRequestStatus] = useState({message: '', loading: false, status: false}) - let [pageLoading, setPageLoading] = useState(true) + let { state } = useLocation(); - //FUNCTION TO HANDLE SUBMIT - const handleSubmit = () => { - setRequestStatus({message: '', loading: true, status: false}) - let reqData = { - amount: Number(state.amount), - Fee: Number(state.fee), - recipientid: Number(state.recipientID) + let [requestStatus, setRequestStatus] = useState({ + message: "", + loading: false, + status: false, + }); + let [pageLoading, setPageLoading] = useState(true); + + //FUNCTION TO HANDLE SUBMIT + const handleSubmit = () => { + setRequestStatus({ message: "", loading: true, status: false }); + let reqData = { + amount: Number(state.amount), + Fee: Number(state.fee), + recipientid: Number(state.recipientID), + }; + apiURL + .sendMoney(reqData) + .then((res) => { + if (res.data.internal_return < 0) { + setRequestStatus({ + message: "Could not perform transaction", + loading: false, + status: false, + }); + return; } - apiURL.sendMoney(reqData).then((res)=>{ - if(res.data.internal_return < 0){ - setRequestStatus({message: 'Could not perform transaction', loading: false, status: false}) - return - } - setRequestStatus({message: 'transfer successful', loading: false, status: true}) - toast.success('Transfer sucessful') - setTimeout(()=>{ - navigate('/my-wallet', {replace: true}) - window.location.reload(true) - }, 1000) - }).catch(error=>{ - setRequestStatus({message: 'Opps! something went wrong! Try Again', loading: false, status: false}) - }) + setRequestStatus({ + message: "transfer successful", + loading: false, + status: true, + }); + toast.success("Transfer sucessful"); + setTimeout(() => { + navigate("/my-wallet", { replace: true }); + window.location.reload(true); + }, 1000); + }) + .catch((error) => { + setRequestStatus({ + message: "Opps! something went wrong! Try Again", + loading: false, + status: false, + }); + }); + }; + + useEffect(() => { + // what happens if not state redirect user + if (!state) { + navigate("/my-wallet/transfer-fund", { replace: true }); + } else { + setPageLoading(false); } - - useEffect(()=>{ - // what happens if not state redirect user - if(!state){ - navigate('/my-wallet/transfer-fund',{replace: true}) - }else{ - setPageLoading(false) - } - },[]) - return ( -
- {pageLoading ? - - : - ( -
-
-
- {wallet.loading ? - - : - wallet.data.length ? -

- {wallet.data.map(item => { - if(item.description == 'Naira'){ - return `Withdraw from Naira Wallet : ${item.symbol}${(item.amount*0.01).toFixed(2)}` - } - })} -

- : - wallet.error ? -

Opps! An Error Occured

- : -

No Wallet Information Found!

- } -
-
-
-

Confirm Withdraw to Account

- {/* AMOUNT */} -
- -
- - {/* RECIPIENT ACC: */} -
- -
- - {/* PROCESSING FEE: */} -
- -
- - {/* TOTAL */} -
- -
- - {/* COMMENT/NOTE */} -
- -
-
- -
- {requestStatus.message &&

{requestStatus.message}

} -
- {requestStatus.loading ? - - : - - } -
-
-
- ) - } - -
-
-

Recent Activity

- {/*

Activity Report

*/} - {payment.loading ? - - : - + }, []); + return ( +
+ {pageLoading ? ( + + ) : ( +
+
+
+ {wallet.loading ? ( + + ) : wallet.data.length ? ( +

+ {wallet.data.map((item) => { + if (item.description == "Naira") { + return `Withdraw from Naira Wallet : ${item.symbol}${( + item.amount * 0.01 + ).toFixed(2)}`; } -

+ })} + + ) : wallet.error ? ( +

+ Opps! An Error Occured +

+ ) : ( +

+ No Wallet Information Found! +

+ )}
+
+
+

+ Confirm Withdraw to Account +

+ {/* AMOUNT */} +
+ +
+ + {/* RECIPIENT ACC: */} +
+ +
+ + {/* PROCESSING FEE: */} +
+ +
+ + {/* TOTAL */} +
+ +
+ + {/* COMMENT/NOTE */} +
+ +
+
+ +
+ {requestStatus.message && ( +

+ {requestStatus.message} +

+ )} +
+ {requestStatus.loading ? ( + + ) : ( + + )} +
+
- ) + )} + +
+
+

+ Recent Activity +

+ {/*

Activity Report

*/} + {payment.loading ? ( + + ) : ( + + )} +
+
+
+ ); } -export default ConfirmTransfer \ No newline at end of file +export default ConfirmTransfer; diff --git a/src/components/MyWallet/TransferFund.jsx b/src/components/MyWallet/TransferFund.jsx index 46af3ef..2d5f67c 100644 --- a/src/components/MyWallet/TransferFund.jsx +++ b/src/components/MyWallet/TransferFund.jsx @@ -1,240 +1,326 @@ -import React, {useEffect, useState} from 'react' -import { Link, useNavigate } from 'react-router-dom' -import RecentActivityTable from './WalletComponent/RecentActivityTable' -import LoadingSpinner from '../Spinners/LoadingSpinner' -import InputCom from '../Helpers/Inputs/InputCom' +import React, { useEffect, useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import InputCom from "../Helpers/Inputs/InputCom"; +import LoadingSpinner from "../Spinners/LoadingSpinner"; +import RecentActivityTable from "./WalletComponent/RecentActivityTable"; -import usersService from '../../services/UsersService' +import usersService from "../../services/UsersService"; -import {toast} from 'react-toastify' - -import {Formik, Form} from 'formik' -import * as Yup from 'yup' +import { Form, Formik } from "formik"; +import * as Yup from "yup"; const validationSchema = Yup.object().shape({ - amount: Yup.number() + amount: Yup.number() .typeError("you must specify a number") - .min(1, 'Amount must be greater than 0') - .required('Amount is required'), - recipientID: Yup.string() - .min(1, 'Minimum 1 characters') - .max(50, 'Maximum 50 characters') - .required('Recipient is required'), - }) - - const initialValues = { - amount: '', - recipientID: '', - comment: '', - } + .min(1, "Amount must be greater than 0") + .required("Amount is required"), + recipientID: Yup.string() + .min(1, "Minimum 1 characters") + .max(50, "Maximum 50 characters") + .required("Recipient is required"), +}); -function TransferFund({payment, wallet}) { - const apiCall = new usersService() // API CLASS CALL +const initialValues = { + amount: "", + recipientID: "", + comment: "", +}; - const navigate = useNavigate() +function TransferFund({ payment, wallet }) { + const apiCall = new usersService(); // API CLASS CALL - let [requestStatus, setRequestStatus] = useState(false) + const navigate = useNavigate(); - let [recipients, setRecipients] = useState({ // FOR COUPON HISTORY - loading: true, - data: [], - error: false - }) + let [requestStatus, setRequestStatus] = useState(false); - let [sendMoneyFee, setSendMoneyFee] = useState({loading: false, fee: 0, total: 0}) // HOLD THE VALUE FOR SEND MONEY FEE + let [recipients, setRecipients] = useState({ + // FOR COUPON HISTORY + loading: true, + data: [], + error: false, + }); + let [sendMoneyFee, setSendMoneyFee] = useState({ + loading: false, + fee: 0, + total: 0, + }); // HOLD THE VALUE FOR SEND MONEY FEE - //FUNCTION TO GET RECIPIENT LIST - const getRecipients = ()=>{ - apiCall.getRecipient().then((res)=>{ - if(res.data.internal_return < 0){ // success but no data - setRecipients(prev => ({...prev, loading: false})) - return - } - setRecipients(prev => ({...prev, loading: false, data: res.data.result_list})) - }).catch((error)=>{ - setRecipients(prev => ({...prev, loading: false, error: true})) - }) - } - - //FUNCTION TO GET SEND MONEY FEE - const getSendMoneyFee = ({target:{value}})=>{ - setSendMoneyFee({loading: true, fee: 0, total: 0}) - let amount = value - if(Number(amount) <= 0 || amount=='' || isNaN(amount)){ - setSendMoneyFee({loading: false, fee: 0, total: 0}) - return + //FUNCTION TO GET RECIPIENT LIST + const getRecipients = () => { + apiCall + .getRecipient() + .then((res) => { + if (res.data.internal_return < 0) { + // success but no data + setRecipients((prev) => ({ ...prev, loading: false })); + return; } - apiCall.getSendMoneyFee(Number(amount)).then((res)=>{ - setSendMoneyFee({loading: false, fee: res.data.processing_fee, total: res.data.total_amount}) - }).catch((error)=>{ - setSendMoneyFee({loading: false, fee: 0, total: 0}) - }) + setRecipients((prev) => ({ + ...prev, + loading: false, + data: res.data.result_list, + })); + }) + .catch((error) => { + setRecipients((prev) => ({ ...prev, loading: false, error: true })); + }); + }; + + //FUNCTION TO GET SEND MONEY FEE + const getSendMoneyFee = ({ target: { value } }) => { + setSendMoneyFee({ loading: true, fee: 0, total: 0 }); + let amount = value; + if (Number(amount) <= 0 || amount == "" || isNaN(amount)) { + setSendMoneyFee({ loading: false, fee: 0, total: 0 }); + return; } + apiCall + .getSendMoneyFee(Number(amount)) + .then((res) => { + setSendMoneyFee({ + loading: false, + fee: res.data.processing_fee, + total: res.data.total_amount, + }); + }) + .catch((error) => { + setSendMoneyFee({ loading: false, fee: 0, total: 0 }); + }); + }; + //FUNCTION TO HANDLE SUBMIT + const handleSubmit = (values, helpers) => { + setRequestStatus(true); + let recipientDetails = recipients.data?.filter( + (item) => item.recipient_id == values.recipientID + ); + let stateData = { + ...values, + ...sendMoneyFee, + details: { ...recipientDetails[0] }, + }; - //FUNCTION TO HANDLE SUBMIT - const handleSubmit = (values, helpers) => { - setRequestStatus(true) - let recipientDetails = recipients.data?.filter(item => item.recipient_id == values.recipientID) - let stateData = {...values, ...sendMoneyFee, details:{...recipientDetails[0]}} + setTimeout(() => { + setRequestStatus(false); + navigate("confirm-transfer", { state: stateData }); + }, 1000); + }; - setTimeout(()=>{ - setRequestStatus(false) - navigate('confirm-transfer', {state: stateData}) - }, 1000) - } + useEffect(() => { + getRecipients(); + }, []); + return ( +
+
+
+ + {(props) => { + return ( +
+ {wallet.loading ? ( + + ) : wallet.data.length ? ( +

+ {wallet.data.map((item) => { + if (item.description == "Naira") { + return `Withdraw from Naira Wallet : ${item.symbol}${( + item.amount * 0.01 + ).toFixed(2)}`; + } + })} +

+ ) : wallet.error ? ( +

+ Opps! An Error Occured +

+ ) : ( +

+ No Wallet Information Found! +

+ )} +
+
+ { + getSendMoneyFee(e); + }} + // props.handleBlur + // onMouseLeave={(e)=>{getSendMoneyFee(e)}} + /> + {props.errors.amount && props.touched.amount && ( +

+ {props.errors.amount} +

+ )} +
- useEffect(()=>{ - getRecipients() - },[]) - return ( -
-
-
- - {(props)=>{ - return ( - - {wallet.loading ? - - : - wallet.data.length ? -

- {wallet.data.map(item => { - if(item.description == 'Naira'){ - return `Withdraw from Naira Wallet : ${item.symbol}${(item.amount*0.01).toFixed(2)}` - } - })} -

- : - wallet.error ? -

Opps! An Error Occured

- : -

No Wallet Information Found!

- } -
+
+ +
+
-
- { - getSendMoneyFee(e) - }} - // props.handleBlur - // onMouseLeave={(e)=>{getSendMoneyFee(e)}} - /> - {(props.errors.amount && props.touched.amount) &&

{props.errors.amount}

} -
- -
- -
-
+
+
+ +
+
-
-
- -
-
- -
-
-
-
- - Add New -
- -
-
- {(props.errors.recipientID && props.touched.recipientID) &&

{props.errors.recipientID}

} -
+
+
+
+
+ + + Add New + +
+ +
+
+ {props.errors.recipientID && props.touched.recipientID && ( +

+ {props.errors.recipientID} +

+ )} +
-
- {/* + {/* */} - -