Compare commits

..

11 Commits

17 changed files with 331 additions and 291 deletions
@@ -15,46 +15,44 @@ function Redirect() {
const codeResponse = queryParams.get("code"); const codeResponse = queryParams.get("code");
useEffect(()=>{ useEffect(()=>{
if(!codeResponse){ if(!codeResponse){
navigate('/login', {replace: true}) navigate('/login', {state: {error: true}})
return
}
console.log(codeResponse);
/*
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code
*/
var reqData = {
auth_type: "GOOGLE",
code: codeResponse,
redirect_uri: process.env.REACT_APP_GOOGLE_REDIRECT_URL,
};
userApi
.authStart(reqData)
.then((res) => {
if (res.status == 200 && res.data.internal_return >= 0 && res.data.member_id && res.data.uid && res.data.session) {
localStorage.setItem("member_id", `${res.data.member_id}`);
localStorage.setItem("uid", `${res.data.uid}`);
localStorage.setItem("session_token", `${res.data.session}`);
dispatch(updateUserDetails({...res.data}));
navigate('/', {replace: true})
return return
} }
console.log(codeResponse); navigate('/login', {state: {error: true}})
/* })
POST /token HTTP/1.1 .catch((error) => {
Host: oauth2.googleapis.com navigate('/login', {state: {error: true}})
Content-Type: application/x-www-form-urlencoded console.log(error);
});
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code
*/
var reqData = {
auth_type: "GOOGLE",
code: codeResponse,
redirect_uri: process.env.REACT_APP_GOOGLE_REDIRECT_URL,
};
userApi
.authStart(reqData)
.then((res) => {
if (res.status != 200) {
navigate('/login', {replace: true})
return;
}
localStorage.setItem("member_id", `${res.data.member_id}`);
localStorage.setItem("uid", `${res.data.uid}`);
localStorage.setItem("session_token", `${res.data.session}`);
dispatch(updateUserDetails({...res.data, loggedIn:true}));
navigate('/', {replace: true})
})
.catch((error) => {
navigate('/login', {replace: true})
console.log(error);
});
},[]) },[])
return ( return (
<AuthLayout> <AuthLayout>
+20 -3
View File
@@ -1,5 +1,5 @@
import React, { useEffect, useLayoutEffect, useState } from "react"; import React, { useEffect, useLayoutEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate, useLocation } from "react-router-dom";
import linkedInLogo from "../../../assets/images/Linkedin.png"; import linkedInLogo from "../../../assets/images/Linkedin.png";
import appleLogo from "../../../assets/images/apple-black.svg"; import appleLogo from "../../../assets/images/apple-black.svg";
import facebookLogo from "../../../assets/images/facebook-4.svg"; import facebookLogo from "../../../assets/images/facebook-4.svg";
@@ -16,6 +16,7 @@ import { updateUserDetails } from "../../../store/UserDetails";
export default function Login() { export default function Login() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const {state} = useLocation()
let [loginType, setLoginType] = useState(''); let [loginType, setLoginType] = useState('');
@@ -76,6 +77,14 @@ export default function Login() {
return; return;
} }
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (regEx.test(email) == false) {
setLoginLoading(false);
setMsgError("Invalid Email");
return setTimeout(()=>{setMsgError("");},3000)
}
if (name == "full") { if (name == "full") {
// Post Data Info for normal Login // Post Data Info for normal Login
postData = { postData = {
@@ -105,7 +114,7 @@ export default function Login() {
userApi userApi
.logInUser(postData) .logInUser(postData)
.then((res) => { .then((res) => {
if (res.status != 200 || res.data.internal_return < 0) { if (res.status != 200 || res.data.internal_return < 0 || !res.data.member_id || !res.data.uid || !res.data.session) {
// setMsgError("Wrong, email/password"); // setMsgError("Wrong, email/password");
setLoginError(true); setLoginError(true);
setLoginLoading(false); setLoginLoading(false);
@@ -115,7 +124,7 @@ export default function Login() {
localStorage.setItem("uid", `${res.data.uid}`); localStorage.setItem("uid", `${res.data.uid}`);
localStorage.setItem("session_token", `${res.data.session}`); localStorage.setItem("session_token", `${res.data.session}`);
// localStorage.setItem("session", `${res.data.session}`); // localStorage.setItem("session", `${res.data.session}`);
dispatch(updateUserDetails({...res.data, loggedIn:true})); dispatch(updateUserDetails({...res.data}));
setTimeout(() => { setTimeout(() => {
navigate("/", { replace: true }); navigate("/", { replace: true });
setLoginLoading(false); setLoginLoading(false);
@@ -175,6 +184,14 @@ export default function Login() {
} }
let loginValue = readCookie('loginType') let loginValue = readCookie('loginType')
setLoginType(loginValue) setLoginType(loginValue)
if(state?.error){ //check if the login path has an error state indicating any social handle login with error
setMsgError("Unexpected Error, Please try again soon.");
setTimeout(()=>{
setMsgError("");
navigate('/login', {replace: true})
},4000)
}
},[]) },[])
+61 -33
View File
@@ -1,26 +1,28 @@
import React, { import React, {
Suspense, Suspense,
lazy,
useCallback, 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/profile-info-profile.png";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout"; import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
import {
FamilyWaitlist,
FamilyAccount,
FamilyProfile,
FamilyTasks,
ProfileInfo,
FamilyPending,
} from "./Tabs";
import localImgLoad from "../../lib/localImgLoad"; import localImgLoad from "../../lib/localImgLoad";
// Lazy Imports for components
const FamilyWaitlist = lazy(() => import("./Tabs/FamilyWaitlist"));
const FamilyAccount = lazy(() => import("./Tabs/FamilyAccount"));
const FamilyProfile = lazy(() => import("./Tabs/FamilyProfile"));
const FamilyTasks = lazy(() => import("./Tabs/FamilyTasks"));
const ProfileInfo = lazy(() => import("./Tabs/ProfileInfo"));
const FamilyPending = lazy(() => import("./Tabs/FamilyPending"));
export default function FamilyManageTabs({ export default function FamilyManageTabs({
className, className,
accountDetails, accountDetails,
@@ -35,14 +37,15 @@ export default function FamilyManageTabs({
}); });
const [errMsg, setErrMsg] = useState(""); const [errMsg, setErrMsg] = useState("");
const [familyTaskPopout, setFamilyTaskPopout] = useState(false); const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
const [profileImg, setProfileImg] = useState(profile);
const profileImgInput = useRef(null);
const [isPending, startTransition] = useTransition();
const apiCall = useMemo(() => new usersService(), []);
const familyPopUpHandler = () => { const familyPopUpHandler = () => {
setFamilyTaskPopout((prev) => !prev); setFamilyTaskPopout((prev) => !prev);
}; };
const [profileImg, setProfileImg] = useState(profile);
const profileImgInput = useRef(null);
const browseProfileImg = () => { const browseProfileImg = () => {
profileImgInput.current.click(); profileImgInput.current.click();
}; };
@@ -57,16 +60,15 @@ export default function FamilyManageTabs({
} }
}; };
const apiCall = useMemo(() => new usersService(), []);
const manageFamily = useCallback(async () => { const manageFamily = useCallback(async () => {
try { try {
setDetails({ setDetails((prevDetails) => ({
...prevDetails,
familyDetails: { loading: true }, familyDetails: { loading: true },
familyTasks: { loading: true }, familyTasks: { loading: true },
familyWaitList: { loading: true }, familyWaitList: { loading: true },
familyPending: { loading: true }, familyPending: { loading: true },
}); }));
const { family_uid } = accountDetails; const { family_uid } = accountDetails;
const reqData = { family_uid }; const reqData = { family_uid };
@@ -89,22 +91,26 @@ export default function FamilyManageTabs({
tasksData?.internal_return < 0 || tasksData?.internal_return < 0 ||
familyWaitData?.internal_return < 0 || familyWaitData?.internal_return < 0 ||
familyPendingData?.internal_return < 0 familyPendingData?.internal_return < 0
) ) {
return; return;
}
setDetails({ startTransition(() => {
familyDetails: { loading: false, data: familyData }, setDetails({
familyTasks: { loading: false, data: tasksData }, familyDetails: { loading: false, data: familyData },
familyWaitList: { loading: false, data: familyWaitData }, familyTasks: { loading: false, data: tasksData },
familyPending: { loading: false, data: familyPendingData }, familyWaitList: { loading: false, data: familyWaitData },
familyPending: { loading: false, data: familyPendingData },
});
}); });
} catch (error) { } catch (error) {
setDetails({ setDetails((prevDetails) => ({
...prevDetails,
familyDetails: { loading: false }, familyDetails: { loading: false },
familyTasks: { loading: false }, familyTasks: { loading: false },
familyWaitList: { loading: false }, familyWaitList: { loading: false },
familyPending: { loading: false }, familyPending: { loading: false },
}); }));
setErrMsg("An error occurred"); setErrMsg("An error occurred");
throw new Error(error); throw new Error(error);
} }
@@ -119,13 +125,15 @@ export default function FamilyManageTabs({
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" },
]; ];
const [tab, setTab] = useState(tabs[0].name); const [tab, setTab] = useState(tabs[0].name);
const tabHandler = (value) => { const tabHandler = (value) => {
setTab(value); startTransition(() => {
setTab(value);
});
}; };
const tabComponents = { const tabComponents = {
@@ -174,7 +182,13 @@ export default function FamilyManageTabs({
const selectedTabComponent = tabComponents[tab] || defaultTabComponent; const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
useEffect(() => { useEffect(() => {
manageFamily(); let __manageFamily = true;
if (__manageFamily) {
manageFamily();
}
return () => {
__manageFamily = false;
};
}, [tab, manageFamily]); }, [tab, manageFamily]);
return ( return (
@@ -202,15 +216,25 @@ export default function FamilyManageTabs({
/> />
<div className="mt-4 flex justify-center items-center gap-2"> <div className="mt-4 flex justify-center items-center gap-2">
<button <button
onClick={() => tabHandler('Account')} onClick={() => tabHandler("Account")}
className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center"> className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center"
<img src={localImgLoad('images/icons/account.svg')} className="w-[70px] h-[70px]" alt='Settings-Icon' /> >
<img
src={localImgLoad("images/icons/account.svg")}
className="w-[70px] h-[70px]"
alt="Settings-Icon"
/>
<p className="mt-2 text-lg text-sky-blue">Account</p> <p className="mt-2 text-lg text-sky-blue">Account</p>
</button> </button>
<button <button
onClick={() => tabHandler('Profile')} onClick={() => tabHandler("Profile")}
className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center"> className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center"
<img src={localImgLoad('images/icons/profile.svg')} className="w-[70px] h-[70px]" alt='Settings-Icon' /> >
<img
src={localImgLoad("images/icons/profile.svg")}
className="w-[70px] h-[70px]"
alt="Settings-Icon"
/>
<p className="mt-2 text-lg text-sky-blue">Profile</p> <p className="mt-2 text-lg text-sky-blue">Profile</p>
</button> </button>
</div> </div>
@@ -243,7 +267,11 @@ export default function FamilyManageTabs({
</div> </div>
<div className="flex-[0.9] lg:min-h-[450px] h-full"> <div className="flex-[0.9] lg:min-h-[450px] h-full">
<div className="h-full p-4 border border-[#dbd9d9] relative overflow-y-auto"> <div className="h-full p-4 border border-[#dbd9d9] relative overflow-y-auto">
{selectedTabComponent} <Suspense
fallback={<LoadingSpinner size="16" color="sky-blue" />}
>
{selectedTabComponent}
</Suspense>
</div> </div>
</div> </div>
</div> </div>
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useTransition } from "react";
import ModalCom from "../../Helpers/ModalCom"; import ModalCom from "../../Helpers/ModalCom";
import Detail from "../../jobPopout/popoutcomponent/Detail"; import Detail from "../../jobPopout/popoutcomponent/Detail";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
@@ -6,7 +6,7 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
import { PriceFormatter } from "../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../Helpers/PriceFormatter";
import { NewTasks } from "./forms"; import { NewTasks } from "./forms";
function AssignTaskPopout({ action, details, situation, familyDetails }) { const AssignTaskPopout = React.memo(({ action, details, situation, familyDetails }) => {
const apiCall = new usersService(); const apiCall = new usersService();
let [requestStatus, setRequestStatus] = useState({ let [requestStatus, setRequestStatus] = useState({
@@ -15,7 +15,7 @@ function AssignTaskPopout({ action, details, situation, familyDetails }) {
message: "", message: "",
}); // HOLDS RESPONSE FOR SENDING API REQUEST }); // HOLDS RESPONSE FOR SENDING API REQUEST
let [familyTask, setFamilyTask] = useState({ loading: true, data: [] }); 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
@@ -156,27 +156,35 @@ function AssignTaskPopout({ action, details, situation, familyDetails }) {
}; };
useEffect(() => { useEffect(() => {
let checkFamilyTask = true;
const reqData = { const reqData = {
limit: 30, limit: 30,
offset: 0, offset: 0,
job_type: "FAMILY", job_type: "FAMILY",
action: 13005, action: 13005,
}; };
apiCall apiCall
.getMyJobList(reqData) .getMyJobList(reqData)
.then((res) => { .then((res) => {
setFamilyTask({ loading: false, data: res?.data?.result_list }); if (checkFamilyTask) {
if (res?.data?.result_list?.length) { setFamilyTask({ loading: false, data: res?.data?.result_list });
setActiveTask((prev) => ({ if (res?.data?.result_list?.length) {
...prev, setActiveTask((prev) => ({
data: res?.data?.result_list[0], ...prev,
})); data: res?.data?.result_list[0],
}));
}
} }
}) })
.catch((err) => { .catch((err) => {
setFamilyTask({ loading: false, data: [] }); setFamilyTask({ loading: false, data: [] });
console.log("Error", err); console.log("Error", err);
}); });
return () => {
checkFamilyTask = false;
};
}, []); }, []);
return ( return (
@@ -428,6 +436,6 @@ function AssignTaskPopout({ action, details, situation, familyDetails }) {
</ModalCom> </ModalCom>
</> </>
); );
} })
export default AssignTaskPopout; export default AssignTaskPopout;
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import usersService from "../../../../services/UsersService"; import usersService from "../../../../services/UsersService";
import InputCom from "../../../Helpers/Inputs/InputCom"; import InputCom from "../../../Helpers/Inputs/InputCom";
// const DEFAULT_IMAGE =
export default function NewTasks({ formState, setFormState }) { export default function NewTasks({ formState, setFormState }) {
let [currency, setCurrency] = useState({ let [currency, setCurrency] = useState({
loading: true, loading: true,
-3
View File
@@ -8,10 +8,7 @@ import PaginatedList from "../Pagination/PaginatedList";
import familyImage from '../../assets/images/no-family-side.png' import familyImage from '../../assets/images/no-family-side.png'
export default function FamilyTable({ className, familyList, loader, popUpHandler }) { export default function FamilyTable({ className, familyList, loader, popUpHandler }) {
const filterCategories = ["All Categories", "Explore", "Featured"];
const [selectedCategory, setCategory] = useState(filterCategories[0]);
const navigate = useNavigate(); const navigate = useNavigate();
// let location = useLocation();
const [currentPage, setCurrentPage] = useState(0); const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage); const indexOfFirstItem = Number(currentPage);
+49 -49
View File
@@ -1,56 +1,56 @@
import { forwardRef } from 'react' import { forwardRef } from "react";
import QRCode from 'react-qr-code'; import QRCode from "react-qr-code";
const FamilyAccount = forwardRef(({ familyData, myRef, handlePrint }, ref) => { const FamilyAccount = forwardRef(({ familyData, myRef, handlePrint }, ref) => {
return ( return (
<div <div
className="w-full lg:min-h-[500px] h-full flex flex-col items-center justify-center" className="w-full lg:min-h-[500px] h-full flex flex-col items-center justify-center"
ref={myRef} ref={myRef}
> >
<div className="update-table w-full lg:min-h-[450px] h-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow "> <div className="update-table w-full lg:min-h-[450px] h-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow ">
<div className="flex items-center justify-around h-[380px]"> <div className="flex items-center justify-around h-[380px]">
<div className="flex flex-col"> <div className="flex flex-col">
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize"> <h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
Username:{" "} Username:{" "}
<span className="ml-2 normal-case"> <span className="ml-2 normal-case">
{familyData?.username ? familyData?.username : "please wait..."} {familyData?.username ? familyData?.username : "please wait..."}
</span> </span>
</h2> </h2>
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize"> <h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
Pin:{" "} Pin:{" "}
<span className="ml-2 normal-case"> <span className="ml-2 normal-case">
{familyData?.pin ? familyData?.pin : "please wait..."} {familyData?.pin ? familyData?.pin : "please wait..."}
</span> </span>
</h2> </h2>
</div>
<span className="text-5xl text-gray-400 opacity-20 font-bold">
or
</span>
<div className="max-w-[200px]">
<p className="text-xl tracking-wide mb-[15px] text-center font-bold text-dark-gray dark:text-white">
Scan the code from mobile app
</p>
<QRCode
size={256}
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
value={`https://www.google.com`}
viewBox={`0 0 256 256`}
/>
</div>
</div> </div>
<div className="h-[50px] w-full flex justify-center items-center">
<button <span className="text-5xl text-gray-400 opacity-20 font-bold">
className="btn-shine w-[116px] h-[46px] text-white rounded-full text-base bg-pink flex justify-center items-center" or
onClick={handlePrint} </span>
>
Print <div className="max-w-[200px]">
</button> <p className="text-xl tracking-wide mb-[15px] text-center font-bold text-dark-gray dark:text-white">
Scan the code from mobile app
</p>
<QRCode
size={256}
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
value={`https://www.google.com`}
viewBox={`0 0 256 256`}
/>
</div> </div>
</div> </div>
<div className="h-[50px] w-full flex justify-center items-center">
<button
className="btn-shine w-[116px] h-[46px] text-white rounded-full text-base bg-pink flex justify-center items-center"
onClick={handlePrint}
>
Print
</button>
</div>
</div> </div>
); </div>
}); );
});
export default FamilyAccount export default FamilyAccount;
@@ -1,4 +1,4 @@
import { useState } from "react"; import { useMemo, useState } from "react";
import { PaginatedList, handlePagingFunc } from "../../Pagination"; import { PaginatedList, handlePagingFunc } from "../../Pagination";
import { PriceFormatter } from "../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../Helpers/PriceFormatter";
import dataImage2 from "../../../assets/images/data-table-user-2.png"; import dataImage2 from "../../../assets/images/data-table-user-2.png";
@@ -13,8 +13,12 @@ export default function FamilyPending({
}) { }) {
let [jobPopout, setJobPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW let [jobPopout, setJobPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW
let filteredFamilyData = familyData?.result_list?.filter( let filteredFamilyData = useMemo(
(data) => data?.family_uid === accountDetails?.family_uid () =>
familyData?.result_list?.filter(
(data) => data?.family_uid === accountDetails?.family_uid
),
[accountDetails?.family_uid, familyData?.result_list]
); );
const [currentPage, setCurrentPage] = useState(0); const [currentPage, setCurrentPage] = useState(0);
@@ -51,7 +55,7 @@ export default function FamilyPending({
value?.currency_code, value?.currency_code,
value?.currency value?.currency
); );
let image = value.banner ? value.banner : 'default.jpg' let image = value.banner ? value.banner : "default.jpg";
return ( return (
<tr <tr
key={index} key={index}
@@ -61,7 +65,9 @@ export default function FamilyPending({
<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/${image}`)} src={localImgLoad(
`images/taskbanners/${image}`
)}
alt="data" alt="data"
className="w-full h-full rounded-full" className="w-full h-full rounded-full"
/> />
@@ -1,31 +1,50 @@
import { useState } from "react"; import { useState, useMemo, memo } from "react";
import { handlePagingFunc, PaginatedList } from "../../Pagination"; import { handlePagingFunc, PaginatedList } from "../../Pagination";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; import LoadingSpinner from "../../Spinners/LoadingSpinner";
import SuggestTask from "../../FamilyPopup/SuggestTask"; import SuggestTask from "../../FamilyPopup/SuggestTask";
import AssignTaskPopout from "../FamilyPopout/AssignTaskPopout"; import AssignTaskPopout from "../FamilyPopout/AssignTaskPopout";
const FamilyWaitlist = ({ familyData, className, accountDetails, loader }) => { const FamilyWaitlist = memo(({ familyData, className, accountDetails, loader }) => {
const [popUp, setPopUp] = useState({ show: false, data: {} }); const [popUp, setPopUp] = useState({ show: false, data: {} });
const [continueTaskPopup, setContinueTaskPopup] = useState({ const [continueTaskPopup, setContinueTaskPopup] = useState({
show: false, show: false,
data: {}, data: {},
}); });
const filteredFamilyData = useMemo(
let filteredFamilyData = familyData?.result_list?.filter( () =>
(data) => data?.family_uid === accountDetails?.family_uid familyData?.result_list?.filter(
(data) => data?.family_uid === accountDetails?.family_uid
),
[familyData, accountDetails]
); );
const [currentPage, setCurrentPage] = useState(0); const [currentPage, setCurrentPage] = useState(0);
const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE); const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE);
const indexOfFirstItem = currentPage; const indexOfFirstItem = currentPage;
const indexOfLastItem = currentPage + itemsPerPage; const indexOfLastItem = currentPage + itemsPerPage;
const currentTask = filteredFamilyData?.slice( const currentTask = useMemo(
indexOfFirstItem, () => filteredFamilyData?.slice(indexOfFirstItem, indexOfLastItem),
indexOfLastItem [filteredFamilyData, indexOfFirstItem, indexOfLastItem]
); );
const handlePagination = (e) => handlePagingFunc(e, setCurrentPage); const handlePagination = (e) => handlePagingFunc(e, setCurrentPage);
const openPopUp = (value) => {
setPopUp({ show: true, data: { ...value } });
};
const closePopUp = () => {
setPopUp({ show: false, data: {} });
};
const openContinueTaskPopup = (value) => {
setContinueTaskPopup({ show: true, data: { ...value } });
};
const closeContinueTaskPopup = () => {
setContinueTaskPopup({ show: false, data: {} });
};
return ( return (
<div <div
className={`update-table w-full bg-white dark:bg-dark-white h-full lg:min-h-[450px] overflow-hidden rounded-2xl section-shadow ${ className={`update-table w-full bg-white dark:bg-dark-white h-full lg:min-h-[450px] overflow-hidden rounded-2xl section-shadow ${
@@ -83,12 +102,7 @@ const FamilyWaitlist = ({ familyData, className, accountDetails, loader }) => {
</td> </td>
<td className="text-right py-4 px-2"> <td className="text-right py-4 px-2">
<button <button
onClick={() => onClick={() => openPopUp(value)}
setPopUp({
show: true,
data: { ...value, selectedImage },
})
}
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"
> >
View View
@@ -114,28 +128,21 @@ const FamilyWaitlist = ({ familyData, className, accountDetails, loader }) => {
{popUp.show && ( {popUp.show && (
<SuggestTask <SuggestTask
details={popUp.data} details={popUp.data}
onClose={() => { onClose={closePopUp}
setPopUp({ show: false, data: {} }); continuePopupData={openContinueTaskPopup}
}}
continuePopupData={(value) =>
setContinueTaskPopup({ show: true, data: { ...value } })
}
situation={popUp.show} situation={popUp.show}
/> />
)} )}
{/* Continue Task */}
{continueTaskPopup.show && ( {continueTaskPopup.show && (
<AssignTaskPopout <AssignTaskPopout
details={continueTaskPopup.data} details={continueTaskPopup.data}
action={() => { action={closeContinueTaskPopup}
setContinueTaskPopup({ show: false, data: {} });
}}
situation={continueTaskPopup.show} situation={continueTaskPopup.show}
/> />
)} )}
</div> </div>
); );
}; });
export default FamilyWaitlist; export default FamilyWaitlist;
+46 -39
View File
@@ -1,9 +1,16 @@
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, {
Suspense,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import InputCom from "../Helpers/Inputs/InputCom"; import InputCom from "../Helpers/Inputs/InputCom";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
import FamilyTable from "./FamilyTable"; import FamilyTable from "./FamilyTable";
import SiteService from "../../services/SiteService"; import SiteService from "../../services/SiteService";
import ModalCom from "../Helpers/ModalCom"; import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
export default function FamilyAcc() { export default function FamilyAcc() {
const [selectTab, setValue] = useState("today"); const [selectTab, setValue] = useState("today");
@@ -20,60 +27,50 @@ export default function FamilyAcc() {
const apiCall = useMemo(() => new SiteService(), []); const apiCall = useMemo(() => new SiteService(), []);
// This is to make sure it's called once and used everywhere
let memberId = localStorage.getItem("member_id");
let uid = localStorage.getItem("uid");
let sessionId = localStorage.getItem("session_token");
const popUpHandler = () => { const popUpHandler = () => {
setPopUp((prev) => !prev); setPopUp((prev) => !prev);
}; };
// tab handler
const filterHandler = (value) => { const filterHandler = (value) => {
setValue(value); setValue(value);
}; };
// For the age drop down const ageRange = useMemo(() => {
let startAge = 5; const startAge = 5;
let endAge = 16; const endAge = 16;
// creates an array of age values ranging from 16 to 70 return Array.from(
const ageRange = Array.from( { length: endAge - startAge + 1 },
{ length: endAge - startAge + 1 }, (_, index) => startAge + index
(_, index) => startAge + index );
); }, []);
// age handler
const handleAgeSelect = (event) => { const handleAgeSelect = (event) => {
setSelectedAge(parseInt(event.target.value)); setSelectedAge(parseInt(event.target.value));
}; };
// Input handler
const handleInputChange = (event) => { const handleInputChange = (event) => {
const { name, value } = event?.target; const { name, value } = event?.target;
setFormData({ ...formData, [name]: value }); setFormData((prevFormData) => ({ ...prevFormData, [name]: value }));
}; };
// Add member
const addMember = async () => { const addMember = async () => {
const { first_name, last_name } = formData; const { first_name, last_name } = formData;
setLoader(true); setLoader(true);
try { try {
if (first_name !== "" && last_name !== "") { if (first_name !== "" && last_name !== "") {
let reqData = { const reqData = {
member_id: memberId,
uid: uid,
session_id: sessionId,
firstname: first_name, firstname: first_name,
lastname: last_name, lastname: last_name,
age: selectedAge, age: selectedAge,
}; };
let res = await apiCall.addFamily(reqData); const res = await apiCall.addFamily(reqData);
const { data } = res; const { data } = res;
if (data?.internal_return > 0 && data?.status == "OK") { if (data?.internal_return > 0 && data?.status === "OK") {
setLoader(false); setLoader(false);
setListReload((prev) => !prev); setListReload((prev) => !prev);
popUpHandler() popUpHandler();
} else { } else {
setLoader(false); setLoader(false);
setMsgErr("Sorry, something went wrong"); setMsgErr("Sorry, something went wrong");
@@ -94,38 +91,42 @@ export default function FamilyAcc() {
first_name: "", first_name: "",
last_name: "", last_name: "",
}); });
setSelectedAge("") setSelectedAge("");
} }
}; };
// member listing
const memberList = useCallback(async () => { const memberList = useCallback(async () => {
setLoader(true); setLoader(true);
try { try {
let reqData = { const reqData = {
member_id: memberId,
uid: uid,
session_id: sessionId,
limit: 20, limit: 20,
offset: 0, offset: 0,
action: 22010, action: 22010,
}; };
let res = await apiCall.familyListings(reqData); const res = await apiCall.familyListings(reqData);
const { data } = res; const { data } = res;
if (data?.internal_return >= 0 && data?.status == "OK") { if (data?.internal_return >= 0 && data?.status === "OK") {
let { result_list } = data; const { result_list } = data;
setFamilyList(result_list); setFamilyList(result_list);
setLoader(false); setLoader(false);
} else return; } else {
return;
}
} catch (error) { } catch (error) {
setLoader(false); setLoader(false);
throw new Error(error); throw new Error(error);
} }
}, [apiCall, memberId, sessionId, uid]); }, [apiCall]);
useEffect(() => { useEffect(() => {
memberList(); let checkMemberList = true;
if (checkMemberList) {
memberList();
}
return () => {
checkMemberList = false;
};
}, [listReload, memberList]); }, [listReload, memberList]);
return ( return (
@@ -158,7 +159,13 @@ export default function FamilyAcc() {
></div> ></div>
</div> </div>
</div> </div>
<FamilyTable familyList={familyList} loader={loader} popUpHandler={popUpHandler} /> <Suspense fallback={<LoadingSpinner color="sky-blue" size="16" />}>
<FamilyTable
familyList={familyList}
loader={loader}
popUpHandler={popUpHandler}
/>
</Suspense>
</div> </div>
</div> </div>
{popUp && ( {popUp && (
+4 -2
View File
@@ -31,6 +31,7 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
const handleSuggestedTask = async (values) => { const handleSuggestedTask = async (values) => {
if (!values.title && !values.description) return; if (!values.title && !values.description) return;
try { try {
setSubmitTask({ loading: true }); setSubmitTask({ loading: true });
const reqData = { ...values }; const reqData = { ...values };
@@ -195,7 +196,8 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
role="group" role="group"
key={idx} key={idx}
htmlFor={`parent-suggested-${idx}`} htmlFor={`parent-suggested-${idx}`}
className={`transition duration-150 ease-in-out parent-suggest`} className={`transition duration-150 ease-in-out parent-suggest group cursor-pointer`}
onClick={() => setSuggestedNextStep(title)}
> >
<input <input
type="radio" type="radio"
@@ -203,7 +205,7 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
value={title} value={title}
checked={suggestedNextStep === title} checked={suggestedNextStep === title}
onChange={switchNextStep} onChange={switchNextStep}
className={`transition duration-150 ease-in-out parent-suggest`} className={`transition duration-150 ease-in-out parent-suggest pointer-events-none`}
/> />
<span <span
onClick={() => setSuggestedNextStep(title)} onClick={() => setSuggestedNextStep(title)}
+12 -74
View File
@@ -39,7 +39,7 @@ export default function WalletItemCard({walletItem}) {
Current Balance Current Balance
</p> </p>
<p className="text-[44px] font-bold text-white tracking-wide leading-10 mb-2"> <p className="text-[44px] font-bold text-white tracking-wide leading-10 mb-2">
{PriceFormatter(walletItem.amount * 0.01, walletItem.code)} {walletItem.amount * 0.01} {walletItem.code}
</p> </p>
<p className="text-lg text-white tracking-wide"> <p className="text-lg text-white tracking-wide">
HOLDINGS : {PriceFormatter(walletItem.escrow * 0.01, walletItem.code)} HOLDINGS : {PriceFormatter(walletItem.escrow * 0.01, walletItem.code)}
@@ -47,11 +47,14 @@ export default function WalletItemCard({walletItem}) {
</p> </p>
</div> </div>
<div className="counters flex space-x-16"> <div className="counters flex space-x-16">
{ <div>
walletItem.action_type != 'AC_AD_FD_ONLY' ? {
<Link to='transfer-fund' className='px-2 py-1 flex items-center gap-2 user-balance cursor-pointer h-[40px] rounded-full relative bg-purple lg:text-xl text-lg font-bold text-white'>Transfer</Link>:'' walletItem.action_type != 'AC_AD_FD_ONLY' ?
} <Link to='transfer-fund' className='px-2 py-1 flex items-center gap-2 user-balance cursor-pointer h-[40px] rounded-full relative bg-purple lg:text-xl text-lg font-bold text-white'>Transfer</Link>:''
<Link to='add-fund' state={{currency:walletItem.description}} className='px-2 py-1 flex items-center gap-2 user-balance cursor-pointer h-[40px] rounded-full relative bg-white lg:text-xl text-lg font-bold'> }
</div>
<div>
<Link to='add-fund' state={{currency:walletItem.description}} className='px-2 py-1 flex items-center gap-2 user-balance cursor-pointer h-[40px] rounded-full relative bg-white lg:text-xl text-lg font-bold'>
<span className=""> <span className="">
<svg xmlns="http://www.w3.org/2000/svg" width="38" <svg xmlns="http://www.w3.org/2000/svg" width="38"
height="38" viewBox="0 0 42 42" fill="none"><path height="38" viewBox="0 0 42 42" fill="none"><path
@@ -59,75 +62,10 @@ export default function WalletItemCard({walletItem}) {
fill="white"></path> fill="white"></path>
</svg> </svg>
</span> </span>
<span className='text-black'>Add Credit</span> <span className='text-black'>Add Credit</span>
</Link> </Link>
</div>
{/*<div className="circle-count">*/}
{/* <div>*/}
{/* <div className="percent">*/}
{/* <svg>*/}
{/* <circle cx="37" cy="37" r="30"></circle>*/}
{/* <circle*/}
{/* cx="37"*/}
{/* cy="37"*/}
{/* r="30"*/}
{/* style={{ "--percent": `${eth}` }}*/}
{/* ></circle>*/}
{/* </svg>*/}
{/* <div className="number">*/}
{/* <h3>*/}
{/* {eth}*/}
{/* <span>%</span>*/}
{/* </h3>*/}
{/* </div>*/}
{/* </div>*/}
{/* <p className="text-18 text-white text-center">2.32 ETH</p>*/}
{/* </div>*/}
{/*</div>*/}
{/*<div className="circle-count">*/}
{/* <div>*/}
{/* <div className="percent">*/}
{/* <svg>*/}
{/* <circle cx="37" cy="37" r="30"></circle>*/}
{/* <circle*/}
{/* cx="37"*/}
{/* cy="37"*/}
{/* r="30"*/}
{/* style={{ "--percent": `${btc}` }}*/}
{/* ></circle>*/}
{/* </svg>*/}
{/* <div className="number">*/}
{/* <h3>*/}
{/* {btc}*/}
{/* <span>%</span>*/}
{/* </h3>*/}
{/* </div>*/}
{/* </div>*/}
{/* <p className="font-18 text-white text-center">1.76 BTC</p>*/}
{/* </div>*/}
{/*</div>*/}
{/*<div className="circle-count">*/}
{/* <div>*/}
{/* <div className="percent">*/}
{/* <svg>*/}
{/* <circle cx="37" cy="37" r="30"></circle>*/}
{/* <circle*/}
{/* cx="37"*/}
{/* cy="37"*/}
{/* r="30"*/}
{/* style={{ "--percent": `${ltc}` }}*/}
{/* ></circle>*/}
{/* </svg>*/}
{/* <div className="number">*/}
{/* <h3>*/}
{/* {ltc}*/}
{/* <span>%</span>*/}
{/* </h3>*/}
{/* </div>*/}
{/* </div>*/}
{/* <p className="text-18 text-white text-center">2.32 LTC</p>*/}
{/* </div>*/}
{/*</div>*/}
</div> </div>
</div> </div>
); );
@@ -11,6 +11,11 @@ import ReferralTable from "../MyWallet/WalletComponent/ReferralTable";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
ref_email: Yup.string() ref_email: Yup.string()
.email("Wrong email format") .email("Wrong email format")
.matches(
// /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/,
/^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
"Invalid email format"
)
.min(3, "Minimum 3 characters") .min(3, "Minimum 3 characters")
.max(50, "Maximum 50 characters") .max(50, "Maximum 50 characters")
.required("Email is required"), .required("Email is required"),
@@ -14,6 +14,11 @@ import * as Yup from "yup";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
email: Yup.string() email: Yup.string()
.email("Wrong email format") .email("Wrong email format")
.matches(
// /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/,
/^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
"Invalid email format"
)
.min(3, "Minimum 3 characters") .min(3, "Minimum 3 characters")
.max(50, "Maximum 50 characters") .max(50, "Maximum 50 characters")
.required("Email is required"), .required("Email is required"),
@@ -96,7 +101,7 @@ export default function PersonalInfoTab({
// setRequestState({message: 'Profile update successfully', loading: false, status: true}) // setRequestState({message: 'Profile update successfully', loading: false, status: true})
toast.success("Update Successful"); toast.success("Update Successful");
setTimeout(() => { setTimeout(() => {
navigate("/", { replace: true }); // navigate("/", { replace: true });
window.location.reload(true); window.location.reload(true);
}, 1000); }, 1000);
}) })
+3 -1
View File
@@ -18,7 +18,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
const { jobListTable } = useSelector((state) => state.tableReload); const { jobListTable } = useSelector((state) => state.tableReload);
const { userDetails:{loggedIn} } = useSelector((state) => state?.userDetails); // CHECKS IF LOGGEDIN IS TRUE const { userDetails:{username, uid} } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = username && uid ? true : false // variable to determine if user is logged in
useEffect(() => { useEffect(() => {
//Removing Data stored at localStorage after session expires //Removing Data stored at localStorage after session expires
+21
View File
@@ -853,6 +853,27 @@ class usersService {
return this.postAuxEnd("/offerinterestlistmsg", postData); return this.postAuxEnd("/offerinterestlistmsg", postData);
} }
// TO ADD FAMILY
addFamily(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/familyadd", postData);
}
familyListings(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/familylist", postData);
}
// FUNCTION TO ASSIGN TASK TO FAMILY MEMBER // FUNCTION TO ASSIGN TASK TO FAMILY MEMBER
assignFamilyTask(reqData) { assignFamilyTask(reqData) {
var postData = { var postData = {
+5 -5
View File
@@ -1,9 +1,9 @@
import FamilyAcc from "../components/FamilyAcc"; import FamilyAcc from "../components/FamilyAcc";
export default function FamilyAccPage() { export default function FamilyAccPage() {
return ( return (
<> <>
<FamilyAcc /> <FamilyAcc />
</> </>
); );
} }