Compare commits

..

2 Commits

Author SHA1 Message Date
victorAnumudu c4af2dfcc8 changed timeout duration 2023-10-09 11:29:11 +01:00
victorAnumudu b186549b8d added profile upload API 2023-10-09 11:22:38 +01:00
14 changed files with 146 additions and 165 deletions
+1 -4
View File
@@ -87,7 +87,4 @@ REACT_APP_MAX_FAMILY_MEMBERS=8
REACT_APP_SHOW_OFFER_GROUP_JOB=0
#UPLOAD PROFILE PICTURE
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
+1 -4
View File
@@ -55,7 +55,4 @@ REACT_APP_MAX_FAMILY_MEMBERS=8
REACT_APP_SHOW_OFFER_GROUP_JOB=0
#UPLOAD PROFILE PICTURE
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
-3
View File
@@ -62,6 +62,3 @@ REACT_APP_SHOW_OFFER_GROUP_JOB=0
#UPLOAD PROFILE PICTURE
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
-1
View File
@@ -21,7 +21,6 @@
"react-chartjs-2": "^4.1.0",
"react-countup": "^6.2.0",
"react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-qr-code": "^2.0.11",
"react-redux": "^8.0.5",
"react-router-dom": "^6.0.2",
@@ -7,8 +7,6 @@ import AuthLayout from "../AuthLayout";
import EmailValidator from "../../../lib/EmailValidator";
import ForgetPwdResponse from "../ForgetPwdResponse";
import ReCAPTCHA from "react-google-recaptcha";
export default function ForgotPassword() {
const [checked, setValue] = useState(false);
const [resetLoading, setResetLoading] = useState(false);
@@ -24,18 +22,9 @@ export default function ForgotPassword() {
setMail(e?.target.value);
};
// const humanChecker = () => {
// setValue(!checked);
// };
function humanChecker(value) {
// console.log("Captcha value:", value);
if(value){
setValue(true)
}else{
setValue(false)
}
}
const humanChecker = () => {
setValue(!checked);
};
const resetHandler = async () => {
if (email == "") {
@@ -124,16 +113,10 @@ export default function ForgotPassword() {
/>
</div>
{/* hCaptha clone for the time being */}
<div className="mb-10 flex justify-center w-full">
<ReCAPTCHA
sitekey={process.env.REACT_APP_GOOGLE_RECAPTCHA_SITEKEY}
onChange={humanChecker}
/>
</div>
{/* <div className="mb-10">
<div className="mb-10">
<div className="w-[303px] h-[78px] mx-auto overflow-hidden">
<div className="w-[300px] h-[74px] bg-white bottom-[1px] rounded border-gray-100 overflow-hidden cursor-pointer">
{/* Checkbox */}
<div className="h-full relative inline-block">
<div className="relative table top-0 h-full">
<div className="table-cell align-middle">
@@ -165,7 +148,7 @@ export default function ForgotPassword() {
<div className="h-full relative inline-block w-16"></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}
+6 -21
View File
@@ -7,7 +7,7 @@ import React, {
useState,
} from "react";
import { useReactToPrint } from "react-to-print";
import profile from "../../assets/images/icons/family.svg";
import profile from "../../assets/images/profile-info-profile.png";
import localImgLoad from "../../lib/localImgLoad";
import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner";
@@ -82,29 +82,14 @@ export default function FamilyManageTabs({
profileImgInput.current.click();
};
/**
* Handles the change event of the profile image input field.
* Checks if the selected file exceeds the maximum file size limit and displays an alert if it does.
* If the file is within the size limit, it reads the file using the FileReader API and sets the profile image state with the result.
*/
// Function to handle changes in the profile image input
const profileImgChangeHandler = (e) => {
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const file = e.target.files[0];
if (file && file.size > MAX_FILE_SIZE) {
alert("File size exceeds the limit.");
return;
}
if (file) {
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = () => {
const imageDataUrl = imgReader.result;
// Set the profile image
setProfileImg(imageDataUrl);
imgReader.onload = (event) => {
setProfileImg(event.target.result);
};
imgReader.readAsDataURL(file);
imgReader.readAsDataURL(e.target.files[0]);
}
};
+5 -10
View File
@@ -1,31 +1,26 @@
import React from "react";
import localImgLoad from "../../../lib/localImgLoad";
export default function ProfileInfo({
profileImg,
profileImgInput,
profileImgChangeHandler,
profileImgChangHandler,
browseProfileImg,
accountDetails,
}) {
// console.log(accountDetails.banner)
return (
<div className="flex flex-col items-center gap-4">
<div className="flex justify-center">
<div className="w-full relative">
<img
src={
profileImg
? profileImg
: localImgLoad(`images/icons/${accountDetails.banner}`)
}
alt="profile"
src={localImgLoad(`images/icons/${accountDetails.banner}`)}
alt=""
className="sm:w-[180px] sm:h-[180px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover"
/>
<input
ref={profileImgInput}
accept="image/*"
onChange={profileImgChangeHandler}
onChange={(e) => profileImgChangHandler(e)}
type="file"
className="hidden"
/>
+52 -44
View File
@@ -12,7 +12,8 @@ function NairaWithdraw({
state,
setShowConfirmNairaWithdraw,
}) {
let MaxNoOfBanks = process.env.REACT_APP_MAX_CREDIT_BANK_ACCOUNT; // HOLDS THE VALUE OF THE MAX NUMBER OF BANKS USER CAN ADD
let MaxNoOfBanks = process.env.REACT_APP_MAX_CREDIT_BANK_ACCOUNT // HOLDS THE VALUE OF THE MAX NUMBER OF BANKS USER CAN ADD
const apiCall = new usersService();
const [tab, setTab] = useState("previous");
let [requestStatus, setRequestStatus] = useState(false);
@@ -24,9 +25,7 @@ function NairaWithdraw({
recipientID: state?.previousAccount?.recipientID || "",
},
newAccount: {
country: wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country,
country: state?.newAccount?.amount || "",
bank: state?.newAccount?.amount || "",
accountNumber: state?.newAccount?.amount || "",
accountType: state?.newAccount?.amount || "",
@@ -68,14 +67,10 @@ function NairaWithdraw({
// Handling card change
const handleBankOptions = (event) => {
let bankCountry = wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country
const { value } = event.target;
setBankName((prev) => ({ loading: true, data: [] }));
apiCall
.getCountryBank({
country: bankCountry
})
.getCountryBank({ country: value })
.then((res) => {
if (res.data.internal_return < 0) {
setBankName((prev) => ({ loading: false, data: [] }));
@@ -145,7 +140,6 @@ function NairaWithdraw({
};
useEffect(() => {
handleBankOptions()
getCountry(); // TO LOAD LIST COUNTRY
getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
}, []);
@@ -232,7 +226,7 @@ function NairaWithdraw({
setShowConfirmNairaWithdraw({ show: true, state: stateData });
}, 1000);
}
if (tab === "new") {
const { accountNumber, accountType, bank, city, country, state } =
values?.newAccount;
@@ -287,8 +281,6 @@ function NairaWithdraw({
getRecipients();
}, []);
console.log("Testing Wallet Country", wallet?.walletCountry[0][0]);
return (
<ModalCom action={action} situation={situation} className="edit-popup">
<div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
@@ -432,11 +424,7 @@ function NairaWithdraw({
<label
onClick={() => setTab("new")}
htmlFor="new"
className={`cursor-pointer flex items-center gap-1 ${
recipients.data.length >= MaxNoOfBanks
? "pointer-events-none"
: ""
}`}
className={`cursor-pointer flex items-center gap-1 ${recipients.data.length >= MaxNoOfBanks ? 'pointer-events-none':''}`}
>
<input
id="new"
@@ -448,12 +436,7 @@ function NairaWithdraw({
tab == "new" ? "" : ""
} tracking-wide transition duration-200`}
/>
New Account{" "}
{recipients.data.length >= MaxNoOfBanks && (
<span className="text-[14px] text-red-500">
Max Reached
</span>
)}
New Account{" "} {recipients.data.length >= MaxNoOfBanks && <span className="text-[14px] text-red-500">Max Reached</span>}
</label>
</div>
</div>
@@ -540,12 +523,12 @@ function NairaWithdraw({
</>
)}
{tab == "new" &&
(recipients.loading ? (
{tab == "new" && (
recipients.loading ?
<div className="mt-3 flex flex-col w-full h-[188px] justify-center items-center">
<LoadingSpinner size="10" color="sky-blue" />
<LoadingSpinner size='10' color='sky-blue' />
</div>
) : recipients.data.length < MaxNoOfBanks ? (
:recipients.data.length < MaxNoOfBanks ?
<div className="w-full mt-3 rounded-md bg-slate-100">
<div className="relative fields w-full flex flex-col p-4">
<div className="flex flex-[2] min-h-[52px]">
@@ -558,12 +541,7 @@ function NairaWithdraw({
Country{" "}
<span className="text-red-500">*</span>
</label>
<div className="w-full text-base p-2 text-dark-gray dark:text-white border border-slate-300 outline-0 flex-[0.6] rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding tracking-[1.5px] flex items-center pointer-events-none">
<span className="text-slate-500 text-lg italic">
{wallet.walletCountry[0][1]}
</span>
</div>
{/* <select
<select
className="w-full text-base p-2 text-dark-gray dark:text-white border border-slate-300 outline-0 flex-[0.6] rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding tracking-[1.5px]"
name="newAccount.country"
value={props.values.newAccount?.country}
@@ -574,7 +552,7 @@ function NairaWithdraw({
>
{allCountries.loading ? (
<option
className="text-slate-500 text-lg"
className="text-slate-500 text-lg"
value=""
>
Loading...
@@ -607,7 +585,13 @@ function NairaWithdraw({
No Options Found!
</option>
)}
</select> */}
</select>
{/* {props.errors.country &&
props.touched.country && (
<p className="text-sm text-red-500">
{props.errors.country}
</p>
)} */}
</div>
{/* bank name */}
@@ -662,6 +646,11 @@ function NairaWithdraw({
</option>
)}
</select>
{/* {props.errors.bank && props.touched.bank && (
<p className="text-sm text-red-500">
{props.errors.bank}
</p>
)} */}
</div>
</div>
@@ -682,12 +671,16 @@ function NairaWithdraw({
name="newAccount.accountNumber"
placeholder="Account No"
maxLength={10}
value={
props.values.newAccount?.accountNumber
}
value={props.values.newAccount?.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>
{/* Account Type */}
@@ -739,6 +732,12 @@ function NairaWithdraw({
</option>
)}
</select>
{/* {props.errors.accountType &&
props.touched.accountType && (
<p className="text-sm text-red-500">
{props.errors.accountType}
</p>
)} */}
</div>
</div>
@@ -749,8 +748,7 @@ function NairaWithdraw({
htmlFor="newAccount.state"
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4]"
>
State{" "}
<span className="text-red-500">*</span>
State <span className="text-red-500">*</span>
</label>
<InputCom
fieldClass="px-6 tracking-[1.5px]"
@@ -762,6 +760,11 @@ function NairaWithdraw({
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 */}
@@ -782,15 +785,20 @@ function NairaWithdraw({
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 for new accounts */}
</div>
</div>
) : (
:
<div className="mt-3 flex w-full h-[188px] justify-center items-center"></div>
))}
)}
</div>
<div className="transfer-fund-btn flex justify-end items-center gap-2 py-4">
+2 -38
View File
@@ -5,6 +5,7 @@ import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner";
const WalletBox = lazy(() => import("./WalletBox"));
const WalletRoutes = () => {
const apiCall = new usersService();
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
@@ -15,12 +16,6 @@ const WalletRoutes = () => {
data: [],
});
const [allCountries, setAllCountries] = useState({
// STATE TO HOLD LIST OF COUNTRIES
loading: true,
data: [],
});
const getPaymentHistory = () => {
apiCall
.getPaymentHx()
@@ -36,45 +31,14 @@ const WalletRoutes = () => {
});
};
// FUNCTION TO GET COUNTRIES
const getCountry = () => {
apiCall
.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: [] }));
});
};
useEffect(() => {
getCountry();
getPaymentHistory();
}, [walletTable]);
console.log(
"Testing all country: ",
allCountries,
"Testing wallet: ",
walletDetails
);
return (
<Layout>
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}>
<WalletBox
wallet={walletDetails}
payment={paymentHistory}
countries={allCountries.data}
/>
<WalletBox wallet={walletDetails} payment={paymentHistory} />
</Suspense>
</Layout>
);
+2 -2
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useCallback, useState } from "react";
import usersService from "../../services/UsersService";
import ConfirmNairaWithdraw from "./Popup/ConfirmNairaWithdraw";
import NairaWithdraw from "./Popup/NairaWithdraw";
@@ -8,7 +8,7 @@ function WalletAction({ walletItem, payment, openPopUp }) {
show: false,
state: {},
}); // DETERMINES WHEN NAIRA WITHDRAWAL POPS UP
const [showConfirmNairaWithdraw, setShowConfirmNairaWithdraw] = useState({
show: false,
state: {},
+2 -2
View File
@@ -4,7 +4,7 @@ import WalletItemCard from "./WalletItemCard";
/**
* Renders a list of wallet items or a loading spinner depending on the state of the `wallet` object.
*/
export default function WalletBox({ wallet, payment, countries }) {
export default function WalletBox({ wallet, payment }) {
const { loading, data } = wallet;
return (
@@ -18,7 +18,7 @@ export default function WalletBox({ wallet, payment, countries }) {
) : (
data.length > 0 && data.map((item) => (
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
<WalletItemCard walletItem={item} payment={payment} countries={countries} />
<WalletItemCard walletItem={item} payment={payment} />
</div>
))
)}
+2 -7
View File
@@ -10,7 +10,7 @@ import WalletAction from "./WalletAction";
/**
* Renders a card displaying information about a wallet item.
*/
export default function WalletItemCard({ walletItem, payment, countries }) {
export default function WalletItemCard({ walletItem, payment }) {
const { userDetails } = useSelector((state) => state.userDetails);
const accountType = userDetails?.account_type === "FAMILY";
const dispatch = useDispatch();
@@ -35,15 +35,10 @@ export default function WalletItemCard({ walletItem, payment, countries }) {
dispatch(tableReload({ type: "WALLETTABLE" }));
};
const currentWalletCurrency = countries
.map((country) => country)
.filter((country) => country[0] === walletItem.country);
const image = walletItem.code
? `${walletItem.code.toLowerCase()}.svg`
: "default.png";
return (
<>
<div
@@ -93,7 +88,7 @@ export default function WalletItemCard({ walletItem, payment, countries }) {
{!accountType && (
<WalletAction
walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
walletItem={walletItem}
payment={payment}
openPopUp={openPopUp}
/>
@@ -51,6 +51,7 @@ export default function PersonalInfoTab({
coverImgInput,
browseCoverImg,
coverImgChangHandler,
uploadStatus
}) {
let { userDetails } = useSelector((state) => state.userDetails);
@@ -361,7 +362,7 @@ export default function PersonalInfoTab({
{/* inputs ends here */}
</div>
</div>
{process.env.REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE != 0 &&
{/* {process.env.REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE != 0 && */}
<div className="w-[232px] mb-10">
<div className="update-profile w-full mb-9">
<h1 className="text-xl tracking-wide font-bold text-dark-gray dark:text-white flex items-center mb-2">
@@ -417,9 +418,11 @@ export default function PersonalInfoTab({
</div>
</div>
</div>
{uploadStatus.message && !uploadStatus.loading && <p className={`text-center ${uploadStatus.status ? 'text-green-500':'text-red-500'}`}>{uploadStatus.message}</p>}
{uploadStatus.loading && <p className="text-center">{uploadStatus.message}</p>}
</div>
</div>
}
{/* } */}
</div>
<div className="content-footer w-full">
+62 -4
View File
@@ -24,10 +24,12 @@ import {
import RecipientAccountTab from "./Tabs/RecipientAccountTab";
export default function Settings({ faq }) {
const apiCall = new usersService();
const { userDetails } = useSelector((state) => state?.userDetails);
const [profileImg, setProfileImg] = useState(
userDetails?.profile_pic_url ? userDetails.profile_pic_url : profile
);
let [uploadStatus, setUploadStatus] = useState({loading: false, status: false, message:''}) // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
const [coverImg, setCoverImg] = useState(cover);
const [reloadCardList, setReloadCardList] = useState(false); // STATE TO DETERMINE WHEN CARD LIST RELOADS. EG: WHEN USER DELETES A CARD
@@ -36,12 +38,68 @@ export default function Settings({ faq }) {
const browseProfileImg = () => {
profileImgInput.current.click();
};
const profileImgChangHandler = (e) => {
// if (e.target.value !== "") {
// const imgReader = new FileReader();
// imgReader.onload = (event) => {
// setProfileImg(event.target.result);
// };
// imgReader.readAsDataURL(e.target.files[0]);
// }
setUploadStatus({loading: false, status: false, message:''})
let acceptedFormat = ["jpeg", "jpg", "png", "bmp", "gif"] // ARRAY OF SUPPORTED FORMATS
let uploadedFile = e.target.files[0] //UPLOADED FILE
if(!acceptedFormat.includes(uploadedFile?.type?.split("/")[1]?.toLowerCase())){ //CHECKING FOR CORRECT UPLOAD FORMAT
let msg = 'Please select '
for(let i=0; i<=acceptedFormat.length-1; i++){
if(i == acceptedFormat.length-1){
msg+=`or ${acceptedFormat[i]}`
}else{
msg+=`${acceptedFormat[i]}, `
}
}
setUploadStatus({loading: false, status: false, message:msg})
return setTimeout(()=>{
profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
}
if(uploadedFile.size > 5*1048576){ // CHECKING FOR CORRECT FILE SIZE
setUploadStatus({loading: false, status: false, message:'File must not exceed 5MB'})
return setTimeout(()=>{
profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
}
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setProfileImg(event.target.result);
let reqData = { // PAYLOAD FOR API CALL
file_name: uploadedFile?.name,
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: event?.target?.result,
msg_type: 'FILE',
action: 'WRENCHBOARD_PICTURE_PROFILE',
// action: 11307
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
apiCall.sendFiles(reqData).then(res=>{
if(res.status != 200 || res.data.internal_return < 0){
return setUploadStatus({loading: false, status: false, message: 'Something went wrong, try again'})
}
setUploadStatus({loading: false, status: true, message: 'Uploaded successfully'})
setProfileImg(event.target.result);
}).catch(error=>{
setUploadStatus({loading: false, status: false, message: 'Network error, try again'})
}).finally(()=>{
setTimeout(()=>{
setUploadStatus({loading: false, status: false, message: ''})
},5000)
})
};
imgReader.readAsDataURL(e.target.files[0]);
}
@@ -61,7 +119,6 @@ export default function Settings({ faq }) {
}
};
const apiCall = useMemo(() => new usersService(), []);
// Tabs Handling
const tabs = [
{
@@ -113,7 +170,7 @@ export default function Settings({ faq }) {
iconName: "page-right",
},
{
id: 8,
id: 9,
name: "terms",
title: "Terms and Conditions",
iconName: "page-right",
@@ -217,6 +274,7 @@ export default function Settings({ faq }) {
coverImgChangHandler={coverImgChangHandler}
browseCoverImg={browseCoverImg}
coverImgInput={coverImgInput}
uploadStatus={uploadStatus}
/>
</div>
)}