Compare commits

...

116 Commits

Author SHA1 Message Date
victorAnumudu 3cd8b6e574 added link to family page 2024-03-22 12:45:34 +01:00
ameye 9850cdd392 Merge branch 'offer-interest-refresh' of WrenchBoard/Users-Wrench into master 2024-03-22 10:30:33 +00:00
victorAnumudu 6d98141c39 offer interest refresh started 2024-03-22 10:40:57 +01:00
victorAnumudu 5fe5ccbd4d merge with master 2024-03-22 07:46:17 +01:00
victorAnumudu 76c0994eb0 initial commit 2024-03-21 22:00:31 +01:00
ameye a1bc6db381 Merge branch 'others-interested-offer' of WrenchBoard/Users-Wrench into master 2024-03-21 20:03:22 +00:00
victorAnumudu 6f5d72e033 merge master 2024-03-21 20:33:37 +01:00
ameye 762de4c23e Merge branch 'market-job-event' of WrenchBoard/Users-Wrench into master 2024-03-21 17:13:37 +00:00
victorAnumudu 2a8b7ba6ec updated marketjob-addded to marketjob-added 2024-03-21 18:05:48 +01:00
victorAnumudu 50e44dab43 initial commit 2024-03-21 17:37:57 +01:00
ameye 7649a90c47 Merge branch 'job-interest-modal' of WrenchBoard/Users-Wrench into master 2024-03-21 15:30:37 +00:00
victorAnumudu 3c2c46e293 added footer style to modal 2024-03-21 16:27:52 +01:00
ameye 8dc634d900 Merge branch 'modal-footer-style-start' of WrenchBoard/Users-Wrench into master 2024-03-21 14:10:51 +00:00
victorAnumudu 3a9cb4667e added some custom style for modal footer 2024-03-21 15:08:26 +01:00
ameye 5f4b032f68 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-21 13:17:35 +00:00
Ebube 8ab3e9ae50 Changed the Name of link 2024-03-21 14:15:28 +01:00
ameye 01b5fba75b Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-21 13:09:19 +00:00
Ebube 66b8c96592 fixed typo on link path 2024-03-21 14:04:34 +01:00
ameye 616352e1ac Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-21 12:53:43 +00:00
Ebube acc4417835 commit issue fix 2024-03-21 13:51:49 +01:00
Ebube 7da693f298 fix commit issue 2024-03-21 13:49:22 +01:00
ameye b0423c665c Merge branch 'popout-fix' of WrenchBoard/Users-Wrench into master 2024-03-21 12:44:43 +00:00
victorAnumudu 7089b8f14b fixed popout header style 2024-03-21 13:38:01 +01:00
ameye 2c2e2b0ca5 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-21 12:33:20 +00:00
Ebube ba3dd91d81 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-03-21 13:28:42 +01:00
Ebube 3f04c9f9f8 added items to right sidebar 2024-03-21 13:28:03 +01:00
ameye 781f5cc5a6 Merge branch 'add-group-email' of WrenchBoard/Users-Wrench into master 2024-03-21 11:33:48 +00:00
ameye 58097d8b57 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-21 11:33:41 +00:00
victorAnumudu 630ccefa51 Made the email input longer 2024-03-21 12:20:20 +01:00
Ebube ed9f2dec0e fixed link location 2024-03-21 12:01:32 +01:00
Ebube d2ed29c6a6 fixed link location 2024-03-21 11:53:58 +01:00
ameye 4e81156d72 Merge branch 'parent-kid-wallet' of WrenchBoard/Users-Wrench into master 2024-03-21 09:50:41 +00:00
ameye e402c02c1f Merge branch 'assign-task-image' of WrenchBoard/Users-Wrench into master 2024-03-21 09:50:34 +00:00
victorAnumudu 5907b5d872 parent kids wallet bug fixed 2024-03-20 21:04:49 +01:00
victorAnumudu 042cc4110c initial commit 2024-03-20 19:16:16 +01:00
victorAnumudu 944fd134f6 added image to assign task popout 2024-03-20 18:02:47 +01:00
tokslaw 5e6b208513 Merge branch 'family-wallet-refresh' of WrenchBoard/Users-Wrench into master 2024-03-20 13:32:48 +00:00
victorAnumudu 762601a5c3 made kid wallet refresh when parent transfers cash 2024-03-20 13:44:14 +01:00
victorAnumudu 1e28a0e15b made kid wallet refresh when parent transfers cash 2024-03-20 13:43:23 +01:00
ameye a910ab177f Merge branch 'modal-change' of WrenchBoard/Users-Wrench into master 2024-03-19 23:33:19 +00:00
victorAnumudu 4e741f587c added color to modal and made the labels same font 2024-03-19 22:42:52 +01:00
tokslaw f779529cc6 Merge branch 'kid-accepts-task' of WrenchBoard/Users-Wrench into master 2024-03-19 20:17:00 +00:00
victorAnumudu 44cedf2f65 Made parent family task list refresh when child accepts task 2024-03-19 20:27:29 +01:00
ameye fbcba191b0 Merge branch 'rounded-select' of WrenchBoard/Users-Wrench into master 2024-03-19 14:51:37 +00:00
victorAnumudu c64d372193 assign job rounded select tag 2024-03-19 14:33:42 +01:00
ameye abff42e0a8 Merge branch 'parent-assign-job-bug' of WrenchBoard/Users-Wrench into master 2024-03-19 12:13:06 +00:00
victorAnumudu d5c342a57a made socket to trigger for refresh for only the child the parent assigns a job to 2024-03-19 13:09:06 +01:00
victorAnumudu 60d6629526 made socket to trigger for refresh for only the child the parent assigns a job to 2024-03-19 11:45:18 +01:00
tokslaw b1fbf89f10 Merge branch 'parent-assign-job' of WrenchBoard/Users-Wrench into master 2024-03-18 21:02:02 +00:00
victorAnumudu ae346d5ac5 parent assign job triggers update in child account 2024-03-18 21:38:41 +01:00
victorAnumudu 75b5102766 Merge master into parent-assign-job 2024-03-18 19:31:01 +01:00
victorAnumudu 9b12ffe0cd initial commit 2024-03-18 19:29:35 +01:00
tokslaw 408165e718 Merge branch 'assign-modal' of WrenchBoard/Users-Wrench into master 2024-03-18 15:35:33 +00:00
victorAnumudu f7a0594447 added bg color to modal head 2024-03-18 16:00:45 +01:00
ameye c733b006fb Merge branch 'assign-job-label' of WrenchBoard/Users-Wrench into master 2024-03-18 13:05:13 +00:00
victorAnumudu 5a6b60578e clean up 2024-03-18 13:44:56 +01:00
victorAnumudu cdd998235e made assign job labels same style 2024-03-18 13:42:58 +01:00
ameye 6e9efd7f43 Merge branch 'wallet-family-api' of WrenchBoard/Users-Wrench into master 2024-03-18 09:46:18 +00:00
ameye 07e9520774 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-18 09:46:04 +00:00
victorAnumudu c1600a2a13 consumed family wallet API 2024-03-17 23:47:35 +01:00
Ebube 58e1745ac5 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-03-17 19:47:27 +01:00
Ebube 35db4fe536 fixed underlying issues 2024-03-17 19:46:38 +01:00
ameye dfdbf404a5 Merge branch 'socket-market-refresh' of WrenchBoard/Users-Wrench into master 2024-03-14 00:52:28 +00:00
victorAnumudu 985afa3c7b clean up 2024-03-13 21:02:37 +01:00
victorAnumudu 70d82d89b3 added socket event to listen to job market post 2024-03-13 19:56:13 +01:00
ameye 7f5eccb3b7 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-13 07:24:29 +00:00
Ebube 6729b780bd Increased Font Size 2024-03-13 03:27:56 +01:00
ameye 06224f121a Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-13 00:52:26 +00:00
Ebube dc91649114 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-03-13 00:01:38 +01:00
Ebube 22f6eb436d Completed the flow 2024-03-13 00:00:58 +01:00
CHIEFSOFT\ameye f2ab0cd6c9 added host 2024-03-12 15:59:13 -04:00
CHIEFSOFT\ameye a2819786ae 76.209.103.227 2024-03-12 13:48:01 -04:00
CHIEFSOFT\ameye 6cd92f6372 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench 2024-03-12 12:35:04 -04:00
CHIEFSOFT\ameye 7173901c9b socker in coposer 2024-03-12 12:34:47 -04:00
ameye 380d014964 Merge branch 'socket-context' of WrenchBoard/Users-Wrench into master 2024-03-12 15:52:32 +00:00
victorAnumudu 9032b36b13 Merge master into socket-context 2024-03-12 16:32:59 +01:00
victorAnumudu f291382786 added a socket context for real time communication 2024-03-12 16:31:08 +01:00
ameye 69dcee859d Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-12 15:01:02 +00:00
Ebube fe295dc775 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-03-12 15:51:44 +01:00
Ebube 044c8edf7d Suggest task flow pt1 2024-03-12 15:50:47 +01:00
CHIEFSOFT\ameye c22cffd167 added socket package 2024-03-12 02:04:10 -04:00
ameye 6d77bfa1b0 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-11 19:55:16 +00:00
Ebube 60cc6f375e Fixed font size and added name to waitlist tab 2024-03-11 20:31:11 +01:00
ameye e6684c56fd Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-11 17:20:31 +00:00
Ebube 4f675b30ef Added assign popup dropdown, fixed the right api for my task page 2024-03-11 18:15:31 +01:00
ameye 00c7f65092 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-10 18:17:56 +00:00
Ebube 9a978b1913 Filtered pending task with family uid and added text to waiting tab 2024-03-10 19:03:16 +01:00
ameye 23f8346734 Merge branch 'family-double-wallet' of WrenchBoard/Users-Wrench into master 2024-03-09 22:05:33 +00:00
victorAnumudu 585632c1e1 implemented family wallet with multiple wallet 2024-03-09 22:55:02 +01:00
ameye 11ee1195c2 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-09 18:18:42 +00:00
ameye c44f456cc1 Merge branch 'pending-task-title' of WrenchBoard/Users-Wrench into master 2024-03-09 18:18:32 +00:00
Ebube b769e4a4ba Fixed the pendingfamilyData 2024-03-09 18:58:25 +01:00
victorAnumudu a6ff06e2b4 added breadcrumb for no pending task 2024-03-09 16:04:04 +01:00
victorAnumudu 0f801b2408 removed double Title from page 2024-03-09 15:49:41 +01:00
ameye c26f2b725a Merge branch 'family-wallet-cleanup' of WrenchBoard/Users-Wrench into master 2024-03-09 12:10:22 +00:00
victorAnumudu ee94cbc92c undefined variable fixed 2024-03-09 08:19:33 +01:00
victorAnumudu dccbe76c5b removed unwanted signup country API 2024-03-09 08:13:52 +01:00
ameye 735d13b440 Merge branch 'family-redeem-options' of WrenchBoard/Users-Wrench into master 2024-03-08 20:57:58 +00:00
victorAnumudu 7f83cd5cc6 added family wallet redeem options 2024-03-08 21:50:42 +01:00
ameye 71ee75072d Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-08 13:58:02 +00:00
ameye 265f2b7655 Merge branch 'family-wallet-font' of WrenchBoard/Users-Wrench into master 2024-03-08 13:57:53 +00:00
Ebube 4d264fa18e Changed btn for suggested task components 2024-03-08 14:07:00 +01:00
victorAnumudu cd6ab8b504 wallet font adjusted 2024-03-08 12:20:37 +01:00
ameye 8c81073443 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-08 10:41:47 +00:00
Ebube 14566de037 . 2024-03-08 04:32:19 +01:00
Ebube 69d711eddc Fixed suggested task bug 2024-03-08 03:47:57 +01:00
Ebube 159623eb69 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-03-08 02:13:00 +01:00
Ebube da26d5c24a Task page bug fix 2024-03-08 02:12:35 +01:00
ameye 40850b7342 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-08 00:38:54 +00:00
Ebube 28098169b9 . 2024-03-07 23:47:15 +01:00
Ebube 2ff6ed777f Fixed bug of tasks and chores page 2024-03-07 23:44:30 +01:00
ameye 723a2a09ab Merge branch 'new-family-wallet' of WrenchBoard/Users-Wrench into master 2024-03-07 20:00:49 +00:00
victorAnumudu 68482c7956 added new family wallet page 2024-03-07 20:25:58 +01:00
ameye 225e3ae34c Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-07 16:55:41 +00:00
Ebube 251d5abf10 Added family waiting data 2024-03-07 17:34:28 +01:00
ameye 22314a61c5 Merge branch 'adding-breadcrumb' of WrenchBoard/Users-Wrench into master 2024-03-07 16:01:30 +00:00
67 changed files with 2506 additions and 1037 deletions
+3
View File
@@ -15,6 +15,9 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
#SOCKETS ENDS
REACT_APP_PRIMARY_SOCKET="https://socket-dev.wrenchboard.com"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser" #"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=600000 REACT_APP_SESSION_EXPIRE_MINUTES=600000
+3
View File
@@ -15,6 +15,9 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
#SOCKETS ENDS
REACT_APP_PRIMARY_SOCKET="https://socket-dev.wrenchboard.com"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser" #"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=600000 REACT_APP_SESSION_EXPIRE_MINUTES=600000
+3
View File
@@ -15,6 +15,9 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1" REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
#SOCKETS ENDS
REACT_APP_PRIMARY_SOCKET="https://socket.wrenchboard.com"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser" #"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=600000 REACT_APP_SESSION_EXPIRE_MINUTES=600000
+10 -1
View File
@@ -21,5 +21,14 @@
"emmet.triggerExpansionOnTab": true, "emmet.triggerExpansionOnTab": true,
"emmet.includeLanguages": { "emmet.includeLanguages": {
"javascript": "javascriptreact" "javascript": "javascriptreact"
} },
"cSpell.words": [
"completesignuplink",
"MOBILEUSER",
"MYFILES",
"mynotifications",
"PASSWORDRESET",
"TRANSFERSTART",
"WRENCHBOARD"
]
} }
+3 -2
View File
@@ -21,9 +21,10 @@ services:
- backend.wrenchboard.api.live:10.10.33.15 - backend.wrenchboard.api.live:10.10.33.15
- backend.wrenchboard.api.test:10.10.33.15 - backend.wrenchboard.api.test:10.10.33.15
- apigate.lotus.g1.wrenchboard.com:10.10.33.15 - apigate.lotus.g1.wrenchboard.com:10.10.33.15
- apigate.nebula.g1.wrenchboard.com:10.10.33.15
- apigate.orion.g1.wrenchboard.com:10.10.33.15 - apigate.orion.g1.wrenchboard.com:10.10.33.15
# #- backend.wrenchboard.api.live:172.31.4.27 - socket-dev.wrenchboard.com:10.10.33.15
# #- backend.wrenchboard.api.test:10.20.30.27 - socket.wrenchboard.com:10.10.33.15
- apigateway.wrenchboard.app.dev.fluxtra.net:10.20.30.19 - apigateway.wrenchboard.app.dev.fluxtra.net:10.20.30.19
- apigateway.wrenchboard.app.lotus.fluxtra.net:172.31.4.19 - apigateway.wrenchboard.app.lotus.fluxtra.net:172.31.4.19
environment: environment:
+1
View File
@@ -30,6 +30,7 @@
"react-to-print": "^2.14.12", "react-to-print": "^2.14.12",
"react-toastify": "^9.0.1", "react-toastify": "^9.0.1",
"redux": "^4.2.0", "redux": "^4.2.0",
"socket.io-client": "^4.4.1",
"slick-carousel": "^1.8.1", "slick-carousel": "^1.8.1",
"web-vitals": "^1.0.1", "web-vitals": "^1.0.1",
"yup": "^1.1.1" "yup": "^1.1.1"
+3
View File
@@ -2,11 +2,13 @@ import { Navigate, useLocation } from "react-router-dom";
import Routers from "./Routers"; import Routers from "./Routers";
import Toaster from "./components/Helpers/Toaster"; import Toaster from "./components/Helpers/Toaster";
import Default from "./components/Partials/Default"; import Default from "./components/Partials/Default";
import SocketIOContextProvider from "./components/Contexts/SocketIOContext";
function App() { function App() {
const { pathname } = useLocation(); const { pathname } = useLocation();
return ( return (
<Default> <Default>
<SocketIOContextProvider>
<> <>
{pathname.startsWith("/@") ? ( {pathname.startsWith("/@") ? (
<Navigate to="/app" replace={true} /> <Navigate to="/app" replace={true} />
@@ -15,6 +17,7 @@ function App() {
)} )}
<Toaster /> <Toaster />
</> </>
</SocketIOContextProvider>
</Default> </Default>
); );
} }
+13 -13
View File
@@ -89,9 +89,9 @@ function AddJob({ popUpHandler, categories }) {
<div className="field w-full mb-6 xl:mb-0"> <div className="field w-full mb-6 xl:mb-0">
<label <label
htmlFor="country" htmlFor="country"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1" className="job-label job-label-flex"
> >
Currency <span>Currency</span>
{props.errors.country && props.touched.country && ( {props.errors.country && props.touched.country && (
<span className="text-[12px] text-red-500"> <span className="text-[12px] text-red-500">
{props.errors.country} {props.errors.country}
@@ -136,9 +136,9 @@ function AddJob({ popUpHandler, categories }) {
{/* Price */} {/* Price */}
<div className="field w-full"> <div className="field w-full">
<InputCom <InputCom
fieldClass="px-6 text-right" fieldClass="px-6 text-right flex"
label="Price" label="Price"
labelClass="tracking-wide" labelClass=""
type="number" type="number"
name="price" name="price"
placeholder="0" placeholder="0"
@@ -159,7 +159,7 @@ function AddJob({ popUpHandler, categories }) {
<InputCom <InputCom
fieldClass="px-6" fieldClass="px-6"
label="Title" label="Title"
labelClass="tracking-wide" labelClass=""
type="text" type="text"
name="title" name="title"
value={props.values.title} value={props.values.title}
@@ -178,7 +178,7 @@ function AddJob({ popUpHandler, categories }) {
<InputCom <InputCom
fieldClass="px-6" fieldClass="px-6"
label="Description" label="Description"
labelClass="tracking-wide" labelClass=""
type="text" type="text"
name="description" name="description"
value={props.values.description} value={props.values.description}
@@ -197,7 +197,7 @@ function AddJob({ popUpHandler, categories }) {
<div className="sm:w-[60%] w-full"> <div className="sm:w-[60%] w-full">
<label <label
htmlFor="Job Delivery Details" htmlFor="Job Delivery Details"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1" className="job-label job-label-flex"
> >
Job Delivery Details Job Delivery Details
{props.errors.job_detail && {props.errors.job_detail &&
@@ -220,13 +220,13 @@ function AddJob({ popUpHandler, categories }) {
</div> </div>
<div className="sm:w-[35%] w-full"> <div className="sm:w-[35%] w-full">
<div <label
htmlFor="Job Categories" htmlFor="Job Categories"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"' className='job-label'
id="checked-group" id="checked-group"
> >
Categories Categories
</div> </label>
<div <div
className="sm:flex-col flex flex-wrap px-3 mt-3" className="sm:flex-col flex flex-wrap px-3 mt-3"
role="group" role="group"
@@ -266,7 +266,7 @@ function AddJob({ popUpHandler, categories }) {
<div className="field w-full mb-[5px]"> <div className="field w-full mb-[5px]">
<div className={`flex items-center justify-between mb-2.5`}> <div className={`flex items-center justify-between mb-2.5`}>
<label <label
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block" className="job-label"
htmlFor="timeline_days" htmlFor="timeline_days"
> >
Timeline Timeline
@@ -328,10 +328,10 @@ function AddJob({ popUpHandler, categories }) {
<div className="flex items-center space-x-4 mr-9"> <div className="flex items-center space-x-4 mr-9">
<button <button
type="button" type="button"
className="text-18 text-light-red tracking-wide " className="text-18 tracking-wide h-11 flex justify-center items-center border border-light-red text-base rounded-full text-light-red cursor-pointer"
> >
<span <span
className="border-b dark:border-[#5356fb29] border-light-red" className="px-2"
onClick={popUpHandler} onClick={popUpHandler}
> >
{" "} {" "}
+2 -1
View File
@@ -145,8 +145,9 @@ export default function Login() {
localStorage.setItem("member_id", `${res.data.member_id}`); localStorage.setItem("member_id", `${res.data.member_id}`);
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}`);
if (name === "family") { if (res.data?.account_type == "FAMILY") {
sessionStorage.setItem("family_uid", res.data?.family_uid); sessionStorage.setItem("family_uid", res.data?.family_uid);
sessionStorage.setItem("parent_uid", res.data?.parent_uid);
} }
// localStorage.setItem("session", `${res.data.session}`); // localStorage.setItem("session", `${res.data.session}`);
dispatch(updateUserDetails({ ...res.data })); dispatch(updateUserDetails({ ...res.data }));
+16 -13
View File
@@ -1,22 +1,25 @@
import React from 'react' import React from "react";
import { Link } from 'react-router-dom' import { Link } from "react-router-dom";
export default function CustomBreadcrumb({ title, breadcrumb }) { export default function CustomBreadcrumb({ title, breadcrumb }) {
return ( return (
<div className=""> <div className="">
<h3 className="text-26 font-bold text-dark-gray dark:text-white">{title}</h3> <h3 className="text-26 font-bold text-dark-gray dark:text-white">
<nav aria-label="breadcrumb" className='text-base text-dark-gray dark:text-white flex items-center'> {title}
</h3>
<nav
aria-label="breadcrumb"
className="text-base text-dark-gray dark:text-white flex items-center"
>
{breadcrumb.map((value, index) => ( {breadcrumb.map((value, index) => (
<p key={index}> <React.Fragment key={index}>
<Link className={`${value.active ? 'opacity-60' : ''}`} to={value.link}>{value.title}</Link> <Link className={value.active ? "opacity-60" : ""} to={value.link}>
{index != breadcrumb.length - 1 ? {value.title}
<span className='px-1'>/</span> </Link>
: {index !== breadcrumb.length - 1 && <span className="px-1">\</span>}
null </React.Fragment>
}
</p>
))} ))}
</nav> </nav>
</div> </div>
) );
} }
+115
View File
@@ -0,0 +1,115 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import { tableReload } from "../../store/TableReloads";
import { useDispatch, useSelector } from "react-redux";
import io from "socket.io-client";
let SocketIOContext = createContext({})
export default function SocketIOContextProvider({children}) {
const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS IF USER UID, to determine if user is active
const dispatch = useDispatch()
const socket = io.connect(process.env.REACT_APP_PRIMARY_SOCKET);
// //Room State
// const [room, setRoom] = useState("");
// // Messages States
// const [message, setMessage] = useState("");
const [socketMsgReceived, setSocketMsgReceived] = useState("");
const joinRoom = (room) => {
if (room !== "") {
socket.emit("join_room", room);
}
};
const sendMessage = (message, room) => {
if(message && room){
socket.emit("send_message", { message, room });
}
};
const marketUpdate = (message, room) => {
if(message && room){
socket.emit("marketjob_added", { message, room });
}
};
const parentAssignJobToKid = (message, room) => {
if(message && room){
socket.emit("family", { message:{...message}, room });
}
};
const sendJobInterestToOwner = (message, room) => {
if(message && room){
socket.emit("marketjob", { message:{...message}, room });
}
};
useEffect(() => {
socket.on("receive_message", (data) => {
// setSocketMsgReceived(data.message);
dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
});
socket.on("received_refreshmarket_jobs", (data) => {
// setSocketMsgReceived(data.message);
dispatch(tableReload({type:'MARKETTABLELIST'})) // dispatches to update market list on full account
});
socket.on("family_actions", (data) => {
// setSocketMsgReceived(data.message);
let user_uid = userDetails.account_type == 'FULL' ? userDetails.uid : sessionStorage.getItem('family_uid') // gets user UID
let {message} = data
if(message.action == "REFRESH_OFFER" && message.family_uid == user_uid && message.audience == "MEMBER"){ // for refreshing child account when parent assigns a job
dispatch(tableReload({type:'FAMILYOFFERLIST'})) // dispatches to update family pending/offer list on family side
}
if(message.action == "REFRESH_TASK" && message.audience == "PARENT"){ // for refreshing parent account when child accepts or rejects a job
dispatch(tableReload({type:'PARENTFAMILYTASKLIST'})) // dispatches to update parent family task list on parent side
}
if(message.action == "REFRESH_WALLET" && message.family_uid == user_uid && message.audience == "MEMBER"){ // for refreshing child wallet account when parent sends money to kid
dispatch(tableReload({type:'WALLETTABLE'})) // dispatches to update wallet balance on family side
}
// console.log('DATA', data)
});
socket.on("marketjob_actions", (data) => { // Triggers refresh on owner side, when somebody sends/shows interest in a job
// let user_uid = userDetails.account_type == 'FULL' ? userDetails.uid : sessionStorage.getItem('family_uid') // gets user UID
let {message} = data
if(message.action == "REFRESH_OFFERS" && message.audience == "MERCHANT"){ // for refreshing job owner offer interest list when any worker sends interest
dispatch(tableReload({type:'OFFERINTERESTLISTRELOAD'}))
}
});
}, [socket]);
let values = {
socket,
sendMessage,
joinRoom,
setSocketMsgReceived,
marketUpdate,
parentAssignJobToKid,
sendJobInterestToOwner,
socketMsgReceived,
// room,
// setRoom,
// message,
// setMessage,
}
return (
<SocketIOContext.Provider value={values}>
{children}
</SocketIOContext.Provider>
)
}
export const SocketValues = () => {
return useContext(SocketIOContext)
}
@@ -29,14 +29,15 @@ const AccountDashboard = ({ className, bannerList }) => {
props; props;
return ( return (
<div key={idx}>
<TopBanner <TopBanner
btn={short_button_text} btn={short_button_text}
image={image} image={image}
title={short_title} title={short_title}
desc={short_description} desc={short_description}
link_path={link_path} link_path={link_path}
key={idx}
/> />
</div>
); );
})} })}
</div> </div>
@@ -48,14 +49,15 @@ const AccountDashboard = ({ className, bannerList }) => {
props; props;
return ( return (
<div key={idx}>
<LowerBanner <LowerBanner
btn={short_button_text} btn={short_button_text}
image={image} image={image}
title={short_title} title={short_title}
desc={short_description} desc={short_description}
link_path={link_path} link_path={link_path}
key={idx}
/> />
</div>
); );
})} })}
</div> </div>
+29 -17
View File
@@ -1,16 +1,11 @@
import React, { Suspense, useMemo, useState } from "react"; import React, { Suspense } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import usersService from "../../services/UsersService"; import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import FamilyTableNew from "./FamilyTableNew"; import FamilyTableNew from "./FamilyTableNew";
export default function FamilyActivities() { export default function FamilyActivities() {
const [familyList, setFamilyList] = useState({});
const [loader, setLoader] = useState(false);
const apiCall = useMemo(() => new usersService(), []);
return ( return (
<Layout> <Layout>
{/*<CommonHead />*/} {/*<CommonHead />*/}
@@ -19,11 +14,26 @@ export default function FamilyActivities() {
{/* heading */} {/* heading */}
<div className="sm:flex justify-between items-center mb-6"> <div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0"> <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"> <CustomBreadcrumb
<span className={``}>Tasks & Chores</span> title={"Tasks & Chores"}
</h1> breadcrumb={[
{ link: "/", title: "Home" },
{
link: "/acc-family",
title: "Family Account",
},
{
link: "/acc-family/activities",
title: "Tasks & Chores",
active: true,
},
]}
/>
</div> </div>
<Link className="flex items-center gap-2" to="/acc-family"> <Link
className="item-content relative text-[18px] transition-all duration-300 ease-in-out bg-[#76a5df] text-white font-medium dark:text-white h-12 px-2 flex items-center gap-2 rounded-md shadow-sm justify-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)]"
to="/acc-family"
>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
fill="none" fill="none"
@@ -42,12 +52,14 @@ export default function FamilyActivities() {
<span>Family</span> <span>Family</span>
</Link> </Link>
</div> </div>
<Suspense fallback={<LoadingSpinner color="sky-blue" size="16" />}> <Suspense
<FamilyTableNew fallback={
familyList={familyList?.result_list} <div className="bg-white">
loader={loader} <LoadingSpinner color="sky-blue" size="16" height='h-[30rem]' />
imageServer={familyList?.session_image_server} </div>
/> }
>
<FamilyTableNew />
</Suspense> </Suspense>
</div> </div>
</div> </div>
+37 -2
View File
@@ -1,8 +1,9 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import FamilyManageTabs from "./FamilyManageTabs"; import FamilyManageTabs from "./FamilyManageTabs";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function FamilyManage() { export default function FamilyManage() {
const [selectTab, setValue] = useState("today"); const [selectTab, setValue] = useState("today");
@@ -34,7 +35,7 @@ export default function FamilyManage() {
<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 */}
<div className="sm:flex justify-between items-center mb-6"> {/* <div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0"> <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"> <h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
<span <span
@@ -50,6 +51,40 @@ export default function FamilyManage() {
className="relative" className="relative"
></div> ></div>
</div> </div>
</div> */}
<div className="w-full mb-5 flex justify-between items-center">
<div className="">
<CustomBreadcrumb
title = {'Manage Family'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/manage-family", title: "Manage Family", active: true},
]
}
/>
</div>
<Link
className="item-content relative text-[18px] transition-all duration-300 ease-in-out bg-[#76a5df] text-white font-medium dark:text-white h-12 px-2 flex items-center gap-2 rounded-md shadow-sm justify-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)]"
to="/acc-family"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-4 h-4"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18"
/>
</svg>
<span>Family</span>
</Link>
</div> </div>
<FamilyManageTabs accountDetails={accountDetails} /> <FamilyManageTabs accountDetails={accountDetails} />
</div> </div>
@@ -187,6 +187,7 @@ export default function FamilyManageTabs({
familyData={details.familyWaitList.data} familyData={details.familyWaitList.data}
accountDetails={accountDetails} accountDetails={accountDetails}
loader={details.familyWaitList.loading} loader={details.familyWaitList.loading}
setUpdatePage={setUpdatePage}
/> />
), ),
Pending: ( Pending: (
+17 -14
View File
@@ -4,39 +4,29 @@ import MyOffersFamilyTable from '../MyTasks/MyOffersFamilyTable'
import LoadingSpinner from '../Spinners/LoadingSpinner'; import LoadingSpinner from '../Spinners/LoadingSpinner';
import usersService from '../../services/UsersService'; import usersService from '../../services/UsersService';
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb'; import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb';
import { useSelector } from 'react-redux';
export default function FamilyPendingOffer() { export default function FamilyPendingOffer() {
const userApi = new usersService(); const userApi = new usersService();
const {familyOfferList} = useSelector((state) => state.tableReload)
const [myOffersList, setMyOffersList] = useState({loading: true, data: []}); const [myOffersList, setMyOffersList] = useState({loading: true, data: []});
const getMyOffersList = async () => { const getMyOffersList = async () => {
try { try {
const res = await userApi.getOffersList(); const res = await userApi.getOffersList();
setMyOffersList({loading:false, data:res.data}); setMyOffersList({loading:false, data:res.data});
console.log('SAME', res.data)
} catch (error) { } catch (error) {
setMyOffersList({loading:false, data:[]}); setMyOffersList({loading:false, data:[]});
console.log("Error getting offers", error);
} }
}; };
useEffect(()=>{ useEffect(()=>{
getMyOffersList() getMyOffersList()
},[]) },[familyOfferList])
return ( return (
<Layout> <Layout>
<div className="mb-5">
<CustomBreadcrumb
title = {'Ready to Start'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/pending", title: "Pending", active: true},
]
}
/>
</div>
{myOffersList.loading ? {myOffersList.loading ?
<div className='w-full flex justify-center items-center rounded-2xl bg-white'> <div className='w-full flex justify-center items-center rounded-2xl bg-white'>
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' /> <LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
@@ -49,9 +39,22 @@ export default function FamilyPendingOffer() {
className="mb-10" className="mb-10"
/> />
: :
<>
<div className="mb-6">
<CustomBreadcrumb
title = {'Ready to Start'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/pending", title: "Pending", active: true},
]
}
/>
</div>
<div className='w-full h-[30rem] bg-white dark:bg-dark-white flex justify-center items-center rounded-2xl'> <div className='w-full h-[30rem] bg-white dark:bg-dark-white flex justify-center items-center rounded-2xl'>
<p className='text-black dark:text-white'>No Record Found!</p> <p className='text-black dark:text-white'>No Record Found!</p>
</div> </div>
</>
} }
</Layout> </Layout>
) )
@@ -1,15 +1,16 @@
import React, { useState } from "react"; import React, { Suspense, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useLocation } from "react-router-dom";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import { tableReload } from "../../../store/TableReloads";
import ModalCom from "../../Helpers/ModalCom"; import ModalCom from "../../Helpers/ModalCom";
import { PriceFormatter } from "../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../Helpers/PriceFormatter";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; import LoadingSpinner from "../../Spinners/LoadingSpinner";
import Detail from "../../jobPopout/popoutcomponent/Detail"; import Detail from "../../jobPopout/popoutcomponent/Detail";
import { NewTasks } from "./forms"; import { NewTasks } from "./forms";
import { tableReload } from "../../../store/TableReloads"; import { SocketValues } from "../../Contexts/SocketIOContext";
import { useDispatch } from "react-redux";
const AssignTaskPopout = React.memo( const AssignTaskPopout = ({
({
action, action,
details, details,
situation, situation,
@@ -17,11 +18,34 @@ const AssignTaskPopout = React.memo(
familyTask, familyTask,
activeTask, activeTask,
setActiveTask, setActiveTask,
setUpdatePage setUpdatePage,
assignTaskChecker,
}) => { }) => {
const {parentAssignJobToKid} = SocketValues()
const apiCall = new usersService(); const apiCall = new usersService();
const dispatch = useDispatch() let { pathname, state } = useLocation();
const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
const [selectedFamilyUid, setSelectedFamilyUid] = useState('');
const handleFamChange = (event) => {
setSelectedFamilyUid(event.target.value);
};
const dispatch = useDispatch();
const getFamilySession = JSON.parse(sessionStorage.getItem("family_list"));
const familyList = getFamilySession?.map((member) => (
<option key={member?.family_uid} value={member?.family_uid}>
{member?.firstname} {member?.lastname}
</option>
));
let [requestStatus, setRequestStatus] = useState({ let [requestStatus, setRequestStatus] = useState({
loading: false, loading: false,
@@ -56,6 +80,14 @@ const AssignTaskPopout = React.memo(
const assignFamilyTask = () => { const assignFamilyTask = () => {
setRequestStatus({ loading: true, status: false, message: "" }); setRequestStatus({ loading: true, status: false, message: "" });
if(!selectedFamilyUid){ // If no family found, throw error
setRequestStatus({ loading: false, status: false, message: "Please Select a Kid" });
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
}
let reqData = {}; let reqData = {};
if (taskType == "select") { if (taskType == "select") {
// RUNS HERE IF TASK TYPE IS SELECT // RUNS HERE IF TASK TYPE IS SELECT
@@ -73,7 +105,9 @@ const AssignTaskPopout = React.memo(
// 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: familyDetailsData?.uid || details?.family_uid, family_uid: selectedFamilyUid
? selectedFamilyUid
: familyDetailsData?.uid || details?.family_uid,
job_description: activeTask.data?.description, job_description: activeTask.data?.description,
assign_mode: 110011, assign_mode: 110011,
}; };
@@ -96,7 +130,7 @@ const AssignTaskPopout = React.memo(
// category, // category,
currency: country, currency: country,
description, description,
'job detail':job_detail, "job detail": job_detail,
price, price,
timeline: timeline_days, timeline: timeline_days,
title, title,
@@ -108,7 +142,9 @@ const AssignTaskPopout = React.memo(
setRequestStatus({ setRequestStatus({
loading: false, loading: false,
status: false, status: false,
message: `${field[0].toUpperCase()+field.slice(1).toLowerCase()} is empty`, message: `${
field[0].toUpperCase() + field.slice(1).toLowerCase()
} is empty`,
}); });
return setTimeout(() => { return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" }); setRequestStatus({ loading: false, status: false, message: "" });
@@ -126,7 +162,9 @@ const AssignTaskPopout = React.memo(
timeline_days, timeline_days,
title, title,
assign_mode: 110055, assign_mode: 110055,
family_uid: details?.family_uid || familyDetailsData?.uid, family_uid: selectedFamilyUid
? selectedFamilyUid
: familyDetailsData?.uid || details?.family_uid,
}; };
} }
@@ -139,21 +177,38 @@ const AssignTaskPopout = React.memo(
status: false, status: false,
message: "failed to assign task", message: "failed to assign task",
}); });
return setTimeout(() => { return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" }); setRequestStatus({ loading: false, status: false, message: "" });
}, 5000); }, 5000);
} }
if (res.status === 200) {
setRequestStatus({ setRequestStatus({
loading: false, loading: false,
status: true, status: true,
message: "action successful", message: "action successful",
}); });
setUpdatePage(prev => !prev) // Updates family task page by calling the useeffect hook
setUpdatePage(prev => !prev); // Updates family task page by calling the useeffect hook
dispatch(tableReload({ type: "WALLETTABLE" })); // RELOADS USER WALLET dispatch(tableReload({ type: "WALLETTABLE" })); // RELOADS USER WALLET
//SENDS MESSAGE TO SOCKET TO UPDATE CHILD ACCOUNT
// message, room
let socketMsg = {
"audience": "MEMBER",
"action": "REFRESH_OFFER",
"family_uid": reqData.family_uid,
}
let socketRoom = `FAMILY-${userDetails.uid}`
parentAssignJobToKid(socketMsg, socketRoom) //SENDS MESSAGE TO SOCKET TO UPDATE CHILD ACCOUNT
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
}, 5000); }, 5000);
}
}) })
.catch((err) => { .catch((err) => {
setRequestStatus({ setRequestStatus({
@@ -161,27 +216,60 @@ const AssignTaskPopout = React.memo(
status: false, status: false,
message: "An Error occured, try again", message: "An Error occured, try again",
}); });
setTimeout(() => { setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" }); setRequestStatus({ loading: false, status: false, message: "" });
}, 5000); }, 5000);
}); });
}; };
let imageSrc = (localStorage.getItem("session_token")
? `${userDetails?.session_image_server}${localStorage.getItem("session_token")}/job/${activeTask.data.job_uid}` : ""); // FOR GETTING JOB IMAGE
useEffect(()=>{ // effect to update family UID when components mounts
if(familyDetailsData?.uid){
setSelectedFamilyUid(familyDetailsData?.uid)
}else if(details?.family_uid){
setSelectedFamilyUid(details?.family_uid)
}else{
setSelectedFamilyUid('')
}
},[])
return ( return (
<> <>
<ModalCom <ModalCom action={action} situation={situation}>
action={action}
situation={situation}
>
<div className="w-11/12 lg:w-[700px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto"> <div className="w-11/12 lg:w-[700px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
<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="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Assign task to{" "} {details ? (
{familyDetailsData?.firstname || details?.firstName} ` Assign ${details?.firstname}'s Task`
) : familyDetailsData ? (
` Assign ${familyDetailsData.firstname}'s Task`
) : (
<div className="flex items-center gap-2">
<span className="text-black">Assign task to{" "}</span>
<div className="w-[270px] h-[40px] flex items-center">
<select
name=""
id=""
className="text-lg text-black/80 px-2 tracking-wide font-semibold transition-all cursor-pointer bg-white focus:outline-none border border-gray-200 rounded-full w-full h-full"
onChange={handleFamChange}
value={selectedFamilyUid}
>
<option value="" className="">
Select a kid
</option>
{familyList}
</select>
</div>
</div>
)}
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={action} onClick={action}
> >
<svg <svg
@@ -249,9 +337,7 @@ const AssignTaskPopout = React.memo(
<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={() => onClick={() => handleActiveTask(item.job_uid, item)}
handleActiveTask(item.job_uid, item)
}
> >
<input <input
type="radio" type="radio"
@@ -302,9 +388,10 @@ const AssignTaskPopout = React.memo(
value={activeTask?.data?.description} value={activeTask?.data?.description}
/> />
</div> </div>
<div className="flex items-center"> <div className="grid grid-cols-2">
<div className="w-full">
<div className="my-3 w-full flex items-center gap-1"> <div className="my-3 w-full flex items-center gap-1">
<label className="text-slate-900 dark:text-white tracking-wide font-semibold"> <label className="job-label">
Price Price
</label> </label>
<p className="p-1 text-sm text-slate-900 dark:text-white"> <p className="p-1 text-sm text-slate-900 dark:text-white">
@@ -317,22 +404,34 @@ const AssignTaskPopout = React.memo(
</div> </div>
<div className="my-3 w-full flex items-center gap-1"> <div className="my-3 w-full flex items-center gap-1">
<label className="text-slate-900 dark:text-white tracking-wide font-semibold"> <label className="job-label">
Timeline Timeline
</label> </label>
<p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p> <p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p>
</div> </div>
</div> </div>
<div className="w-full flex items-center justify-center">
<div className="w-28 h-28 rounded-2xl flex items-center justify-center">
<img
className="w-full h-auto"
loading="lazy"
src={imageSrc}
alt='job image'
/>
</div>
</div>
</div>
<div className="my-3 sm:flex items-center"> {/* Dummy, no value found for created! thus commented*/}
{/* <div className="my-3 sm:flex items-center">
<Detail <Detail
label="Created" label="Created"
value={`Dummy, no value found for created!`} value={`Dummy, no value found for created!`}
/> />
</div> </div> */}
<div className="my-3"> <div className="my-3">
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold"> <label className="w-full job-label">
Delivery Detail Delivery Detail
</label> </label>
<textarea <textarea
@@ -354,7 +453,7 @@ const AssignTaskPopout = React.memo(
</div> </div>
{/* BTN */} {/* BTN */}
<div className="py-2 px-4 border-t-2 flex justify-between items-center"> <div className="modal-footer-wrapper">
{/* error or success display */} {/* error or success display */}
<div className="w-auto h-auto flex items-center"> <div className="w-auto h-auto flex items-center">
{requestStatus.message != "" && {requestStatus.message != "" &&
@@ -376,39 +475,43 @@ const AssignTaskPopout = React.memo(
</div> </div>
{/* End of error or success display */} {/* End of error or success display */}
<div className="w-auto h-auto flex items-center gap-3"> <div className="w-auto h-auto flex items-center gap-20">
<button <button
disabled={requestStatus.loading} disabled={requestStatus.loading}
onClick={action} onClick={action}
type="button" type="button"
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer" className="custom-btn border-gradient"
> >
<span className="text-gradient">Close</span> <span className="text-gradient">Close</span>
</button> </button>
<div className=""> <div className="">
{requestStatus.loading ? ( {requestStatus.loading ? (
<LoadingSpinner color="sky-blue" size="8" /> <LoadingSpinner color="sky-blue" size="8" />
) : taskType == "select" ? (
<button
type="button"
disabled={requestStatus.loading}
onClick={assignFamilyTask}
className="px-1 w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
>
Assign
</button>
) : ( ) : (
<button <button
type="button" type="button"
disabled={requestStatus.loading} disabled={requestStatus.loading}
onClick={assignFamilyTask} onClick={assignFamilyTask}
className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer" className="custom-btn btn-gradient text-white"
> >
{`Assign to ${ Assign
familyDetailsData?.firstname || details?.firstName
}`}
</button> </button>
)} )
// : (
// <button
// type="button"
// disabled={requestStatus.loading}
// onClick={assignFamilyTask}
// className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
// >
// {details
// ? `Assign task to ${details?.firstname}`
// : familyDetailsData
// ? `Assign task to ${familyDetailsData.firstname}`
// : "Assign"}
// </button>
// )
}
</div> </div>
</div> </div>
</div> </div>
@@ -418,7 +521,6 @@ const AssignTaskPopout = React.memo(
</ModalCom> </ModalCom>
</> </>
); );
} };
);
export default AssignTaskPopout; export default AssignTaskPopout;
@@ -56,7 +56,7 @@ export default function NewTasks({ formState, setFormState }) {
<div className="field w-full mb-6 xl:mb-0"> <div className="field w-full mb-6 xl:mb-0">
<label <label
htmlFor="country" htmlFor="country"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1" className="job-label"
> >
Currency Currency
{/* {props.errors.country && props.touched.country && <span className="text-[12px] text-red-500">{props.errors.country}</span>} */} {/* {props.errors.country && props.touched.country && <span className="text-[12px] text-red-500">{props.errors.country}</span>} */}
@@ -98,10 +98,11 @@ export default function NewTasks({ formState, setFormState }) {
{/* Price */} {/* Price */}
<div className="field w-full"> <div className="field w-full">
<label htmlFor="price" className="job-label">Price</label>
<InputCom <InputCom
fieldClass="px-6 text-right" fieldClass="px-6 text-right"
label="Price" // label="Price"
labelClass="tracking-wide" // labelClass="tracking-wide"
inputBg="bg-slate-100" inputBg="bg-slate-100"
type="number" type="number"
name="price" name="price"
@@ -117,7 +118,7 @@ export default function NewTasks({ formState, setFormState }) {
<div className="field w-full mb-6 xl:mb-0"> <div className="field w-full mb-6 xl:mb-0">
<label <label
htmlFor="timeline_days" htmlFor="timeline_days"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1" className="job-label"
> >
Timeline Timeline
{/* {props.errors.country && props.touched.country && <span className="text-[12px] text-red-500">{props.errors.country}</span>} */} {/* {props.errors.country && props.touched.country && <span className="text-[12px] text-red-500">{props.errors.country}</span>} */}
@@ -151,10 +152,11 @@ export default function NewTasks({ formState, setFormState }) {
{/* Title */} {/* Title */}
<div className="field w-full mb-[5px]"> <div className="field w-full mb-[5px]">
<label htmlFor="title" className="job-label">Title</label>
<InputCom <InputCom
fieldClass="px-6" fieldClass="px-6"
label="Title" // label="Title"
labelClass="tracking-wide" // labelClass="tracking-wide"
inputBg="bg-slate-100" inputBg="bg-slate-100"
type="text" type="text"
name="title" name="title"
@@ -167,10 +169,11 @@ export default function NewTasks({ formState, setFormState }) {
{/* Description */} {/* Description */}
<div className="field w-full mb-[5px]"> <div className="field w-full mb-[5px]">
<label htmlFor="description" className="job-label">Description</label>
<InputCom <InputCom
fieldClass="px-6" fieldClass="px-6"
label="Description" // label="Description"
labelClass="tracking-wide" // labelClass="tracking-wide"
inputBg="bg-slate-100" inputBg="bg-slate-100"
type="text" type="text"
name="description" name="description"
@@ -186,7 +189,7 @@ export default function NewTasks({ formState, setFormState }) {
<div className="w-full"> <div className="w-full">
<label <label
htmlFor="Job Delivery Details" htmlFor="Job Delivery Details"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1' className='job-label'
> >
Job Delivery Details Job Delivery Details
{/* {props.errors.job_detail && props.touched.job_detail && <span className="text-[12px] text-red-500">{props.errors.job_detail}</span>} */} {/* {props.errors.job_detail && props.touched.job_detail && <span className="text-[12px] text-red-500">{props.errors.job_detail}</span>} */}
@@ -1,11 +1,12 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
import CustomBreadcrumb from "../../Breadcrumb/CustomBreadcrumb";
import Icons from "../../Helpers/Icons"; import Icons from "../../Helpers/Icons";
import Layout from "../../Partials/Layout"; import Layout from "../../Partials/Layout";
import { AddFamily, FamilyBanner, Relatives } from "./Tabs"; import { AddFamily, FamilyBanner, Relatives } from "./Tabs";
const FamilySettings = () => { const FamilySettings = () => {
let {state} = useLocation() let { state } = useLocation();
const tabs = [ const tabs = [
{ {
id: 1, id: 1,
@@ -58,15 +59,42 @@ const FamilySettings = () => {
{/* heading */} {/* heading */}
<div className="sm:flex justify-between items-center mb-6"> <div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0"> <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"> <CustomBreadcrumb
<span className={``}>Family Settings</span> title={"Family Settings"}
</h1> breadcrumb={[
{ link: "/", title: "Home" },
{
link: "/acc-family",
title: "Family Account",
},
{
link: "/familysettings",
title: "Family Settings",
active: true,
},
]}
/>
</div> </div>
<Link to="/acc-family" className="flex gap-2 items-center text-dark-gray dark:text-white"> <Link
<svg className="w-5 h-5 rtl:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor"> className="item-content relative text-[18px] transition-all duration-300 ease-in-out bg-[#76a5df] text-white font-medium dark:text-white h-12 px-2 flex items-center gap-2 rounded-md shadow-sm justify-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)]"
<path strokeLinecap="round" strokeLinejoin="round" d="M6.75 15.75L3 12m0 0l3.75-3.75M3 12h18" /> to="/acc-family"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-4 h-4"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18"
/>
</svg> </svg>
Family
<span>Family</span>
</Link> </Link>
</div> </div>
+74 -87
View File
@@ -1,37 +1,32 @@
import React, { import React, { Suspense, lazy, useEffect, useMemo, useState } from "react";
Suspense, import { useLocation } from "react-router-dom";
lazy, import { apiConst } from "../../lib/apiConst";
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useReactToPrint } from "react-to-print";
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";
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout"; import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
import FamilyWallet from "./Tabs/FamilyWallet"; import { useSelector } from "react-redux";
import { apiConst } from "../../lib/apiConst";
// Lazy Imports for components // Lazy Imports for components
const FamilyWaitlist = lazy(() => import("./Tabs/FamilyWaitlist")); const FamilyWaitlist = lazy(() => import("./Tabs/FamilyNewWaitlist"));
const FamilyAccount = lazy(() => import("./Tabs/FamilyAccount")); const FamilyTasks = lazy(() => import("./Tabs/FamilyNewTasks"));
const FamilyProfile = lazy(() => import("./Tabs/FamilyProfile")); const FamilyPending = lazy(() => import("./Tabs/FamilyNewPending"));
const FamilyTasks = lazy(() => import("./Tabs/FamilyTasks"));
const FamilyPending = lazy(() => import("./Tabs/FamilyPending")); export default function FamilyTableNew() {
const { parentFamilyTaskList } = useSelector((state) => state.tableReload);
console.log('parentFamilyTaskList', parentFamilyTaskList)
let { pathname } = useLocation();
export default function FamilyTableNew({
className,
accountDetails,
listReload,
loader,
}) {
// Initial state for family details // Initial state for family details
const initialDetailState = { const initialDetailState = {
loading: false, loading: true,
data: null, data: null,
link: "",
}; };
const [assignTaskChecker, setAssignTaskChecker] = useState(false);
// console.log('accountDetails',accountDetails) // console.log('accountDetails',accountDetails)
// State for family details, tasks, waitlist, and pending // State for family details, tasks, waitlist, and pending
const [details, setDetails] = useState({ const [details, setDetails] = useState({
@@ -51,7 +46,7 @@ import React, {
}); });
}; };
const [updatePage, setUpdatePage] = useState(false) // State to determine when to update the page const [updatePage, setUpdatePage] = useState(false); // State to determine when to update the page
// State for family task data // State for family task data
const [familyTask, setFamilyTask] = useState({ loading: false, data: [] }); const [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
@@ -73,15 +68,6 @@ import React, {
setFamilyTaskPopout((prev) => !prev); setFamilyTaskPopout((prev) => !prev);
}; };
// Ref for the account section
const accountRef = useRef();
// React-to-Print hook for handling printing
const useHandlePrint = useReactToPrint({
content: () => accountRef.current,
});
// Array of tab names // Array of tab names
const tabs = [ const tabs = [
{ id: 1, name: "Tasks" }, { id: 1, name: "Tasks" },
@@ -101,47 +87,31 @@ import React, {
const tabComponents = { const tabComponents = {
Tasks: ( Tasks: (
<FamilyTasks <FamilyTasks
className={className} image_link={details.familyTasks.link}
loader={details.familyTasks.loading} loader={details.familyTasks.loading}
familyData={details.familyTasks.data} familyData={details.familyTasks.data}
accountDetails={accountDetails} action={familyPopUpHandler}
setAssignTaskChecker={setAssignTaskChecker}
/> />
), ),
Waiting: ( Waiting: (
<FamilyWaitlist <FamilyWaitlist
image_link={details.familyWaitList.link}
familyData={details.familyWaitList.data} familyData={details.familyWaitList.data}
accountDetails={accountDetails}
loader={details.familyWaitList.loading} loader={details.familyWaitList.loading}
setUpdatePage={setUpdatePage}
/> />
), ),
Pending: ( Pending: (
<FamilyPending <FamilyPending
image_link={details.familyPending.link}
familyData={details.familyPending.data} familyData={details.familyPending.data}
accountDetails={accountDetails}
loader={details.familyPending.loading} loader={details.familyPending.loading}
/> />
), ),
Account: (
<FamilyAccount
familyData={details.familyDetails.data}
myRef={accountRef}
loader={details.familyDetails.loading}
handlePrint={useHandlePrint}
/>
),
Profile: <FamilyProfile familyData={details.familyDetails.data} />,
wallet: <FamilyWallet familyData={details.familyDetails.data} />,
}; };
// Default tab component const defaultTabComponent = tabComponents.Tasks;
const defaultTabComponent = (
<FamilyTasks
className={className}
loader={details.familyTasks.loading}
familyData={details.familyTasks.data}
accountDetails={accountDetails}
/>
);
// Selected tab component based on the current 'tab' // Selected tab component based on the current 'tab'
const selectedTabComponent = tabComponents[tab] || defaultTabComponent; const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
@@ -150,51 +120,67 @@ import React, {
useEffect(() => { useEffect(() => {
const manageFamily = async () => { const manageFamily = async () => {
try { try {
resetDetails(); // resetDetails();
setDetails({ // setDetails({
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 };
const [familyRes, tasksRes, familyWaitRes, familyPending] = const [familyTasksData, familyWaitingRes, familyPendingRes] =
await Promise.all([ await Promise.all([
apiCall.ManageFamily(reqData), apiCall.getMyActiveJobList(),
apiCall.ManageTasks(reqData), apiCall.ManageFamilyNewWaitlist(),
apiCall.ManageFamilyWaitlist(),
apiCall.ManageFamilyPending(), apiCall.ManageFamilyPending(),
]); ]);
const familyData = familyRes.data; let tasksData = familyTasksData?.data?.result_list;
const tasksData = tasksRes.data; let _familyWaitData = familyWaitingRes?.data?.result_list;
const familyWaitData = familyWaitRes.data; let familyPendingData = familyPendingRes?.data?.result_list;
const familyPendingData = familyPending.data;
// Getting the image server link
let imageServerLink = familyWaitingRes.data?.session_image_server;
// Function to check for errors in data // Function to check for errors in data
const checkDataError = (data) => data?.internal_return < 0; const checkDataError = (data) => data?.internal_return < 0;
if ( if (
checkDataError(familyData) ||
checkDataError(tasksData) || checkDataError(tasksData) ||
checkDataError(familyWaitData) || checkDataError(_familyWaitData) ||
checkDataError(familyPendingData) checkDataError(familyPendingData)
) { ) {
return; return;
} }
setDetails({ setDetails({
familyDetails: { loading: false, data: familyData }, familyTasks: {
familyTasks: { loading: false, data: tasksData }, loading: false,
familyWaitList: { loading: false, data: familyWaitData }, data: tasksData,
familyPending: { loading: false, data: familyPendingData }, link: imageServerLink,
},
familyWaitList: {
loading: false,
data: _familyWaitData,
link: imageServerLink,
},
familyPending: {
loading: false,
data: familyPendingData,
link: imageServerLink,
},
}); });
} catch (error) { } catch (error) {
resetDetails(); // resetDetails();
setDetails({
familyDetails: { ...initialDetailState, loading: false, },
familyTasks: { ...initialDetailState, loading: false, },
familyWaitList: { ...initialDetailState, loading: false,},
familyPending: { ...initialDetailState, loading: false, },
})
setErrMsg("An error occurred"); setErrMsg("An error occurred");
throw new Error(error); throw new Error(error);
} }
@@ -202,7 +188,7 @@ import React, {
// Invoke the manageFamily function when the component mounts // Invoke the manageFamily function when the component mounts
manageFamily(); manageFamily();
}, [updatePage]); }, [updatePage, parentFamilyTaskList]);
// Effect to manage family tasks // Effect to manage family tasks
useEffect(() => { useEffect(() => {
@@ -239,11 +225,11 @@ import React, {
}; };
}, []); }, []);
// console.log(updatePage);
return ( return (
<div <div
className={`w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow h-full ${ className={`w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow h-full`}
className || ""
}`}
> >
<div className="relative w-full sm:rounded-lg overflow-x-auto"> <div className="relative w-full sm:rounded-lg overflow-x-auto">
<Suspense <Suspense
@@ -304,11 +290,12 @@ import React, {
setFamilyTask={setFamilyTask} setFamilyTask={setFamilyTask}
setActiveTask={setActiveTask} setActiveTask={setActiveTask}
activeTask={activeTask} activeTask={activeTask}
familyDetailsData={details.familyDetails.data}
setUpdatePage={setUpdatePage} setUpdatePage={setUpdatePage}
// updateFamilyPendingTable={updateFamilyPendingTable}
pathname={pathname}
assignTaskChecker={assignTaskChecker}
/> />
)} )}
</div> </div>
); );
} }
@@ -0,0 +1,154 @@
import { useMemo, useState } from "react";
import { PriceFormatter } from "../../Helpers/PriceFormatter";
import { PaginatedList, handlePagingFunc } from "../../Pagination";
import PendingJobsPopout from "../../jobPopout/PendingJobsPopout";
export default function FamilyPending({ familyData, image_link, loader }) {
let [jobPopout, setJobPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW
let filteredFamilyData = useMemo(
() => familyData?.filter((data) => data.family_uid !== ""),
[familyData]
);
const [currentPage, setCurrentPage] = useState(0);
const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentPendingTasks = filteredFamilyData?.slice(
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
console.log(image_link);
return (
<div
className={`update-table w-full p-3 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow lg:min-h-[538px]`}
>
{familyData && (
<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>
{
<>
{currentPendingTasks.length > 0 ? (
currentPendingTasks.map((value, index) => {
let deliveryDate = value?.expire?.split(" ")[0];
let thePrice = PriceFormatter(
value?.price * 0.01,
value?.currency_code,
value?.currency
);
let image = `${image_link}${localStorage.getItem(
"session_token"
)}/job/${value.job_uid}`;
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-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img
src={image}
alt="data"
className="w-full h-full rounded-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>{value.description}</div>
<span className="text-sm text-thin-light-gray flex items-start gap-1">
Price:{" "}
<span className="text-purple">
{thePrice}
</span>
</span>
<div className="flex items-center gap-4">
<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">
Expire:{" "}
<span className="text-purple">
{" "}
{deliveryDate}
</span>
</span>
<span className="text-sm text-thin-light-gray">
Sent to:{" "}
<span className="text-purple">
{" "}
{value.job_to}
</span>
</span>
</div>
</div>
</div>
</td>
<td className="text-right py-4 px-2 flex justify-end items-center">
<button
type="button"
onClick={() => {
setJobPopout({ show: true, data: value });
}}
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
View
</button>
</td>
</tr>
);
})
) : (
<tr>
<td className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap text-center py-4 px-2">
No Pending Task!
</td>
</tr>
)}
</>
}
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0}
next={currentPage + itemsPerPage >= filteredFamilyData.length}
data={filteredFamilyData}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
)}
{/* Active Job Popout */}
{jobPopout.show && (
<PendingJobsPopout
details={jobPopout.data}
onClose={() => {
setJobPopout({ show: false, data: {} });
}}
situation={jobPopout.show}
/>
)}
{/* End of Active Job Popout */}
</div>
);
}
@@ -0,0 +1,171 @@
import React, { useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import Icons from "../../Helpers/Icons";
import { PriceFormatter } from "../../Helpers/PriceFormatter";
import { handlePagingFunc } from "../../Pagination/HandlePagination";
import PaginatedList from "../../Pagination/PaginatedList";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
export default function FamilyNewTasks({
familyData,
className,
loader,
action,
image_link,
}) {
let navigate = useNavigate();
let { pathname } = useLocation();
// ...
let filteredFamilyData = useMemo(
() => familyData?.filter((data) => data.family_uid !== ""),
[familyData]
);
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentTasks = filteredFamilyData?.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-[538px] overflow-hidden rounded-2xl section-shadow p-3 ${
familyData?.length <= 0 && "flex items-center justify-center"
}`}
>
{loader ? (
<div className="w-full h-full flex justify-center items-center lg:min-h-[470px]">
<LoadingSpinner size={16} color="sky-blue" />
</div>
) : (
<>
{familyData && (
<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?.length <= 0 ? (
<tr>
<td
colSpan="2"
className="text-center py-4 font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap flex items-center justify-center gap-1"
>
You currently have no active tasks{" "}
<span
className="text-blue-400 cursor-pointer hover:underline transition duration-150"
onClick={action}
>
add new
</span>
</td>
</tr>
) : (
currentTasks.map((value, index) => {
// find due date
const dueDate = value?.delivery_date.split(" ")[0];
// the price
let thePrice = PriceFormatter(
value?.price * 0.01,
value?.currency_code,
value?.currency
);
let image = `${image_link}${localStorage.getItem(
"session_token"
)}/job/${value.job_uid}`;
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-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img
src={image}
alt="data"
className="w-full h-full rounded-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 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">
Price:{" "}
<span className="text-purple">
{thePrice}
</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) >=
filteredFamilyData?.length
? true
: false
}
data={filteredFamilyData}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
)}
</>
)}
</div>
);
}
@@ -0,0 +1,154 @@
import { useState } from "react";
import SuggestTask from "../../FamilyPopup/SuggestTask";
import { PaginatedList, handlePagingFunc } from "../../Pagination";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
import AssignTaskPopout from "../FamilyPopout/AssignTaskPopout";
import Icons from "../../Helpers/Icons";
const FamilyNewWaitlist = ({
familyData,
className,
accountDetails,
loader,
setUpdatePage
}) => {
const [popUp, setPopUp] = useState({ show: false, data: {} });
const [continueTaskPopup, setContinueTaskPopup] = useState({
show: false,
data: {},
});
const [currentPage, setCurrentPage] = useState(0);
const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE);
const indexOfFirstItem = currentPage;
const indexOfLastItem = currentPage + itemsPerPage;
const currentTask = familyData?.slice(
indexOfFirstItem,
indexOfLastItem
);
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: {} });
};
console.log("Check this >>",continueTaskPopup)
return (
<div
className={`update-table w-full bg-white dark:bg-dark-white h-full lg:min-h-[538px] p-3 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 && (
<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>
{currentTask.map((value) => {
const addedDate = value?.added.split(" ")[0];
const selectedImage = require(`../../../assets/images/family/${
value?.banner || "default.jpg"
}`);
// console.log("VALUE", value);
// let image = `${familyData.session_image_server}${localStorage.getItem('session_token')}/job/${value.job_uid}`
return (
<tr
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
key={value.uid}
>
<td className="py-4">
<div className="w-full flex justify-between items-center">
<div className="account-name flex space-x-4 items-center">
<div className="icon w-14 h-14 flex justify-center items-center">
<img
src={selectedImage}
alt="task_img"
className="w-full object-cover"
/>
</div>
<div className="">
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
{value.title}
</p>
<p className="text-sm text-thin-light-gray font-medium">
{value.description}
</p>
</div>
</div>
<div className="px-2 flex flex-col items-center justify-center">
<p className="text-sm font-bold text-dark-gray dark:text-white">
{addedDate}
</p>
<p className="text-xs py-1.5 w-[70px] cursor-default tracking-wide rounded-full bg-gold text-white flex justify-center items-center">
{value.firstname}
</p>
</div>
</div>
</td>
<td className="text-right py-4 px-2 flex justify-end">
<button
onClick={() => openPopUp(value)}
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{/* View */}
<Icons name="right-arrow" />
</button>
</td>
</tr>
);
})}
</tbody>
</table>
<PaginatedList
onClick={handlePagination}
prev={currentPage === 0}
next={currentPage + itemsPerPage >= familyData?.length}
data={familyData}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
</div>
)}
</>
)}
{popUp.show && (
<SuggestTask
details={popUp.data}
onClose={closePopUp}
continuePopupData={openContinueTaskPopup}
situation={popUp.show}
/>
)}
{continueTaskPopup.show && (
<AssignTaskPopout
details={continueTaskPopup.data}
action={closeContinueTaskPopup}
situation={continueTaskPopup.show}
setUpdatePage={setUpdatePage}
/>
)}
</div>
);
};
export default FamilyNewWaitlist;
@@ -5,7 +5,7 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
import AssignTaskPopout from "../FamilyPopout/AssignTaskPopout"; import AssignTaskPopout from "../FamilyPopout/AssignTaskPopout";
const FamilyWaitlist = memo( const FamilyWaitlist = memo(
({ familyData, className, accountDetails, loader }) => { ({ familyData, className, accountDetails, loader, setUpdatePage }) => {
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,
@@ -144,6 +144,7 @@ const FamilyWaitlist = memo(
details={continueTaskPopup.data} details={continueTaskPopup.data}
action={closeContinueTaskPopup} action={closeContinueTaskPopup}
situation={continueTaskPopup.show} situation={continueTaskPopup.show}
setUpdatePage={setUpdatePage}
/> />
)} )}
</div> </div>
@@ -15,8 +15,10 @@ function FamilyWallet({familyData}) {
useEffect(()=>{ useEffect(()=>{
setFamilyWallet({loading:true, data: []}) setFamilyWallet({loading:true, data: []})
apiUrl.getFamilyWallet({family_uid:familyData?.uid}).then(res => { apiUrl.getKidWallets({family_uid:familyData?.uid}).then(res => {
setFamilyWallet({loading:false, data: res?.data?.result_list || []}) setFamilyWallet({loading:false, data: res?.data?.result_list || []})
console.log('familyData', familyData, res?.data?.result_list)
}).catch(error => { }).catch(error => {
setFamilyWallet({loading:false, data: []}) setFamilyWallet({loading:false, data: []})
}) })
@@ -9,8 +9,9 @@ import usersService from "../../../../services/UsersService";
import LoadingSpinner from "../../../Spinners/LoadingSpinner"; import LoadingSpinner from "../../../Spinners/LoadingSpinner";
import { PriceFormatter } from "../../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../../Helpers/PriceFormatter";
import { tableReload } from "../../../../store/TableReloads"; import { tableReload } from "../../../../store/TableReloads";
import { useDispatch } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { apiConst } from "../../../../lib/apiConst"; import { apiConst } from "../../../../lib/apiConst";
import { SocketValues } from "../../../Contexts/SocketIOContext";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
// amount: Yup.string() // amount: Yup.string()
@@ -30,6 +31,11 @@ const validationSchema = Yup.object().shape({
}); });
function FamilyAddFundPopout({ action, situation, wallet, familyData }) { function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
const {userDetails} = useSelector((state) => state?.userDetails); // Gets User Detail
const { parentAssignJobToKid } = SocketValues() // socket emit event from FULL account
const dispatch = useDispatch(); const dispatch = useDispatch();
const apiUrl = new usersService(); const apiUrl = new usersService();
@@ -54,6 +60,7 @@ function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
}; };
// FUNCTION TO PERFORM FAMILY TRANSFER // FUNCTION TO PERFORM FAMILY TRANSFER
const handleAddFund = (values) => { const handleAddFund = (values) => {
setRequestStatus({ loading: true, status: false, message: "" }); setRequestStatus({ loading: true, status: false, message: "" });
let senderBal = startTransfer?.data?.origing_current_balance || ""; // SENDER'S ACCOUNT BALANCE let senderBal = startTransfer?.data?.origing_current_balance || ""; // SENDER'S ACCOUNT BALANCE
@@ -132,6 +139,17 @@ function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
status: true, status: true,
message: "Transfer Successful", message: "Transfer Successful",
}); });
//SENDS MESSAGE TO SOCKET TO UPDATE CHILD ACCOUNT
// message, room
let socketMsg = {
"audience": "MEMBER",
"action": "REFRESH_WALLET",
"family_uid": reqData.family_uid,
}
let socketRoom = `FAMILY-${userDetails.uid}`
parentAssignJobToKid(socketMsg, socketRoom) //SENDS MESSAGE TO SOCKET TO UPDATE CHILD ACCOUNT
setTimeout(() => { setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" }); setRequestStatus({ loading: false, status: false, message: "" });
dispatch(tableReload({ type: "WALLETTABLE" })); // UPDATES PARENT WALLET ACCOUNT dispatch(tableReload({ type: "WALLETTABLE" })); // UPDATES PARENT WALLET ACCOUNT
@@ -170,13 +188,13 @@ function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
return ( return (
<ModalCom action={action} situation={situation}> <ModalCom action={action} situation={situation}>
<div className="relative logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="relative logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Add Fund Add Fund
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={action} onClick={action}
> >
<svg <svg
@@ -271,7 +289,7 @@ function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
<div className="field w-full mb-[0.5rem]"> <div className="field w-full mb-[0.5rem]">
<div className="w-full"> <div className="w-full">
<label <label
htmlFor="Job Delivery Details" htmlFor="job-label"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1" className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
> >
Comment Comment
+14 -13
View File
@@ -109,6 +109,7 @@ export default function FamilyAcc() {
if (data?.internal_return >= 0 && data?.status === "OK") { if (data?.internal_return >= 0 && data?.status === "OK") {
const { result_list, session_image_server } = data; const { result_list, session_image_server } = data;
setFamilyList({ result_list, session_image_server }); setFamilyList({ result_list, session_image_server });
sessionStorage.setItem("family_list", JSON.stringify(result_list))
setLoader(false); setLoader(false);
} else { } else {
return; return;
@@ -145,7 +146,7 @@ export default function FamilyAcc() {
breadcrumb={ breadcrumb={
[ [
{ link: "/", title: "Home" }, { link: "/", title: "Home" },
{ link: "/acc-family", title: "Family-acc", active: true}, { link: "/acc-family", title: "Family Account", active: true},
] ]
} }
/> />
@@ -164,13 +165,13 @@ export default function FamilyAcc() {
</h1> </h1>
</div> </div>
<div className="flex gap-2 items-center"> <div className="flex gap-4 items-center">
<Link to="/acc-family/activities" className={`nav-item flex items-center `}> <Link state={familyList} to="/acc-family/activities" className={`nav-item flex items-center rounded-md shadow-sm justify-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)] bg-[#76a5df] text-white px-2 gap-2`}>
<span className="item-icon group-hover:bg-purple group-hover:text-white w-8 h-8 flex justify-center items-center transition-all duration-300 ease-in-out bg-light-purple dark:bg-dark-light-purple rounded-full text-dark-gray dark:text-white dark:text-lighter-gray"> <span className="item-icon group-hover:bg-purple group-hover:text-white w-8 h-8 flex justify-center items-center transition-all duration-300 ease-in-out bg-light-purple dark:bg-dark-light-purple rounded-full text-dark-gray dark:text-white dark:text-lighter-gray">
<Icons name="pending-job" /> <Icons name="pending-job" />
</span> </span>
<span <span
className={`item-content relative group-hover:text-purple text-[18px] transition-all duration-300 ease-in-out text-lighter-gray font-medium`} className={`item-content relative text-[18px] transition-all duration-300 ease-in-out font-medium dark:text-white h-12 flex items-center`}
> >
Activities Activities
</span> </span>
@@ -178,7 +179,7 @@ export default function FamilyAcc() {
<Link <Link
to={`/familysettings`} to={`/familysettings`}
state={{ imageServer: familyList?.session_image_server }} state={{ imageServer: familyList?.session_image_server }}
className="slider-btns flex space-x-4 w-12 h-12 rounded-md shadow-sm justify-center items-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)]" className="slider-btns flex space-x-4 w-12 h-12 rounded-md shadow-sm justify-center items-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)] bg-[#76a5df] text-white"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -247,13 +248,13 @@ const FamilyForm = ({
}) => { }) => {
return ( return (
<div className="logout-modal-wrapper w-11/12 lg:w-[460px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto"> <div className="logout-modal-wrapper w-11/12 lg:w-[460px] 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:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Add Members Add Members
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={popUpHandler} onClick={popUpHandler}
> >
<CloseIcon /> <CloseIcon />
@@ -266,8 +267,8 @@ const FamilyForm = ({
name="first_name" name="first_name"
type="text" type="text"
parentClass="flex items-center gap-1 w-full" parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.2] mb-0" labelClass="flex-[0.4] mb-0"
inputClass="flex-[0.8] input-curve lg border border-[#dce4e9]" inputClass="flex-[0.6] input-curve lg border border-[#dce4e9]"
fieldClass="px-2" fieldClass="px-2"
value={first_name} value={first_name}
inputHandler={inputHandler} inputHandler={inputHandler}
@@ -278,8 +279,8 @@ const FamilyForm = ({
name="last_name" name="last_name"
type="text" type="text"
parentClass="flex items-center gap-1 w-full" parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.2] mb-0" labelClass="flex-[0.4] mb-0"
inputClass="flex-[0.8] input-curve lg border border-[#dce4e9]" inputClass="flex-[0.6] input-curve lg border border-[#dce4e9]"
fieldClass="px-2" fieldClass="px-2"
value={last_name} value={last_name}
inputHandler={inputHandler} inputHandler={inputHandler}
@@ -288,7 +289,7 @@ const FamilyForm = ({
{/* Age dropdown */} {/* Age dropdown */}
<div className=""> <div className="">
<label <label
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold" className="job-label"
htmlFor="age-selection" htmlFor="age-selection"
> >
Birthday: (Year/Month) Birthday: (Year/Month)
+90 -41
View File
@@ -1,10 +1,9 @@
import { Form, Formik } from "formik";
import { useState } from "react"; import { useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import ModalCom from "../Helpers/ModalCom";
import { Form, Formik } from "formik";
import InputCom from "../Helpers/Inputs/InputCom";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import Icons from "../Helpers/Icons"; import InputCom from "../Helpers/Inputs/InputCom";
import ModalCom from "../Helpers/ModalCom";
const DEFAULT_IMAGE = require("../../assets/images/family/default.jpg"); const DEFAULT_IMAGE = require("../../assets/images/family/default.jpg");
const SuggestTask = ({ details, onClose, situation, continuePopupData }) => { const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
@@ -51,26 +50,52 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
}; };
const handleParentSuggestion = (values) => { const handleParentSuggestion = (values) => {
if (suggestedNextStep == "Send Task") { if (suggestedNextStep === "Send Task") {
let firstName = state?.firstname; let firstname = state?.firstname || details?.firstname;
let family_uid = state?.family_uid; let family_uid = state?.family_uid || details?.family_uid;
continuePopupData({ ...details, firstName, family_uid }); continuePopupData({
...details,
firstname,
family_uid,
});
} }
onClose(); onClose();
}; };
const isActivitiesPage = pathname === "/acc-family/activities";
const isManageFamilyPage = pathname === "/manage-family";
const getButtonText = () => {
if (isActivitiesPage) {
return suggestedNextStep === "Send Task" ? "Continue" : "Complete";
} else {
if (!isManageFamilyPage) {
if (submitTask.loading) return "Submitting Task";
if (submitTask.state === "success") return "Task Submitted";
if (submitTask.state === "bad") return "An Error Occurred";
return "Send to Parents";
} else {
return suggestedNextStep === "Send Task" ? "Continue" : "Complete";
}
}
};
console.log(details);
return ( return (
<ModalCom action={onClose} situation={situation}> <ModalCom action={onClose} situation={situation}>
<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-wrapper lw-[90%] md:w-[48rem] min-h-[500px] bg-white dark:bg-dark-white lg:rounded-2xl">
<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"> <div className="modal-header-con">
<h1 className="text-base md:text-lg font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
{pathname === "/manage-family" {isManageFamilyPage
? `${state?.firstname}'s Suggested Task` ? `${state?.firstname}'s Suggested Task`
: isActivitiesPage
? `${details?.firstname}'s Suggested Task`
: "Suggest to Parent"} : "Suggest to Parent"}
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
@@ -97,19 +122,21 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
onSubmit={ onSubmit={
pathname !== "/manage-family" isActivitiesPage
? handleSuggestedTask ? handleParentSuggestion
: handleParentSuggestion : isManageFamilyPage
? handleParentSuggestion
: handleSuggestedTask
} }
> >
{(props) => { {(props) => {
return ( return (
<Form> <Form className="h-[33.875rem] flex flex-col">
<div className="p-5 w-full bg-white rounded-md flex justify-between"> <div className="px-5 w-full bg-white rounded-md flex justify-between items-center h-full">
{/* Image Section */} {/* Image Section */}
<div className="p-4 w-full md:w-2/4 md:border-r-2"> <div className="p-4 w-full md:w-2/4 md:border-r-2 h-full flex items-center">
<div <div
className="w-full h-[236px] p-6 bg-gray-400 rounded-xl overflow-hidden" className="w-full h-[14.75rem] p-6 bg-gray-400 rounded-xl overflow-hidden"
style={{ style={{
background: `url(${selectedImage}) center / contain no-repeat`, background: `url(${selectedImage}) center / contain no-repeat`,
}} }}
@@ -117,17 +144,22 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
</div> </div>
{/* ACTION SECTION */} {/* ACTION SECTION */}
<div className="p-4 w-full md:w-2/4 h-full"> <div className="p-4 w-full md:w-2/4 h-full flex flex-col justify-between">
{/* Title */} {/* Title */}
<div className="field w-full mb-[15px]"> <div className="field w-full mb-[.9375rem]">
<InputCom <InputCom
fieldClass={ fieldClass={
pathname === "/manage-family" ? "px-2" : "px-6" pathname === "/manage-family" ||
pathname === "/acc-family/activities"
? "px-2"
: "px-6"
} }
label="Title" label="Title"
labalClass="text-[1.125rem]"
labelClass="tracking-wide" labelClass="tracking-wide"
inputBg={ inputBg={
pathname === "/manage-family" pathname === "/manage-family" ||
pathname === "/acc-family/activities"
? "bg-white" ? "bg-white"
: "bg-slate-100" : "bg-slate-100"
} }
@@ -147,15 +179,15 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
</div> </div>
{/* Description */} {/* Description */}
<div className="field w-full mb-[5px]"> <div className="w-full mb-[.3125rem]">
<label <label
htmlFor="description" htmlFor="description"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1' className='job-label'
> >
Description Description
{props.errors.description && {props.errors.description &&
props.touched.description && ( props.touched.description && (
<span className="text-[12px] text-red-500"> <span className="text-[.75rem] text-red-500">
{props.errors.description} {props.errors.description}
</span> </span>
)} )}
@@ -164,9 +196,10 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
id="description" id="description"
rows="5" rows="5"
className={`input-field pt-2 placeholder:text-base text-dark-gray dark:text-white w-full ${ className={`input-field pt-2 placeholder:text-base text-dark-gray dark:text-white w-full ${
pathname === "/manage-family" pathname === "/manage-family" ||
? "px-2 h-[110px]" pathname === "/acc-family/activities"
: "bg-slate-100 px-3 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] h-[130px]" ? "px-2 h-[6.875rem]"
: "bg-slate-100 px-3 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[.625rem] h-[8.125rem]"
}`} }`}
style={{ resize: "none" }} style={{ resize: "none" }}
name="description" name="description"
@@ -177,8 +210,9 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
</div> </div>
{/* Radio buttons for family */} {/* Radio buttons for family */}
{pathname === "/manage-family" ? ( {pathname === "/manage-family" ||
<div className="h-[20px] w-full border-t dark:border-[#5356fb29] border-light-purple relative"> pathname === "/acc-family/activities" ? (
<div className="h-[3.75rem] w-full border-t dark:border-[#5356fb29] border-light-purple relative">
<div id="my-radio-group" className="sr-only"> <div id="my-radio-group" className="sr-only">
Parent suggested next step Parent suggested next step
</div> </div>
@@ -196,7 +230,7 @@ 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 group cursor-pointer`} className={`transition duration-150 ease-in-out parent-suggest group cursor-pointer flex items-center`}
onClick={() => setSuggestedNextStep(title)} onClick={() => setSuggestedNextStep(title)}
> >
<input <input
@@ -205,19 +239,19 @@ 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 pointer-events-none`} className={`transition duration-150 ease-in-out parent-suggest pointer-events-none w-[1.125rem] h-[1.125rem]`}
/> />
<span <span
onClick={() => setSuggestedNextStep(title)} onClick={() => setSuggestedNextStep(title)}
id={`parent-suggested-${idx}`} id={`parent-suggested-${idx}`}
name="parent-suggested" name="parent-suggested"
className={`ml-1 ${ className={`ml-1 ${
title == "Not Now" title === "Not Now"
? "text-red-500" ? "text-red-500"
: title == "Duplicate" : title === "Duplicate"
? "text-purple" ? "text-purple"
: "text-black" : "text-black"
} font-semibold`} } font-semibold text-[1.125rem]`}
> >
{title} {title}
</span> </span>
@@ -229,7 +263,7 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
</div> </div>
</div> </div>
<div className="w-full h-[70px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center"> <div className="w-full h-[4.375rem] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
<div className="flex items-center space-x-4 mr-9"> <div className="flex items-center space-x-4 mr-9">
<button <button
type="button" type="button"
@@ -243,19 +277,31 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
disabled={props.isSubmitting} disabled={props.isSubmitting}
className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full transition duration-150 ease-in-out flex items-center" className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full transition duration-150 ease-in-out flex items-center"
> >
{/* {pathname === "/acc-family/activities" ? (
<>
{suggestedNextStep === "Send Task" ? (
<>
Continue <Icons name="chevron-right" />
</>
) : (
"Complete"
)}
</>
) : (
<>
{pathname !== "/manage-family" ? ( {pathname !== "/manage-family" ? (
<> <>
{submitTask.loading {submitTask.loading
? "Submitting Task" ? "Submitting Task"
: submitTask.state == "success" : submitTask.state === "success"
? "Task Submitted" ? "Task Submitted"
: submitTask.state == "bad" : submitTask.state === "bad"
? "An Error Occurred" ? "An Error Occurred"
: "Send to Parents"} : "Send to Parents"}
</> </>
) : ( ) : (
<> <>
{suggestedNextStep == "Send Task" ? ( {suggestedNextStep === "Send Task" ? (
<> <>
Continue <Icons name="chevron-right" /> Continue <Icons name="chevron-right" />
</> </>
@@ -264,6 +310,9 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
)} )}
</> </>
)} )}
</>
)} */}
{getButtonText()}
</button> </button>
</div> </div>
</div> </div>
+1 -1
View File
@@ -7,7 +7,7 @@ function DataIteration(props) {
{datas && {datas &&
datas?.length >= endLength && datas?.length >= endLength &&
datas?.slice(startLength, endLength) datas?.slice(startLength, endLength)
.map((value) => children({ datas: value }))} .map((value, index) => children({ datas: value, index }))}
</> </>
); );
} }
@@ -54,7 +54,7 @@ export default function InputCom({
<div className={`flex items-center justify-between mb-2.5 ${labelClass}`}> <div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
{label && ( {label && (
<label <label
className={`input-label text-[#181c32] text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1 ${labalClass}`} className={`job-label ${error && 'job-label-flex'} ${labalClass}`}
htmlFor={name} htmlFor={name}
> >
{label} {label}
+5 -5
View File
@@ -89,13 +89,13 @@ export default function AddGroup({ action, situation, setUpdateList }) {
return ( return (
<ModalCom action={action} situation={situation}> <ModalCom action={action} situation={situation}>
<div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Add Group Add Group
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={action} onClick={action}
> >
<svg <svg
@@ -139,9 +139,9 @@ export default function AddGroup({ action, situation, setUpdateList }) {
<button <button
onClick={action} onClick={action}
type="button" type="button"
className="text-base text-light-red tracking-wide " className="w-[152px] h-[46px] flex justify-center items-center rounded-full text-base text-light-red tracking-wide border border-light-red"
> >
<span className="border-b dark:border-[#5356fb29] border-light-red"> <span className="">
Cancel Cancel
</span> </span>
</button> </button>
+3 -3
View File
@@ -21,13 +21,13 @@ export default function DeleteMember({action, situation, details}) {
situation={situation} situation={situation}
> >
<div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Remove Member Remove Member
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={action} onClick={action}
> >
<svg <svg
+66 -12
View File
@@ -24,12 +24,6 @@ export default function MemberList({
const handleFieldsChange = ({ target: { name, value } }) => { const handleFieldsChange = ({ target: { name, value } }) => {
setFields((prev) => ({ ...prev, [name]: value })); setFields((prev) => ({ ...prev, [name]: value }));
// let error = requestState?.errors?.indexOf(name) //// checks if the input field was in error array and removes it when the input changes
// if(error >= 0){
// let oldErrorArr = requestState.errors
// let newErrorArr = oldErrorArr.splice(error, 1)
// setRequestState(prev => ({...prev, errors:oldErrorArr}))
// }
if (value == "") { if (value == "") {
setRequestState({ setRequestState({
@@ -89,6 +83,63 @@ export default function MemberList({
// return // return
// } // }
if(fields.firstname.length > 25){ // checks if firstname length is more than 25
setRequestState({
loading: false,
status: false,
message: "Firstname must not be more than 25 characters",
data: [],
errors: [],
});
return setTimeout(() => {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
}, 3000);
}
if(fields.lastname.length > 25){ // checks if lastname length is more than 25
setRequestState({
loading: false,
status: false,
message: "Lastname must not be more than 25 characters",
data: [],
errors: [],
});
return setTimeout(() => {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
}, 3000);
}
if(fields.email.length > 45){ // checks if email length is more than 45
setRequestState({
loading: false,
status: false,
message: "Email must not be more than 45 characters",
data: [],
errors: [],
});
return setTimeout(() => {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
}, 3000);
}
//checks if email is a valid email address //checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/; let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (!EmailValidator(fields.email)) { if (!EmailValidator(fields.email)) {
@@ -201,7 +252,7 @@ export default function MemberList({
{selectedGroup?.name} {selectedGroup?.name}
</h1> </h1>
<div className="w-full flex flex-col-reverse lg:flex-col"> <div className="w-full flex flex-col-reverse lg:flex-col">
<div className="py-3 w-full"> <div className="relative py-3 w-full">
<div className="relative grid grid-cols-1 sm:grid-cols-2 gap-2 place-content-center"> <div className="relative grid grid-cols-1 sm:grid-cols-2 gap-2 place-content-center">
<div className="input-item"> <div className="input-item">
<InputCom <InputCom
@@ -229,13 +280,15 @@ export default function MemberList({
// iconName="message" // iconName="message"
/> />
</div> </div>
<div className="input-item w-full"> </div>
<div className="sm:flex gap-2 items-center">
<div className="input-item my-2 w-full sm:w-9/12">
<InputCom <InputCom
labelClass="tracking-wider" labelClass="tracking-wider"
fieldClass="sm:px-6 px-2" fieldClass="sm:px-6 px-2"
value={fields.email} value={fields.email}
inputHandler={handleFieldsChange} inputHandler={handleFieldsChange}
inputClass="xl:w-[16rem] 2xl:w-full" inputClass=""
placeholder="Email" placeholder="Email"
// label="Email" // label="Email"
name="email" name="email"
@@ -243,7 +296,7 @@ export default function MemberList({
// iconName="message" // iconName="message"
/> />
</div> </div>
<div className="flex justify-end items-end"> <div className="flex justify-end items-end w-full sm:w-3/12">
{requestState.loading ? ( {requestState.loading ? (
<LoadingSpinner size="8" color="sky-blue" /> <LoadingSpinner size="8" color="sky-blue" />
) : ( ) : (
@@ -266,10 +319,11 @@ export default function MemberList({
</button> </button>
)} )}
</div> </div>
</div>
<div className="absolute top-full w-full my-1 text-center">
{!requestState.loading && requestState.message && ( {!requestState.loading && requestState.message && (
<p <p
className={`text-lg absolute -bottom-7 left-0 ${ className={`text-base ${
requestState.status ? "text-green-500" : "text-red-500" requestState.status ? "text-green-500" : "text-red-500"
}`} }`}
> >
+37 -2
View File
@@ -4,6 +4,7 @@ import ListView from "../../assets/images/list-view.png";
import AvailableJobsCard from "../Cards/AvailableJobsCard"; import AvailableJobsCard from "../Cards/AvailableJobsCard";
import DataIteration from "../Helpers/DataIteration"; import DataIteration from "../Helpers/DataIteration";
import SelectBox from "../Helpers/SelectBox"; import SelectBox from "../Helpers/SelectBox";
import NewPaginatedList from "../Pagination/NewPaginatedList";
export default function MainSection({ export default function MainSection({
className, className,
@@ -108,8 +109,8 @@ export default function MainSection({
startLength={process.env.REACT_APP_ZERO_STATE} startLength={process.env.REACT_APP_ZERO_STATE}
endLength={products?.length} endLength={products?.length}
> >
{({ datas }) => ( {({ datas, index }) => (
<div key={datas.job_uid}> <div key={datas.job_uid+index}>
<AvailableJobsCard <AvailableJobsCard
contentDisplay={contentDisplay} contentDisplay={contentDisplay}
image_server={image_server} image_server={image_server}
@@ -120,6 +121,40 @@ export default function MainSection({
</DataIteration> </DataIteration>
</div> </div>
</div> </div>
{/* {products?.length &&
<NewPaginatedList
data={products}
itemsPerPage={6}
filterItem=''
tableTitle=''
>
{
({data})=>(
<div className="filter-navigate-content w-full min-h-[600px]">
<div
className={
contentDisplay == "grid"
? "grid lg:grid-cols-3 sm:grid-cols-2 gap-[30px]"
: "w-full"
}
>
{
data.map((datum, index) => (
<div key={datum.job_uid+index}>
<AvailableJobsCard
contentDisplay={contentDisplay}
image_server={image_server}
datas={datum}
/>
</div>
))
}
</div>
</div>
)
}
</NewPaginatedList>
} */}
</div> </div>
</div> </div>
); );
@@ -1,11 +1,26 @@
import { useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import ModalCom from "../../Helpers/ModalCom"; import ModalCom from "../../Helpers/ModalCom";
import { PriceFormatter } from "../../Helpers/PriceFormatter"; import { PriceFormatter } from "../../Helpers/PriceFormatter";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; import LoadingSpinner from "../../Spinners/LoadingSpinner";
import { SocketValues } from "../../Contexts/SocketIOContext";
const MarketPopUp = ({ details, onClose, situation, marketInt }) => { const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
let {sendJobInterestToOwner} = SocketValues() // function to emit job interest request
const emitOfferInterest = () => {
let message = {
"audience": "MERCHANT",
"action": "REFRESH_OFFERS",
"offer_code": details?.offer_code,
"offer_uid": details?.offer_uid,
"job_uid": details?.job_uid,
}
let room = `INTEREST-${details?.market_uid}`
sendJobInterestToOwner(message, room)
}
const [textValue, setTextValue] = useState(""); const [textValue, setTextValue] = useState("");
const [errMsg, setErrMsg] = useState({ const [errMsg, setErrMsg] = useState({
market: false, market: false,
@@ -88,7 +103,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
state: true, state: true,
}); });
} }
emitOfferInterest() // FUNCTIONS TO EMIT EVENT INDICATING SOMEONE SENDS AN INTEREST IN YOUR JOB
setTimeout(() => setManageInt({ msg: "" }), 3000); setTimeout(() => setManageInt({ msg: "" }), 3000);
} catch (error) { } catch (error) {
throw new Error(error); throw new Error(error);
@@ -118,9 +133,9 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
return ( return (
<ModalCom action={onClose} situation={situation}> <ModalCom action={onClose} situation={situation}>
<div className="logout-modal-wrapper w-11/12 md:w-[650px] md:h-[580px] h-full bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto"> <div className="w-11/12 md:w-[650px] 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]"> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
{details.offer_code} {details.offer_code}
</h1> </h1>
<CloseIcon onClose={onClose} /> <CloseIcon onClose={onClose} />
@@ -128,7 +143,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<div className="md:flex bg-white dark:bg-dark-white text-slate-900 dark:text-white rounded-lg"> <div className="md:flex bg-white dark:bg-dark-white text-slate-900 dark:text-white rounded-lg">
<div className="p-4 w-full md:w-[75%] md:border-r-1"> <div className="p-4 w-full md:w-[75%] md:border-r-1">
<div className="max-h-[240px] h-full"> <div className="min-h-[240px]">
<h2 className="font-semibold text-slate-900 dark:text-white tracking-wide"> <h2 className="font-semibold text-slate-900 dark:text-white tracking-wide">
{details?.title} {details?.title}
</h2> </h2>
@@ -153,7 +168,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
}, },
].map(({ name, content, danger }, idx) => ( ].map(({ name, content, danger }, idx) => (
<div className={`my-3 md:flex items-center`} key={idx}> <div className={`my-3 md:flex items-center`} key={idx}>
<label className="w-full md:w-[19%] tracking-wide font-semibold whitespace-pre-wrap"> <label className="job-label w-full md:w-[19%]">
{name} {name}
</label> </label>
<div <div
@@ -198,7 +213,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<hr /> <hr />
<div className="w-full flex flex-col gap-3"> <div className="w-full flex flex-col gap-3">
<div className="w-full"> <div className="w-full">
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold"> <label className="job-label w-full">
If you have any questions about this task: If you have any questions about this task:
</label> </label>
<textarea <textarea
@@ -218,7 +233,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
{errMsg.market && "Something went wrong"} {errMsg.market && "Something went wrong"}
</span> </span>
<button <button
className="self-end w-[150px] h-[48px] rounded-full text-base bg-yellow-500 text-white" className="custom-btn self-end bg-yellow-500 text-white"
name="market-message" name="market-message"
onClick={MarketDetail} onClick={MarketDetail}
> >
@@ -235,7 +250,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<div className="w-full md:w-[23%] h-full flex flex-col"> <div className="w-full md:w-[23%] h-full flex flex-col">
<div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] px-4 rounded-md md:min-h-[420px] flex flex-col justify-between"> <div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] px-4 rounded-md md:min-h-[420px] flex flex-col justify-between">
<div className="w-full flex flex-col justify-center pb-4 gap-2"> <div className="w-full flex flex-col justify-center pb-4 gap-2">
<p className="w-full text-slate-900 tracking-wide my-1 font-semibold"> <p className="job-label w-full">
Interested in the task? Interested in the task?
</p> </p>
<hr /> <hr />
@@ -270,33 +285,39 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<div className="text-slate-900"> <div className="text-slate-900">
<p className="flex items-center tracking-wide"> <p className="flex items-center tracking-wide">
Interest: <b className="ml-1">{details.interest_count}</b> <span className="job-label">Interest: </span> <b className="ml-1">{details.interest_count}</b>
</p> </p>
<hr /> <hr />
<p className="my-1">Expire: {details.expire}</p> <p className="my-1 flex flex-col">
<span className="job-label">Expire: </span>
<span> {new Date(details.expire).toLocaleString()} </span>
</p>
</div> </div>
</div> </div>
</div>
{/* END OF ACTION SECTION */}
</div>
<div className="modal-footer-wrapper">
<button <button
className="self-center w-[150px] mt-2 h-[48px] rounded-full text-base bg-transparent border border-red-500 text-red-500 mx-auto" className="custom-btn bg-transparent border border-red-500 text-red-500 ml-auto"
name="cancel" name="cancel"
onClick={onClose} onClick={onClose}
> >
Cancel Cancel
</button> </button>
</div> </div>
{/* END OF ACTION SECTION */}
</div>
</div> </div>
</ModalCom> </ModalCom>
); );
}; };
export default MarketPopUp; export default MarketPopUp;
const CloseIcon = ({ onClose }) => ( const CloseIcon = ({ onClose }) => (
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
+15 -3
View File
@@ -11,8 +11,11 @@ import IndexJobActions from "./JobActions/IndexJobActions";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import { PriceFormatter } from "../Helpers/PriceFormatter"; import { PriceFormatter } from "../Helpers/PriceFormatter";
import { SocketValues } from "../Contexts/SocketIOContext";
function ActiveJobs(props) { function ActiveJobs(props) {
let {sendMessage, joinRoom} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
const ApiCall = new usersService(); const ApiCall = new usersService();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -139,6 +142,9 @@ function ActiveJobs(props) {
status: true, status: true,
message: "Message Sent Successfully", message: "Message Sent Successfully",
}); });
// function to trigger socket to emit 'send_message'
sendMessage(messageToSend, `${props.details.contract}-${props.details.contract_uid}`)
props.reloadActiveJobList((prev) => !prev); // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD props.reloadActiveJobList((prev) => !prev); // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
setMessageToSend(""); // SENDS MESSAGE TO SEND BACK TO EMPTY STRINGS setMessageToSend(""); // SENDS MESSAGE TO SEND BACK TO EMPTY STRINGS
}) })
@@ -255,6 +261,12 @@ function ActiveJobs(props) {
props.details?.currency props.details?.currency
); );
useEffect(()=>{
// calls function to add user to a room
joinRoom(`${props.details.contract}-${props.details.contract_uid}`)
},[props.details.contract, props.details.contract_uid])
return ( return (
<Layout> <Layout>
<div className="py-[20px] bg-white dark:bg-black dark:text-white px-4 rounded-2xl shadow-md md:flex justify-between items-start gap-16"> <div className="py-[20px] bg-white dark:bg-black dark:text-white px-4 rounded-2xl shadow-md md:flex justify-between items-start gap-16">
@@ -534,13 +546,13 @@ function ActiveJobs(props) {
{/* MESSAGE SECTION */} {/* MESSAGE SECTION */}
<div className="w-full lg:w-1/2"> <div className="w-full lg:w-1/2">
<div className="flex justify-between items-center gap-5"> <div className="flex justify-between items-center gap-5 justify-between">
<p className="w-full text-lg font-bold text-dark-gray dark:text-white tracking-wide flex items-center gap-2"> <p className="w-full text-lg font-bold text-dark-gray dark:text-white tracking-wide flex items-center gap-2 justify-between">
<span>Message</span> <span>Message</span>
<button <button
type="button" type="button"
onClick={popUpHandler} onClick={popUpHandler}
className="text-[12px] tracking-wider text-emerald-600 dark:text-emerald-300" className="text-[12px] tracking-wider text-gray-400 dark:text-slate-400"
> >
View all View all
</button> </button>
+14 -2
View File
@@ -4,6 +4,7 @@ import Layout from "../Partials/Layout";
import MyJobTable from "./MyJobTable"; import MyJobTable from "./MyJobTable";
import CommonHead from "../UserHeader/CommonHead"; import CommonHead from "../UserHeader/CommonHead";
import AddJobPage from "../../views/AddJobPage"; import AddJobPage from "../../views/AddJobPage";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function MyJobs(props) { export default function MyJobs(props) {
let { state } = useLocation(); let { state } = useLocation();
@@ -32,8 +33,8 @@ export default function MyJobs(props) {
<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 */}
<div className="sm:flex items-center mb-6"> <div className="sm:flex items-center mb-2">
<div className="mb-5 sm:mb-0"> <div className="w-full">
<h1 className="text-26 font-bold flex items-center space-x-1 text-dark-gray dark:text-white gap-2"> <h1 className="text-26 font-bold flex items-center space-x-1 text-dark-gray dark:text-white gap-2">
<span>My Jobs</span> <span>My Jobs</span>
@@ -46,6 +47,17 @@ export default function MyJobs(props) {
</h1> </h1>
</div> </div>
</div> </div>
<div className="mb-5">
<CustomBreadcrumb
// title = 'My Jobs'
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/myjobs", title: "My Jobs", active: true},
]
}
/>
</div>
<MyJobTable MyJobList={props.MyJobList} /> <MyJobTable MyJobList={props.MyJobList} />
</div> </div>
</div> </div>
+13 -1
View File
@@ -3,6 +3,7 @@ import OfferCard from "../Cards/OfferCard";
import Icons from "../Helpers/Icons"; import Icons from "../Helpers/Icons";
import SliderCom from "../Helpers/SliderCom"; import SliderCom from "../Helpers/SliderCom";
import FamilyOfferJobPopout from "../jobPopout/FamilyOfferJobPopout"; import FamilyOfferJobPopout from "../jobPopout/FamilyOfferJobPopout";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function MyOffersFamilyTable({ className, familyOffers, image_server }) { export default function MyOffersFamilyTable({ className, familyOffers, image_server }) {
let [offerPopout, setOfferPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW let [offerPopout, setOfferPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW
@@ -60,10 +61,21 @@ export default function MyOffersFamilyTable({ className, familyOffers, image_ser
> >
{/* heading */} {/* heading */}
<div className="flex justify-between items-center mb-6"> <div className="flex justify-between items-center mb-6">
<div> {/* <div>
<h1 className="text-26 font-bold text-dark-gray dark:text-white"> <h1 className="text-26 font-bold text-dark-gray dark:text-white">
Ready to Start? Ready to Start?
</h1> </h1>
</div> */}
<div className="">
<CustomBreadcrumb
title = {'Ready to Start'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/pending", title: "Pending", active: true},
]
}
/>
</div> </div>
<div className="slider-btns flex space-x-3"> <div className="slider-btns flex space-x-3">
<button onClick={nextHandler} type="button"> <button onClick={nextHandler} type="button">
+91 -15
View File
@@ -2,33 +2,109 @@ import { useSelector } from "react-redux";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import WalletItemCard from "./WalletItemCard"; import WalletItemCard from "./WalletItemCard";
import WalletItemCardFamily from "./WalletItemCardFamily"; import WalletItemCardFamily from "./WalletItemCardFamily";
import { useEffect, useState } from "react";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import SearchCom from "../Helpers/SearchCom";
import { localImgLoad } from "../../lib";
import background from "../../assets/images/bg-sky-blue.jpg";
import FamilyWalletRedeemOptions from "./FamilyWalletRedeemOptions";
/** /**
* 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 FamilyWalletBox({ wallet, payment, countries }) { export default function FamilyWalletBox({ wallet, payment }) {
const { loading, data } = wallet; // const { loading, data } = wallet;
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 [selectedWallet, setSelectedWallet] = useState('')
const [activeWalletBtn, setActiveWalletBtn] = useState('')
const handleChangeWallet = ({target:{name}}) => { // FUNCTION TO SWITCH WALLET IF USER HAS MORE THAN TWO WALLETS
const currentWalletSelected = wallet?.data?.filter((item) => item.code == name);
setSelectedWallet(currentWalletSelected[0])
setActiveWalletBtn(name)
// console.log(name, currentWalletSelected)
}
const image = selectedWallet?.code
? `${selectedWallet?.code.toLowerCase()}.svg`
: "default.png";
useEffect(()=>{
setSelectedWallet(wallet.data[0])
setActiveWalletBtn(wallet?.data[0]?.code)
},[wallet])
return ( return (
<div className="my-wallet-wrapper w-full mb-10"> <div className="w-full">
<div className="main-wrapper w-full"> <div className="my-wallet-wrapper w-full">
<div className="balance-inquery w-auto grid sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-[repeat(auto-fill,_minmax(354px,_1fr))] min-[1440px]:grid-cols-[repeat(auto-fill,_minmax(415px,_1fr))] gap-5 mb-11 h-auto"> <div className="main-wrapper w-full mb-10">
{loading ? ( <div className="w-full mb-10 sm:grid grid-cols-2 gap-4">
<div className="w-full mb-4 sm:mb-0 rounded-2xl bg-white dark:bg-dark-white overflow-hidden">
{wallet?.loading ?
<div className="w-full h-full flex items-center justify-center bg-white"> <div className="w-full h-full flex items-center justify-center bg-white">
<LoadingSpinner size="16" color="sky-blue" height='h-[30rem]' /> <LoadingSpinner size="16" color="sky-blue" height='min-h-[240px]' />
</div> </div>
) : ( : wallet?.data.length > 0 ?
data.length > 0 && data.map((item) => ( <>
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0"> {wallet?.data?.length > 1 &&
<WalletItemCardFamily walletItem={item} payment={payment} countries={countries} /> <div className="wal-selection px-5 py-2 text-black dark:text-white flex items-center gap-2">
{wallet?.data?.map(item =>(
<button
className={`py-0.5 px-1 mb-1 rounded-lg border border-orange-500 ${activeWalletBtn == item?.code && 'bg-orange-500'}`}
key={item?.wallet_uid}
name={item?.code}
onClick={handleChangeWallet}
>
{item?.description}
</button>
))}
</div> </div>
)) }
)} <div className="p-5 bg-white-opacity min-h-[240px]"
style={{
background: `url(${background}) 0% 0% / cover no-repeat`,
}}
>
{/* image */}
<div className="min-w-[100px] min-h-[100px] max-w-min md:max-w-[100px] max-h-min md:max-h-[100px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
<img
src={localImgLoad(`images/currency/${image}`)}
className="w-full h-full"
alt="currency-icon"
/>
</div>
<p className="text-base sm:text-lg text-white opacity-[70%] tracking-wide my-3">Current Balance</p>
<p className="text-[44px] lg:text-[62px] font-bold text-white tracking-wide leading-10">
{PriceFormatter(selectedWallet?.amount/100, selectedWallet?.code, undefined, "text-[2rem]")}
</p>
</div>
</>
:
<div className="w-full h-full flex justify-center items-center rounded-2xl bg-white">
<p>No Wallet Record Found</p>
</div>
}
</div>
<div className="p-5 w-full rounded-2xl bg-white dark:bg-dark-white text-black dark:text-white h-full min-h-[240px] max-h-96">
<h1 className="text-xl font-bold text-black dark:text-white">Recent Activities</h1>
</div>
</div>
</div>
<div className="w-full">
<FamilyWalletRedeemOptions />
</div> </div>
</div> </div>
</div> </div>
); );
} }
// data.length>0 && data.map((item) => (
// <div key={item.wallet_uid} className="w-full h-full mb-10 ">
// {/* <WalletItemCardFamily walletItem={item} payment={payment} countries={countries} /> */}
// </div>
// ))
@@ -6,9 +6,12 @@ import LoadingSpinner from "../Spinners/LoadingSpinner";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb"; import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
const FamilyWalletBox = lazy(() => import("./FamilyWalletBox")); const FamilyWalletBox = lazy(() => import("./FamilyWalletBox"));
const FamilyWallet = () => { const FamilyWalletCon = () => {
const apiCall = new usersService(); const apiCall = new usersService();
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE // const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
const {userDetails} = useSelector((state) => state?.userDetails); // GETS USER INFO
const { walletTable } = useSelector((state) => state.tableReload); const { walletTable } = useSelector((state) => state.tableReload);
const [paymentHistory, setPaymentHistory] = useState({ const [paymentHistory, setPaymentHistory] = useState({
@@ -16,12 +19,20 @@ const FamilyWallet = () => {
data: [], data: [],
}); });
const [allCountries, setAllCountries] = useState({ const [familyWalletBal, setFamilyWalletBal] = useState({
// STATE TO HOLD LIST OF COUNTRIES
loading: true, loading: true,
data: [], data: []
}); });
const getFamilyWalletBal = () => {
setFamilyWalletBal({loading:true, data: []})
apiCall.getFamilyWallet({family_uid: userDetails.uid}).then(res => {
setFamilyWalletBal({loading:false, data: res?.data?.result_list})
}).catch(error => {
setFamilyWalletBal({loading:false, data: []})
})
};
const getPaymentHistory = () => { const getPaymentHistory = () => {
apiCall apiCall
.getPaymentHx() .getPaymentHx()
@@ -30,6 +41,7 @@ const FamilyWallet = () => {
setPaymentHistory({ loading: false, data: [] }); setPaymentHistory({ loading: false, data: [] });
} else { } else {
setPaymentHistory({ loading: false, data: res.data?.result_list }); setPaymentHistory({ loading: false, data: res.data?.result_list });
// console.log('Hist', res.data?.result_list)
} }
}) })
.catch(() => { .catch(() => {
@@ -37,37 +49,11 @@ const FamilyWallet = () => {
}); });
}; };
// 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?.result_list,
}));
})
.catch((error) => {
setAllCountries((prev) => ({ loading: false, data: [] }));
});
};
useEffect(() => { useEffect(() => {
getCountry();
getPaymentHistory(); getPaymentHistory();
getFamilyWalletBal()
}, [walletTable]); }, [walletTable]);
console.log(
"Testing all country: ",
allCountries,
"Testing wallet: ",
walletDetails
);
return ( return (
<Layout> <Layout>
<div className='mb-4'> <div className='mb-4'>
@@ -81,15 +67,18 @@ const FamilyWallet = () => {
} }
/> />
</div> </div>
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}> <Suspense fallback={
<div className="bg-white rounded-2xl">
<LoadingSpinner size="16" color="sky-blue" height='h-[30rem]' />
</div>
}>
<FamilyWalletBox <FamilyWalletBox
wallet={walletDetails} wallet={familyWalletBal}
payment={paymentHistory} payment={paymentHistory}
countries={allCountries.data}
/> />
</Suspense> </Suspense>
</Layout> </Layout>
); );
}; };
export default FamilyWallet; export default FamilyWalletCon;
@@ -0,0 +1,82 @@
import React, { useEffect, useState } from 'react'
import SearchCom from '../Helpers/SearchCom'
import LoadingSpinner from '../Spinners/LoadingSpinner';
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';
export default function FamilyWalletRedeemOptions() {
const { familyWalletRedeemOptList } = useSelector((state) => state.familyWalletRedeemOptList); // FAMILY WALLET REDDEM OPTIONS LIST
const [filteredRedeemData, setFilteredRedeemData] = useState({value: '', data:{}}) // State to hold filtered redeem banner option
const handleFilterRedeemData = ({target}) => {
// thiskey01
let filterWord = target.value
let filteredData = {}
if(!filterWord){
filteredData = {...familyWalletRedeemOptList?.data}
}else{
let matchedData = Object.keys(familyWalletRedeemOptList?.data)?.filter(item => (item.toLowerCase().startsWith(filterWord.toLowerCase())))
filteredData = matchedData.map(item => familyWalletRedeemOptList.data[item])
}
setFilteredRedeemData({value:target.value, data: {...filteredData}})
}
useEffect(()=>{
setFilteredRedeemData(prev => ({...prev, data:{...familyWalletRedeemOptList?.data}}))
}, [familyWalletRedeemOptList.image])
return (
<div className="w-full">
<div className="w-full sm:flex items-center gap-4">
<h1 className="text-2xl font-bold text-black dark:text-white">Redeem Options</h1>
<div className="sm:w-1/2 w-full sm:pr-20 pr-0 mb-5 sm:mb-0">
<SearchCom
placeholder='Search...'
value={filteredRedeemData.value}
handleSearch={handleFilterRedeemData}
/>
</div>
</div>
{/* redeem options */}
{familyWalletRedeemOptList.loading ?
<div className='mt-5 w-full h-[20rem] rounded-2xl bg-white dark:bg-dark-white text-black dark:text-white flex justify-center items-center'>
<LoadingSpinner size='10' color='sky-blue' height='h-[30rem]' />
</div>
: familyWalletRedeemOptList?.data && Object.keys(familyWalletRedeemOptList?.data)?.length > 0 ?
Object.keys(filteredRedeemData?.data)?.length ?
<div className="mt-5 grid sm:grid-cols-2 lg:grid-cols-3 xxl:grid-cols-4 gap-4">
{ Object.keys(filteredRedeemData?.data)?.map((item)=>{
// text, image, description, action
let newData = filteredRedeemData?.data[item].banner
let bgImage = `url(${newData?.image})`
return (
<Link to={''} key={item}>
<div className={`group relative h-60 text-black dark:text-white rounded-2xl shadow-lg hover:shadow-md transition-all duration-300 overflow-hidden`}
style={{
// background: `#ffffff ${bgImage} no-repeat center center / cover`
}}
>
<img src={newData?.image} alt='Redeem Image' className='w-full h-full bg-cover rounded-2xl group-hover:scale-110 transition-all duration-300' />
<div className='absolute bottom-0 mb-1 left-1/2 -translate-x-1/2 p-2 bg-white/80 rounded-2xl w-[90%] flex flex-col justify-center items-center gap-2'>
<h1 className='text-lg font-bold text-[#083e21]'>{newData.text}</h1>
</div>
</div>
</Link>
)
})}
</div>
:
<div className='mt-5 w-full h-[20rem] rounded-2xl bg-white dark:bg-dark-white text-black dark:text-white flex justify-center items-center'>
<p>Search Item not Found!</p>
</div>
:
<div className='mt-5 w-full h-[20rem] rounded-2xl bg-white dark:bg-dark-white text-black dark:text-white flex justify-center items-center'>
<p>No Redeem Options Found!</p>
</div>
}
</div>
)
}
@@ -4,7 +4,6 @@ import background from "../../assets/images/bg-sky-blue.jpg"; //shape/balance-bg
import localImgLoad from "../../lib/localImgLoad"; import localImgLoad from "../../lib/localImgLoad";
import { tableReload } from "../../store/TableReloads"; import { tableReload } from "../../store/TableReloads";
import { PriceFormatter } from "../Helpers/PriceFormatter"; import { PriceFormatter } from "../Helpers/PriceFormatter";
import CreditPopup from "./Popup/CreditPopup";
import WalletAction from "./WalletAction"; import WalletAction from "./WalletAction";
/** /**
@@ -13,26 +12,15 @@ import WalletAction from "./WalletAction";
export default function WalletItemCardFamily({ walletItem, payment, countries }) { export default function WalletItemCardFamily({ walletItem, payment, countries }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [creditPopup, setCreditPopup] = useState({ show: false, data: {} });
/** /**
* Opens the credit popup. * Opens the credit popup.
* @param {Object} value - The value object. * @param {Object} value - The value object.
*/ */
const openPopUp = (value) => {
setCreditPopup({
show: true,
data: { ...value },
});
};
/** /**
* Closes the credit popup and dispatches a table reload action. * Closes the credit popup and dispatches a table reload action.
*/ */
const closePopUp = () => {
setCreditPopup({ show: false, data: {} });
dispatch(tableReload({ type: "WALLETTABLE" }));
};
const currentWalletCurrency = countries?.filter((country) => country.code === walletItem.country); const currentWalletCurrency = countries?.filter((country) => country.code === walletItem.country);
@@ -43,10 +31,10 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
return ( return (
<> <>
<div <div
className="current-balance-widget w-full h-full rounded-2xl overflow-hidden flex flex-col items-center gap-2 p-8 justify-between" className="current-balance-widget w-full h-full rounded-2xl overflow-hidden flex flex-col items-center gap-2 p-8 justify-between bg-family-header-bg"
style={{ // style={{
background: `url(${background}) 0% 0% / cover no-repeat`, // background: `url(${background}) 0% 0% / cover no-repeat`,
}} // }}
> >
<div className="wallet w-full flex justify-between items-center gap-3"> <div className="wallet w-full flex justify-between items-center gap-3">
<div className="min-w-[100px] min-h-[100px] max-w-min md:max-w-[150px] max-h-min md:max-h-[150px] rounded-full bg-[#e3e3e3] flex justify-center items-center"> <div className="min-w-[100px] min-h-[100px] max-w-min md:max-w-[150px] max-h-min md:max-h-[150px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
@@ -72,24 +60,7 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
</div> </div>
</div> </div>
</div> </div>
<div className="my-2 w-full h-[1px] bg-white"></div>
{/* <WalletAction
walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
payment={payment}
openPopUp={openPopUp}
/> */}
</div> </div>
{creditPopup.show && (
<CreditPopup
details={creditPopup.data}
walletItem={walletItem}
onClose={closePopUp}
situation={openPopUp}
/>
)}
</> </>
); );
} }
@@ -28,6 +28,7 @@ export default function OffersInterestTable({offerInterestList, className}) {
handlePagingFunc(e, setCurrentPage); handlePagingFunc(e, setCurrentPage);
}; };
let imgServer = offerInterestList?.imgServer // FOR RENDERING IMAGE FROM SERVER
return ( return (
<div <div
className={`update-table w-full my-8 p-8 bg-white dark:bg-dark-white rounded-2xl section-shadow min-h-[520px] ${ className={`update-table w-full my-8 p-8 bg-white dark:bg-dark-white rounded-2xl section-shadow min-h-[520px] ${
@@ -54,14 +55,19 @@ export default function OffersInterestTable({offerInterestList, className}) {
</thead> </thead>
<tbody className="h-full"> <tbody className="h-full">
{currentOfferInterestList?.map((item, index) => { {currentOfferInterestList?.map((item, index) => {
let image = item.banner ? item.banner : 'default.jpg' // let image = item.banner ? item.banner : 'default.jpg'
const image = localStorage.getItem("session_token")
? `${imgServer}${localStorage.getItem("session_token")}/job/${
item.job_uid
}`
: "";
return ( return (
<tr key={index} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"> <tr key={index} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
<td className=" py-4"> <td className=" py-4">
<div className="flex space-x-2 items-center"> <div className="flex space-x-2 items-center">
<div className="w-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center"> <div className="min-w-[60px] max-w-[60px] min-h-[60px] max-h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img <img
src={localImgLoad(`images/taskbanners/${image}`)} src={`${image}`}
alt="data" alt="data"
className="w-full h-full rounded-full" className="w-full h-full rounded-full"
/> />
@@ -90,7 +96,7 @@ export default function OffersInterestTable({offerInterestList, className}) {
<button <button
onClick={() => { onClick={() => {
navigate("/manage-offer", { navigate("/manage-offer", {
state: { ...item, pathname }, state: { ...item, pathname, jobImage:image },
}); });
}} }}
type="button" type="button"
@@ -56,13 +56,18 @@ export default function OthersInterestTable({othersInterestedList, className}) {
</thead> </thead>
<tbody className="h-full"> <tbody className="h-full">
{currentOthersInterestedList?.map((item, index) => { {currentOthersInterestedList?.map((item, index) => {
const image = localStorage.getItem("session_token")
? `${othersInterestedList.imageServer}${localStorage.getItem("session_token")}/job/${
item.job_uid
}`
: "";
return ( return (
<tr key={index} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"> <tr key={index} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
<td className=" py-4"> <td className=" py-4">
<div className="flex space-x-2 items-center"> <div className="flex space-x-2 items-center">
<div className="min-w-[60px] min-h-[60px] rounded-full overflow-hidden flex justify-center items-center"> <div className="min-w-[60px] min-h-[60px] rounded-full overflow-hidden flex justify-center items-center">
<img <img
src={dataImage1} src={image}
alt="data" alt="data"
className="w-full h-full" className="w-full h-full"
/> />
+1
View File
@@ -9,6 +9,7 @@ export default function OffersInterest(props) {
const filterHandler = (value) => { const filterHandler = (value) => {
setValue(value); setValue(value);
}; };
return ( return (
<Layout> <Layout>
<CommonHead <CommonHead
@@ -0,0 +1,101 @@
import { useEffect, useState } from "react";
const data1 = [];
export default function NewPaginatedList({
data = data1,
itemsPerPage = 5,
filterItem,
tableTitle,
children,
}) {
const [searchTerm, setSearchTerm] = useState("");
const [filteredData, setFilteredData] = useState(data);
const [currentPage, setCurrentPage] = useState(0);
const [newData, setNewData] = useState([]);
const numberOfSelection = itemsPerPage;
const handlePrev = () => {
if (currentPage != 0) {
setCurrentPage((prev) => prev - numberOfSelection);
}
};
const handleNext = () => {
if (currentPage < data.length) {
setCurrentPage((prev) => prev + numberOfSelection);
}
};
const handleSearch = ({ target: { value } }, name) => {
setSearchTerm(value);
let newFilteredData = data.filter((item) =>
item[name].toLowerCase().startsWith(value.toLowerCase())
);
setFilteredData(newFilteredData);
setCurrentPage(0);
};
useEffect(() => {
setNewData(
filteredData?.slice(currentPage, numberOfSelection + currentPage)
);
}, [currentPage, filteredData]);
console.log("newData", newData, filteredData);
return (
<div className="w-full">
<h1 className="text-2xl mb-5 font-semibold">{tableTitle}</h1>
{data.length > 0 && filterItem && (
<div className="mb-10 flex justify-end items-center gap-2">
{filterItem.map((item, index) => (
<label
key={index}
className="flex flex-col sm:flex-row items-center gap-2 text-slate-600 dark:text-slate-100 transition-all duration-500"
>
Search by {item[0].toUpperCase() + item.slice(1)}
<input
name={item}
type="text"
className="py-1 px-2 text-sm min-w-[100px] text-black dark:text-white bg-white dark:bg-slate-800 rounded-full border-0 outline-none ring-1 ring-slate-300 dark:ring-white transition-all duration-500"
value={searchTerm}
onChange={(e) => {
handleSearch(e, item);
}}
/>
</label>
))}
</div>
)}
{children({ data: newData })}
{/* show prev and next button if data exist */}
{data.length > 0 && (
<div className="mt-10 w-full flex gap-4 justify-center items-center">
<button
onClick={handlePrev}
className={`w-12 h-12 rounded-full flex justify-center items-center border ${
currentPage == 0
? "text-slate-300 border-slate-300 dark:text-slate-400 dark:border-slate-400 pointer-events-none"
: "text-slate-600 border-slate-600 dark:text-slate-300 dark:border-slate-300"
} transition-all duration-500`}
>
&lt;
</button>
<button
onClick={handleNext}
className={`w-12 h-12 rounded-full flex justify-center items-center border ${
currentPage + numberOfSelection >= data.length
? "text-slate-300 border-slate-300 dark:text-slate-400 dark:border-slate-400 pointer-events-none"
: "text-slate-600 border-slate-600 dark:text-slate-300 dark:border-slate-300"
} transition-all duration-500`}
>
&gt;
</button>
</div>
)}
</div>
);
}
+1 -4
View File
@@ -20,10 +20,7 @@ export default function Layout({ children }) {
}; };
const navigate = useNavigate(); const navigate = useNavigate();
const logOut = () => { const logOut = () => {
localStorage.removeItem("session_token"); sessionStorage.clear();
localStorage.removeItem("member_id");
localStorage.removeItem("uid");
sessionStorage.removeItem("family_uid");
localStorage.clear(); localStorage.clear();
// toast.success("Come Back Soon", { // toast.success("Come Back Soon", {
// icon: `🙂`, // icon: `🙂`,
+13 -7
View File
@@ -89,7 +89,9 @@ export default function MobileSidebar({
<ul className="flex flex-col space-y-6"> <ul className="flex flex-col space-y-6">
{/* Using mini component reduces the bulk amount of html */} {/* Using mini component reduces the bulk amount of html */}
<ListItem <ListItem
title= {userDetails?.account_type == "FULL" ? "Dashboard" : "Home"} title={
userDetails?.account_type == "FULL" ? "Dashboard" : "Home"
}
route="/" route="/"
sidebar={sidebar} sidebar={sidebar}
iconName="new-dashboard" iconName="new-dashboard"
@@ -190,17 +192,21 @@ export default function MobileSidebar({
<div className="items"> <div className="items">
<ul className="flex flex-col space-y-6"> <ul className="flex flex-col space-y-6">
{[ {[
{ name: "List", path: "/myjobs", iconName: "job-list" }, {
name: "List",
path: "/myjobs",
iconName: "job-list",
},
// {
// name: "Waiting",
// path: "/pend-interest",
// iconName: "pending-job",
// },
{ {
name: "Offers", name: "Offers",
path: "/my-offers", path: "/my-offers",
iconName: "pending-job", iconName: "pending-job",
}, },
{
name: "Waiting",
path: "/pend-interest",
iconName: "pending-job",
},
{ {
name: "Active", name: "Active",
path: "/my-active-jobs", path: "/my-active-jobs",
+33
View File
@@ -4,6 +4,7 @@ import { NavLink } from "react-router-dom";
//import SideStatistics from "./SideStatistics"; //import SideStatistics from "./SideStatistics";
import { localImgLoad } from "../../lib"; import { localImgLoad } from "../../lib";
import DarkModeContext from "../Contexts/DarkModeContext"; import DarkModeContext from "../Contexts/DarkModeContext";
import Icons from "../Helpers/Icons";
export default function RightSideBar({ myJobList }) { export default function RightSideBar({ myJobList }) {
const filterDatas = ["Last 15 days", "Last Month", "Last 6 month"]; const filterDatas = ["Last 15 days", "Last Month", "Last 6 month"];
@@ -81,6 +82,19 @@ export default function RightSideBar({ myJobList }) {
{/* action */} {/* action */}
</div> </div>
<div className="item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 rounded-full flex items-center justify-center">
<Icons name="pending-job" />
</div>
{/* name */}
<div>
<p className="text-thin-light-gray text-base font-medium">
<NavLink to="/pend-interest">Waiting</NavLink>
</p>
</div>
{/* action */}
</div>
<div className="item flex space-x-3 items-center mb-4"> <div className="item flex space-x-3 items-center mb-4">
{/* image */} {/* image */}
<div className="w-8 h-8 rounded-full"> <div className="w-8 h-8 rounded-full">
@@ -235,6 +249,7 @@ export default function RightSideBar({ myJobList }) {
/> />
</svg> </svg>
)} )}
</span> </span>
<p className="text-thin-light-gray text-base font-medium"> <p className="text-thin-light-gray text-base font-medium">
{darkMode.theme === "light" ? "Dark" : "Light"} Mode {darkMode.theme === "light" ? "Dark" : "Light"} Mode
@@ -274,6 +289,24 @@ export default function RightSideBar({ myJobList }) {
{/* action */} {/* action */}
</div> </div>
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 p-[4px] rounded-full">
<img
src={localImgLoad("images/icons/job_active.svg")}
className="w-full h-full"
alt="Active Task"
/>
</div>
{/* name */}
<div>
<p className="text-thin-light-gray text-base font-medium">
<NavLink to="/offer-interest">Offers Interest</NavLink>
</p>
</div>
{/* action */}
</div>
<div className="px-8 item flex space-x-3 items-center mb-4"> <div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */} {/* image */}
<div className="w-8 h-8 p-[4px] rounded-full"> <div className="w-8 h-8 p-[4px] rounded-full">
+5 -5
View File
@@ -216,11 +216,11 @@ export default function Sidebar({
path: "/myjobs", path: "/myjobs",
iconName: "job-list", iconName: "job-list",
}, },
{ // {
name: "Waiting", // name: "Waiting",
path: "/pend-interest", // path: "/pend-interest",
iconName: "pending-job", // iconName: "pending-job",
}, // },
{ {
name: "Offers", name: "Offers",
path: "/my-offers", path: "/my-offers",
+5 -5
View File
@@ -64,13 +64,13 @@ function DeleteJobPopout({ details, onClose, situation }) {
return ( return (
<ModalCom action={onClose} situation={situation}> <ModalCom action={onClose} situation={situation}>
<div className="logout-modal-wrapper lg:w-[600px] bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="logout-modal-wrapper lg:w-[600px] bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Delete Job Delete Job
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
@@ -119,10 +119,10 @@ function DeleteJobPopout({ details, onClose, situation }) {
{details.title} {details.title}
</p> </p>
<p className="text-lg tracking-wide text-dark-gray dark:text-white flex items-start gap-1"> <p className="text-lg tracking-wide text-dark-gray dark:text-white flex items-start gap-1">
Price: {details.thePrice} <span className="job-label">Price: </span>{details.thePrice}
</p> </p>
<p className="text-lg tracking-wide text-dark-gray dark:text-white"> <p className="text-lg tracking-wide text-dark-gray dark:text-white">
Duration: {details.timeline_days} day(s) <span className="job-label">Duration: </span>{details.timeline_days} day(s)
</p> </p>
</div> </div>
<div className="flex space-x-2.5"> <div className="flex space-x-2.5">
+7 -7
View File
@@ -212,13 +212,13 @@ const EditJobPopOut = ({
return ( return (
<ModalCom action={onClose} situation={situation}> <ModalCom action={onClose} situation={situation}>
<div className="logout-modal-wrapper w-11/12 lg:w-[600px] bg-white dark:bg-dark-white lg:rounded-2xl"> <div className="logout-modal-wrapper w-11/12 lg:w-[600px] bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Edit Job Edit Job
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
@@ -328,8 +328,8 @@ const EditJobPopOut = ({
<div className="field flex flex-col sm:flex-row w-full mb-[5px] gap-2"> <div className="field flex flex-col sm:flex-row w-full mb-[5px] gap-2">
<div className="sm:w-[60%] w-full"> <div className="sm:w-[60%] w-full">
<label <label
htmlFor="Job Delivery Details" htmlFor="job-label"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"' className='job-label'
> >
Job Delivery Details Job Delivery Details
</label> </label>
@@ -352,7 +352,7 @@ const EditJobPopOut = ({
<div className="sm:w-[35%] w-full"> <div className="sm:w-[35%] w-full">
<div <div
htmlFor="Job Categories" htmlFor="Job Categories"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"' className='job-label'
id="checked-group" id="checked-group"
> >
Categories Categories
@@ -422,7 +422,7 @@ const EditJobPopOut = ({
<div className="field w-1/2"> <div className="field w-1/2">
<div className={`flex items-center justify-between`}> <div className={`flex items-center justify-between`}>
<label <label
className="w-full input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex flex-col" className="job-label flex flex-col"
htmlFor="timeline_days" htmlFor="timeline_days"
> >
Timeline - Timeline -
@@ -10,7 +10,12 @@ import localImgLoad from "../../lib/localImgLoad";
import { tableReload } from "../../store/TableReloads"; import { tableReload } from "../../store/TableReloads";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { SocketValues } from "../Contexts/SocketIOContext";
function FamilyOfferJobPopout({ details, onClose, situation }) { function FamilyOfferJobPopout({ details, onClose, situation }) {
const {parentAssignJobToKid} = SocketValues()
const apiUrl = new usersService(); const apiUrl = new usersService();
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -69,6 +74,18 @@ function FamilyOfferJobPopout({ details, onClose, situation }) {
message: `Offer ${name}ed Successfully`, message: `Offer ${name}ed Successfully`,
trigger: "", trigger: "",
}); });
// trigger socket event to refresh parent side
//SENDS MESSAGE TO SOCKET TO UPDATE PARENT ACCOUNT WHEN CHILD ACCEPTS OR REJECTS A JOB ASSIGNED BY PARENT
// message, room
let socketMsg = {
"audience": "PARENT",
"action": "REFRESH_TASK",
"family_uid": sessionStorage.getItem('family_uid'),
}
let socketRoom = `FAMILY-${sessionStorage.getItem('parent_uid')}`
parentAssignJobToKid(socketMsg, socketRoom) //SENDS MESSAGE TO SOCKET TO UPDATE CHILD ACCOUNT
// end of socket event trigger
setTimeout(() => { setTimeout(() => {
onClose(); onClose();
dispatch(tableReload({ type: "MYTASKTABLE" })); dispatch(tableReload({ type: "MYTASKTABLE" }));
+16 -10
View File
@@ -8,6 +8,7 @@ import InputCom from "../Helpers/Inputs/InputCom/index";
import ModalCom from "../Helpers/ModalCom"; import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import Detail from "./popoutcomponent/Detail"; import Detail from "./popoutcomponent/Detail";
import { SocketValues } from "../Contexts/SocketIOContext";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
family: Yup.string().required("This is required "), family: Yup.string().required("This is required "),
@@ -29,6 +30,9 @@ function JobListPopout({
openWallet, openWallet,
setWalletItem, setWalletItem,
}) { }) {
let {marketUpdate} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
const [selectedTab, setSelectedTab] = useState("public"); const [selectedTab, setSelectedTab] = useState("public");
const tabs = ["public", "individual", "group"]; const tabs = ["public", "individual", "group"];
@@ -201,7 +205,9 @@ function JobListPopout({
setRequestStatus({ message: "", status: false }); setRequestStatus({ message: "", status: false });
}, 3000); }, 3000);
} }
dispatch(tableReload({ type: "JOBTABLE" })); marketUpdate('market', 'full-markets-jobs') // sends an event to the socket to update market lists
dispatch(tableReload({ type: "JOBTABLE" })); // reloads my job page
dispatch(tableReload({ type: "MARKETTABLELIST" })); // reloads market page
setRequestStatus({ message: data?.status_msg ? data?.status_msg : "Offer Assigned Successful", status: true }); setRequestStatus({ message: data?.status_msg ? data?.status_msg : "Offer Assigned Successful", status: true });
setTimeout(() => { setTimeout(() => {
setLoader({ jobFields: false }); setLoader({ jobFields: false });
@@ -224,6 +230,12 @@ function JobListPopout({
members: [], members: [],
}); });
const DetailsSection = ({ label, value }) => (
<div className="my-3 md:flex">
<Detail label={label} value={value} />
</div>
);
// FUNCTION TO POPULATE USER GROUP LIST // FUNCTION TO POPULATE USER GROUP LIST
useEffect(() => { useEffect(() => {
// setGroupList({loading: true, groups: [], members: []}) // setGroupList({loading: true, groups: [], members: []})
@@ -250,12 +262,6 @@ function JobListPopout({
}); });
}, []); }, []);
const DetailsSection = ({ label, value }) => (
<div className="my-3 md:flex">
<Detail label={label} value={value} />
</div>
);
const DetailsComponent = () => { const DetailsComponent = () => {
const detailsArray = [ const detailsArray = [
{ label: "Description", value: details.description }, { label: "Description", value: details.description },
@@ -297,13 +303,13 @@ function JobListPopout({
return ( return (
<ModalCom action={onClose} situation={situation} className=""> <ModalCom action={onClose} situation={situation} className="">
<div className="logout-modal-wrapper w-[90%] md:w-[768px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto"> <div className="logout-modal-wrapper w-[90%] md:w-[768px] 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"> <div className="modal-header-con">
<h1 className="text-base md:text-lg font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
{details.title} {details.title}
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
@@ -135,13 +135,13 @@ function PendingJobsPopout({ details, onClose, situation }) {
return ( return (
<ModalCom action={onClose} situation={situation}> <ModalCom action={onClose} situation={situation}>
<div className="logout-modal-wrapper w-[90%] md:w-[768px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto"> <div className="logout-modal-wrapper w-[90%] md:w-[768px] 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"> <div className="modal-header-con">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Manage Pending Item Manage Pending Item
</h1> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={onClose} onClick={onClose}
> >
<svg <svg
@@ -170,7 +170,7 @@ function PendingJobsPopout({ details, onClose, situation }) {
<p className="text-base font-semibold text-slate-900 dark:text-white tracking-wide"> <p className="text-base font-semibold text-slate-900 dark:text-white tracking-wide">
{details.title} {details.title}
</p> </p>
<div className="my-2 p-2 flex justify-start items-center space-x-2 bg-red-100 border-2 border-red-300"> <div className="my-2 p-2 flex justify-start items-center space-x-2 bg-red-100 border-2 border-red-300 rounded-2xl">
<span className="w-8 h-8 text-center text-sm rounded-full flex justify-center items-center text-red-300 bg-yellow-100"> <span className="w-8 h-8 text-center text-sm rounded-full flex justify-center items-center text-red-300 bg-yellow-100">
! !
</span> </span>
@@ -236,7 +236,7 @@ function PendingJobsPopout({ details, onClose, situation }) {
{/* ACTION SECTION */} {/* ACTION SECTION */}
<div className="p-4 w-full md:w-1/4 h-full"> <div className="p-4 w-full md:w-1/4 h-full">
<p className="mb-6 text-sm dark:text-white">Actions</p> <p className="job-label mb-6 dark:text-white">Actions</p>
<div className="mb-3"> <div className="mb-3">
<p className="px-2 py-1 text-sm bg-slate-100"> <p className="px-2 py-1 text-sm bg-slate-100">
@@ -3,7 +3,7 @@ import React from 'react'
function Detail({label, value, bg,}) { function Detail({label, value, bg,}) {
return ( return (
<> <>
<label className='w-full md:w-1/4 text-slate-900 dark:text-white tracking-wide font-semibold'>{label}</label> <label className='job-label w-full md:w-1/4'>{label}</label>
<p className={`p-1 w-full md:w-3/4 text-sm text-slate-900 dark:text-white ${bg ? bg : null}`}>{value}</p> <p className={`p-1 w-full md:w-3/4 text-sm text-slate-900 dark:text-white ${bg ? bg : null}`}>{value}</p>
</> </>
) )
+32
View File
@@ -152,6 +152,38 @@
--toastify-color-success: #f539f8; --toastify-color-success: #f539f8;
} }
@layer components{
.job-label{
@apply text-base text-slate-900 dark:text-white tracking-wide font-semibold
}
.job-label-flex{
@apply flex items-center gap-2
}
/* STYLES FOR MODAL */
/* Modal Header */
.modal-header-con{
@apply w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] bg-sky-blue/50 border-b dark:border-[#5356fb29] border-light-purple
}
.modal-title{
@apply text-2xl leading-8 font-bold text-dark-gray dark:text-white tracking-wide flex items-center
}
.modal-close-btn{
@apply text-[#000] dark:text-red-500
}
/* modal footer */
.modal-footer-wrapper{
@apply py-2 px-4 border-t-2 flex justify-between items-center
}
/* END OF STYLES FOR MODAL BOX */
/* STYLES FOR BUTTON */
.custom-btn {
@apply px-2 min-w-[80px] h-11 flex justify-center items-center text-base rounded-full cursor-pointer
}
}
/* ===================== EXTRA ===================== */ /* ===================== EXTRA ===================== */
.bottomMargin { .bottomMargin {
margin-bottom: 15px; margin-bottom: 15px;
+48 -10
View File
@@ -13,8 +13,13 @@ import { updateUserJobList } from "../store/userJobList";
import { updateWalletDetails } from "../store/walletDetails"; import { updateWalletDetails } from "../store/walletDetails";
import { familyBannersList } from "../store/FamilyBannerList"; import { familyBannersList } from "../store/FamilyBannerList";
import { familyResources } from "../store/FamilyResources"; import { familyResources } from "../store/FamilyResources";
import {familyWalletRedeemOptList} from '../store/FamilyWalletRedeemOpt'
import { SocketValues } from "../components/Contexts/SocketIOContext";
const AuthRoute = ({ redirectPath = "/login", children }) => { const AuthRoute = ({ redirectPath = "/login", children }) => {
let {joinRoom} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
const apiCall = useMemo(() => new usersService(), []); const apiCall = useMemo(() => new usersService(), []);
const dispatch = useDispatch(); const dispatch = useDispatch();
const [lastActivityTime, setLastActivityTime] = useState(Date.now()); const [lastActivityTime, setLastActivityTime] = useState(Date.now());
@@ -22,12 +27,12 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
const [loadProfileDetails, setLoadProfileDetails] = useState([]); const [loadProfileDetails, setLoadProfileDetails] = useState([]);
const navigate = useNavigate(); const navigate = useNavigate();
const { jobListTable, walletTable, familyBannersListTable } = useSelector( const { jobListTable, marketTableList, walletTable, familyBannersListTable } = useSelector(
(state) => state.tableReload (state) => state.tableReload
); );
const { const {
userDetails: { username, uid, session, account_type }, userDetails: { username, uid, session, account_type, parent_uid },
} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = username && session && uid ? true : false; // variable to determine if user is logged in let loggedIn = username && session && uid ? true : false; // variable to determine if user is logged in
@@ -35,10 +40,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
useEffect(() => { useEffect(() => {
//Removing Data stored at localStorage after session expires //Removing Data stored at localStorage after session expires
const expireSession = () => { const expireSession = () => {
localStorage.removeItem("uid"); sessionStorage.clear();
localStorage.removeItem("member_id");
localStorage.removeItem("session_token");
sessionStorage.removeItem("family_uid");
localStorage.clear(); localStorage.clear();
navigate("/login", { replace: true }); // redirects user to login page after session expires navigate("/login", { replace: true }); // redirects user to login page after session expires
}; };
@@ -104,6 +106,8 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}); });
}; };
loadProfile(); loadProfile();
}else{
setIsLogin({ loading: false, status: true });
} }
}, []); }, []);
@@ -188,6 +192,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}, [jobListTable, isLogin.status]); }, [jobListTable, isLogin.status]);
useEffect(() => { useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
return
}
const getMyWalletList = async () => { const getMyWalletList = async () => {
dispatch(updateWalletDetails({ loading: true, data: [] })); dispatch(updateWalletDetails({ loading: true, data: [] }));
try { try {
@@ -202,7 +209,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
} }
}; };
getMyWalletList(); getMyWalletList();
}, [walletTable]); }, [walletTable, isLogin.status]);
useEffect(() => { useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
@@ -218,7 +225,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
} }
}; };
getMarketActiveJobList(); getMarketActiveJobList();
}, [apiCall, dispatch, jobListTable, isLogin.status]); }, [apiCall, dispatch, marketTableList, isLogin.status]);
//FUNCTION TO GET COMMON HEAD DATA //FUNCTION TO GET COMMON HEAD DATA
useEffect(() => { useEffect(() => {
@@ -228,7 +235,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
apiCall apiCall
.getHeroJBanners() .getHeroJBanners()
.then((res) => { .then((res) => {
if (res.data.internal_return < 0) { if (res.data?.internal_return < 0) {
return; return;
} }
dispatch(commonHeadBanner(res.data)); dispatch(commonHeadBanner(res.data));
@@ -240,6 +247,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
//FUNCTION TO GET COMMON HEAD DATA //FUNCTION TO GET COMMON HEAD DATA
useEffect(() => { useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
return
}
apiCall apiCall
.getRecentActivitiedData() .getRecentActivitiedData()
.then((res) => { .then((res) => {
@@ -252,7 +262,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
.catch((error) => { .catch((error) => {
console.log("ERROR ", error); console.log("ERROR ", error);
}); });
}, []); }, [isLogin.status]);
//FUNCTION TO GET FAMILY BANNERS //FUNCTION TO GET FAMILY BANNERS
@@ -291,6 +301,34 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}, [isLogin.status]); }, [isLogin.status]);
//FUNCTION TO GET FAMILY WALLET REDEEM OPTIONS
useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FULL'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
return
}
const familyWalletRedeemOptions = async () => { // FUNCTION TO GET FAMILY WALLET REDDEM OPTIONS
dispatch(familyWalletRedeemOptList({loading: true, image: '', data:{}}))
apiCall.getFamilyWalletRedeemOptions().then((res)=>{
dispatch(familyWalletRedeemOptList({loading: false, image: res?.data?.session_image_server, data:res?.data?.result_list}))
}).catch((err)=>{
console.log(err)
dispatch(familyWalletRedeemOptList({loading: false, image: '', data:{}}))
})
};
familyWalletRedeemOptions()
}, [isLogin.status]);
useEffect(()=>{ // sends an event to the socket to enable user join a room to be able to receive update when jobs enters the market
joinRoom('full-markets-jobs')
},[isLogin.status])
useEffect(()=>{ // sends an event to the socket to enable user join a room to be able to receive update for parent child job assign
if(loggedIn || isLogin.status){
joinRoom(`FAMILY-${account_type == 'FULL' ? uid : sessionStorage.getItem('parent_uid')}`)
console.log(`Room joined for parent child task assign as ${account_type} with ${account_type == 'FULL' ? uid : sessionStorage.getItem('parent_uid')}}`)
}
},[isLogin.status])
// RENDER PAGE // RENDER PAGE
return isLogin.loading && !loggedIn ? ( return isLogin.loading && !loggedIn ? (
<LoadingSpinner size="32" color="sky-blue" height="h-screen" /> <LoadingSpinner size="32" color="sky-blue" height="h-screen" />
+40 -2
View File
@@ -388,13 +388,26 @@ class usersService {
uid: localStorage.getItem("uid"), uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"), member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"), sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_JOB_CREATEJOB, action: apiConst.WRENCHBOARD_JOB_CREATEJOB || apiConst.WRENCHBOARD_FAMILY_LIST,
limit: 30, limit: 30,
offset: 0, offset: 0,
}; };
return this.postAuxEnd("/familywaitingtasks", postData); return this.postAuxEnd("/familywaitingtasks", postData);
} }
ManageFamilyNewWaitlist() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_FAMILY_LIST,
limit: 20,
page: 1,
offset: 0,
};
return this.postAuxEnd("/familywaitingtasks", postData);
}
ManageFamilyPending() { ManageFamilyPending() {
var postData = { var postData = {
uuid: localStorage.getItem("uid"), uuid: localStorage.getItem("uid"),
@@ -1161,7 +1174,7 @@ class usersService {
return this.postAuxEnd("/suggeststatus", postData); return this.postAuxEnd("/suggeststatus", postData);
} }
// FUNCTION TO GET FAMILY WALLET // FUNCTION TO GET FAMILY WALLET AS A KID
getFamilyWallet(reqData) { getFamilyWallet(reqData) {
var postData = { var postData = {
uid: localStorage.getItem("uid"), uid: localStorage.getItem("uid"),
@@ -1173,6 +1186,18 @@ class usersService {
return this.postAuxEnd("/familywallet", postData); return this.postAuxEnd("/familywallet", postData);
} }
// FUNCTION TO GET FAMILY WALLET AS A PARENT
getKidWallets(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_FAMILY_WALLET,
...reqData,
};
return this.postAuxEnd("/kidwallets", postData);
}
// FUNCTION TO START FAMILY TRANSFER // FUNCTION TO START FAMILY TRANSFER
familyTransferStart(reqData) { familyTransferStart(reqData) {
var postData = { var postData = {
@@ -1293,6 +1318,19 @@ class usersService {
return this.postAuxEnd("/blogdata", postData); return this.postAuxEnd("/blogdata", postData);
} }
// API FUNCTION FOR FAMILY WALLET REDEEM OPTIONS
getFamilyWalletRedeemOptions() {
var postData = {
uuid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_JOB_ACTIVE,
offset: 0,
limit: 30,
};
return this.postAuxEnd("/familywallet/redeem/options", postData);
}
/* /*
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username) - 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username)
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password) - 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password)
+20
View File
@@ -0,0 +1,20 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
familyWalletRedeemOptList: {loading: true, image: '', data: {}}
};
export const familyWalletRedeemOptListSlice = createSlice({
name: "familyWalletRedeemOptList",
initialState,
reducers: {
familyWalletRedeemOptList: (state,action) => {
state.familyWalletRedeemOptList = {...action.payload}
},
},
});
// Action creators are generated for each case reducer function
export const { familyWalletRedeemOptList } = familyWalletRedeemOptListSlice.actions;
export default familyWalletRedeemOptListSlice.reducer;
+20
View File
@@ -9,6 +9,11 @@ const initialState = {
walletTable: false, walletTable: false,
uploadsTable: false, uploadsTable: false,
familyBannersListTable: false, familyBannersListTable: false,
chatMessageList: false,
marketTableList: false,
familyOfferList: false,
parentFamilyTaskList: false,
offerInterestListReload: false,
}; };
export const tableReloadSlice = createSlice({ export const tableReloadSlice = createSlice({
@@ -41,6 +46,21 @@ export const tableReloadSlice = createSlice({
case "FAMILYBANNERSLIST": case "FAMILYBANNERSLIST":
state.familyBannersListTable = !state.familyBannersListTable; state.familyBannersListTable = !state.familyBannersListTable;
return; return;
case "CHATMESSAGELIST":
state.chatMessageList = !state.chatMessageList;
return;
case "MARKETTABLELIST":
state.marketTableList = !state.marketTableList;
return;
case "FAMILYOFFERLIST":
state.familyOfferList = !state.familyOfferList;
return;
case "PARENTFAMILYTASKLIST": // reloads list of active family task on parent side
state.parentFamilyTaskList = !state.parentFamilyTaskList;
return;
case "OFFERINTERESTLISTRELOAD": // to reload offer interest list of owner when a worker sends interest in a job
state.offerInterestListReload = !state.offerInterestListReload;
return;
default: default:
return state; return state;
} }
+3 -1
View File
@@ -10,6 +10,7 @@ import userJobListReducer from "./userJobList";
import walletDetails from "./walletDetails"; import walletDetails from "./walletDetails";
import familyBannerListReducer from "./FamilyBannerList" import familyBannerListReducer from "./FamilyBannerList"
import familyResourcesReducer from './FamilyResources' import familyResourcesReducer from './FamilyResources'
import familyWalletRedeemOptListReducer from './FamilyWalletRedeemOpt'
export default configureStore({ export default configureStore({
reducer: { reducer: {
@@ -22,6 +23,7 @@ export default configureStore({
notifications: notificationsReducer, notifications: notificationsReducer,
walletDetails: walletDetails, walletDetails: walletDetails,
familyBannersList: familyBannerListReducer, familyBannersList: familyBannerListReducer,
familyResources: familyResourcesReducer familyResources: familyResourcesReducer,
familyWalletRedeemOptList: familyWalletRedeemOptListReducer
}, },
}); });
+5 -5
View File
@@ -6,13 +6,13 @@ function AddJobPage({ action, situation, categories }) {
return ( return (
<ModalCom action={action} situation={situation}> <ModalCom action={action} situation={situation}>
<div className="lg:w-[600px] w-11/12 lg:overflow-hidden lg:rounded-2xl bg-white dark:bg-dark-white dark:text-white"> <div className="lg:w-[600px] w-11/12 lg:overflow-hidden lg:rounded-2xl bg-white dark:bg-dark-white dark:text-white">
<div className="heading flex justify-between items-center py-6 md:px-[30px] px-[23px] border-b border-light-purple dark:border-[#5356fb29] "> <div className="modal-header-con">
<p className="text-26 font-bold text-dark-gray dark:text-white tracking-wide"> <h1 className="modal-title">
Create New Job New Job
</p> </h1>
<button <button
type="button" type="button"
className="text-[#374557] dark:text-red-500" className="modal-close-btn"
onClick={action} onClick={action}
> >
<svg <svg
+2 -2
View File
@@ -1,5 +1,5 @@
import FamilyWallet from "../components/MyWallet/FamilyWallet"; import FamilyWalletCon from "../components/MyWallet/FamilyWalletCon";
export default function FamilyWalletPage() { export default function FamilyWalletPage() {
return <FamilyWallet />; return <FamilyWalletCon />;
} }
+6 -1
View File
@@ -2,12 +2,17 @@ import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs"; import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
import usersService from "../services/UsersService"; import usersService from "../services/UsersService";
import { useSelector } from "react-redux";
/** /**
* This code defines a React functional component called `ManageActiveJobs`. * 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. * It fetches a list of active job messages and renders the `ActiveJobs` component with the necessary props.
*/ */
function ManageActiveJobs() { function ManageActiveJobs() {
const { chatMessageList } = useSelector(
(state) => state.tableReload
);
const ApiCall = new usersService(); const ApiCall = new usersService();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -54,7 +59,7 @@ function ManageActiveJobs() {
} }
setDetails(state); setDetails(state);
getActiveJobMesList(); getActiveJobMesList();
}, [activeJobMesListReload]); }, [activeJobMesListReload, chatMessageList]);
return ( return (
<ActiveJobs <ActiveJobs
+3 -3
View File
@@ -12,7 +12,7 @@ export default function MyReviewDueJobsPage() {
let { othersInterestedTable } = useSelector((state) => state.tableReload); // FOR OTHERS INTERESTED TABLE RELOAD let { othersInterestedTable } = useSelector((state) => state.tableReload); // FOR OTHERS INTERESTED TABLE RELOAD
const apiCall = new usersService(); const apiCall = new usersService();
const [othersInterestedList, setOthersInterestedList] = useState({loading: true, data: []}) const [othersInterestedList, setOthersInterestedList] = useState({loading: true, data: [], imageServer:''})
useEffect(() => { useEffect(() => {
if(!state){ if(!state){
@@ -26,9 +26,9 @@ export default function MyReviewDueJobsPage() {
}else{ }else{
newData = [] newData = []
} }
setOthersInterestedList({loading: false, data: newData}) setOthersInterestedList({loading: false, data: newData, imageServer:res.data.session_image_server})
}).catch(err => { }).catch(err => {
setOthersInterestedList({loading: false, data: []}) setOthersInterestedList({loading: false, data: [], imageServer:''})
console.log('Error: ', err) console.log('Error: ', err)
}) })
}, [othersInterestedTable]); }, [othersInterestedTable]);
+16 -3
View File
@@ -5,20 +5,33 @@ import OffersInterest from "../components/OffersInterest";
import usersService from "../services/UsersService"; import usersService from "../services/UsersService";
import { SocketValues } from "../components/Contexts/SocketIOContext"; // for reading socket context values
export default function OffersInterestPage() { export default function OffersInterestPage() {
const { offerInterestListReload } = useSelector((state) => state.tableReload); // table/list reload variable
const {userDetails} = useSelector((state) => state?.userDetails); // Gets USER Details
let {joinRoom} = SocketValues() // function to join room for socket
const apiCall = new usersService() const apiCall = new usersService()
let {commonHeadBanner} = useSelector(state => state.commonHeadBanner) let {commonHeadBanner} = useSelector(state => state.commonHeadBanner)
let [offerInterestList, setOfferInterestList] = useState({loading: true, data: []}) let [offerInterestList, setOfferInterestList] = useState({loading: true, data: [], imgServer:''})
useEffect(()=>{ useEffect(()=>{
apiCall.offersInterestList().then(res => { apiCall.offersInterestList().then(res => {
setOfferInterestList({loading: false, data: res.data.result_list}) setOfferInterestList({loading: false, data: res.data.result_list, imgServer:res.data.session_image_server})
}).catch(err => { }).catch(err => {
setOfferInterestList({loading: false, data: []}) setOfferInterestList({loading: false, data: [], imgServer:''})
console.log('Error: ', err) console.log('Error: ', err)
}) })
},[offerInterestListReload])
useEffect(()=>{
joinRoom(`INTEREST-${userDetails?.uid}`)
},[]) },[])
return ( return (