Compare commits

...

20 Commits

Author SHA1 Message Date
victorAnumudu 119f48642d implemented multi file upload 2023-06-05 02:48:22 +01:00
ameye 1a0f97030f Merge branch 'market-item-view-popup' of WrenchBoard/Users-Wrench into master 2023-06-05 01:08:38 +00:00
CHIEFSOFT\ameye 71d1b61bbd Single file send 2023-06-04 17:43:38 -04:00
Ebube 17ffe957e8 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into market-item-view-popup 2023-06-04 20:40:18 +01:00
Ebube e23aa95685 . 2023-06-04 20:32:29 +01:00
ameye 1c1293989b Merge branch 'width-adjustment' of WrenchBoard/Users-Wrench into master 2023-06-04 18:27:25 +00:00
victorAnumudu 63448429b2 width adjusted 2023-06-04 19:14:08 +01:00
ameye 8d1eac9ff6 Merge branch 'familytasks' of WrenchBoard/Users-Wrench into master 2023-06-04 17:21:21 +00:00
Ebube 25e5c3f47a Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into familytasks 2023-06-04 15:01:03 +01:00
Ebube 9f9c36ec85 . 2023-06-04 14:59:54 +01:00
CHIEFSOFT\ameye 05eb1a020d Activities on home page 2023-06-04 08:40:38 -04:00
ameye 30d344833c Merge branch 'pending-jobs-pop-apis' of WrenchBoard/Users-Wrench into master 2023-06-04 12:14:58 +00:00
CHIEFSOFT\ameye acdf167a69 List page 2023-06-03 22:56:27 -04:00
Ebube fd00113aab Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into pending-jobs-pop-apis 2023-06-04 02:23:49 +01:00
Ebube 8765329256 . 2023-06-04 02:13:00 +01:00
Ebube 3b9c0987b8 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into pending-jobs-pop-apis 2023-06-04 00:40:05 +01:00
Ebube 0304eaa328 . 2023-06-04 00:39:17 +01:00
ameye 85ac8d183c Merge branch 'fileupload_implementation' of WrenchBoard/Users-Wrench into master 2023-06-03 16:26:04 +00:00
Ebube 18b85e0ec9 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into pending-jobs-pop-apis 2023-06-03 17:08:13 +01:00
Ebube 024c8bbed1 . 2023-06-03 17:07:34 +01:00
16 changed files with 660 additions and 1183 deletions
+1
View File
@@ -18,6 +18,7 @@ REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=300000
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
REACT_APP_SESSION_EXPIRE_CHECKER=60000
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
+1
View File
@@ -18,6 +18,7 @@ REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=300000
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
REACT_APP_SESSION_EXPIRE_CHECKER=60000
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
+1
View File
@@ -18,6 +18,7 @@ REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/svs/user"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=300000
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
REACT_APP_SESSION_EXPIRE_CHECKER=60000
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
+40 -25
View File
@@ -1,44 +1,59 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import Layout from "../Partials/Layout";
import FamilyManageTabs from "./FamilyManageTabs";
import { useLocation } from "react-router-dom";
import FamilyManageTabs from "./Tabs/FamilyManageTabs";
import { useLocation, useNavigate } from "react-router-dom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
export default function FamilyManage() {
const [selectTab, setValue] = useState("today");
let [pageLoading, setPageLoading] = useState(true);
let location = useLocation();
let accountDetails = location?.state
let navigate = useNavigate();
let accountDetails = location?.state;
// tab handler
const filterHandler = (value) => {
setValue(value);
};
useEffect(() => {
if (!accountDetails) {
navigate("/acc-family", { replace: true });
} else {
setPageLoading(false);
}
}, []);
return (
<Layout>
{/*<CommonHead />*/}
<div className="notification-page w-full mb-10">
<div className="notification-wrapper w-full">
{/* heading */}
<div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0">
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
Manage Family
</span>
</h1>
</div>
<div className="slider-btns flex space-x-4">
<div
onClick={() => filterHandler("today")}
className="relative"
></div>
{pageLoading ? (
<LoadingSpinner size={8} color="sky-blue" />
) : (
<div className="notification-page w-full mb-10">
<div className="notification-wrapper w-full">
{/* heading */}
<div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0">
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
Manage Family
</span>
</h1>
</div>
<div className="slider-btns flex space-x-4">
<div
onClick={() => filterHandler("today")}
className="relative"
></div>
</div>
</div>
<FamilyManageTabs accountDetails={accountDetails} />
</div>
<FamilyManageTabs accountDetails={accountDetails} />
</div>
</div>
)}
</Layout>
);
}
}
-127
View File
@@ -1,127 +0,0 @@
import React, { useState } from "react";
import dataImage1 from "../../assets/images/data-table-user-1.png";
import dataImage2 from "../../assets/images/data-table-user-2.png";
import dataImage3 from "../../assets/images/data-table-user-3.png";
import dataImage4 from "../../assets/images/data-table-user-4.png";
import SelectBox from "../Helpers/SelectBox";
import PaginatedList from "../Pagination/PaginatedList";
import { handlePagingFunc } from "../Pagination/HandlePagination";
export default function FamilyTasks({ className }) {
const filterCategories = ["All Categories", "Explore", "Featured"];
const [selectedCategory, setCategory] = useState(filterCategories[0]);
let data = ['1', '2', '3', '4', '5', '6'] // to be replaced later by result from API CALL
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem = Number(indexOfFirstItem)+Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentTask = data.slice(indexOfFirstItem, indexOfLastItem);
const handlePagination = (e) => {
handlePagingFunc(e,setCurrentPage)
}
return (
<div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow ${
className || ""
}`}
>
{data.length &&
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
<table className="table-auto w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<tr className="text-base text-thin-light-gray border-b default-border-b dark:border-[#5356fb29] ottom ">
<td className="py-4">All Product</td>
<td className="py-4 text-center">Value</td>
<td className="py-4 text-center">USD</td>
<td className="py-4 text-right">Status</td>
</tr>
{
currentTask.map((item,index)=>(
<tr key={index} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
<td className=" py-4">
<div className="flex space-x-2 items-center">
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
<img
src={dataImage3}
alt="data"
className="w-full h-full"
/>
</div>
<div className="flex flex-col">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
Mullican Computer Joy
</h1>
<span className="text-sm text-thin-light-gray">
Owned by <span className="text-purple">Xoeyam</span>
</span>
</div>
</div>
</td>
<td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center">
<span className="text-base text-dark-gray dark:text-white font-medium">
7473 ETH
</span>
</div>
</td>
<td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center">
<span>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.55225 0C7.8457 0 8.13914 0 8.43205 0C8.44829 0.026534 8.47537 0.0151623 8.49756 0.0162453C9.28966 0.0649812 10.0606 0.220936 10.8013 0.505229C12.7699 1.26172 14.2323 2.58354 15.183 4.46638C15.5999 5.29218 15.8506 6.16997 15.9561 7.08891C15.9691 7.201 15.9621 7.3158 16 7.42465C16 7.80858 16 8.19251 16 8.57698C15.9778 8.5916 15.9854 8.61543 15.9838 8.63546C15.9475 9.10387 15.8744 9.56686 15.7515 10.0206C15.1787 12.1342 13.9524 13.7603 12.0818 14.8942C11.1516 15.4579 10.1397 15.8002 9.06064 15.941C8.89497 15.9626 8.72875 15.98 8.56308 15.9995C8.17217 15.9995 7.78127 15.9995 7.39036 16C7.3752 15.9789 7.35138 15.9865 7.33135 15.9848C6.96752 15.9545 6.60639 15.9009 6.25068 15.8197C4.77639 15.4829 3.48998 14.793 2.4131 13.7311C0.998917 12.3372 0.204656 10.6461 0.0270709 8.66687C0.0205739 8.59431 0.033568 8.51904 0 8.44972C0 8.15081 0 7.85244 0 7.55352C0.0265295 7.53403 0.0151597 7.50479 0.016784 7.47988C0.0730915 6.64162 0.251218 5.83044 0.564158 5.05066C1.10179 3.71043 1.93774 2.59058 3.07634 1.70142C4.33839 0.715876 5.77098 0.159745 7.36762 0.0270755C7.4288 0.0216604 7.49432 0.0341151 7.55225 0ZM7.24635 9.86252C7.24635 10.2383 7.24526 10.6147 7.24743 10.9905C7.24797 11.0457 7.23389 11.0679 7.17596 11.0593C7.09691 11.0479 7.01678 11.0446 6.93774 11.0338C6.26746 10.9461 5.63563 10.7371 5.03952 10.4192C5.00379 10.4002 4.97834 10.3802 4.9621 10.4425C4.81375 11.0176 4.66324 11.5926 4.51164 12.1666C4.50027 12.2094 4.51272 12.2278 4.54954 12.2473C4.66486 12.3096 4.78235 12.3665 4.90309 12.4152C5.5961 12.6968 6.31998 12.8408 7.06497 12.8842C7.14131 12.8885 7.16134 12.9112 7.1608 12.9865C7.15701 13.4159 7.16026 13.8453 7.15809 14.2747C7.15755 14.3397 7.17488 14.3619 7.2431 14.3614C7.69085 14.3581 8.13914 14.3576 8.5869 14.3614C8.66432 14.3619 8.67731 14.3359 8.67731 14.2666C8.67461 13.8026 8.67677 13.3385 8.67461 12.8744C8.67407 12.8089 8.68544 12.7786 8.76015 12.765C9.09962 12.7049 9.4288 12.6058 9.74228 12.4607C10.3498 12.1802 10.8408 11.7703 11.1603 11.1724C11.4288 10.6699 11.51 10.1327 11.4618 9.56957C11.4158 9.03239 11.2366 8.55207 10.8787 8.14431C10.5506 7.77121 10.1402 7.51129 9.69843 7.29522C9.39145 7.14523 9.07363 7.02284 8.75041 6.91129C8.7098 6.89721 8.67407 6.88693 8.67407 6.82736C8.67623 6.14993 8.67569 5.4725 8.67461 4.79507C8.67461 4.75121 8.68489 4.73117 8.73308 4.73767C8.87547 4.75717 9.01895 4.77016 9.16134 4.79236C9.634 4.86493 10.0796 5.02467 10.5116 5.22395C10.5717 5.25157 10.5945 5.24886 10.6123 5.17684C10.7434 4.6467 10.8771 4.1171 11.0162 3.58913C11.0379 3.5079 11.0244 3.47541 10.948 3.44076C10.2799 3.13751 9.57282 3.01025 8.8457 2.97614C8.78018 2.97289 8.76123 2.95556 8.76178 2.88896C8.76503 2.50232 8.76232 2.11568 8.76448 1.72904C8.76503 1.66785 8.75041 1.64727 8.68489 1.64727C8.23173 1.64998 7.77802 1.64998 7.32485 1.64727C7.26151 1.64673 7.24418 1.66406 7.24418 1.72742C7.24689 2.1433 7.24256 2.55972 7.24797 2.9756C7.24905 3.06116 7.2209 3.08661 7.14239 3.10285C6.73579 3.18679 6.34651 3.32271 5.98646 3.53281C5.20628 3.98822 4.72117 4.64724 4.61938 5.5586C4.51597 6.48837 4.83812 7.2427 5.57661 7.81778C6.05739 8.19251 6.60639 8.43781 7.1738 8.64683C7.2274 8.66633 7.24743 8.68907 7.24689 8.7481C7.24472 9.12066 7.24635 9.49159 7.24635 9.86252Z"
fill="#59BE59"
/>
<path
d="M7.2452 9.86252C7.2452 9.49158 7.24358 9.12119 7.24683 8.75026C7.24737 8.69123 7.22734 8.66903 7.17374 8.64899C6.60687 8.43997 6.05787 8.19467 5.57655 7.81994C4.8386 7.24486 4.51591 6.49053 4.61933 5.56076C4.72057 4.6494 5.20568 3.99092 5.98641 3.53497C6.34645 3.32486 6.73519 3.18894 7.14233 3.10501C7.22084 3.08876 7.24899 3.06277 7.24791 2.97775C7.2425 2.56187 7.24683 2.14545 7.24412 1.72957C7.24358 1.66621 7.2609 1.64888 7.32479 1.64943C7.77796 1.65213 8.23167 1.65213 8.68483 1.64943C8.7498 1.64888 8.76442 1.66946 8.76442 1.73119C8.76171 2.11783 8.76496 2.50447 8.76171 2.89111C8.76117 2.95717 8.78012 2.97504 8.84563 2.97829C9.57276 3.01295 10.2793 3.13966 10.948 3.44291C11.0243 3.47757 11.0373 3.51006 11.0162 3.59128C10.877 4.11926 10.7433 4.64885 10.6123 5.17899C10.5944 5.25156 10.5717 5.25372 10.5116 5.2261C10.079 5.02683 9.63394 4.86708 9.16128 4.79452C9.01889 4.77286 8.87595 4.75932 8.73302 4.73983C8.68483 4.73333 8.67455 4.75337 8.67455 4.79723C8.67563 5.47466 8.67617 6.15209 8.674 6.82952C8.674 6.88908 8.70974 6.89937 8.75034 6.91345C9.07303 7.02446 9.39138 7.14684 9.69837 7.29738C10.1396 7.51344 10.5506 7.77283 10.8787 8.14647C11.2365 8.55369 11.4157 9.03455 11.4618 9.57173C11.51 10.1349 11.4287 10.6726 11.1602 11.1746C10.8408 11.7724 10.3497 12.1818 9.74222 12.4629C9.42874 12.608 9.09956 12.7071 8.76009 12.7672C8.68483 12.7802 8.674 12.811 8.67455 12.8766C8.67671 13.3406 8.67455 13.8047 8.67725 14.2688C8.67779 14.3381 8.66426 14.3646 8.58684 14.3636C8.13908 14.3598 7.69079 14.3608 7.24304 14.3636C7.17536 14.3641 7.15803 14.3424 7.15803 14.2769C7.1602 13.8475 7.15695 13.4181 7.16074 12.9887C7.16128 12.9128 7.14179 12.8906 7.06491 12.8863C6.31992 12.843 5.59658 12.699 4.90303 12.4174C4.78229 12.3681 4.66426 12.3112 4.54948 12.2495C4.51321 12.23 4.50075 12.2116 4.51158 12.1688C4.66318 11.5943 4.81369 11.0197 4.96204 10.4446C4.97829 10.3824 5.00373 10.4024 5.03947 10.4214C5.63557 10.7387 6.2674 10.9477 6.93768 11.036C7.01672 11.0463 7.09685 11.0501 7.1759 11.0614C7.23383 11.0695 7.24737 11.0479 7.24737 10.9927C7.24412 10.6147 7.2452 10.2383 7.2452 9.86252ZM8.68537 9.36325C8.67942 9.37245 8.67455 9.37678 8.67455 9.38112C8.674 9.83978 8.67401 10.2984 8.67292 10.7571C8.67292 10.8177 8.70216 10.7928 8.72598 10.7755C8.82452 10.7046 8.90736 10.619 8.96691 10.5123C9.17698 10.1333 9.05679 9.63725 8.68537 9.36325ZM7.23871 6.11147C7.23871 5.75354 7.23871 5.40589 7.23871 5.05174C6.92522 5.33982 6.92522 5.77249 7.23871 6.11147Z"
fill="#FEFEFE"
/>
<path
d="M8.68433 9.36328C9.05574 9.63729 9.17539 10.1333 8.96586 10.5118C8.90631 10.619 8.82347 10.7046 8.72493 10.775C8.70111 10.7918 8.67188 10.8172 8.67188 10.7566C8.67242 10.2979 8.67296 9.83927 8.6735 9.38061C8.67404 9.37682 8.67891 9.37249 8.68433 9.36328Z"
fill="#59BE59"
/>
<path
d="M7.23882 6.11149C6.92533 5.77305 6.92587 5.33984 7.23882 5.05176C7.23882 5.40591 7.23882 5.75355 7.23882 6.11149Z"
fill="#59BE59"
/>
</svg>
</span>
<span className="text-base text-dark-gray dark:text-white font-medium">
6392.99$
</span>
</div>
</td>
<td className="text-right py-4 px-2">
<button
type="button"
className="text-sm text-white bg-purple px-2.5 py-1.5 rounded-full"
>
Active
</button>
</td>
</tr>
))
}
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList onClick={handlePagination} prev={currentPage == 0 ? true : false} next={currentPage+Number(process.env.REACT_APP_ITEM_PER_PAGE) >= data.length ? true : false} data={data} start={indexOfFirstItem} stop={indexOfLastItem} />
{/* END OF PAGINATION BUTTON */}
</div>
}
</div>
);
}
@@ -1,18 +1,18 @@
import React, {
Suspense,
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState,
forwardRef,
Suspense,
} from "react";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import profile from "../../assets/images/profile-info-profile.png";
import usersService from "../../services/UsersService";
import FamilyTasks from "./FamilyTasks";
import QRCode from "react-qr-code";
import { useReactToPrint } from "react-to-print";
import usersService from "../../../services/UsersService";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
import profile from "../../../assets/images/profile-info-profile.png";
import FamilyTasks from "./FamilyTasks";
export default function FamilyManageTabs({
className,
@@ -20,7 +20,16 @@ export default function FamilyManageTabs({
listReload,
loader,
}) {
const [familyDetails, setFamilyDetails] = useState(null);
const [details, setDetails] = useState({
familyDetails: {
loading: false,
data: null,
},
familyTasks: {
loading: false,
data: null,
},
});
const [errMsg, setErrMsg] = useState("");
// List of tabs
const tabs = [
@@ -57,26 +66,46 @@ export default function FamilyManageTabs({
imgReader.readAsDataURL(e.target.files[0]);
}
};
// Api call
const apiCall = useMemo(() => new usersService(), []);
// function for manage family
const familyManageHandler = useCallback(async () => {
const manageFamily = useCallback(async () => {
try {
setDetails({
familyDetails: { loading: true },
familyTasks: { loading: true },
});
let { family_uid } = accountDetails;
let reqData = { family_uid };
let res = await apiCall.ManageFamily(reqData);
let { data } = await res;
if (data?.internal_return < 0) return;
setFamilyDetails(data);
const familyRes = await apiCall.ManageFamily(reqData);
const familyData = familyRes.data;
const tasksRes = await apiCall.ManageTasks(reqData);
const tasksData = tasksRes.data;
// checking the internal return
if (familyData?.internal_return < 0 || tasksData?.internal_return < 0)
return;
setDetails({
familyDetails: { loading: false, data: familyData },
familyTasks: { loading: false, data: tasksData },
});
} catch (error) {
setDetails({
familyDetails: { loading: false },
familyTasks: { loading: false },
});
setErrMsg("An error occurred");
throw new Error(error);
}
}, [apiCall, accountDetails]);
useEffect(() => {
familyManageHandler();
}, [tab]);
manageFamily();
}, [tab, manageFamily]);
const accountRef = useRef();
// to handle printing
@@ -132,16 +161,21 @@ export default function FamilyManageTabs({
<div
className={`${
tab === name ? "block" : "hidden"
} h-full p-4 border border-[#dbd9d9]`}
} h-full p-4 border border-[#dbd9d9] relative overflow-y-auto`}
key={id}
>
{name === "Tasks" && (
<FamilyTasks className={className} loader={loader} />
<FamilyTasks
className={className}
loader={details.familyTasks.loading}
familyData={details.familyTasks.data}
/>
)}
{name === "Account" && (
<Account
familyDetails={familyDetails}
familyData={details.familyDetails.data}
myRef={accountRef}
loader={details.familyDetails.loading}
handlePrint={useHandlePrint}
/>
)}
@@ -166,7 +200,6 @@ function ProfileInfo({
browseProfileImg,
accountDetails,
}) {
let { firstname, lastname, age } = accountDetails;
return (
<div className="flex flex-col items-center gap-6">
<div className="flex justify-center">
@@ -207,20 +240,20 @@ function ProfileInfo({
</div>
<div className="flex flex-col justify-center gap-3 items-center">
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
{firstname}
{accountDetails?.firstname}
</h1>
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
{lastname}
{accountDetails?.lastname}
</h1>
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
{age}
{accountDetails?.age}
</h1>
</div>
</div>
);
}
const Account = forwardRef(({ familyDetails, myRef, handlePrint }) => {
const Account = forwardRef(({ familyData, myRef, handlePrint }, ref) => {
return (
<div
className="w-full lg:min-h-[500px] h-full flex flex-col items-center justify-center"
@@ -232,15 +265,13 @@ const Account = forwardRef(({ familyDetails, myRef, handlePrint }) => {
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
Username:{" "}
<span className="ml-2 normal-case">
{familyDetails?.username
? familyDetails?.username
: "please wait..."}
{familyData?.username ? familyData?.username : "please wait..."}
</span>
</h2>
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
Pin:{" "}
<span className="ml-2 normal-case">
{familyDetails?.pin ? familyDetails?.pin : "please wait..."}
{familyData?.pin ? familyData?.pin : "please wait..."}
</span>
</h2>
</div>
@@ -0,0 +1,142 @@
import React, { useState } from "react";
import dataImage2 from "../../../assets/images/data-table-user-2.png";
import { useNavigate, useLocation } from "react-router-dom";
import { handlePagingFunc } from "../../Pagination/HandlePagination";
import PaginatedList from "../../Pagination/PaginatedList";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
import Icons from "../../Helpers/Icons";
export default function FamilyTasks({ familyData, className, loader }) {
const filterCategories = ["All Categories", "Explore", "Featured"];
const [selectedCategory, setCategory] = useState(filterCategories[0]);
let navigate = useNavigate();
let { pathname } = useLocation();
let data = ["1", "2", "3", "4", "5", "6"]; // to be replaced later by result from API CALL
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentTask = familyData?.result_list.slice(
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
return (
<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 || ""
}`}
>
{loader ? (
<div className="w-full h-full flex justify-center items-center lg:min-h-[470px]">
<LoadingSpinner size={16} color="sky-blue" />
</div>
) : (
<>
{" "}
{familyData && familyData?.result_list && (
<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">
<tbody>
{
<>
{familyData &&
familyData?.result_list &&
familyData.result_list.length > 0 &&
currentTask.map((value, index) => {
// find due date
const dueDate = value?.delivery_date.split(" ")[0]
return (
<tr
key={index}
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
>
<td className=" py-4">
<div className="flex space-x-2 items-center w-full">
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] max-w-[60px] min-w-[60px]">
<img
src={dataImage2}
alt="data"
className="w-full h-full"
/>
</div>
<div className="flex flex-col flex-[0.9]">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.title}
</h1>
<div className="flex gap-4 items-center">
<span className="text-sm text-thin-light-gray">
Price:{" "}
<span className="text-purple">
{value.price * 0.01}
</span>
</span>
<span className="text-sm text-thin-light-gray">
Duration:{" "}
<span className="text-purple">
{" "}
{value.timeline_days} day(s)
</span>
</span>
<span className="text-sm text-thin-light-gray">
Due Date:{" "}
<span className="text-purple">
{" "}
{dueDate}
</span>
</span>
</div>
</div>
</div>
</td>
<td className="text-right py-4 px-2">
<button
type="button"
onClick={() => {
navigate("/manage-active-job", {
state: { ...value, pathname },
});
}}
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
<Icons name="right-arrow" />
</button>
</td>
</tr>
)
})}
</>
}
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
familyData?.result_list.length
? true
: false
}
data={familyData?.result_list}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
)}
</>
)}
</div>
);
}
+15
View File
@@ -468,6 +468,21 @@ export default function Icons({ name }) {
>
<rect y="0.823242" width="20" height="2.35294" rx="1.17647" />
</svg>
) : name === "right-arrow" ? (
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
// enableBackground="new 0 0 24 24"
viewBox="0 0 24 24"
className="fill-black dark:fill-white"
id="right-arrow"
>
<path
d="M15.5,11.3L9.9,5.6c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l4.9,4.9l-4.9,4.9c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.6,0.4,1,1,1
c0.3,0,0.5-0.1,0.7-0.3l5.7-5.7c0,0,0,0,0,0C15.9,12.3,15.9,11.7,15.5,11.3z"
></path>
</svg>
) : (
""
)}
File diff suppressed because it is too large Load Diff
@@ -31,7 +31,13 @@ export default function ActiveJobMessage({ activeJobMesList }) {
<tbody>
{currentActiveJobMesList.map((item, index) => (
<tr key={index} className='text-slate-500'>
<td className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></td>
<td>
<div className="msg_box">
<div className="msg_header">{item.msg_date} {item.msg_firstname}</div>
<span className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></span>
</div>
</td>
</tr>
))}
</tbody>
+49 -52
View File
@@ -96,64 +96,61 @@ function ActiveJobs(props) {
// FUNCTION TO SEND FILES
const sendFile = async () => {
setRequestStatus({loading: true, status: false, message: ''})
setRequestStatus({loading: true, status: false, message: ''})
if(!filesToSend.length){ // checks if file to send is empty
setRequestStatus({loading: false, status: false, message: 'No File(s) selected'})
return setTimeout(()=>{
setRequestStatus({loading: false, status: false, message: ''})
}, 5000)
}
// let reqData = new FormData()
if(!filesToSend.length){ // checks if file to send is empty
setRequestStatus({loading: false, status: false, message: 'No File(s) selected'})
return setTimeout(()=>{
setRequestStatus({loading: false, status: false, message: ''})
}, 5000)
}
for(let i=0; i<=filesToSend.length-1; i++){ // Loops through files to send array and trigger upload API call
const fileToBase64 = async () =>{ // Converts file data to base64 string
try {
const base64String = await convertFileToBase64(filesToSend[i]);
return base64String;
} catch (error) {
return false;
}
}
// if(await !fileToBase64()){
// return
// }
let reqData={file_name: filesToSend[i].name, file_size: filesToSend[i].size, file_type: 'image/png', file_data: await fileToBase64(), msg_type: 'FILE', contract:props.details.contract}
// for(let files of filesToSend){
// reqData.append(files.name, files)
// }
// let reqData={file_size: filesToSend[0].size, file_type: 'image/png', file_data: filesToSend[0], msg_type: 'FILE', contract:props.details.contract}
// for(let files of filesToSend){
// reqData[files.name] = files
// }
const fileToBase64 = async () =>{
try {
const base64String = await convertFileToBase64(filesToSend[0]);
return base64String;
} catch (error) {
return false;
}
}
if(await !fileToBase64()){
return
}
let reqData={file_name: filesToSend[0].name, file_size: filesToSend[0].size, file_type: 'image/png', file_data: await fileToBase64(), msg_type: 'FILE', contract:props.details.contract}
console.log(reqData)
ApiCall.sendFiles(reqData).then((res)=>{
if(res.status != 200 || res.data.internal_return < 0){
setRequestStatus({loading: false, status: false, message: 'Files(s) could not be sent, try again later'})
return
}
setRequestStatus({loading: false, status: true, message: 'File(s) Uploaded Successfully'})
props.reloadActiveJobList(prev => !prev) // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
setFilesToSend([]) // SETS FILES TO SEND TO SEND BACK TO EMPTY ARRAY
}).catch(error => {
setRequestStatus({loading: false, status: false, message: 'Opps! something went wrong'})
}).finally(()=>{
setTimeout(()=>{
setRequestStatus({loading: false, status: false, message: ''})
}, 5000)
})
}
ApiCall.sendFiles(reqData).then((res)=>{
// if(res.status != 200 || res.data.internal_return < 0){
// setRequestStatus({loading: false, status: false, message: 'Files(s) could not be sent, try again later'})
// return
// }
// setRequestStatus({loading: false, status: true, message: 'File(s) Uploaded Successfully'})
// props.reloadActiveJobList(prev => !prev) // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
// setFilesToSend([]) // SETS FILES TO SEND TO SEND BACK TO EMPTY ARRAY
}).catch(error => {
// setRequestStatus({loading: false, status: false, message: 'Opps! something went wrong'})
}).finally(()=>{
if(i==filesToSend.length-1){
setRequestStatus({loading: false, status: true, message: 'File(s) Uploaded Successfully'})
setFilesToSend([]) // SETS FILES TO SEND TO SEND BACK TO EMPTY ARRAY
props.reloadActiveJobList(prev => !prev) // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
setTimeout(()=>{
setRequestStatus({loading: false, status: false, message: ''})
}, 5000)
}
})
}
}
return (
<Layout>
<div className="py-[20px] bg-white px-4 rounded-2xl shadow-md lg:flex justify-between items-start space-y-4 lg:space-x-4 lg:space-y-0">
<div className="py-[20px] bg-white px-4 rounded-2xl shadow-md md:flex justify-between items-start space-y-4 md:space-x-4 md:space-y-0">
{/* job title */}
<div className="w-full lg:w-1/2">
<div className="w-full md:w-8/12">
<div className="w-full flex justify-start space-x-3 items-start">
<button
type="button"
@@ -194,7 +191,7 @@ function ActiveJobs(props) {
{/* end of job title */}
{/* job details */}
<div className="w-full lg:w-1/2">
<div className="w-full md:w-4/12">
<p className="text-base text-sky-blue">Delivery Detail</p>
<div className="mt-2">
<p className="text-base text-slate-700 dark:text-black">
+1 -1
View File
@@ -100,7 +100,7 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
// User Profile
let { firstname, lastname, email, profile_pic } = userDetails;
let userEmail = email.split("@")[0];
let userEmail = email?.split("@")[0];
return (
<>
+60 -31
View File
@@ -1,46 +1,63 @@
import React, { useMemo, useState } from "react";
import React, { useCallback, useMemo, useState } from "react";
import Detail from "./popoutcomponent/Detail";
import ModalCom from "../Helpers/ModalCom";
import usersService from "../../services/UsersService";
import { toast } from "react-toastify";
import LoadingSpinner from "../Spinners/LoadingSpinner";
const showSuccessToast = (message) => {
toast.success(message, {
autoClose: 3000,
hideProgressBar: true,
});
};
function PendingJobsPopout({ details, onClose, situation }) {
const [pendingJobLoader, setPendingJobLoader] = useState(false)
const [pendingJobLoader, setPendingJobLoader] = useState({
extend: false,
offer: false,
});
const apiCall = useMemo(() => new usersService(), []);
const handlePendingJobsBtn = async ({ target: { name } }) => {
setPendingJobLoader(true)
let { job_uid, offer_code } = details;
let reqData;
const handlePendingJobsBtn = useCallback(
async ({ target: { name } }) => {
let { job_uid, offer_code } = details;
let pendingData = { job_uid, offer_code };
let reqData;
let pendingData = { job_uid, offer_code };
if (name === "extend") {
try {
reqData = { ...pendingData };
let { data } = await apiCall.pendingJobExtend(reqData);
console.log("This is for extend", data);
setPendingJobLoader(false)
if (name === "extend") {
setPendingJobLoader({ extend: true });
reqData = { ...pendingData };
// let { data } =
await apiCall.pendingJobExtend(reqData);
// console.log("This is for extend", data);
showSuccessToast("Job has been extended by a week!");
} else if (name === "offer") {
setPendingJobLoader({ offer: true });
reqData = { ...pendingData };
// let { data } =
await apiCall.pendingJobSendTome(reqData);
// console.log("This is for offer", data);
showSuccessToast("Offer sent, check your email");
} else return;
setTimeout(() => {
setPendingJobLoader({ extend: false, offer: false });
onClose();
}, 2700);
} catch (error) {
setPendingJobLoader(false)
setPendingJobLoader({ extend: false, offer: false });
throw new Error(error);
}
} else if (name === "offer") {
try {
reqData = { ...pendingData };
let { data } = await apiCall.pendingJobSendTome(reqData);
console.log("This is for offer", data);
setPendingJobLoader(false)
} catch (error) {
setPendingJobLoader(false)
throw new Error(error);
}
} else return;
},
[onClose, apiCall, details]
);
onClose();
};
return (
<ModalCom action={onClose} situation={situation}>
<ModalCom action={onClose} 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 overflow-y-auto">
<div className="logout-modal-header w-full flex items-center justify-between lg:p-6 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">
@@ -159,7 +176,13 @@ function PendingJobsPopout({ details, onClose, situation }) {
onClick={handlePendingJobsBtn}
name="extend"
>
Extend by a week
{pendingJobLoader.extend ? (
<div className="w-[136px] flex justify-center items-center h-full">
<LoadingSpinner size={5} color="sky-blue" />
</div>
) : (
"Extend by a week"
)}
</button>
</div>
@@ -169,7 +192,13 @@ function PendingJobsPopout({ details, onClose, situation }) {
onClick={handlePendingJobsBtn}
name="offer"
>
Send to me
{pendingJobLoader.offer ? (
<div className="w-[96px] flex justify-center items-center h-full">
<LoadingSpinner size={5} color="sky-blue" />
</div>
) : (
"Send to me"
)}
</button>
</div>
@@ -200,4 +229,4 @@ function PendingJobsPopout({ details, onClose, situation }) {
);
}
export default PendingJobsPopout;
export default PendingJobsPopout;
+11
View File
@@ -9,6 +9,17 @@
font-family: "Product Sans";
src: url("./assets/fonts/Product Sans Bold.ttf");
}
.msg_box{
background-color: aliceblue;
margin: 5px;
padding: 5px;
border-radius: 15px;
}
.msg_header{
background-color: #1a3544;
color: white;
font-weight: bold;
}
.siderCardHeader{
margin: 40px 40px 10px 40px;
font-size: 24px;
+28 -14
View File
@@ -12,23 +12,36 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
const dispatch = useDispatch();
const [lastActivityTime, setLastActivityTime] = useState(Date.now());
const [isLogin, setIsLogin] = useState({ loading: true, status: false });
const [loadProfileDetails, setLoadProfileDetails] = useState([]);
const navigate = useNavigate();
const {jobListTable} = useSelector((state) => state.tableReload)
const { jobListTable } = useSelector((state) => state.tableReload);
useEffect(() => {
//Removing Data stored at localStorage after session expires
const expireSession = () => {
localStorage.clear();
localStorage.removeItem("uid");
localStorage.removeItem("member_id");
localStorage.removeItem("session_token");
navigate("/login", { replace: true }); // redirects user to login page after session expires
};
const checkInactivity = setInterval(() => {
if (
Date.now() - lastActivityTime >
process.env.REACT_APP_SESSION_EXPIRE_MINUTES
) {
expireSession();
let { account_type } = loadProfileDetails;
if (account_type === "FAMILY") {
if (
Date.now() - lastActivityTime >
process.env.REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY
) {
expireSession();
}
} else {
if (
Date.now() - lastActivityTime >
process.env.REACT_APP_SESSION_EXPIRE_MINUTES
) {
expireSession();
}
}
}, process.env.REACT_APP_SESSION_EXPIRE_CHECKER); // Checks for inactivity every minute
@@ -65,6 +78,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
setIsLogin({ loading: false, status: false });
return;
}
setLoadProfileDetails(res.data);
dispatch(updateUserDetails(res.data));
setIsLogin({ loading: false, status: true });
})
@@ -76,22 +90,22 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}
}, []);
useEffect(()=>{
useEffect(() => {
const getMyJobList = async () => {
dispatch(updateUserJobList({loading: true, data:[]}))
dispatch(updateUserJobList({ loading: true, data: [] }));
try {
const res = await apiCall.getMyJobList();
// setMyJobList({loading: false, data:res.data})
// setMyJobList(res.data);
dispatch(updateUserJobList({loading: false, data:res.data}))
dispatch(updateUserJobList({ loading: false, data: res.data }));
} catch (error) {
dispatch(updateUserJobList({loading: false, data:[]}))
dispatch(updateUserJobList({ loading: false, data: [] }));
// setMyJobList({loading: false, data:[]})
console.log("Error getting mode");
}
};
getMyJobList()
},[jobListTable])
getMyJobList();
}, [jobListTable]);
useEffect(() => {
// Getting market data
+17 -1
View File
@@ -212,6 +212,20 @@ class usersService {
return this.postAuxEnd("/familymanage", postData);
}
// Family Tasks
ManageTasks(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
limit: 30,
offset: 0,
action: 13008,
...reqData
};
return this.postAuxEnd("/jobmanageractive", postData);
}
// Task for the person doing the job
getMyActiveTaskList() {
var postData = {
@@ -549,7 +563,9 @@ class usersService {
for (let data in postData) {
formData.append(data, postData[data]);
}
return this.postAuxEnd("/uploads", formData);
// return this.postAuxEnd("/uploads", formData);
return this.postAuxEnd("/uploads", postData);
}
// END POINT TO DELETE A JOB