Compare commits

...

35 Commits

Author SHA1 Message Date
victorAnumudu 9b6c5b72ad changed cancel btn style 2023-10-22 05:52:47 +01:00
ameye afc5e25cfc Merge branch 'login-captcha' of WrenchBoard/Users-Wrench into master 2023-10-17 17:40:06 +00:00
victorAnumudu 58fe5eb82c captcha added in login page 2023-10-17 18:26:46 +01:00
CHIEFSOFT\ameye 2f3fdc0695 google captach settings 2023-10-17 07:01:05 -04:00
ameye 0a465fceb0 Merge branch 'btn-height-adjustment' of WrenchBoard/Users-Wrench into master 2023-10-16 20:26:23 +00:00
victorAnumudu 5e968db2f5 adjusted btn height 2023-10-16 21:08:06 +01:00
ameye 1916bc1a65 Merge branch 'btn-rename' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:55 +00:00
ameye 1103127cae Merge branch 'btn-customized' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:47 +00:00
ameye 751369071c Merge branch 'family-task-reload' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:39 +00:00
ameye 4cc8f27c14 Merge branch 'profile-upload-revert' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:07 +00:00
ameye aab455c2c3 Merge branch 'Changed-Naira-Wallet-Country-Display' of WrenchBoard/Users-Wrench into master 2023-10-16 13:52:03 +00:00
Ebube 21843c4bc7 Changed Naira Wallet Country Display 2023-10-16 13:43:48 +01:00
Ebube 8702728ffa Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into Recent-Activities 2023-10-16 13:12:24 +01:00
victorAnumudu 79dcd0f2b5 btn style customized 2023-10-16 11:49:03 +01:00
ameye 47b25f3dfe Merge branch 'google-recaptcha' of WrenchBoard/Users-Wrench into master 2023-10-16 00:30:06 +00:00
victorAnumudu 89925a6af9 added google recaptcha 2023-10-16 01:18:48 +01:00
CHIEFSOFT\ameye 3c0f951b6e Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench 2023-10-15 19:32:29 -04:00
CHIEFSOFT\ameye ffbfb1da35 added "react-google-recaptcha": "^3.1.0" 2023-10-15 19:32:22 -04:00
victorAnumudu a8416a8433 made family page to reload after adding a task 2023-10-10 10:17:22 +01:00
victorAnumudu 70c9d1778c renamed edit job btn to save 2023-10-10 07:02:52 +01:00
Ebube 930559c96b Family Picture 2023-10-09 13:32:07 +01:00
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
ameye ab191b6a72 Merge branch 'upload-profile' of WrenchBoard/Users-Wrench into master 2023-10-08 12:02:52 +00:00
victorAnumudu d130687cf9 made upload profile to show from env 2023-10-08 08:58:37 +01:00
ameye 5e9a442eac Merge branch 'online-name' of WrenchBoard/Users-Wrench into master 2023-10-07 18:38:23 +00:00
victorAnumudu 1093c25207 added online name 2023-10-07 18:28:30 +01:00
ameye 0623227807 Merge branch 'Recent-Activities' of WrenchBoard/Users-Wrench into master 2023-10-02 13:07:50 +00:00
Ebube 3a05790125 fixed table responsive issue 2023-10-02 12:26:18 +01:00
Ebube 85b0456011 Added price to review due task 2023-09-30 07:18:23 +01:00
ameye 6ddd16ee24 Merge branch 'Recent-Activities' of WrenchBoard/Users-Wrench into master 2023-09-27 23:54:04 +00:00
Ebube d034f9be45 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into Recent-Activities 2023-09-27 17:33:22 +01:00
Ebube 2f3940f99c fixed responsiveness issues for the layout 2023-09-27 17:31:31 +01:00
ameye 5e998e5e42 Merge branch 'btn-name' of WrenchBoard/Users-Wrench into master 2023-09-27 13:48:05 +00:00
Ebube 42a3df2d65 Fixed assign popup data display delay 2023-09-27 13:33:12 +01:00
31 changed files with 1168 additions and 834 deletions
+7
View File
@@ -85,3 +85,10 @@ REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
REACT_APP_MAX_FAMILY_MEMBERS=8 REACT_APP_MAX_FAMILY_MEMBERS=8
REACT_APP_SHOW_OFFER_GROUP_JOB=0 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=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
+7
View File
@@ -53,3 +53,10 @@ REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
REACT_APP_MAX_FAMILY_MEMBERS=8 REACT_APP_MAX_FAMILY_MEMBERS=8
REACT_APP_SHOW_OFFER_GROUP_JOB=0 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=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
+7
View File
@@ -59,3 +59,10 @@ REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
REACT_APP_MAX_FAMILY_MEMBERS=8 REACT_APP_MAX_FAMILY_MEMBERS=8
REACT_APP_SHOW_OFFER_GROUP_JOB=0 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=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
+1
View File
@@ -21,6 +21,7 @@
"react-chartjs-2": "^4.1.0", "react-chartjs-2": "^4.1.0",
"react-countup": "^6.2.0", "react-countup": "^6.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-qr-code": "^2.0.11", "react-qr-code": "^2.0.11",
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"react-router-dom": "^6.0.2", "react-router-dom": "^6.0.2",
@@ -24,7 +24,7 @@ const ForgetPwdResponse = ({title, message, type}) => {
<button <button
type="button" type="button"
onClick={() => navigate("/login")} onClick={() => navigate("/login")}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`} className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
> >
<span>Home</span> <span>Home</span>
</button> </button>
@@ -7,6 +7,8 @@ import AuthLayout from "../AuthLayout";
import EmailValidator from "../../../lib/EmailValidator"; import EmailValidator from "../../../lib/EmailValidator";
import ForgetPwdResponse from "../ForgetPwdResponse"; import ForgetPwdResponse from "../ForgetPwdResponse";
import ReCAPTCHA from "react-google-recaptcha";
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);
@@ -22,9 +24,18 @@ export default function ForgotPassword() {
setMail(e?.target.value); setMail(e?.target.value);
}; };
const humanChecker = () => { // const humanChecker = () => {
setValue(!checked); // setValue(!checked);
}; // };
function humanChecker(value) {
// console.log("Captcha value:", value);
if(value){
setValue(true)
}else{
setValue(false)
}
}
const resetHandler = async () => { const resetHandler = async () => {
if (email == "") { if (email == "") {
@@ -113,10 +124,16 @@ export default function ForgotPassword() {
/> />
</div> </div>
{/* hCaptha clone for the time being */} {/* hCaptha clone for the time being */}
<div className="mb-10"> <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="w-[303px] h-[78px] mx-auto overflow-hidden"> <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"> <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="h-full relative inline-block">
<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">
@@ -148,18 +165,25 @@ export default function ForgotPassword() {
<div className="h-full relative inline-block w-16"></div> <div className="h-full relative inline-block w-16"></div>
</div> </div>
</div> </div>
</div> </div> */}
{msgError && ( {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]"> <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} {msgError}
</div> </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-4">
<button
type="button"
onClick={() => navigate("/login")}
className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white hover:text-white flex justify-center bg-red-500 hover:bg-red-600 transition-all duration-300 items-center py-[0.8875rem] px-[1.8125rem] `}
>
Cancel
</button>
<button <button
type="button" type="button"
onClick={resetHandler} onClick={resetHandler}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`} className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
> >
{resetLoading ? ( {resetLoading ? (
<div className="signup btn-loader"></div> <div className="signup btn-loader"></div>
@@ -167,13 +191,6 @@ export default function ForgotPassword() {
<span>Send Code</span> <span>Send Code</span>
)} )}
</button> </button>
<button
type="button"
onClick={() => navigate("/login")}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-[#009ef7] hover:text-white flex justify-center bg-[#f1faff] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.8125rem] `}
>
Cancel
</button>
</div> </div>
</div> </div>
</div> </div>
+35 -2
View File
@@ -14,10 +14,14 @@ import { useGoogleLogin } from "@react-oauth/google";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { updateUserDetails } from "../../../store/UserDetails"; import { updateUserDetails } from "../../../store/UserDetails";
import ReCAPTCHA from "react-google-recaptcha";
export default function Login() { export default function Login() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { state } = useLocation(); const { state } = useLocation();
const [validCaptcha, setValidCaptcha] = useState({show: false, valid:''}); // FOR CAPTCHA
let [loginType, setLoginType] = useState(""); let [loginType, setLoginType] = useState("");
const [loginLoading, setLoginLoading] = useState(false); const [loginLoading, setLoginLoading] = useState(false);
@@ -107,6 +111,14 @@ export default function Login() {
}, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT)); }, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT));
return; return;
} }
if(name == "full" && !validCaptcha.valid && validCaptcha.show){ // RUNS AND DISPLAYS CAPTCHA, IF ERROR OCCURED DURING LOGIN FOR FULL LOGIN ALONE
setMsgError("Please Verify Captcha");
setLoginLoading(false);
setTimeout(() => {
setMsgError("");
}, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT));
return;
}
userApi userApi
.logInUser(postData) .logInUser(postData)
.then((res) => { .then((res) => {
@@ -120,6 +132,7 @@ export default function Login() {
// setMsgError("Wrong, email/password"); // setMsgError("Wrong, email/password");
setLoginError(true); setLoginError(true);
setLoginLoading(false); setLoginLoading(false);
setValidCaptcha(prev => ({...prev, show:true})) // DISPLAYS CAPTCHA IF ERROR
return; return;
} }
localStorage.setItem("member_id", `${res.data.member_id}`); localStorage.setItem("member_id", `${res.data.member_id}`);
@@ -135,6 +148,7 @@ export default function Login() {
.catch((error) => { .catch((error) => {
setMsgError("Unable to login, try again"); setMsgError("Unable to login, try again");
setLoginLoading(false); setLoginLoading(false);
setValidCaptcha(prev => ({...prev, show:true})) // DISPLAYS CAPTCHA IF ERROR
}) })
.finally(() => { .finally(() => {
setTimeout(() => { setTimeout(() => {
@@ -145,6 +159,14 @@ export default function Login() {
}); });
}; };
function captchaChecker(value) { // FUNCTION TO VALIDATE CAPTCHA
if(value){
setValidCaptcha({show: true, valid:value})
}else{
setValidCaptcha({show: true, valid:''})
}
}
const googleLogin = useGoogleLogin({ const googleLogin = useGoogleLogin({
flow: "auth-code", flow: "auth-code",
ux_mode: "redirect", ux_mode: "redirect",
@@ -296,6 +318,17 @@ export default function Login() {
forgotPassword forgotPassword
/> />
</div> </div>
{/* hCaptha clone for the time being */}
{validCaptcha.show &&
<div className="mb-5 flex justify-center w-full">
<ReCAPTCHA
sitekey={process.env.REACT_APP_GOOGLE_RECAPTCHA_SITEKEY}
onChange={captchaChecker}
/>
</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{" "}
@@ -320,7 +353,7 @@ export default function Login() {
onClick={doLogin} onClick={doLogin}
type="button" type="button"
disabled={loginLoading} disabled={loginLoading}
className={`btn-login rounded-[0.475rem] mb-6 text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`} className={`btn-login rounded-full mb-6 text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
> >
{loginLoading ? ( {loginLoading ? (
<div className="signup btn-loader"></div> <div className="signup btn-loader"></div>
@@ -433,7 +466,7 @@ export default function Login() {
onClick={doLogin} onClick={doLogin}
disabled={loginLoading} disabled={loginLoading}
type="button" type="button"
className={`btn-login rounded-[0.475rem] text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`} className={`btn-login rounded-full text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
> >
{loginLoading ? ( {loginLoading ? (
<div className="signup btn-loader"></div> <div className="signup btn-loader"></div>
+1 -1
View File
@@ -325,7 +325,7 @@ export default function SignUp() {
disabled={countries.loading} disabled={countries.loading}
type="button" type="button"
onClick={handleSignUp} onClick={handleSignUp}
className={`rounded-[0.475rem] mb-6 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`} className={`rounded-full mb-6 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`}
> >
{signUpLoading ? ( {signUpLoading ? (
<div className="signup btn-loader"></div> <div className="signup btn-loader"></div>
+166 -78
View File
@@ -1,15 +1,13 @@
import React, { import React, {
Suspense, Suspense,
lazy, lazy,
useCallback,
useEffect, useEffect,
useMemo, useMemo,
useRef, useRef,
useState, useState,
useTransition,
} from "react"; } from "react";
import { useReactToPrint } from "react-to-print"; import { useReactToPrint } from "react-to-print";
import profile from "../../assets/images/profile-info-profile.png"; import profile from "../../assets/images/icons/family.svg";
import localImgLoad from "../../lib/localImgLoad"; import localImgLoad from "../../lib/localImgLoad";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
@@ -29,113 +27,113 @@ export default function FamilyManageTabs({
listReload, listReload,
loader, loader,
}) { }) {
// Initial state for family details
const initialDetailState = {
loading: false,
data: null,
};
// State for family details, tasks, waitlist, and pending
const [details, setDetails] = useState({ const [details, setDetails] = useState({
familyDetails: { loading: false, data: null }, familyDetails: { ...initialDetailState },
familyTasks: { loading: false, data: null }, familyTasks: { ...initialDetailState },
familyWaitList: { loading: false, data: null }, familyWaitList: { ...initialDetailState },
familyPending: { loading: false, data: null }, familyPending: { ...initialDetailState },
}); });
// Function to reset family details, tasks, waitlist, and pending
const resetDetails = () => {
setDetails({
familyDetails: { ...initialDetailState },
familyTasks: { ...initialDetailState },
familyWaitList: { ...initialDetailState },
familyPending: { ...initialDetailState },
});
};
const [updatePage, setUpdatePage] = useState(false) // State to determine when to update the page
// State for family task data
const [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
// State for active task
const [activeTask, setActiveTask] = useState({ id: 0, data: {} });
// State for error messages
const [errMsg, setErrMsg] = useState(""); const [errMsg, setErrMsg] = useState("");
// State for family task popout
const [familyTaskPopout, setFamilyTaskPopout] = useState(false); const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
// State for profile image
const [profileImg, setProfileImg] = useState(profile); const [profileImg, setProfileImg] = useState(profile);
// Ref for profile image input
const profileImgInput = useRef(null); const profileImgInput = useRef(null);
const [isPending, startTransition] = useTransition();
// Create an instance of the usersService class
const apiCall = useMemo(() => new usersService(), []); const apiCall = useMemo(() => new usersService(), []);
// Function to handle toggling the family task popout
const familyPopUpHandler = () => { const familyPopUpHandler = () => {
setFamilyTaskPopout((prev) => !prev); setFamilyTaskPopout((prev) => !prev);
}; };
// Function to trigger a click on the hidden profile image input
const browseProfileImg = () => { const browseProfileImg = () => {
profileImgInput.current.click(); 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.
*/
const profileImgChangeHandler = (e) => { const profileImgChangeHandler = (e) => {
if (e.target.value !== "") { const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const imgReader = new FileReader();
imgReader.onload = (event) => {
setProfileImg(event.target.result);
};
imgReader.readAsDataURL(e.target.files[0]);
}
};
const manageFamily = useCallback(async () => { const file = e.target.files[0];
try { if (file && file.size > MAX_FILE_SIZE) {
setDetails((prevDetails) => ({ alert("File size exceeds the limit.");
...prevDetails,
familyDetails: { loading: true },
familyTasks: { loading: true },
familyWaitList: { loading: true },
familyPending: { loading: true },
}));
const { family_uid } = accountDetails;
const reqData = { family_uid };
const [familyRes, tasksRes, familyWaitRes, familyPending] =
await Promise.all([
apiCall.ManageFamily(reqData),
apiCall.ManageTasks(reqData),
apiCall.ManageFamilyWaitlist(),
apiCall.ManageFamilyPending(),
]);
const familyData = familyRes.data;
const tasksData = tasksRes.data;
const familyWaitData = familyWaitRes.data;
const familyPendingData = familyPending.data;
if (
familyData?.internal_return < 0 ||
tasksData?.internal_return < 0 ||
familyWaitData?.internal_return < 0 ||
familyPendingData?.internal_return < 0
) {
return; return;
} }
startTransition(() => { if (file) {
setDetails({ const imgReader = new FileReader();
familyDetails: { loading: false, data: familyData }, imgReader.onload = () => {
familyTasks: { loading: false, data: tasksData }, const imageDataUrl = imgReader.result;
familyWaitList: { loading: false, data: familyWaitData },
familyPending: { loading: false, data: familyPendingData },
});
});
} catch (error) {
setDetails((prevDetails) => ({
...prevDetails,
familyDetails: { loading: false },
familyTasks: { loading: false },
familyWaitList: { loading: false },
familyPending: { loading: false },
}));
setErrMsg("An error occurred");
throw new Error(error);
}
}, [apiCall, accountDetails]);
// Set the profile image
setProfileImg(imageDataUrl);
};
imgReader.readAsDataURL(file);
}
};
// Ref for the account section
const accountRef = useRef(); const accountRef = useRef();
// React-to-Print hook for handling printing
const useHandlePrint = useReactToPrint({ const useHandlePrint = useReactToPrint({
content: () => accountRef.current, content: () => accountRef.current,
}); });
// Array of tab names
const tabs = [ const tabs = [
{ id: 1, name: "Tasks" }, { id: 1, name: "Tasks" },
{ id: 2, name: "Waiting" }, { id: 2, name: "Waiting" },
{ id: 3, name: "Pending" }, { id: 3, name: "Pending" },
]; ];
// State for the currently selected tab
const [tab, setTab] = useState(tabs[0].name); const [tab, setTab] = useState(tabs[0].name);
// Function to handle tab changes
const tabHandler = (value) => { const tabHandler = (value) => {
startTransition(() => {
setTab(value); setTab(value);
});
}; };
// Object that maps tab names to their corresponding components
const tabComponents = { const tabComponents = {
Tasks: ( Tasks: (
<FamilyTasks <FamilyTasks
@@ -156,7 +154,7 @@ export default function FamilyManageTabs({
<FamilyPending <FamilyPending
familyData={details.familyPending.data} familyData={details.familyPending.data}
accountDetails={accountDetails} accountDetails={accountDetails}
loader={details.familyWaitList.loading} loader={details.familyPending.loading}
/> />
), ),
Account: ( Account: (
@@ -170,6 +168,7 @@ export default function FamilyManageTabs({
Profile: <FamilyProfile />, Profile: <FamilyProfile />,
}; };
// Default tab component
const defaultTabComponent = ( const defaultTabComponent = (
<FamilyTasks <FamilyTasks
className={className} className={className}
@@ -179,17 +178,101 @@ export default function FamilyManageTabs({
/> />
); );
// Selected tab component based on the current 'tab'
const selectedTabComponent = tabComponents[tab] || defaultTabComponent; const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
// Effect to manage family details and related data
useEffect(() => { useEffect(() => {
let __manageFamily = true; const manageFamily = async () => {
if (__manageFamily) { try {
manageFamily(); resetDetails();
setDetails({
familyDetails: { loading: true },
familyTasks: { loading: true },
familyWaitList: { loading: true },
familyPending: { loading: true },
});
const { family_uid } = accountDetails;
const reqData = { family_uid };
const [familyRes, tasksRes, familyWaitRes, familyPending] =
await Promise.all([
apiCall.ManageFamily(reqData),
apiCall.ManageTasks(reqData),
apiCall.ManageFamilyWaitlist(),
apiCall.ManageFamilyPending(),
]);
const familyData = familyRes.data;
const tasksData = tasksRes.data;
const familyWaitData = familyWaitRes.data;
const familyPendingData = familyPending.data;
// Function to check for errors in data
const checkDataError = (data) => data?.internal_return < 0;
if (
checkDataError(familyData) ||
checkDataError(tasksData) ||
checkDataError(familyWaitData) ||
checkDataError(familyPendingData)
) {
return;
}
setDetails({
familyDetails: { loading: false, data: familyData },
familyTasks: { loading: false, data: tasksData },
familyWaitList: { loading: false, data: familyWaitData },
familyPending: { loading: false, data: familyPendingData },
});
} catch (error) {
resetDetails();
setErrMsg("An error occurred");
throw new Error(error);
} }
return () => {
__manageFamily = false;
}; };
}, [tab, manageFamily]);
// Invoke the manageFamily function when the component mounts
manageFamily();
}, [updatePage]);
// Effect to manage family tasks
useEffect(() => {
let checkFamilyTask = true;
const reqData = {
limit: 30,
offset: 0,
job_type: "FAMILY",
action: 13005,
};
if (checkFamilyTask) {
setFamilyTask({ loading: true });
apiCall
.getMyJobList(reqData)
.then((res) => {
setFamilyTask({ loading: false, data: res?.data?.result_list });
if (res?.data?.result_list?.length) {
setActiveTask((prev) => ({
...prev,
data: res?.data?.result_list[0],
}));
}
})
.catch((err) => {
setFamilyTask({ loading: false, data: [] });
console.log("Error", err);
});
}
// Cleanup function to prevent memory leaks
return () => {
checkFamilyTask = false;
};
}, []);
return ( return (
<div <div
@@ -285,7 +368,12 @@ export default function FamilyManageTabs({
<AssignTaskPopout <AssignTaskPopout
action={familyPopUpHandler} action={familyPopUpHandler}
situation={familyTaskPopout} situation={familyTaskPopout}
familyDetails={details.familyDetails.data} familyTask={familyTask}
setFamilyTask={setFamilyTask}
setActiveTask={setActiveTask}
activeTask={activeTask}
familyDetailsData={details.familyDetails.data}
setUpdatePage={setUpdatePage}
/> />
)} )}
</div> </div>
@@ -1,12 +1,22 @@
import React, { useState, useEffect, useTransition } from "react"; import React, { useState } from "react";
import ModalCom from "../../Helpers/ModalCom";
import Detail from "../../jobPopout/popoutcomponent/Detail";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; import ModalCom from "../../Helpers/ModalCom";
import { PriceFormatter } from "../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../Helpers/PriceFormatter";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
import Detail from "../../jobPopout/popoutcomponent/Detail";
import { NewTasks } from "./forms"; import { NewTasks } from "./forms";
const AssignTaskPopout = React.memo(({ action, details, situation, familyDetails }) => { const AssignTaskPopout = React.memo(
({
action,
details,
situation,
familyDetailsData,
familyTask,
activeTask,
setActiveTask,
setUpdatePage
}) => {
const apiCall = new usersService(); const apiCall = new usersService();
let [requestStatus, setRequestStatus] = useState({ let [requestStatus, setRequestStatus] = useState({
@@ -15,12 +25,8 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
message: "", message: "",
}); // HOLDS RESPONSE FOR SENDING API REQUEST }); // HOLDS RESPONSE FOR SENDING API REQUEST
let [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK
let [activeTask, setActiveTask] = useState({ id: 0, data: {} }); // HOLDS SELECTED TASK
const switchTaskType = ({ target: { value } }) => { const switchTaskType = ({ target: { value } }) => {
// FUNCTION TO CHANGE SELECTED ACTIVE TASK // FUNCTION TO CHANGE SELECTED ACTIVE TASK
setTaskType(value); setTaskType(value);
@@ -63,7 +69,7 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
// API PAYLOADS // API PAYLOADS
job_id: activeTask.data?.job_id, job_id: activeTask.data?.job_id,
job_uid: activeTask.data?.job_uid, job_uid: activeTask.data?.job_uid,
family_uid: familyDetails?.uid || details?.family_uid, family_uid: familyDetailsData?.uid || details?.family_uid,
job_description: activeTask.data?.description, job_description: activeTask.data?.description,
assign_mode: 110011, assign_mode: 110011,
}; };
@@ -116,7 +122,7 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
timeline_days, timeline_days,
title, title,
assign_mode: 110055, assign_mode: 110055,
family_uid: details?.family_uid || familyDetails?.uid, family_uid: details?.family_uid || familyDetailsData?.uid,
}; };
} }
@@ -138,6 +144,7 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
status: true, status: true,
message: "action successful", message: "action successful",
}); });
setUpdatePage(prev => !prev) // Updates family task page by calling the useeffect hook
setTimeout(() => { setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" }); setRequestStatus({ loading: false, status: false, message: "" });
action(); // FUNCTION THAT CLOSES THE MODAL BOX action(); // FUNCTION THAT CLOSES THE MODAL BOX
@@ -155,38 +162,6 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
}); });
}; };
useEffect(() => {
let checkFamilyTask = true;
const reqData = {
limit: 30,
offset: 0,
job_type: "FAMILY",
action: 13005,
};
apiCall
.getMyJobList(reqData)
.then((res) => {
if (checkFamilyTask) {
setFamilyTask({ loading: false, data: res?.data?.result_list });
if (res?.data?.result_list?.length) {
setActiveTask((prev) => ({
...prev,
data: res?.data?.result_list[0],
}));
}
}
})
.catch((err) => {
setFamilyTask({ loading: false, data: [] });
console.log("Error", err);
});
return () => {
checkFamilyTask = false;
};
}, []);
return ( return (
<> <>
<ModalCom <ModalCom
@@ -197,7 +172,8 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
<div className="w-full h-full lg:w-[700px] lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="w-full h-full lg:w-[700px] lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple"> <div className="w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
Assign task to {familyDetails?.firstname || details?.firstName} Assign task to{" "}
{familyDetailsData?.firstname || details?.firstName}
</h1> </h1>
<button <button
type="button" type="button"
@@ -269,7 +245,9 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
<div <div
key={item.job_uid} key={item.job_uid}
className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer" className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer"
onClick={() => handleActiveTask(item.job_uid, item)} onClick={() =>
handleActiveTask(item.job_uid, item)
}
> >
<input <input
type="radio" type="radio"
@@ -423,7 +401,7 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer" className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
> >
{`Assign to ${ {`Assign to ${
familyDetails?.firstname || details?.firstName familyDetailsData?.firstname || details?.firstName
}`} }`}
</button> </button>
)} )}
@@ -436,6 +414,7 @@ const AssignTaskPopout = React.memo(({ action, details, situation, familyDetail
</ModalCom> </ModalCom>
</> </>
); );
}) }
);
export default AssignTaskPopout; export default AssignTaskPopout;
@@ -90,7 +90,7 @@ export default function FamilyTasks({
<h1 className="font-bold text-xl text-dark-gray dark:text-white"> <h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.title} {value.title}
</h1> </h1>
<div className="flex gap-4 items-center"> <div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
<span className="text-sm text-thin-light-gray flex flex-start gap-1"> <span className="text-sm text-thin-light-gray flex flex-start gap-1">
Price:{" "} Price:{" "}
<span className="text-purple"> <span className="text-purple">
+10 -5
View File
@@ -1,26 +1,31 @@
import React from "react"; import React from "react";
import localImgLoad from "../../../lib/localImgLoad"; import localImgLoad from "../../../lib/localImgLoad";
export default function ProfileInfo({ export default function ProfileInfo({
profileImg, profileImg,
profileImgInput, profileImgInput,
profileImgChangHandler, profileImgChangeHandler,
browseProfileImg, browseProfileImg,
accountDetails, accountDetails,
}) { }) {
// console.log(accountDetails.banner)
return ( return (
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<div className="flex justify-center"> <div className="flex justify-center">
<div className="w-full relative"> <div className="w-full relative">
<img <img
src={localImgLoad(`images/icons/${accountDetails.banner}`)} src={
alt="" profileImg
? profileImg
: localImgLoad(`images/icons/${accountDetails.banner}`)
}
alt="profile"
className="sm:w-[180px] sm:h-[180px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover" className="sm:w-[180px] sm:h-[180px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover"
/> />
<input <input
ref={profileImgInput} ref={profileImgInput}
onChange={(e) => profileImgChangHandler(e)} accept="image/*"
onChange={profileImgChangeHandler}
type="file" type="file"
className="hidden" className="hidden"
/> />
+16 -41
View File
@@ -1,24 +1,17 @@
import React from "react";
import datas from "../../data/product_data.json";
import Hero from "./Hero";
// import HomeTaskDisplay from "./HomeTaskDisplay";
import usersService from "../../services/UsersService";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
// import SellHistoryMarketVisitorAnalytic from './SellHistoryMarketVisitorAnalytic';
// import TopSellerTopBuyerSliderSection from "./TopSellerTopBuyerSliderSection";
//import UpdateTable from "./UpdateTable";
import HomeActivities from "./HomeActivities";
import MyOffersTable from "../MyTasks/MyOffersTable";
import MyJobTable from "../MyTasks/MyJobTable"; import MyJobTable from "../MyTasks/MyJobTable";
import MyOffersTable from "../MyTasks/MyOffersTable";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import Hero from "./Hero";
import HomeActivities from "./HomeActivities";
export default function FullAccountDash(props) { export default function FullAccountDash(props) {
console.log("PROPS IN HOME->", props); // console.log("PROPS IN HOME->", props);
const { userDetails } = useSelector((state) => state?.userDetails); const { userDetails } = useSelector((state) => state?.userDetails);
return ( return (
<div> <>
<div className="home-page-wrapper"> <div className="home-page-wrapper">
<Hero <Hero
className="mb-10" className="mb-10"
@@ -26,30 +19,30 @@ export default function FullAccountDash(props) {
bannerList={props.bannerList} bannerList={props.bannerList}
nextDueTask={props.nextDueTask} nextDueTask={props.nextDueTask}
/> />
{ props.offersList?.data?.result_list?.length ? {props.offersList?.data?.result_list?.length ? (
<MyOffersTable <MyOffersTable
MyActiveOffersList={props.offersList?.data} MyActiveOffersList={props.offersList?.data}
className="mb-10" className="mb-10"
/> />
: props.MyActiveJobList?.data?.length ? ) : props.MyActiveJobList?.data?.length ? (
<> <>
<div className="w-full mb-5 flex justify-between items-center gap-1"> <div className="w-full mb-5 flex justify-between items-center gap-1">
<h1 className="text-26 font-bold text-dark-gray dark:text-white"> <h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span> <span>My Tasks</span>
My Tasks
</span>
</h1> </h1>
</div> </div>
<MyJobTable ActiveJobList={props.MyActiveJobList} Account={userDetails} /> <MyJobTable
ActiveJobList={props.MyActiveJobList}
Account={userDetails}
/>
</> </>
) : !props.offersList?.loading && !props.MyActiveJobList?.loading ? (
: !props.offersList?.loading && !props.MyActiveJobList?.loading?
<HomeActivities className="mb-10" /> <HomeActivities className="mb-10" />
: ) : (
<div className="w-full h-[220px] flex items-center justify-center"> <div className="w-full h-[220px] flex items-center justify-center">
<LoadingSpinner size="16" color="sky-blue" /> <LoadingSpinner size="16" color="sky-blue" />
</div> </div>
} )}
{/*<UpdateTable className="mb-10"/>*/} {/*<UpdateTable className="mb-10"/>*/}
{/*<SellHistoryMarketVisitorAnalytic className="mb-10"/>*/} {/*<SellHistoryMarketVisitorAnalytic className="mb-10"/>*/}
@@ -61,24 +54,6 @@ export default function FullAccountDash(props) {
{/* bannerList={props.bannerList}*/} {/* bannerList={props.bannerList}*/}
{/*/>*/} {/*/>*/}
</div> </div>
</div> </>
); );
} }
// /*
// <Layout>
// <div className="home-page-wrapper">
// <Hero className="mb-10" data={userDetails} />
// {/* <CreateNft />
// <TrendingSection trending={trending} className="mb-10" />*/}
// <HomeTaskDisplay
// jobData={jobData}
// className="mb-10"
// bannerList={props.bannerList}
// />
{
/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
<TopSellerTopBuyerSliderSection className="mb-10" />
<UpdateTable className="mb-10"/>*/
}
// </div>
// </Layout>
@@ -225,7 +225,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
</div> </div>
</div> </div>
<div className="w-full md:w-[23%] h-full "> <div className="w-full md:w-[23%] h-full flex flex-col">
<div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] p-4 rounded-md md:min-h-[498px] flex flex-col justify-between"> <div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] p-4 rounded-md md:min-h-[498px] flex flex-col justify-between">
<div className="w-full flex flex-col justify-center py-4 gap-2"> <div className="w-full flex flex-col justify-center py-4 gap-2">
<p className="w-full text-slate-900 tracking-wide my-1"> <p className="w-full text-slate-900 tracking-wide my-1">
@@ -270,7 +270,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
</div> </div>
</div> </div>
<button <button
className="self-end w-[150px] mt-2 h-[52px] rounded-md text-base bg-transparent border border-red-500 text-red-500 mx-auto" className="self-center w-[150px] mt-2 h-[48px] rounded-full text-base bg-transparent border border-red-500 text-red-500 mx-auto"
name="cancel" name="cancel"
onClick={onClose} onClick={onClose}
> >
+23 -10
View File
@@ -10,24 +10,25 @@ import ActiveJobMessage from "./ActiveJobMessage";
import IndexJobActions from "./JobActions/IndexJobActions"; import IndexJobActions from "./JobActions/IndexJobActions";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import { PriceFormatter } from "../Helpers/PriceFormatter";
function ActiveJobs(props) { function ActiveJobs(props) {
const ApiCall = new usersService(); const ApiCall = new usersService();
let navigate = useNavigate(); const navigate = useNavigate();
let { userDetails } = useSelector((state) => state.userDetails); const { userDetails } = useSelector((state) => state.userDetails);
let [passDue, setPassDue] = useState( const [passDue, setPassDue] = useState(
new Date() > new Date(props.details?.delivery_date) new Date() > new Date(props.details?.delivery_date)
); // STATE TO KNOW IF TASK IS PASSED DUE TIME ); // STATE TO KNOW IF TASK IS PASSED DUE TIME
let [messageToSend, setMessageToSend] = useState(""); // State to hold the value of message to be sent const [messageToSend, setMessageToSend] = useState(""); // State to hold the value of message to be sent
let [filesToSend, setFilesToSend] = useState([]); // State to hold the value of files to be sent const [filesToSend, setFilesToSend] = useState([]); // State to hold the value of files to be sent
let [tab, setTab] = useState("message"); const [tab, setTab] = useState("message");
let [requestStatus, setRequestStatus] = useState({ const [requestStatus, setRequestStatus] = useState({
loading: false, loading: false,
status: false, status: false,
message: "", message: "",
@@ -248,7 +249,11 @@ function ActiveJobs(props) {
} }
}, [passDue]); }, [passDue]);
console.log("AC JOBS >>", props); let thePrice = PriceFormatter(
props.details?.price * 0.01,
props.details?.currency_code,
props.details?.currency
);
return ( return (
<Layout> <Layout>
@@ -311,10 +316,11 @@ function ActiveJobs(props) {
<span className="font-semibold">Due: </span> <span className="font-semibold">Due: </span>
{props?.details && props.details.delivery_date.split(" ")[0]} {props?.details && props.details.delivery_date.split(" ")[0]}
</p> </p>
{props?.delivery_date && (
<p className="py-2 text-base text-slate-700"> <p className="py-2 text-base text-slate-700">
{props?.delivery_date && {props.details.delivery_date.split(" ")[1]}
props.details.delivery_date.split(" ")[1]}
</p> </p>
)}
</div> </div>
) : ( ) : (
<div className="my-1 flex items-start gap-3"> <div className="my-1 flex items-start gap-3">
@@ -334,6 +340,13 @@ function ActiveJobs(props) {
</div> </div>
)} )}
<div className="my-1 text-base text-slate-700 tracking-wide flex items-center gap-3">
<span className="font-semibold text-black dark:text-white">
Price:{" "}
</span>
<span className="">{thePrice}</span>
</div>
<div className="my-1 text-base text-slate-700 tracking-wide flex items-center gap-3"> <div className="my-1 text-base text-slate-700 tracking-wide flex items-center gap-3">
<span className="font-semibold text-black dark:text-white"> <span className="font-semibold text-black dark:text-white">
Duration:{" "} Duration:{" "}
@@ -118,7 +118,11 @@ function PastDueJobAction({jobDetails}) {
<tr> <tr>
<td> <td>
<div className="flex justify-center items-center"> <div className="flex justify-center items-center">
<button type="button" onClick={popUpHandler} className="w-[180px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"> <button
type="button"
onClick={popUpHandler}
className="px-4 h-[48px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
Cancel or Extend Timeline Cancel or Extend Timeline
</button> </button>
</div> </div>
@@ -230,8 +234,12 @@ function PastDueJobAction({jobDetails}) {
{/* cancel btn */} {/* cancel btn */}
<div className='flex justify-end items-center'> <div className='flex justify-end items-center'>
<button onClick={popUpHandler} type="button" className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white"> <button onClick={popUpHandler} type="button"
<span className='text-gradient'>Cancel</span> // className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white"
className='w-[150px] mt-2 h-[48px] rounded-full text-base bg-transparent border border-red-500 text-red-500'
>
Cancel
{/* <span className='text-gradient'>Cancel</span> */}
</button> </button>
</div> </div>
</div> </div>
@@ -1,10 +1,9 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import dataImage2 from "../../assets/images/data-table-user-2.png"; import localImgLoad from "../../lib/localImgLoad";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import { handlePagingFunc } from "../Pagination/HandlePagination"; import { handlePagingFunc } from "../Pagination/HandlePagination";
import PaginatedList from "../Pagination/PaginatedList"; import PaginatedList from "../Pagination/PaginatedList";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import localImgLoad from "../../lib/localImgLoad";
export default function MyActiveJobTable({ MyJobList, className }) { export default function MyActiveJobTable({ MyJobList, className }) {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -25,7 +24,7 @@ export default function MyActiveJobTable({ MyJobList, className }) {
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-3 sm:p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
className || "" className || ""
}`} }`}
> >
@@ -33,11 +32,6 @@ export default function MyActiveJobTable({ MyJobList, className }) {
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full"> <div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400"> <table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody> <tbody>
{/*<tr className="text-base text-thin-light-gray border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom ">*/}
{/* <td className="py-4">All Product</td>*/}
{/* <td className="py-4 text-right">.</td>*/}
{/*</tr>*/}
{ {
<> <>
{MyJobList && {MyJobList &&
@@ -59,7 +53,9 @@ export default function MyActiveJobTable({ MyJobList, className }) {
<div className="flex space-x-2 items-center w-full"> <div className="flex space-x-2 items-center w-full">
<div className="w-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center"> <div className="w-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img <img
src={localImgLoad(`images/taskbanners/${value.banner}`)} src={localImgLoad(
`images/taskbanners/${value.banner}`
)}
alt="data" alt="data"
className="w-full h-full rounded-full" className="w-full h-full rounded-full"
/> />
@@ -75,7 +71,7 @@ export default function MyActiveJobTable({ MyJobList, className }) {
{thePrice} {thePrice}
</span> </span>
</span> </span>
<div className="flex gap-4 items-center"> <div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
<span className="text-sm text-thin-light-gray"> <span className="text-sm text-thin-light-gray">
Duration:{" "} Duration:{" "}
<span className="text-purple"> <span className="text-purple">
@@ -115,7 +111,9 @@ export default function MyActiveJobTable({ MyJobList, className }) {
}} }}
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white" className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
> >
{value.owner_status == 'OWNER' ? 'Manage' : 'Send Updates'} {value.owner_status == "OWNER"
? "Manage"
: "Send Updates"}
</button> </button>
</div> </div>
</td> </td>
@@ -1,5 +1,4 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Link } from "react-router-dom";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
import CommonHead from "../UserHeader/CommonHead"; import CommonHead from "../UserHeader/CommonHead";
import MyActiveJobTable from "./MyActiveJobTable"; import MyActiveJobTable from "./MyActiveJobTable";
@@ -11,9 +10,7 @@ export default function MyReviewDueJobs(props) {
}; };
return ( return (
<Layout> <Layout>
<CommonHead <CommonHead commonHeadData={props.commonHeadData} />
commonHeadData={props.commonHeadData}
/>
<div className="notification-page w-full mb-10"> <div className="notification-page w-full mb-10">
<div className="notification-wrapper w-full"> <div className="notification-wrapper w-full">
{/* heading */} {/* heading */}
@@ -34,7 +31,7 @@ export default function MyReviewDueJobs(props) {
></div> ></div>
</div> </div>
</div> </div>
<MyActiveJobTable MyJobList={props.MyJobList} /> <MyActiveJobTable MyJobList={props.myJobList} />
</div> </div>
</div> </div>
</Layout> </Layout>
+1 -1
View File
@@ -96,7 +96,7 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
Price: Price:
<span className="text-purple ml-1">{thePrice}</span> <span className="text-purple ml-1">{thePrice}</span>
</span> </span>
<div className="flex gap-4 items-center"> <div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
<span className="text-sm text-thin-light-gray"> <span className="text-sm text-thin-light-gray">
Duration: Duration:
<span className="text-purple ml-1"> <span className="text-purple ml-1">
+42 -50
View File
@@ -12,8 +12,7 @@ function NairaWithdraw({
state, state,
setShowConfirmNairaWithdraw, 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 apiCall = new usersService();
const [tab, setTab] = useState("previous"); const [tab, setTab] = useState("previous");
let [requestStatus, setRequestStatus] = useState(false); let [requestStatus, setRequestStatus] = useState(false);
@@ -25,7 +24,9 @@ function NairaWithdraw({
recipientID: state?.previousAccount?.recipientID || "", recipientID: state?.previousAccount?.recipientID || "",
}, },
newAccount: { newAccount: {
country: state?.newAccount?.amount || "", country: wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country,
bank: state?.newAccount?.amount || "", bank: state?.newAccount?.amount || "",
accountNumber: state?.newAccount?.amount || "", accountNumber: state?.newAccount?.amount || "",
accountType: state?.newAccount?.amount || "", accountType: state?.newAccount?.amount || "",
@@ -67,10 +68,14 @@ function NairaWithdraw({
// Handling card change // Handling card change
const handleBankOptions = (event) => { const handleBankOptions = (event) => {
const { value } = event.target; let bankCountry = wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country
setBankName((prev) => ({ loading: true, data: [] })); setBankName((prev) => ({ loading: true, data: [] }));
apiCall apiCall
.getCountryBank({ country: value }) .getCountryBank({
country: bankCountry
})
.then((res) => { .then((res) => {
if (res.data.internal_return < 0) { if (res.data.internal_return < 0) {
setBankName((prev) => ({ loading: false, data: [] })); setBankName((prev) => ({ loading: false, data: [] }));
@@ -140,6 +145,7 @@ function NairaWithdraw({
}; };
useEffect(() => { useEffect(() => {
handleBankOptions()
getCountry(); // TO LOAD LIST COUNTRY getCountry(); // TO LOAD LIST COUNTRY
getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
}, []); }, []);
@@ -281,6 +287,8 @@ function NairaWithdraw({
getRecipients(); getRecipients();
}, []); }, []);
console.log("Testing Wallet Country", wallet?.walletCountry[0][0]);
return ( return (
<ModalCom action={action} situation={situation} className="edit-popup"> <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"> <div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
@@ -424,7 +432,11 @@ function NairaWithdraw({
<label <label
onClick={() => setTab("new")} onClick={() => setTab("new")}
htmlFor="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 <input
id="new" id="new"
@@ -436,7 +448,12 @@ function NairaWithdraw({
tab == "new" ? "" : "" tab == "new" ? "" : ""
} tracking-wide transition duration-200`} } 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> </label>
</div> </div>
</div> </div>
@@ -523,12 +540,12 @@ function NairaWithdraw({
</> </>
)} )}
{tab == "new" && ( {tab == "new" &&
recipients.loading ? (recipients.loading ? (
<div className="mt-3 flex flex-col w-full h-[188px] justify-center items-center"> <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> </div>
:recipients.data.length < MaxNoOfBanks ? ) : recipients.data.length < MaxNoOfBanks ? (
<div className="w-full mt-3 rounded-md bg-slate-100"> <div className="w-full mt-3 rounded-md bg-slate-100">
<div className="relative fields w-full flex flex-col p-4"> <div className="relative fields w-full flex flex-col p-4">
<div className="flex flex-[2] min-h-[52px]"> <div className="flex flex-[2] min-h-[52px]">
@@ -541,7 +558,12 @@ function NairaWithdraw({
Country{" "} Country{" "}
<span className="text-red-500">*</span> <span className="text-red-500">*</span>
</label> </label>
<select <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
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]" 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" name="newAccount.country"
value={props.values.newAccount?.country} value={props.values.newAccount?.country}
@@ -585,13 +607,7 @@ function NairaWithdraw({
No Options Found! No Options Found!
</option> </option>
)} )}
</select> </select> */}
{/* {props.errors.country &&
props.touched.country && (
<p className="text-sm text-red-500">
{props.errors.country}
</p>
)} */}
</div> </div>
{/* bank name */} {/* bank name */}
@@ -646,11 +662,6 @@ function NairaWithdraw({
</option> </option>
)} )}
</select> </select>
{/* {props.errors.bank && props.touched.bank && (
<p className="text-sm text-red-500">
{props.errors.bank}
</p>
)} */}
</div> </div>
</div> </div>
@@ -671,16 +682,12 @@ function NairaWithdraw({
name="newAccount.accountNumber" name="newAccount.accountNumber"
placeholder="Account No" placeholder="Account No"
maxLength={10} maxLength={10}
value={props.values.newAccount?.accountNumber} value={
props.values.newAccount?.accountNumber
}
inputHandler={props.handleChange} inputHandler={props.handleChange}
blurHandler={props.handleBlur} blurHandler={props.handleBlur}
/> />
{/* {props.errors.accountNumber &&
props.touched.accountNumber && (
<p className="text-sm text-red-500">
{props.errors.accountNumber}
</p>
)} */}
</div> </div>
{/* Account Type */} {/* Account Type */}
@@ -732,12 +739,6 @@ function NairaWithdraw({
</option> </option>
)} )}
</select> </select>
{/* {props.errors.accountType &&
props.touched.accountType && (
<p className="text-sm text-red-500">
{props.errors.accountType}
</p>
)} */}
</div> </div>
</div> </div>
@@ -748,7 +749,8 @@ function NairaWithdraw({
htmlFor="newAccount.state" htmlFor="newAccount.state"
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4]" 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> </label>
<InputCom <InputCom
fieldClass="px-6 tracking-[1.5px]" fieldClass="px-6 tracking-[1.5px]"
@@ -760,11 +762,6 @@ function NairaWithdraw({
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>
)} */}
</div> </div>
{/* city */} {/* city */}
@@ -785,20 +782,15 @@ function NairaWithdraw({
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>
)} */}
</div> </div>
</div> </div>
{/* end of inputs for new accounts */} {/* end of inputs for new accounts */}
</div> </div>
</div> </div>
: ) : (
<div className="mt-3 flex w-full h-[188px] justify-center items-center"></div> <div className="mt-3 flex w-full h-[188px] justify-center items-center"></div>
)} ))}
</div> </div>
<div className="transfer-fund-btn flex justify-end items-center gap-2 py-4"> <div className="transfer-fund-btn flex justify-end items-center gap-2 py-4">
+38 -2
View File
@@ -5,7 +5,6 @@ import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
const WalletBox = lazy(() => import("./WalletBox")); const WalletBox = lazy(() => import("./WalletBox"));
const WalletRoutes = () => { const WalletRoutes = () => {
const apiCall = new usersService(); const apiCall = new usersService();
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
@@ -16,6 +15,12 @@ const WalletRoutes = () => {
data: [], data: [],
}); });
const [allCountries, setAllCountries] = useState({
// STATE TO HOLD LIST OF COUNTRIES
loading: true,
data: [],
});
const getPaymentHistory = () => { const getPaymentHistory = () => {
apiCall apiCall
.getPaymentHx() .getPaymentHx()
@@ -31,14 +36,45 @@ 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(() => { useEffect(() => {
getCountry();
getPaymentHistory(); getPaymentHistory();
}, [walletTable]); }, [walletTable]);
console.log(
"Testing all country: ",
allCountries,
"Testing wallet: ",
walletDetails
);
return ( return (
<Layout> <Layout>
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}> <Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}>
<WalletBox wallet={walletDetails} payment={paymentHistory} /> <WalletBox
wallet={walletDetails}
payment={paymentHistory}
countries={allCountries.data}
/>
</Suspense> </Suspense>
</Layout> </Layout>
); );
+1 -1
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react"; import React, { useEffect, useState } from "react";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import ConfirmNairaWithdraw from "./Popup/ConfirmNairaWithdraw"; import ConfirmNairaWithdraw from "./Popup/ConfirmNairaWithdraw";
import NairaWithdraw from "./Popup/NairaWithdraw"; import NairaWithdraw from "./Popup/NairaWithdraw";
+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. * Renders a list of wallet items or a loading spinner depending on the state of the `wallet` object.
*/ */
export default function WalletBox({ wallet, payment }) { export default function WalletBox({ wallet, payment, countries }) {
const { loading, data } = wallet; const { loading, data } = wallet;
return ( return (
@@ -18,7 +18,7 @@ export default function WalletBox({ wallet, payment }) {
) : ( ) : (
data.length > 0 && data.map((item) => ( data.length > 0 && data.map((item) => (
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0"> <div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
<WalletItemCard walletItem={item} payment={payment} /> <WalletItemCard walletItem={item} payment={payment} countries={countries} />
</div> </div>
)) ))
)} )}
+7 -2
View File
@@ -10,7 +10,7 @@ import WalletAction from "./WalletAction";
/** /**
* Renders a card displaying information about a wallet item. * Renders a card displaying information about a wallet item.
*/ */
export default function WalletItemCard({ walletItem, payment }) { export default function WalletItemCard({ walletItem, payment, countries }) {
const { userDetails } = useSelector((state) => state.userDetails); const { userDetails } = useSelector((state) => state.userDetails);
const accountType = userDetails?.account_type === "FAMILY"; const accountType = userDetails?.account_type === "FAMILY";
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -35,10 +35,15 @@ export default function WalletItemCard({ walletItem, payment }) {
dispatch(tableReload({ type: "WALLETTABLE" })); dispatch(tableReload({ type: "WALLETTABLE" }));
}; };
const currentWalletCurrency = countries
.map((country) => country)
.filter((country) => country[0] === walletItem.country);
const image = walletItem.code const image = walletItem.code
? `${walletItem.code.toLowerCase()}.svg` ? `${walletItem.code.toLowerCase()}.svg`
: "default.png"; : "default.png";
return ( return (
<> <>
<div <div
@@ -88,7 +93,7 @@ export default function WalletItemCard({ walletItem, payment }) {
{!accountType && ( {!accountType && (
<WalletAction <WalletAction
walletItem={walletItem} walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
payment={payment} payment={payment}
openPopUp={openPopUp} openPopUp={openPopUp}
/> />
+1 -1
View File
@@ -74,7 +74,7 @@ export default function Layout({ children }) {
</div> </div>
{/* container */} {/* container */}
<div className="nft-container 2xl:flex 2xl:space-x-8 h-full mb-12 lg:mt-[140px] mt-24 xl:mt-10 flex flex-col xl:flex-row items-start justify-center gap-4"> <div className="nft-container 2xl:flex 2xl:space-x-8 h-full mb-12 lg:mt-[140px] mt-24 xl:mt-10 flex flex-col xl:flex-row items-start justify-center gap-4">
<div className="nft-main-container flex-[80%]"> <div className="nft-main-container flex-[80%] w-full">
{children && children} {children && children}
</div> </div>
<div className="nft-right-side-content 2xl:w-[270px] w-full h-full 2xl:flex justify-center relative flex-[20%]"> <div className="nft-right-side-content 2xl:w-[270px] w-full h-full 2xl:flex justify-center relative flex-[20%]">
@@ -51,6 +51,7 @@ export default function PersonalInfoTab({
coverImgInput, coverImgInput,
browseCoverImg, browseCoverImg,
coverImgChangHandler, coverImgChangHandler,
uploadStatus
}) { }) {
let { userDetails } = useSelector((state) => state.userDetails); let { userDetails } = useSelector((state) => state.userDetails);
@@ -68,7 +69,7 @@ export default function PersonalInfoTab({
pref_email: 0, pref_email: 0,
pref_phone: 0, pref_phone: 0,
accept_promo: false, accept_promo: false,
online_name: "", online_name: userDetails?.online_name,
}; };
let [profile, setProfile] = useState({ let [profile, setProfile] = useState({
@@ -158,7 +159,7 @@ export default function PersonalInfoTab({
fieldClass="px-6" fieldClass="px-6"
label="User Name" label="User Name"
type="text" type="text"
name="online_name" name="username"
placeholder="Username" placeholder="Username"
value={userDetails?.username} value={userDetails?.username}
disable={true} disable={true}
@@ -361,6 +362,7 @@ export default function PersonalInfoTab({
{/* inputs ends here */} {/* inputs ends here */}
</div> </div>
</div> </div>
{/* {process.env.REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE != 0 && */}
<div className="w-[232px] mb-10"> <div className="w-[232px] mb-10">
<div className="update-profile w-full mb-9"> <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"> <h1 className="text-xl tracking-wide font-bold text-dark-gray dark:text-white flex items-center mb-2">
@@ -416,8 +418,11 @@ export default function PersonalInfoTab({
</div> </div>
</div> </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>
{/* } */}
</div> </div>
<div className="content-footer w-full"> <div className="content-footer w-full">
+61 -3
View File
@@ -24,10 +24,12 @@ import {
import RecipientAccountTab from "./Tabs/RecipientAccountTab"; import RecipientAccountTab from "./Tabs/RecipientAccountTab";
export default function Settings({ faq }) { export default function Settings({ faq }) {
const apiCall = new usersService();
const { userDetails } = useSelector((state) => state?.userDetails); const { userDetails } = useSelector((state) => state?.userDetails);
const [profileImg, setProfileImg] = useState( const [profileImg, setProfileImg] = useState(
userDetails?.profile_pic_url ? userDetails.profile_pic_url : profile 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 [coverImg, setCoverImg] = useState(cover);
const [reloadCardList, setReloadCardList] = useState(false); // STATE TO DETERMINE WHEN CARD LIST RELOADS. EG: WHEN USER DELETES A CARD 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 = () => { const browseProfileImg = () => {
profileImgInput.current.click(); profileImgInput.current.click();
}; };
const profileImgChangHandler = (e) => { 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 !== "") { if (e.target.value !== "") {
const imgReader = new FileReader(); const imgReader = new FileReader();
imgReader.onload = (event) => { imgReader.onload = (event) => {
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); 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]); imgReader.readAsDataURL(e.target.files[0]);
} }
@@ -61,7 +119,6 @@ export default function Settings({ faq }) {
} }
}; };
const apiCall = useMemo(() => new usersService(), []);
// Tabs Handling // Tabs Handling
const tabs = [ const tabs = [
{ {
@@ -113,7 +170,7 @@ export default function Settings({ faq }) {
iconName: "page-right", iconName: "page-right",
}, },
{ {
id: 8, id: 9,
name: "terms", name: "terms",
title: "Terms and Conditions", title: "Terms and Conditions",
iconName: "page-right", iconName: "page-right",
@@ -217,6 +274,7 @@ export default function Settings({ faq }) {
coverImgChangHandler={coverImgChangHandler} coverImgChangHandler={coverImgChangHandler}
browseCoverImg={browseCoverImg} browseCoverImg={browseCoverImg}
coverImgInput={coverImgInput} coverImgInput={coverImgInput}
uploadStatus={uploadStatus}
/> />
</div> </div>
)} )}
+1 -1
View File
@@ -351,7 +351,7 @@ const EditJobPopOut = ({
className="w-[120px] h-[40px] flex justify-center items-center btn-gradient text-base rounded-full text-white" className="w-[120px] h-[40px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
// className='w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white' // className='w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white'
> >
Edit Job Save
</button> </button>
)} )}
</div> </div>
+123 -31
View File
@@ -30,22 +30,24 @@
background-color: darkgreen; background-color: darkgreen;
} }
.referral { .referral {
margin-bottom: 20px margin-bottom: 20px;
} }
.task_action_panel { .task_action_panel {
font-family: sans; color: white; font-family: sans;
color: white;
font-weight: bolder; font-weight: bolder;
font-size: 14px; font-size: 14px;
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif; font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
padding: 0px 10px 5px 10px padding: 0px 10px 5px 10px;
} }
.heroSilderTitle { .heroSilderTitle {
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
font-family: sans; color: white; font-family: sans;
color: white;
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif; font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
} }
.back-dark1 { .back-dark1 {
background-color: #193F5F; background-color: #193f5f;
min-width: 280px !important; min-width: 280px !important;
} }
.job-action { .job-action {
@@ -110,7 +112,13 @@
} }
.offer-slide-item { .offer-slide-item {
background: rgb(2, 0, 36); background: rgb(2, 0, 36);
background: radial-gradient(circle, rgba(2,0,36,1) 0%, rgba(3,51,2,0.782125350140056) 0%, rgba(0,212,255,0.07904411764705888) 0%, rgba(153,182,201,1) 99%); background: radial-gradient(
circle,
rgba(2, 0, 36, 1) 0%,
rgba(3, 51, 2, 0.782125350140056) 0%,
rgba(0, 212, 255, 0.07904411764705888) 0%,
rgba(153, 182, 201, 1) 99%
);
margin: 5px; margin: 5px;
border-radius: 15px; border-radius: 15px;
padding: 15px; padding: 15px;
@@ -133,6 +141,7 @@
font-family: "Product Sans"; font-family: "Product Sans";
src: url("./assets/fonts/Product Sans Regular.ttf"); src: url("./assets/fonts/Product Sans Regular.ttf");
} }
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@@ -144,7 +153,6 @@
--toastify-color-success: #f539f8; --toastify-color-success: #f539f8;
} }
/* ===================== EXTRA ===================== */ /* ===================== EXTRA ===================== */
.bottomMargin { .bottomMargin {
margin-bottom: 15px; margin-bottom: 15px;
@@ -159,7 +167,12 @@ html {
font-family: "Product Sans"; font-family: "Product Sans";
} }
.primary-gradient { .primary-gradient {
background: linear-gradient(134.38deg, #f539f8 0%, #284f64 43.55%, #1a3544 104.51%); background: linear-gradient(
134.38deg,
#f539f8 0%,
#284f64 43.55%,
#1a3544 104.51%
);
/* background-image: url("./assets/images/left-myft.jpg"); /* background-image: url("./assets/images/left-myft.jpg");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; */ background-size: cover; */
@@ -199,7 +212,12 @@ html {
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%); background: linear-gradient(
134.38deg,
#5356fb 0%,
#c342f9 43.55%,
#f539f8 104.51%
);
opacity: 30%; opacity: 30%;
} }
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
@@ -229,10 +247,20 @@ input[type="text"][dir="rtl"] {
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }
.btn-gradient { .btn-gradient {
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); background: linear-gradient(
134.38deg,
#f539f8 0%,
#c342f9 43.55%,
#5356fb 104.51%
);
} }
.btn-gradient:hover { .btn-gradient:hover {
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%); background: linear-gradient(
134.38deg,
#5356fb 0%,
#c342f9 43.55%,
#f539f8 104.51%
);
} }
.text-26 { .text-26 {
font-size: 26px; font-size: 26px;
@@ -246,7 +274,12 @@ input[type="text"][dir="rtl"] {
} }
.text-gradient { .text-gradient {
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); background: linear-gradient(
134.38deg,
#f539f8 0%,
#c342f9 43.55%,
#5356fb 104.51%
);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
} }
@@ -305,6 +338,16 @@ input[type="text"][dir="rtl"] {
transform: scale(1); transform: scale(1);
width: 80%; width: 80%;
} }
@media screen and (min-width: 25rem) {
.sidebar-logo.enter {
width: 65%;
}
.sidebar-logo.enter + span{
position: revert;
}
}
.sidebar-logo { .sidebar-logo {
transform: scale(0); transform: scale(0);
width: 0; width: 0;
@@ -437,7 +480,12 @@ input[type="text"][dir="rtl"] {
.home-page-wrapper .hero-slider .slick-slider .slick-dots li { .home-page-wrapper .hero-slider .slick-slider .slick-dots li {
margin: 0; margin: 0;
} }
.home-page-wrapper .hero-slider .slick-slider .slick-dots li.slick-active button { .home-page-wrapper
.hero-slider
.slick-slider
.slick-dots
li.slick-active
button {
background: white; background: white;
} }
.home-page-wrapper .hero-slider .slick-slider .slick-dots li button { .home-page-wrapper .hero-slider .slick-slider .slick-dots li button {
@@ -460,7 +508,12 @@ input[type="text"][dir="rtl"] {
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%); background: linear-gradient(
134.38deg,
#5356fb 0%,
#c342f9 43.55%,
#f539f8 104.51%
);
z-index: -1; z-index: -1;
opacity: 30%; opacity: 30%;
} }
@@ -476,8 +529,10 @@ input[type="text"][dir="rtl"] {
margin: 0 16px; margin: 0 16px;
} }
.transfer-field, .transfer-field:focus, .transfer-field:focus-within{ .transfer-field,
background: #FFF !important; .transfer-field:focus,
.transfer-field:focus-within {
background: #fff !important;
border: none !important; border: none !important;
outline: none !important; outline: none !important;
box-shadow: none !important; box-shadow: none !important;
@@ -597,7 +652,7 @@ input[type="text"][dir="rtl"] {
top: 0; top: 0;
right: -100%; right: -100%;
opacity: 0; opacity: 0;
transition: all .5s; transition: all 0.5s;
background-color: white; background-color: white;
} }
@@ -612,7 +667,12 @@ input[type="text"][dir="rtl"] {
.notification-page .content-item .notifications { .notification-page .content-item .notifications {
@apply flex space-x-4 items-center; @apply flex space-x-4 items-center;
} }
.notification-page .content-item .notifications .notification-page .content-item .notifications { .notification-page
.content-item
.notifications
.notification-page
.content-item
.notifications {
@apply mb-0; @apply mb-0;
} }
.notification-setting-tab .notification-settings-items li:last-child { .notification-setting-tab .notification-settings-items li:last-child {
@@ -621,7 +681,11 @@ input[type="text"][dir="rtl"] {
.faq-tab .accordion-items .accordion-item:first-child .accordion-title-bar { .faq-tab .accordion-items .accordion-item:first-child .accordion-title-bar {
padding-top: 0; padding-top: 0;
} }
.faq-tab .accordion-items .accordion-item:last-child .accordion-body .accordion-body-content { .faq-tab
.accordion-items
.accordion-item:last-child
.accordion-body
.accordion-body-content {
padding-bottom: 20px; padding-bottom: 20px;
} }
.faq-tab .accordion-title-bar { .faq-tab .accordion-title-bar {
@@ -669,7 +733,8 @@ input[type="text"][dir="rtl"] {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
.job-action-modal-body button, .message-modal-header button { .job-action-modal-body button,
.message-modal-header button {
display: none; display: none;
} }
.message-modal-wrapper .message-table { .message-modal-wrapper .message-table {
@@ -839,20 +904,26 @@ TODO: Responsive ===========================
} }
} }
/* LoginPage */ /* LoginPage */
.main-wrapper.login-wrapper { .main-wrapper.login-wrapper {
background-image: url('./assets/images/login-dots.jpg'); background-image: url("./assets/images/login-dots.jpg");
background-attachment: fixed; background-attachment: fixed;
background-size: contain; background-size: contain;
background-position-y: bottom; background-position-y: bottom;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.layout-wrapper.login { .layout-wrapper.login {
background: rgb(236, 237, 241); background: rgb(236, 237, 241);
background: linear-gradient(90deg, rgba(236,237,241,1) 0%, rgba(252,252,252,1) 31%, rgba(255,255,255,0.9416141456582633) 41%, rgba(255,255,255,0.9752275910364145) 61%, rgba(252,252,252,1) 71%, rgba(236,237,241,1) 100%); background: linear-gradient(
90deg,
rgba(236, 237, 241, 1) 0%,
rgba(252, 252, 252, 1) 31%,
rgba(255, 255, 255, 0.9416141456582633) 41%,
rgba(255, 255, 255, 0.9752275910364145) 61%,
rgba(252, 252, 252, 1) 71%,
rgba(236, 237, 241, 1) 100%
);
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif; font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
font-weight: 400; font-weight: 400;
font-size: 1.125rem; font-size: 1.125rem;
@@ -861,8 +932,12 @@ TODO: Responsive ===========================
.content-wrapper.login { .content-wrapper.login {
--bg-color: 255, 255, 255; --bg-color: 255, 255, 255;
background: linear-gradient(90deg, rgba(236,237,240,1) 0%, rgba(255,255,255,1) 50%, rgba(236,237,240,1) 100%); background: linear-gradient(
90deg,
rgba(236, 237, 240, 1) 0%,
rgba(255, 255, 255, 1) 50%,
rgba(236, 237, 240, 1) 100%
);
} }
.content-wrapper select { .content-wrapper select {
@@ -880,7 +955,8 @@ TODO: Responsive ===========================
} }
/* Update table scrollbar */ /* Update table scrollbar */
.update-table::-webkit-scrollbar-track, .update-table > *::-webkit-scrollbar-track, .update-table::-webkit-scrollbar-track,
.update-table > *::-webkit-scrollbar-track,
.market-pop::-webkit-scrollbar-track, .market-pop::-webkit-scrollbar-track,
.wallet.coupon::-webkit-scrollbar-track { .wallet.coupon::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
@@ -888,19 +964,27 @@ TODO: Responsive ===========================
border-radius: 10px; border-radius: 10px;
} }
.update-table::-webkit-scrollbar, .update-table > *::-webkit-scrollbar, .update-table::-webkit-scrollbar,
.update-table > *::-webkit-scrollbar,
.market-pop::-webkit-scrollbar, .market-pop::-webkit-scrollbar,
.wallet.coupon::-webkit-scrollbar { .wallet.coupon::-webkit-scrollbar {
width: 10px; width: 10px;
background-color: transparent; background-color: transparent;
} }
.update-table::-webkit-scrollbar-thumb, .update-table > *::-webkit-scrollbar-thumb, .wallet.coupon::-webkit-scrollbar-thumb { .update-table::-webkit-scrollbar-thumb,
.update-table > *::-webkit-scrollbar-thumb,
.wallet.coupon::-webkit-scrollbar-thumb {
border-radius: 10px; border-radius: 10px;
border-top-right-radius: 50px; border-top-right-radius: 50px;
border-bottom-right-radius: 50px; border-bottom-right-radius: 50px;
background-color: #fff; background-color: #fff;
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); background: linear-gradient(
134.38deg,
#f539f8 0%,
#c342f9 43.55%,
#5356fb 104.51%
);
} }
.market-pop::-webkit-scrollbar-thumb { .market-pop::-webkit-scrollbar-thumb {
@@ -909,7 +993,15 @@ TODO: Responsive ===========================
/* background-color: #fafafa; */ /* background-color: #fafafa; */
/* background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); */ /* background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); */
background: rgb(236, 237, 241); background: rgb(236, 237, 241);
background: linear-gradient(90deg, rgba(236,237,241,1) 0%, rgba(252,252,252,1) 31%, rgba(255,255,255,0.9416141456582633) 41%, rgba(255,255,255,0.9752275910364145) 61%, rgba(252,252,252,1) 71%, rgba(236,237,241,1) 100%); background: linear-gradient(
90deg,
rgba(236, 237, 241, 1) 0%,
rgba(252, 252, 252, 1) 31%,
rgba(255, 255, 255, 0.9416141456582633) 41%,
rgba(255, 255, 255, 0.9752275910364145) 61%,
rgba(252, 252, 252, 1) 71%,
rgba(236, 237, 241, 1) 100%
);
} }
.input-curve.lg { .input-curve.lg {
+16 -10
View File
@@ -1,31 +1,37 @@
import React, { useState, useEffect } from "react"; import React, { useEffect, useState } from "react";
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
import usersService from "../services/UsersService"; import usersService from "../services/UsersService";
/**
* This code defines a React functional component called `ManageActiveJobs`.
* It fetches a list of active job messages and renders the `ActiveJobs` component with the necessary props.
*/
function ManageActiveJobs() { function ManageActiveJobs() {
const ApiCall = new usersService(); const ApiCall = new usersService();
let navigate = useNavigate(); const navigate = useNavigate();
let { state } = useLocation(); const { state } = useLocation();
let [details, setDetails] = useState({}); // to hold state values const [details, setDetails] = useState({});
let [activeJobMesList, setActiveJobMesList] = useState({ const [activeJobMesList, setActiveJobMesList] = useState({
loading: true, loading: true,
error: false, error: false,
data: [], data: [],
}); });
let [activeJobMesListReload, setActiveJobMesListReload] = useState(false); // state to determine when ACTIVE JOB MESSAGE LIST RELOADS/RE-RENDERS const [activeJobMesListReload, setActiveJobMesListReload] = useState(false);
/**
* Fetches the active job message list.
*/
const getActiveJobMesList = () => { const getActiveJobMesList = () => {
// FUNCTION TO GET ACTIVE JOB MESSAGE LIST
setActiveJobMesList({ loading: true, error: false, data: [] }); setActiveJobMesList({ loading: true, error: false, data: [] });
let contract = { contract: state.contract }; const contract = { contract: state.contract };
ApiCall.activeJobMesList(contract) ApiCall.activeJobMesList(contract)
.then((res) => { .then((res) => {
if (res.status != 200 || res.data.internal_return < 0) { if (res.status !== 200 || res.data.internal_return < 0) {
setActiveJobMesList({ loading: false, error: false, data: [] }); setActiveJobMesList({ loading: false, error: false, data: [] });
return; return;
} }
+13 -8
View File
@@ -1,12 +1,18 @@
import React, { useContext,useState, useEffect } from "react"; import React, { useEffect, useState } from "react";
import usersService from "../services/UsersService";
import MyReviewDueJobs from "../components/MyActiveJobs/MyReviewDueJobs";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import MyReviewDueJobs from "../components/MyActiveJobs/MyReviewDueJobs";
import usersService from "../services/UsersService";
/**
* React component that fetches a list of review due jobs and renders the `MyReviewDueJobs` component with the fetched data.
*/
export default function MyReviewDueJobsPage() { export default function MyReviewDueJobsPage() {
let {commonHeadBanner} = useSelector(state => state.commonHeadBanner) const { commonHeadBanner } = useSelector((state) => state.commonHeadBanner);
const [MyJobList, setMyJobList] = useState([]); const [myJobList, setMyJobList] = useState([]);
useEffect(() => {
const api = new usersService(); const api = new usersService();
const getMyJobList = async () => { const getMyJobList = async () => {
try { try {
const res = await api.getMyReviewDueJobList(); const res = await api.getMyReviewDueJobList();
@@ -15,15 +21,14 @@ export default function MyReviewDueJobsPage() {
console.log("Error getting mode"); console.log("Error getting mode");
} }
}; };
useEffect(() => {
getMyJobList(); getMyJobList();
}, []); }, []);
// debugger;
return ( return (
<> <>
<MyReviewDueJobs <MyReviewDueJobs
MyJobList={MyJobList} myJobList={myJobList}
commonHeadData={commonHeadBanner.result_list} commonHeadData={commonHeadBanner.result_list}
/> />
</> </>