Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c64d372193 | |||
| abff42e0a8 | |||
| d5c342a57a | |||
| 60d6629526 | |||
| b1fbf89f10 | |||
| ae346d5ac5 | |||
| 75b5102766 | |||
| 9b12ffe0cd | |||
| 408165e718 | |||
| f7a0594447 | |||
| c733b006fb | |||
| 5a6b60578e | |||
| cdd998235e | |||
| 6e9efd7f43 | |||
| 07e9520774 | |||
| c1600a2a13 | |||
| 58e1745ac5 | |||
| 35db4fe536 | |||
| dfdbf404a5 | |||
| 985afa3c7b | |||
| 70d82d89b3 | |||
| 7f5eccb3b7 | |||
| 6729b780bd | |||
| 06224f121a | |||
| dc91649114 | |||
| 22f6eb436d | |||
| f2ab0cd6c9 | |||
| a2819786ae | |||
| 6cd92f6372 | |||
| 7173901c9b | |||
| 380d014964 | |||
| 9032b36b13 | |||
| f291382786 | |||
| 69dcee859d | |||
| fe295dc775 | |||
| 044c8edf7d | |||
| c22cffd167 | |||
| 6d77bfa1b0 | |||
| 60cc6f375e | |||
| e6684c56fd | |||
| 4f675b30ef | |||
| 00c7f65092 | |||
| 9a978b1913 | |||
| 23f8346734 | |||
| 585632c1e1 | |||
| 11ee1195c2 | |||
| c44f456cc1 | |||
| b769e4a4ba | |||
| a6ff06e2b4 | |||
| 0f801b2408 | |||
| c26f2b725a | |||
| ee94cbc92c | |||
| dccbe76c5b | |||
| 735d13b440 | |||
| 7f83cd5cc6 | |||
| 71ee75072d | |||
| 265f2b7655 | |||
| 4d264fa18e | |||
| cd6ab8b504 | |||
| 8c81073443 | |||
| 14566de037 | |||
| 69d711eddc | |||
| 159623eb69 | |||
| da26d5c24a | |||
| 40850b7342 | |||
| 28098169b9 | |||
| 2ff6ed777f | |||
| 723a2a09ab | |||
| 68482c7956 | |||
| 225e3ae34c | |||
| 251d5abf10 | |||
| 22314a61c5 | |||
| a9cf3c9d22 | |||
| 01bf8a4c52 | |||
| 68ab094bf6 | |||
| d938202f7a | |||
| c9f66bdacb | |||
| 5854ad194a | |||
| 0f25a92b88 | |||
| 9d7bcd91f4 | |||
| 68115e79fa | |||
| de379c2bbc | |||
| 2c11a0755d | |||
| f4ed892c5c | |||
| 30403f27c5 | |||
| cf2df7529d | |||
| b3695324b3 | |||
| cf8f32ed64 |
@@ -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_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"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
@@ -108,4 +111,7 @@ REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls
|
||||
REACT_APP_SHOW_NEW_FAMILY_DASH=1
|
||||
|
||||
# Displays the account dashboard
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
|
||||
# Displays the slider banners
|
||||
REACT_APP_SHOW_SLIDER_BANNERS=0
|
||||
+7
-1
@@ -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_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"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
@@ -76,4 +79,7 @@ REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls
|
||||
REACT_APP_SHOW_NEW_FAMILY_DASH=1
|
||||
|
||||
# Displays the account dashboard
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
|
||||
# Displays the slider banners
|
||||
REACT_APP_SHOW_SLIDER_BANNERS=0
|
||||
+7
-1
@@ -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_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"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
@@ -82,4 +85,7 @@ REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls
|
||||
REACT_APP_SHOW_NEW_FAMILY_DASH=1
|
||||
|
||||
# Displays the account dashboard
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
REACT_APP_SHOW_ACCOUNT_DASH=1
|
||||
|
||||
# Displays the slider banners
|
||||
REACT_APP_SHOW_SLIDER_BANNERS=0
|
||||
+3
-2
@@ -21,9 +21,10 @@ services:
|
||||
- backend.wrenchboard.api.live:10.10.33.15
|
||||
- backend.wrenchboard.api.test: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
|
||||
# #- backend.wrenchboard.api.live:172.31.4.27
|
||||
# #- backend.wrenchboard.api.test:10.20.30.27
|
||||
- socket-dev.wrenchboard.com:10.10.33.15
|
||||
- socket.wrenchboard.com:10.10.33.15
|
||||
- apigateway.wrenchboard.app.dev.fluxtra.net:10.20.30.19
|
||||
- apigateway.wrenchboard.app.lotus.fluxtra.net:172.31.4.19
|
||||
environment:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"react-to-print": "^2.14.12",
|
||||
"react-toastify": "^9.0.1",
|
||||
"redux": "^4.2.0",
|
||||
"socket.io-client": "^4.4.1",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"web-vitals": "^1.0.1",
|
||||
"yup": "^1.1.1"
|
||||
|
||||
+11
-8
@@ -2,19 +2,22 @@ import { Navigate, useLocation } from "react-router-dom";
|
||||
import Routers from "./Routers";
|
||||
import Toaster from "./components/Helpers/Toaster";
|
||||
import Default from "./components/Partials/Default";
|
||||
import SocketIOContextProvider from "./components/Contexts/SocketIOContext";
|
||||
|
||||
function App() {
|
||||
const { pathname } = useLocation();
|
||||
return (
|
||||
<Default>
|
||||
<>
|
||||
{pathname.startsWith("/@") ? (
|
||||
<Navigate to="/app" replace={true} />
|
||||
) : (
|
||||
<Routers />
|
||||
)}
|
||||
<Toaster />
|
||||
</>
|
||||
<SocketIOContextProvider>
|
||||
<>
|
||||
{pathname.startsWith("/@") ? (
|
||||
<Navigate to="/app" replace={true} />
|
||||
) : (
|
||||
<Routers />
|
||||
)}
|
||||
<Toaster />
|
||||
</>
|
||||
</SocketIOContextProvider>
|
||||
</Default>
|
||||
);
|
||||
}
|
||||
|
||||
+5
-2
@@ -64,6 +64,8 @@ import FamAIQuestionPage from "./views/FamAIQuestionPage"
|
||||
import FamMyFilesPage from "./views/FamMyFilesPage"
|
||||
import FamWorkInProgressPage from "./views/FamWorkInProgressPage";
|
||||
import MyPastDueTasksPage from "./views/MyPastDueTasksPage";
|
||||
import FamilyWalletPage from "./views/FamilyWalletPage";
|
||||
import FamilyActivitiesPage from "./views/FamilyActivitiesPage";
|
||||
|
||||
export default function Routers() {
|
||||
return (
|
||||
@@ -124,13 +126,13 @@ export default function Routers() {
|
||||
<Route exact path="/notification" element={<Notification />} />
|
||||
<Route exact path="/market-place" element={<MarketPlacePage />} />
|
||||
<Route exact path="/shop-details" element={<ShopDetailsPage />} />
|
||||
<Route exact path="/my-wallet" element={<MyWalletPage />} />
|
||||
<Route exact path="/my-collection" element={<MyCollection />} />*/}
|
||||
<Route exact path="/my-collection" element={<MyCollection />} />*/}
|
||||
<Route exact path="/reminders" element={<RemindersPage />} />
|
||||
<Route exact path="/tracking" element={<TrackingPage />} />
|
||||
<Route exact path="/calendar" element={<CalendarPage />} />
|
||||
<Route exact path="/resources" element={<ResourcePage />} />
|
||||
<Route exact path="/my-wallet/*" element={<MyWalletPage />} />
|
||||
<Route exact path="/family-wallet" element={<FamilyWalletPage />} />
|
||||
<Route exact path="/my-coupon" element={<MyCouponPage />} />
|
||||
<Route exact path="/notification" element={<Notification />} />
|
||||
<Route exact path="/market-place" element={<MarketPlacePage />} />
|
||||
@@ -167,6 +169,7 @@ export default function Routers() {
|
||||
element={<MyReviewDueJobsPage />}
|
||||
/>
|
||||
<Route exact path="/acc-family" element={<FamilyAccPage />} />
|
||||
<Route exact path="/acc-family/activities" element={<FamilyActivitiesPage />} />
|
||||
<Route exact path="/manage-family" element={<FamilyManagePage />} />
|
||||
<Route exact path="/start-job" element={<StartJob />} />
|
||||
<Route exact path="/yourpage" element={<YourPages />} />
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function LoginLayout({ slogan, children }) {
|
||||
>
|
||||
</div> */}
|
||||
<div className="p-5 sm:p-7 flex place-content-center lg:col-start-2">
|
||||
<div className="py-5 w-full sm:w-11/12 max-w-2xl shadow-md bg-slate-50 rounded-[0.475rem]">
|
||||
<div className="py-5 w-full sm:w-11/12 max-w-[550px] shadow-md bg-slate-50 rounded-[0.475rem]">
|
||||
<div className="w-full flex justify-center items-center">
|
||||
{children && children}
|
||||
</div>
|
||||
|
||||
@@ -145,8 +145,9 @@ export default function Login() {
|
||||
localStorage.setItem("member_id", `${res.data.member_id}`);
|
||||
localStorage.setItem("uid", `${res.data.uid}`);
|
||||
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("parent_uid", res.data?.parent_uid);
|
||||
}
|
||||
// localStorage.setItem("session", `${res.data.session}`);
|
||||
dispatch(updateUserDetails({ ...res.data }));
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function CustomBreadcrumb({title, breadcrumb}) {
|
||||
export default function CustomBreadcrumb({ title, breadcrumb }) {
|
||||
return (
|
||||
<div className="">
|
||||
<h3 className="text-26 font-bold text-dark-gray dark:text-white">{title}</h3>
|
||||
<nav aria-label="breadcrumb" className='text-base text-dark-gray dark:text-white flex items-center'>
|
||||
{breadcrumb.map((value, index) => (
|
||||
<p key={index}>
|
||||
<Link className={`${value.active ? 'opacity-60' : ''}`} to={value.link}>{value.title}</Link>
|
||||
{index != breadcrumb.length - 1 ?
|
||||
<span className='px-1'>/</span>
|
||||
:
|
||||
null
|
||||
}
|
||||
</p>
|
||||
))}
|
||||
</nav>
|
||||
<h3 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
{title}
|
||||
</h3>
|
||||
<nav
|
||||
aria-label="breadcrumb"
|
||||
className="text-base text-dark-gray dark:text-white flex items-center"
|
||||
>
|
||||
{breadcrumb.map((value, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<Link className={value.active ? "opacity-60" : ""} to={value.link}>
|
||||
{value.title}
|
||||
</Link>
|
||||
{index !== breadcrumb.length - 1 && <span className="px-1">\</span>}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
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_addded", { message, room });
|
||||
}
|
||||
};
|
||||
|
||||
const parentAssignJobToKid = (message, room) => {
|
||||
if(message && room){
|
||||
socket.emit("family", { message:{...message}, room });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
socket.on("receive_message", (data) => {
|
||||
// setSocketMsgReceived(data.message);
|
||||
dispatch(tableReload({type:'CHATMESSAGELIST'}))
|
||||
});
|
||||
socket.on("received_refreshmarket_jobs", (data) => {
|
||||
// setSocketMsgReceived(data.message);
|
||||
dispatch(tableReload({type:'MARKETTABLELIST'}))
|
||||
});
|
||||
socket.on("family_actions", (data) => {
|
||||
// setSocketMsgReceived(data.message);
|
||||
let user_uid = userDetails.account_type == 'FULL' ? userDetails.uid : sessionStorage.getItem('family_uid')
|
||||
let {message} = data
|
||||
if(message.action == "REFRESH_OFFER" && message.family_uid == user_uid && message.audience == "MEMBER"){
|
||||
dispatch(tableReload({type:'FAMILYOFFERLIST'}))
|
||||
}
|
||||
});
|
||||
}, [socket]);
|
||||
|
||||
let values = {
|
||||
socket,
|
||||
sendMessage,
|
||||
joinRoom,
|
||||
setSocketMsgReceived,
|
||||
marketUpdate,
|
||||
parentAssignJobToKid,
|
||||
socketMsgReceived,
|
||||
// room,
|
||||
// setRoom,
|
||||
// message,
|
||||
// setMessage,
|
||||
}
|
||||
|
||||
return (
|
||||
<SocketIOContext.Provider value={values}>
|
||||
{children}
|
||||
</SocketIOContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export const SocketValues = () => {
|
||||
return useContext(SocketIOContext)
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
// import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -41,39 +40,6 @@ export default function FamilyParentDashboard({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* countdown */}
|
||||
{nextDueTask?.next_due &&
|
||||
Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Current Task
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{nextDueTask.next_due.item_code.substr(0, 4) + "..."}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Next due in
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span className="text-base font-thin tracking-wide text-white flex items-end">
|
||||
Last Login : {loginDate}
|
||||
</span>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
// import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -38,38 +37,6 @@ export default function HomeDashboard({ className, bannerList, nextDueTask }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* countdown */}
|
||||
{nextDueTask?.next_due &&
|
||||
Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Current Task
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{nextDueTask.next_due.item_code.substr(0, 4) + "..."}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Next due in
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span className="text-base font-thin tracking-wide text-white flex items-end">
|
||||
Last Login : {loginDate}
|
||||
</span>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
// import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -42,38 +41,6 @@ export default function JobOwnerDashboard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* countdown */}
|
||||
{nextDueTask?.next_due &&
|
||||
Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Current Task
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{nextDueTask.next_due.item_code.substr(0, 4) + "..."}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Next due in
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span className="text-base font-thin tracking-wide text-white flex items-end">
|
||||
Last Login : {loginDate}
|
||||
</span>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import heroBg from "../../assets/images/bg-sky-blue.jpg"; //hero-bg.svg";
|
||||
import heroUser from "../../assets/images/hero-user.png";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
// import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
import HomeSliders from "../Home/HomeSliders";
|
||||
|
||||
export default function WorkerDashboard({ className, bannerList, nextDueTask }) {
|
||||
export default function WorkerDashboard({
|
||||
className,
|
||||
bannerList,
|
||||
nextDueTask,
|
||||
}) {
|
||||
const settings = {
|
||||
autoplay: true,
|
||||
dots: true,
|
||||
@@ -57,32 +59,37 @@ export default function WorkerDashboard({ className, bannerList, nextDueTask })
|
||||
</div>
|
||||
</div>
|
||||
{/* countdown */}
|
||||
{nextDueTask?.next_due && Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Current Task</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{(nextDueTask.next_due.item_code).substr(0,4)+'...'}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Next due in</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
{nextDueTask?.next_due &&
|
||||
Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Current Task
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{nextDueTask.next_due.item_code.substr(0, 4) + "..."}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Next due in
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
{/* action */}
|
||||
<div className="flex lg:space-x-3 space-x-1 items-center">
|
||||
<Link to="/mytask" className="text-white text-base">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
// import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -41,39 +40,6 @@ export default function WorkerDashboard({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* countdown */}
|
||||
{nextDueTask?.next_due &&
|
||||
Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border back-dark1 border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Current Task
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{nextDueTask.next_due.item_code.substr(0, 4) + "..."}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">
|
||||
Next due in
|
||||
</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span className="text-base font-thin tracking-wide text-white flex items-end">
|
||||
Last Login : {loginDate}
|
||||
</span>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import React, { Suspense } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
|
||||
import Layout from "../Partials/Layout";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import FamilyTableNew from "./FamilyTableNew";
|
||||
|
||||
export default function FamilyActivities() {
|
||||
return (
|
||||
<Layout>
|
||||
{/*<CommonHead />*/}
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<CustomBreadcrumb
|
||||
title={"Tasks & Chores"}
|
||||
breadcrumb={[
|
||||
{ link: "/", title: "Home" },
|
||||
{
|
||||
link: "/acc-family",
|
||||
title: "Family Account",
|
||||
},
|
||||
{
|
||||
link: "/acc-family/activities",
|
||||
title: "Tasks & Chores",
|
||||
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>
|
||||
<Suspense fallback={<LoadingSpinner color="sky-blue" size="16" />}>
|
||||
<FamilyTableNew />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
const CloseIcon = () => (
|
||||
<svg
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -187,6 +187,7 @@ export default function FamilyManageTabs({
|
||||
familyData={details.familyWaitList.data}
|
||||
accountDetails={accountDetails}
|
||||
loader={details.familyWaitList.loading}
|
||||
setUpdatePage={setUpdatePage}
|
||||
/>
|
||||
),
|
||||
Pending: (
|
||||
|
||||
@@ -4,39 +4,29 @@ import MyOffersFamilyTable from '../MyTasks/MyOffersFamilyTable'
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner';
|
||||
import usersService from '../../services/UsersService';
|
||||
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
export default function FamilyPendingOffer() {
|
||||
const userApi = new usersService();
|
||||
|
||||
const {familyOfferList} = useSelector((state) => state.tableReload)
|
||||
|
||||
const [myOffersList, setMyOffersList] = useState({loading: true, data: []});
|
||||
|
||||
const getMyOffersList = async () => {
|
||||
try {
|
||||
const res = await userApi.getOffersList();
|
||||
setMyOffersList({loading:false, data:res.data});
|
||||
console.log('SAME', res.data)
|
||||
} catch (error) {
|
||||
setMyOffersList({loading:false, data:[]});
|
||||
console.log("Error getting offers", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
getMyOffersList()
|
||||
},[])
|
||||
},[familyOfferList])
|
||||
return (
|
||||
<Layout>
|
||||
<div className="mb-5">
|
||||
<CustomBreadcrumb
|
||||
title = {'Ready to Start'}
|
||||
breadcrumb={
|
||||
[
|
||||
{ link: "/", title: "Home" },
|
||||
{ link: "/pending", title: "Pending", active: true},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{myOffersList.loading ?
|
||||
<div className='w-full flex justify-center items-center rounded-2xl bg-white'>
|
||||
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
|
||||
@@ -49,9 +39,22 @@ export default function FamilyPendingOffer() {
|
||||
className="mb-10"
|
||||
/>
|
||||
:
|
||||
<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>
|
||||
</div>
|
||||
<>
|
||||
<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'>
|
||||
<p className='text-black dark:text-white'>No Record Found!</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -1,424 +1,508 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import { tableReload } from "../../../store/TableReloads";
|
||||
import ModalCom from "../../Helpers/ModalCom";
|
||||
import { PriceFormatter } from "../../Helpers/PriceFormatter";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import Detail from "../../jobPopout/popoutcomponent/Detail";
|
||||
import { NewTasks } from "./forms";
|
||||
import { tableReload } from "../../../store/TableReloads";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { SocketValues } from "../../Contexts/SocketIOContext";
|
||||
|
||||
const AssignTaskPopout = React.memo(
|
||||
({
|
||||
action,
|
||||
details,
|
||||
situation,
|
||||
familyDetailsData,
|
||||
familyTask,
|
||||
activeTask,
|
||||
setActiveTask,
|
||||
setUpdatePage
|
||||
}) => {
|
||||
const apiCall = new usersService();
|
||||
const AssignTaskPopout = ({
|
||||
action,
|
||||
details,
|
||||
situation,
|
||||
familyDetailsData,
|
||||
familyTask,
|
||||
activeTask,
|
||||
setActiveTask,
|
||||
setUpdatePage,
|
||||
assignTaskChecker,
|
||||
|
||||
}) => {
|
||||
const {parentAssignJobToKid} = SocketValues()
|
||||
const apiCall = new usersService();
|
||||
let { pathname, state } = useLocation();
|
||||
|
||||
const dispatch = useDispatch()
|
||||
const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // HOLDS RESPONSE FOR SENDING API REQUEST
|
||||
const [selectedFamilyUid, setSelectedFamilyUid] = useState('');
|
||||
|
||||
let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK
|
||||
const handleFamChange = (event) => {
|
||||
setSelectedFamilyUid(event.target.value);
|
||||
};
|
||||
|
||||
const switchTaskType = ({ target: { value } }) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setTaskType(value);
|
||||
};
|
||||
|
||||
const handleActiveTask = (id = 0, data = {}) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setActiveTask({ id, data });
|
||||
};
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// New Task
|
||||
const [formState, setFormState] = useState({
|
||||
// Initialize form state with desired fields
|
||||
banner: details?.banner || "default.jpg",
|
||||
country: details?.country || "",
|
||||
price: details?.price || "",
|
||||
title: details?.title || "",
|
||||
description: details?.description || "",
|
||||
job_detail: details?.job_detail || "",
|
||||
timeline_days: details?.timeline_days || "",
|
||||
category: details?.category || "",
|
||||
});
|
||||
const getFamilySession = JSON.parse(sessionStorage.getItem("family_list"));
|
||||
|
||||
const assignFamilyTask = () => {
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
let reqData = {};
|
||||
if (taskType == "select") {
|
||||
// RUNS HERE IF TASK TYPE IS SELECT
|
||||
if (!Object.keys(activeTask.data).length) {
|
||||
const familyList = getFamilySession?.map((member) => (
|
||||
<option key={member?.family_uid} value={member?.family_uid}>
|
||||
{member?.firstname} {member?.lastname}
|
||||
</option>
|
||||
));
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // HOLDS RESPONSE FOR SENDING API REQUEST
|
||||
|
||||
let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK
|
||||
|
||||
const switchTaskType = ({ target: { value } }) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setTaskType(value);
|
||||
};
|
||||
|
||||
const handleActiveTask = (id = 0, data = {}) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setActiveTask({ id, data });
|
||||
};
|
||||
|
||||
// New Task
|
||||
const [formState, setFormState] = useState({
|
||||
// Initialize form state with desired fields
|
||||
banner: details?.banner || "default.jpg",
|
||||
country: details?.country || "",
|
||||
price: details?.price || "",
|
||||
title: details?.title || "",
|
||||
description: details?.description || "",
|
||||
job_detail: details?.job_detail || "",
|
||||
timeline_days: details?.timeline_days || "",
|
||||
category: details?.category || "",
|
||||
});
|
||||
|
||||
const assignFamilyTask = () => {
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
|
||||
if(!selectedFamilyUid){ // If no family found, throw error
|
||||
setRequestStatus({ loading: false, status: false, message: "Please Select Family Member" });
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
let reqData = {};
|
||||
if (taskType == "select") {
|
||||
// RUNS HERE IF TASK TYPE IS SELECT
|
||||
if (!Object.keys(activeTask.data).length) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "No Task is seleted",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
reqData = {
|
||||
// API PAYLOADS
|
||||
job_id: activeTask.data?.job_id,
|
||||
job_uid: activeTask.data?.job_uid,
|
||||
family_uid: selectedFamilyUid
|
||||
? selectedFamilyUid
|
||||
: familyDetailsData?.uid || details?.family_uid,
|
||||
job_description: activeTask.data?.description,
|
||||
assign_mode: 110011,
|
||||
};
|
||||
}
|
||||
|
||||
if (taskType === "new") {
|
||||
const {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
} = formState;
|
||||
|
||||
const requiredFields = {
|
||||
banner,
|
||||
// category,
|
||||
currency: country,
|
||||
description,
|
||||
"job detail": job_detail,
|
||||
price,
|
||||
timeline: timeline_days,
|
||||
title,
|
||||
};
|
||||
|
||||
for (let field in requiredFields) {
|
||||
if (requiredFields[field] == "") {
|
||||
// let currencyErrMsg = field == "country" && "currency"
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "No Task is seleted",
|
||||
message: `${
|
||||
field[0].toUpperCase() + field.slice(1).toLowerCase()
|
||||
} is empty`,
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
reqData = {
|
||||
// API PAYLOADS
|
||||
job_id: activeTask.data?.job_id,
|
||||
job_uid: activeTask.data?.job_uid,
|
||||
family_uid: familyDetailsData?.uid || details?.family_uid,
|
||||
job_description: activeTask.data?.description,
|
||||
assign_mode: 110011,
|
||||
};
|
||||
}
|
||||
|
||||
if (taskType === "new") {
|
||||
const {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
} = formState;
|
||||
reqData = {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price: price * 100,
|
||||
timeline_days,
|
||||
title,
|
||||
assign_mode: 110055,
|
||||
family_uid: selectedFamilyUid
|
||||
? selectedFamilyUid
|
||||
: familyDetailsData?.uid || details?.family_uid,
|
||||
};
|
||||
}
|
||||
|
||||
const requiredFields = {
|
||||
banner,
|
||||
// category,
|
||||
currency:country,
|
||||
description,
|
||||
'job detail':job_detail,
|
||||
price,
|
||||
timeline:timeline_days,
|
||||
title,
|
||||
};
|
||||
apiCall
|
||||
.assignFamilyTask(reqData)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "failed to assign task",
|
||||
});
|
||||
|
||||
for (let field in requiredFields) {
|
||||
if (requiredFields[field] == "") {
|
||||
// let currencyErrMsg = field == "country" && "currency"
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: `${field[0].toUpperCase()+field.slice(1).toLowerCase()} is empty`,
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
if (res.status === 200) {
|
||||
|
||||
reqData = {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price: price * 100,
|
||||
timeline_days,
|
||||
title,
|
||||
assign_mode: 110055,
|
||||
family_uid: details?.family_uid || familyDetailsData?.uid,
|
||||
};
|
||||
}
|
||||
|
||||
apiCall
|
||||
.assignFamilyTask(reqData)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "failed to assign task",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: true,
|
||||
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
|
||||
|
||||
//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(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
action(); // FUNCTION THAT CLOSES THE MODAL BOX
|
||||
}, 5000);
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "An Error occured, try again",
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "An Error occured, try again",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalCom
|
||||
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-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Assign task to{" "}
|
||||
{familyDetailsData?.firstname || details?.firstName}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={action}
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
});
|
||||
};
|
||||
|
||||
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 (
|
||||
<>
|
||||
<ModalCom 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-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">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide flex items-center">
|
||||
{details ? (
|
||||
` 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 relative after:absolute after:content-['▼'] active:after:rotate-180 after:transition-all after:duration-300 after:z-20 after:right-2 after:top-1/2 after:-translate-y-1/2 after:text-white after:text-lg">
|
||||
<select
|
||||
name=""
|
||||
id=""
|
||||
className="relative z-10 appearance-none text-lg text-white px-2 tracking-wide font-semibold transition-all cursor-pointer bg-blue-900 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>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#000] dark:text-red-500"
|
||||
onClick={action}
|
||||
>
|
||||
<svg
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{familyTask?.loading ? (
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
</div>
|
||||
{familyTask?.loading ? (
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`job-action-modal-body w-full md:grid ${
|
||||
taskType !== "new" ? "md:grid-cols-2" : "md:grid-cols-1"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="mb-2 w-full flex items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="select"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "select"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>Select Task</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="new"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "new"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>New Task</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`job-action-modal-body w-full md:grid ${
|
||||
taskType !== "new" ? "md:grid-cols-2" : "md:grid-cols-1"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="mb-2 w-full flex items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="select"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "select"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>Select Task</span>
|
||||
</div>
|
||||
{/* Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<div className="p-4 w-full h-[400px] overflow-y-auto bg-slate-100 rounded-md dark:bg-[#11131f] dark:text-white">
|
||||
{familyTask?.data?.length ? (
|
||||
familyTask?.data?.map((item, index) => (
|
||||
<div
|
||||
key={item.job_uid}
|
||||
className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer"
|
||||
onClick={() =>
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="new"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "new"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>New Task</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<div className="p-4 w-full h-[400px] overflow-y-auto bg-slate-100 rounded-md dark:bg-[#11131f] dark:text-white">
|
||||
{familyTask?.data?.length ? (
|
||||
familyTask?.data?.map((item, index) => (
|
||||
<div
|
||||
key={item.job_uid}
|
||||
className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer"
|
||||
onClick={() => handleActiveTask(item.job_uid, item)}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="task-list"
|
||||
checked={
|
||||
activeTask.id == item.job_uid ||
|
||||
(activeTask.id == index && true)
|
||||
}
|
||||
onChange={() =>
|
||||
handleActiveTask(item.job_uid, item)
|
||||
}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="task-list"
|
||||
checked={
|
||||
activeTask.id == item.job_uid ||
|
||||
(activeTask.id == index && true)
|
||||
}
|
||||
onChange={() =>
|
||||
handleActiveTask(item.job_uid, item)
|
||||
}
|
||||
className="w-[15px] h-[15px] cursor-pointer"
|
||||
/>
|
||||
<p className="w-full text-dark-gray dark:text-white tracking-wide">
|
||||
{item?.title}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center cursor-default">
|
||||
No Task found!
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{taskType == "new" && (
|
||||
<div className="p-4 w-full h-[400px]">
|
||||
<NewTasks
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/*Right Hand Side for details && Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<>
|
||||
{familyTask?.data?.length > 0 ? (
|
||||
<div className="p-4">
|
||||
<div className="w-full">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide border-b-2">
|
||||
{activeTask?.data?.title}
|
||||
className="w-[15px] h-[15px] cursor-pointer"
|
||||
/>
|
||||
<p className="w-full text-dark-gray dark:text-white tracking-wide">
|
||||
{item?.title}
|
||||
</p>
|
||||
<div className="my-3">
|
||||
<Detail
|
||||
label="Description"
|
||||
value={activeTask?.data?.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Price
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">
|
||||
{PriceFormatter(
|
||||
activeTask?.data?.price * 0.01,
|
||||
activeTask?.data?.currency,
|
||||
activeTask?.data?.curreny_code
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Timeline
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="my-3 sm:flex items-center">
|
||||
<Detail
|
||||
label="Created"
|
||||
value={`Dummy, no value found for created!`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="my-3">
|
||||
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Delivery Detail
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
value={activeTask?.data?.job_detail}
|
||||
readOnly
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<></>
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center cursor-default">
|
||||
No Task found!
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
{taskType == "new" && (
|
||||
<div className="p-4 w-full h-[400px]">
|
||||
<NewTasks
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* BTN */}
|
||||
<div className="py-2 px-4 border-t-2 flex justify-between items-center">
|
||||
{/* error or success display */}
|
||||
<div className="w-auto h-auto flex items-center">
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
{/*Right Hand Side for details && Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<>
|
||||
{familyTask?.data?.length > 0 ? (
|
||||
<div className="p-4">
|
||||
<div className="w-full">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide border-b-2">
|
||||
{activeTask?.data?.title}
|
||||
</p>
|
||||
<div className="my-3">
|
||||
<Detail
|
||||
label="Description"
|
||||
value={activeTask?.data?.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="job-label">
|
||||
Price
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">
|
||||
{PriceFormatter(
|
||||
activeTask?.data?.price * 0.01,
|
||||
activeTask?.data?.currency,
|
||||
activeTask?.data?.curreny_code
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="job-label">
|
||||
Timeline
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dummy, no value found for created! thus commented*/}
|
||||
{/* <div className="my-3 sm:flex items-center">
|
||||
<Detail
|
||||
label="Created"
|
||||
value={`Dummy, no value found for created!`}
|
||||
/>
|
||||
</div> */}
|
||||
|
||||
<div className="my-3">
|
||||
<label className="w-full job-label">
|
||||
Delivery Detail
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
value={activeTask?.data?.job_detail}
|
||||
readOnly
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* BTN */}
|
||||
<div className="py-2 px-4 border-t-2 flex justify-between items-center">
|
||||
{/* error or success display */}
|
||||
<div className="w-auto h-auto flex items-center">
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`relative p-2 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px] self-start`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
requestStatus.status && (
|
||||
<div
|
||||
className={`relative p-2 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px] self-start`}
|
||||
className={`relative p-2 text-green-700 bg-slate-200 border-slate-800 mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
requestStatus.status && (
|
||||
<div
|
||||
className={`relative p-2 text-green-700 bg-slate-200 border-slate-800 mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* End of error or success display */}
|
||||
<div className="w-auto h-auto flex items-center gap-3">
|
||||
<button
|
||||
disabled={requestStatus.loading}
|
||||
onClick={action}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
<span className="text-gradient">Close</span>
|
||||
</button>
|
||||
<div className="">
|
||||
{requestStatus.loading ? (
|
||||
<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
|
||||
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"
|
||||
>
|
||||
{`Assign to ${
|
||||
familyDetailsData?.firstname || details?.firstName
|
||||
}`}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{/* End of error or success display */}
|
||||
<div className="w-auto h-auto flex items-center gap-20">
|
||||
<button
|
||||
disabled={requestStatus.loading}
|
||||
onClick={action}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
<span className="text-gradient">Close</span>
|
||||
</button>
|
||||
<div className="">
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner color="sky-blue" size="8" />
|
||||
) : (
|
||||
<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
|
||||
// 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>
|
||||
</ModalCom>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</ModalCom>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AssignTaskPopout;
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function NewTasks({ formState, setFormState }) {
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<label
|
||||
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
|
||||
{/* {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 */}
|
||||
<div className="field w-full">
|
||||
<label htmlFor="price" className="job-label">Price</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 text-right"
|
||||
label="Price"
|
||||
labelClass="tracking-wide"
|
||||
// label="Price"
|
||||
// labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="number"
|
||||
name="price"
|
||||
@@ -117,7 +118,7 @@ export default function NewTasks({ formState, setFormState }) {
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
<label
|
||||
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
|
||||
{/* {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 */}
|
||||
<div className="field w-full mb-[5px]">
|
||||
<label htmlFor="title" className="job-label">Title</label>
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Title"
|
||||
labelClass="tracking-wide"
|
||||
// label="Title"
|
||||
// labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="title"
|
||||
@@ -167,10 +169,11 @@ export default function NewTasks({ formState, setFormState }) {
|
||||
|
||||
{/* Description */}
|
||||
<div className="field w-full mb-[5px]">
|
||||
<label htmlFor="description" className="job-label">Description</label>
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Description"
|
||||
labelClass="tracking-wide"
|
||||
// label="Description"
|
||||
// labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="description"
|
||||
@@ -186,7 +189,7 @@ export default function NewTasks({ formState, setFormState }) {
|
||||
<div className="w-full">
|
||||
<label
|
||||
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
|
||||
{/* {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 { Link, useLocation } from "react-router-dom";
|
||||
import CustomBreadcrumb from "../../Breadcrumb/CustomBreadcrumb";
|
||||
import Icons from "../../Helpers/Icons";
|
||||
import Layout from "../../Partials/Layout";
|
||||
import { AddFamily, FamilyBanner, Relatives } from "./Tabs";
|
||||
|
||||
const FamilySettings = () => {
|
||||
let {state} = useLocation()
|
||||
let { state } = useLocation();
|
||||
const tabs = [
|
||||
{
|
||||
id: 1,
|
||||
@@ -58,15 +59,42 @@ const FamilySettings = () => {
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span className={``}>Family Settings</span>
|
||||
</h1>
|
||||
<CustomBreadcrumb
|
||||
title={"Family Settings"}
|
||||
breadcrumb={[
|
||||
{ link: "/", title: "Home" },
|
||||
{
|
||||
link: "/acc-family",
|
||||
title: "Family Account",
|
||||
},
|
||||
{
|
||||
link: "/familysettings",
|
||||
title: "Family Settings",
|
||||
active: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Link to="/acc-family" className="flex gap-2 items-center text-dark-gray dark:text-white">
|
||||
<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">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6.75 15.75L3 12m0 0l3.75-3.75M3 12h18" />
|
||||
<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>
|
||||
Family
|
||||
|
||||
<span>Family</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
import React, { Suspense, lazy, useEffect, useMemo, useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { apiConst } from "../../lib/apiConst";
|
||||
import usersService from "../../services/UsersService";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
|
||||
|
||||
// Lazy Imports for components
|
||||
const FamilyWaitlist = lazy(() => import("./Tabs/FamilyNewWaitlist"));
|
||||
const FamilyTasks = lazy(() => import("./Tabs/FamilyNewTasks"));
|
||||
const FamilyPending = lazy(() => import("./Tabs/FamilyNewPending"));
|
||||
|
||||
export default function FamilyTableNew() {
|
||||
let { pathname } = useLocation();
|
||||
|
||||
// Initial state for family details
|
||||
const initialDetailState = {
|
||||
loading: false,
|
||||
data: null,
|
||||
link: "",
|
||||
};
|
||||
|
||||
const [assignTaskChecker, setAssignTaskChecker] = useState(false);
|
||||
|
||||
// console.log('accountDetails',accountDetails)
|
||||
// State for family details, tasks, waitlist, and pending
|
||||
const [details, setDetails] = useState({
|
||||
familyDetails: { ...initialDetailState },
|
||||
familyTasks: { ...initialDetailState },
|
||||
familyWaitList: { ...initialDetailState },
|
||||
familyPending: { ...initialDetailState },
|
||||
});
|
||||
|
||||
// Function to reset family details, tasks, waitlist, and pending
|
||||
const resetDetails = () => {
|
||||
setDetails({
|
||||
familyDetails: { ...initialDetailState },
|
||||
familyTasks: { ...initialDetailState },
|
||||
familyWaitList: { ...initialDetailState },
|
||||
familyPending: { ...initialDetailState },
|
||||
});
|
||||
};
|
||||
|
||||
const [updatePage, setUpdatePage] = useState(false); // State to determine when to update the page
|
||||
|
||||
// State for family task data
|
||||
const [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
|
||||
|
||||
// State for active task
|
||||
const [activeTask, setActiveTask] = useState({ id: 0, data: {} });
|
||||
|
||||
// State for error messages
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
|
||||
// State for family task popout
|
||||
const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
|
||||
|
||||
// Create an instance of the usersService class
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
// Function to handle toggling the family task popout
|
||||
const familyPopUpHandler = () => {
|
||||
setFamilyTaskPopout((prev) => !prev);
|
||||
};
|
||||
|
||||
// Array of tab names
|
||||
const tabs = [
|
||||
{ id: 1, name: "Tasks" },
|
||||
{ id: 2, name: "Waiting" },
|
||||
{ id: 3, name: "Pending" },
|
||||
];
|
||||
|
||||
// State for the currently selected tab
|
||||
const [tab, setTab] = useState(tabs[0].name);
|
||||
|
||||
// Function to handle tab changes
|
||||
const tabHandler = (value) => {
|
||||
setTab(value);
|
||||
};
|
||||
|
||||
// Object that maps tab names to their corresponding components
|
||||
const tabComponents = {
|
||||
Tasks: (
|
||||
<FamilyTasks
|
||||
image_link={details.familyTasks.link}
|
||||
loader={details.familyTasks.loading}
|
||||
familyData={details.familyTasks.data}
|
||||
action={familyPopUpHandler}
|
||||
setAssignTaskChecker={setAssignTaskChecker}
|
||||
/>
|
||||
),
|
||||
Waiting: (
|
||||
<FamilyWaitlist
|
||||
image_link={details.familyWaitList.link}
|
||||
familyData={details.familyWaitList.data}
|
||||
loader={details.familyWaitList.loading}
|
||||
setUpdatePage={setUpdatePage}
|
||||
/>
|
||||
),
|
||||
Pending: (
|
||||
<FamilyPending
|
||||
image_link={details.familyPending.link}
|
||||
familyData={details.familyPending.data}
|
||||
loader={details.familyPending.loading}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
const defaultTabComponent = tabComponents.Tasks;
|
||||
|
||||
// Selected tab component based on the current 'tab'
|
||||
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
|
||||
|
||||
// Effect to manage family details and related data
|
||||
useEffect(() => {
|
||||
const manageFamily = async () => {
|
||||
try {
|
||||
resetDetails();
|
||||
|
||||
setDetails({
|
||||
familyTasks: { loading: true },
|
||||
familyWaitList: { loading: true },
|
||||
familyPending: { loading: true },
|
||||
});
|
||||
|
||||
// const { family_uid } = accountDetails;
|
||||
// const reqData = { family_uid };
|
||||
|
||||
const [familyTasksData, familyWaitingRes, familyPendingRes] =
|
||||
await Promise.all([
|
||||
apiCall.getMyActiveJobList(),
|
||||
apiCall.ManageFamilyNewWaitlist(),
|
||||
apiCall.ManageFamilyPending(),
|
||||
]);
|
||||
|
||||
let tasksData = familyTasksData?.data?.result_list;
|
||||
let _familyWaitData = familyWaitingRes?.data?.result_list;
|
||||
let familyPendingData = familyPendingRes?.data?.result_list;
|
||||
|
||||
// Getting the image server link
|
||||
let imageServerLink = familyWaitingRes.data?.session_image_server;
|
||||
|
||||
// Function to check for errors in data
|
||||
const checkDataError = (data) => data?.internal_return < 0;
|
||||
|
||||
if (
|
||||
checkDataError(tasksData) ||
|
||||
checkDataError(_familyWaitData) ||
|
||||
checkDataError(familyPendingData)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDetails({
|
||||
familyTasks: {
|
||||
loading: false,
|
||||
data: tasksData,
|
||||
link: imageServerLink,
|
||||
},
|
||||
familyWaitList: {
|
||||
loading: false,
|
||||
data: _familyWaitData,
|
||||
link: imageServerLink,
|
||||
},
|
||||
familyPending: {
|
||||
loading: false,
|
||||
data: familyPendingData,
|
||||
link: imageServerLink,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
resetDetails();
|
||||
setErrMsg("An error occurred");
|
||||
throw new Error(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Invoke the manageFamily function when the component mounts
|
||||
manageFamily();
|
||||
}, [updatePage]);
|
||||
|
||||
// Effect to manage family tasks
|
||||
useEffect(() => {
|
||||
let checkFamilyTask = true;
|
||||
const reqData = {
|
||||
limit: 30,
|
||||
offset: 0,
|
||||
job_type: "FAMILY",
|
||||
action: apiConst.WRENCHBOARD_PICTURE_FAMMEMBER,
|
||||
};
|
||||
|
||||
if (checkFamilyTask) {
|
||||
setFamilyTask({ loading: true });
|
||||
apiCall
|
||||
.getMyJobList(reqData)
|
||||
.then((res) => {
|
||||
setFamilyTask({ loading: false, data: res?.data?.result_list });
|
||||
if (res?.data?.result_list?.length) {
|
||||
setActiveTask((prev) => ({
|
||||
...prev,
|
||||
data: res?.data?.result_list[0],
|
||||
}));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setFamilyTask({ loading: false, data: [] });
|
||||
console.log("Error", err);
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup function to prevent memory leaks
|
||||
return () => {
|
||||
checkFamilyTask = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// console.log(updatePage);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow h-full`}
|
||||
>
|
||||
<div className="relative w-full sm:rounded-lg overflow-x-auto">
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="h-full min-h-[609px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="w-full h-full text-sm text-left text-gray-500 dark:text-gray-400 relative grid grid-cols-3 min-h-[575px]">
|
||||
<div className="col-span-3 h-full w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="w-full pr-8 flex items-center gap-1 border-b border-b-[#FAFAF]">
|
||||
<ul className="flex gap-2 items-center w-full">
|
||||
{tabs.map(({ name, id }) => (
|
||||
<li
|
||||
onClick={() => tabHandler(name)}
|
||||
className={`p-4 flex hover:text-purple transition-all ease-in-out items-center cursor-pointer overflow-hidden text-xl relative top-[2px] ${
|
||||
tab === name
|
||||
? "text-purple border-r"
|
||||
: "text-thin-light-gray"
|
||||
}`}
|
||||
key={id}
|
||||
>
|
||||
<h1>{name}</h1>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
onClick={familyPopUpHandler}
|
||||
className="p-1 my-1 w-[100px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Add task
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-[0.9] h-full">
|
||||
<div className="h-full relative overflow-y-auto">
|
||||
<Suspense
|
||||
fallback={<LoadingSpinner size="16" color="sky-blue" />}
|
||||
>
|
||||
{selectedTabComponent}
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{familyTaskPopout && (
|
||||
<AssignTaskPopout
|
||||
action={familyPopUpHandler}
|
||||
situation={familyTaskPopout}
|
||||
familyTask={familyTask}
|
||||
setFamilyTask={setFamilyTask}
|
||||
setActiveTask={setActiveTask}
|
||||
activeTask={activeTask}
|
||||
setUpdatePage={setUpdatePage}
|
||||
// updateFamilyPendingTable={updateFamilyPendingTable}
|
||||
pathname={pathname}
|
||||
assignTaskChecker={assignTaskChecker}
|
||||
/>
|
||||
)}
|
||||
</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";
|
||||
|
||||
const FamilyWaitlist = memo(
|
||||
({ familyData, className, accountDetails, loader }) => {
|
||||
({ familyData, className, accountDetails, loader, setUpdatePage }) => {
|
||||
const [popUp, setPopUp] = useState({ show: false, data: {} });
|
||||
const [continueTaskPopup, setContinueTaskPopup] = useState({
|
||||
show: false,
|
||||
@@ -144,6 +144,7 @@ const FamilyWaitlist = memo(
|
||||
details={continueTaskPopup.data}
|
||||
action={closeContinueTaskPopup}
|
||||
situation={continueTaskPopup.show}
|
||||
setUpdatePage={setUpdatePage}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -7,11 +7,13 @@ import React, {
|
||||
} from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import usersService from "../../services/UsersService";
|
||||
import Icons from "../Helpers/Icons";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import FamilyTable from "./FamilyTable";
|
||||
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
|
||||
|
||||
export default function FamilyAcc() {
|
||||
// State to store the selected year and month
|
||||
@@ -107,6 +109,7 @@ export default function FamilyAcc() {
|
||||
if (data?.internal_return >= 0 && data?.status === "OK") {
|
||||
const { result_list, session_image_server } = data;
|
||||
setFamilyList({ result_list, session_image_server });
|
||||
sessionStorage.setItem("family_list", JSON.stringify(result_list))
|
||||
setLoader(false);
|
||||
} else {
|
||||
return;
|
||||
@@ -136,7 +139,18 @@ export default function FamilyAcc() {
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span className={``}>Family Accounts</span>
|
||||
{/* <span className={``}>Family Accounts</span> */}
|
||||
<div className="mb-5">
|
||||
<CustomBreadcrumb
|
||||
title = {'Family Account'}
|
||||
breadcrumb={
|
||||
[
|
||||
{ link: "/", title: "Home" },
|
||||
{ link: "/acc-family", title: "Family Account", active: true},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{familyList?.result_list?.length <
|
||||
process.env.REACT_APP_MAX_FAMILY_MEMBERS &&
|
||||
!loader && (
|
||||
@@ -150,31 +164,44 @@ export default function FamilyAcc() {
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
<Link
|
||||
to={`/familysettings`}
|
||||
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%)]"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6 dark:stroke-white"
|
||||
|
||||
<div className="flex gap-4 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">
|
||||
<Icons name="pending-job" />
|
||||
</span>
|
||||
<span
|
||||
className={`item-content relative text-[18px] transition-all duration-300 ease-in-out font-medium dark:text-white h-12 flex items-center`}
|
||||
>
|
||||
Activities
|
||||
</span>
|
||||
</Link>
|
||||
<Link
|
||||
to={`/familysettings`}
|
||||
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%)] bg-[#76a5df] text-white"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</Link>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6 dark:stroke-white"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<Suspense fallback={<LoadingSpinner color="sky-blue" size="16" />}>
|
||||
<FamilyTable
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Form, Formik } from "formik";
|
||||
import { useState } from "react";
|
||||
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 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 SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
@@ -51,21 +50,47 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
};
|
||||
|
||||
const handleParentSuggestion = (values) => {
|
||||
if (suggestedNextStep == "Send Task") {
|
||||
let firstName = state?.firstname;
|
||||
let family_uid = state?.family_uid;
|
||||
continuePopupData({ ...details, firstName, family_uid });
|
||||
if (suggestedNextStep === "Send Task") {
|
||||
let firstname = state?.firstname || details?.firstname;
|
||||
let family_uid = state?.family_uid || details?.family_uid;
|
||||
continuePopupData({
|
||||
...details,
|
||||
firstname,
|
||||
family_uid,
|
||||
});
|
||||
}
|
||||
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 (
|
||||
<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-header w-full flex items-center justify-between lg:p-6 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-base md:text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{pathname === "/manage-family"
|
||||
<div className="logout-modal-wrapper lw-[90%] md:w-[48rem] h-full lg:h-[627px] 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-[1.875rem] py-[1.4375rem] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{isManageFamilyPage
|
||||
? `${state?.firstname}'s Suggested Task`
|
||||
: isActivitiesPage
|
||||
? `${details?.firstname}'s Suggested Task`
|
||||
: "Suggest to Parent"}
|
||||
</h1>
|
||||
<button
|
||||
@@ -97,19 +122,21 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={
|
||||
pathname !== "/manage-family"
|
||||
? handleSuggestedTask
|
||||
: handleParentSuggestion
|
||||
isActivitiesPage
|
||||
? handleParentSuggestion
|
||||
: isManageFamilyPage
|
||||
? handleParentSuggestion
|
||||
: handleSuggestedTask
|
||||
}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form>
|
||||
<div className="p-5 w-full bg-white rounded-md flex justify-between">
|
||||
<Form className="h-[33.875rem] flex flex-col">
|
||||
<div className="px-5 w-full bg-white rounded-md flex justify-between items-center h-full">
|
||||
{/* 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
|
||||
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={{
|
||||
background: `url(${selectedImage}) center / contain no-repeat`,
|
||||
}}
|
||||
@@ -117,17 +144,22 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
</div>
|
||||
|
||||
{/* 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 */}
|
||||
<div className="field w-full mb-[15px]">
|
||||
<div className="field w-full mb-[.9375rem]">
|
||||
<InputCom
|
||||
fieldClass={
|
||||
pathname === "/manage-family" ? "px-2" : "px-6"
|
||||
pathname === "/manage-family" ||
|
||||
pathname === "/acc-family/activities"
|
||||
? "px-2"
|
||||
: "px-6"
|
||||
}
|
||||
label="Title"
|
||||
labalClass="text-[1.125rem]"
|
||||
labelClass="tracking-wide"
|
||||
inputBg={
|
||||
pathname === "/manage-family"
|
||||
pathname === "/manage-family" ||
|
||||
pathname === "/acc-family/activities"
|
||||
? "bg-white"
|
||||
: "bg-slate-100"
|
||||
}
|
||||
@@ -147,15 +179,15 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="field w-full mb-[5px]">
|
||||
<div className="field w-full mb-[.3125rem]">
|
||||
<label
|
||||
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='input-label text-[#181c32] dark:text-white text-[1.125rem] leading-[1.3102rem] font-semibold flex items-center gap-1'
|
||||
>
|
||||
Description
|
||||
{props.errors.description &&
|
||||
props.touched.description && (
|
||||
<span className="text-[12px] text-red-500">
|
||||
<span className="text-[.75rem] text-red-500">
|
||||
{props.errors.description}
|
||||
</span>
|
||||
)}
|
||||
@@ -164,9 +196,10 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
id="description"
|
||||
rows="5"
|
||||
className={`input-field pt-2 placeholder:text-base text-dark-gray dark:text-white w-full ${
|
||||
pathname === "/manage-family"
|
||||
? "px-2 h-[110px]"
|
||||
: "bg-slate-100 px-3 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] h-[130px]"
|
||||
pathname === "/manage-family" ||
|
||||
pathname === "/acc-family/activities"
|
||||
? "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" }}
|
||||
name="description"
|
||||
@@ -177,8 +210,9 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
</div>
|
||||
|
||||
{/* Radio buttons for family */}
|
||||
{pathname === "/manage-family" ? (
|
||||
<div className="h-[20px] w-full border-t dark:border-[#5356fb29] border-light-purple relative">
|
||||
{pathname === "/manage-family" ||
|
||||
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">
|
||||
Parent suggested next step
|
||||
</div>
|
||||
@@ -196,7 +230,7 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
role="group"
|
||||
key={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)}
|
||||
>
|
||||
<input
|
||||
@@ -205,19 +239,19 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
value={title}
|
||||
checked={suggestedNextStep === title}
|
||||
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
|
||||
onClick={() => setSuggestedNextStep(title)}
|
||||
id={`parent-suggested-${idx}`}
|
||||
name="parent-suggested"
|
||||
className={`ml-1 ${
|
||||
title == "Not Now"
|
||||
title === "Not Now"
|
||||
? "text-red-500"
|
||||
: title == "Duplicate"
|
||||
: title === "Duplicate"
|
||||
? "text-purple"
|
||||
: "text-black"
|
||||
} font-semibold`}
|
||||
} font-semibold text-[1.125rem]`}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
@@ -229,7 +263,7 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
</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">
|
||||
<button
|
||||
type="button"
|
||||
@@ -243,19 +277,9 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
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"
|
||||
>
|
||||
{pathname !== "/manage-family" ? (
|
||||
{/* {pathname === "/acc-family/activities" ? (
|
||||
<>
|
||||
{submitTask.loading
|
||||
? "Submitting Task"
|
||||
: submitTask.state == "success"
|
||||
? "Task Submitted"
|
||||
: submitTask.state == "bad"
|
||||
? "An Error Occurred"
|
||||
: "Send to Parents"}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{suggestedNextStep == "Send Task" ? (
|
||||
{suggestedNextStep === "Send Task" ? (
|
||||
<>
|
||||
Continue <Icons name="chevron-right" />
|
||||
</>
|
||||
@@ -263,7 +287,32 @@ const SuggestTask = ({ details, onClose, situation, continuePopupData }) => {
|
||||
"Complete"
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
) : (
|
||||
<>
|
||||
{pathname !== "/manage-family" ? (
|
||||
<>
|
||||
{submitTask.loading
|
||||
? "Submitting Task"
|
||||
: submitTask.state === "success"
|
||||
? "Task Submitted"
|
||||
: submitTask.state === "bad"
|
||||
? "An Error Occurred"
|
||||
: "Send to Parents"}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{suggestedNextStep === "Send Task" ? (
|
||||
<>
|
||||
Continue <Icons name="chevron-right" />
|
||||
</>
|
||||
) : (
|
||||
"Complete"
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)} */}
|
||||
{getButtonText()}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ export default function InputCom({
|
||||
forgotPassword,
|
||||
parentClass,
|
||||
labelClass,
|
||||
labalClass,
|
||||
inputClass,
|
||||
fieldClass,
|
||||
onClick,
|
||||
@@ -53,7 +54,7 @@ export default function InputCom({
|
||||
<div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
|
||||
{label && (
|
||||
<label
|
||||
className="input-label text-[#181c32] text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
|
||||
className={`input-label text-[#181c32] text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1 ${labalClass}`}
|
||||
htmlFor={name}
|
||||
>
|
||||
{label}
|
||||
|
||||
@@ -42,14 +42,16 @@ export default function FamilyDash({ MyActiveJobList=[], serverImg }) {
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
{/* Header */}
|
||||
<div className="text-white mb-4 p-2 w-full rounded-xl bg-sky-blue place-content-center">
|
||||
<div className="w-full flex flex-wrap gap-x-4">
|
||||
<p className="text-lg font-normal leading-5">Welcome</p>
|
||||
<div className="">
|
||||
<h1 className="text-lg font-normal leading-5">{`${userDetails?.firstname} ${userDetails?.lastname}`}</h1>
|
||||
<div className="text-white mb-4 min-h-[3rem] px-2 w-full flex justify-between items-center rounded-xl bg-family-header-bg">
|
||||
<div className="w-full">
|
||||
<div className="w-full flex flex-wrap gap-x-4 ">
|
||||
<p className="text-lg font-normal leading-5">Welcome</p>
|
||||
<div className="">
|
||||
<h1 className="text-lg font-normal leading-5">{`${userDetails?.firstname} ${userDetails?.lastname}`}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full text-sm flex justify-end items-end">
|
||||
<div className="py-1 w-full text-sm text-right self-end">
|
||||
<p className="leading-4">Last Login: {`${userDetails?.last_login.split(' ')[0]}`}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -229,12 +229,13 @@ export default function MemberList({
|
||||
// iconName="message"
|
||||
/>
|
||||
</div>
|
||||
<div className="input-item w-full sm:w-[150%]">
|
||||
<div className="input-item w-full">
|
||||
<InputCom
|
||||
labelClass="tracking-wider"
|
||||
fieldClass="sm:px-6 px-2"
|
||||
value={fields.email}
|
||||
inputHandler={handleFieldsChange}
|
||||
inputClass="xl:w-[16rem] 2xl:w-full"
|
||||
placeholder="Email"
|
||||
// label="Email"
|
||||
name="email"
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function MainSection({
|
||||
);
|
||||
const [tab, setTab] = useState(Object.keys(marketCategories)[0]);
|
||||
|
||||
let [contentDisplay, setContentDisplay] = useState("grid"); // STATE TO HOLD LIST VIEW STYLE
|
||||
let [contentDisplay, setContentDisplay] = useState("list"); // STATE TO HOLD LIST VIEW STYLE
|
||||
|
||||
// Convert to array in order to map
|
||||
const mappedArray = Object.entries(marketCategories).map(([key, value]) => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useSelector } from "react-redux";
|
||||
import Layout from "../Partials/Layout";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
import MainSection from "./MainSection";
|
||||
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
|
||||
|
||||
export default function MarketPlace({ commonHeadData }) {
|
||||
let { jobLists } = useSelector((state) => state.jobLists);
|
||||
@@ -13,6 +14,17 @@ export default function MarketPlace({ commonHeadData }) {
|
||||
<>
|
||||
<Layout>
|
||||
<CommonHead commonHeadData={commonHeadData} />
|
||||
<div className="mb-5">
|
||||
<CustomBreadcrumb
|
||||
title = {'Market'}
|
||||
breadcrumb={
|
||||
[
|
||||
{ link: "/", title: "Home" },
|
||||
{ link: "/market", title: "Market", active: true},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<MainSection
|
||||
marketPlaceProduct={marketData}
|
||||
categories={categories}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function ActiveJobMessage({ activeJobMesList }) {
|
||||
|
||||
return (
|
||||
<div className='flex flex-col justify-between'>
|
||||
<div className="w-full min-h-[450px] max-h-[450px] overflow-y-scroll">
|
||||
<div className="w-full h-full min-h-[400px] max-h-[400px] overflow-y-auto">
|
||||
<table className="wallet-activity w-full table-auto border-collapse text-left">
|
||||
<thead className='border-b-2'>
|
||||
<tr className='text-slate-600'>
|
||||
|
||||
@@ -11,8 +11,11 @@ import IndexJobActions from "./JobActions/IndexJobActions";
|
||||
|
||||
import usersService from "../../services/UsersService";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import { SocketValues } from "../Contexts/SocketIOContext";
|
||||
|
||||
function ActiveJobs(props) {
|
||||
let {sendMessage, joinRoom} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
|
||||
|
||||
const ApiCall = new usersService();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -139,6 +142,9 @@ function ActiveJobs(props) {
|
||||
status: true,
|
||||
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
|
||||
setMessageToSend(""); // SENDS MESSAGE TO SEND BACK TO EMPTY STRINGS
|
||||
})
|
||||
@@ -255,6 +261,12 @@ function ActiveJobs(props) {
|
||||
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 (
|
||||
<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">
|
||||
@@ -286,7 +298,7 @@ function ActiveJobs(props) {
|
||||
<path d="M19 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H19v-2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 className="text-[22px] font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
<h1 className="text-[20px] font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{props.details?.title && props.details.title}
|
||||
</h1>
|
||||
</div>
|
||||
@@ -421,7 +433,7 @@ function ActiveJobs(props) {
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<div className="p-4 w-full h-[300px] text-base text-slate-600 border border-slate-300">
|
||||
<div className="p-4 w-full h-[200px] text-base text-slate-600 border border-slate-300">
|
||||
<div className="files">
|
||||
<label
|
||||
htmlFor="file"
|
||||
@@ -535,8 +547,15 @@ function ActiveJobs(props) {
|
||||
{/* MESSAGE SECTION */}
|
||||
<div className="w-full lg:w-1/2">
|
||||
<div className="flex justify-between items-center gap-5">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Message
|
||||
<p className="w-full text-lg font-bold text-dark-gray dark:text-white tracking-wide flex items-center gap-2">
|
||||
<span>Message</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={popUpHandler}
|
||||
className="text-[12px] tracking-wider text-emerald-600 dark:text-emerald-300"
|
||||
>
|
||||
View all
|
||||
</button>
|
||||
</p>
|
||||
{/* <button
|
||||
type="button"
|
||||
|
||||
@@ -13,13 +13,6 @@ function CurrentJobAction() {
|
||||
<div>
|
||||
Waiting for the completion message from the client before you can approve.
|
||||
</div>
|
||||
{/*<div className="flex flex-col flex-[0.9]"> </div>*/}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2">
|
||||
<div className="flex justify-center items-center">
|
||||
.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,6 +3,7 @@ import OfferCard from "../Cards/OfferCard";
|
||||
import Icons from "../Helpers/Icons";
|
||||
import SliderCom from "../Helpers/SliderCom";
|
||||
import FamilyOfferJobPopout from "../jobPopout/FamilyOfferJobPopout";
|
||||
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
|
||||
|
||||
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
|
||||
@@ -60,10 +61,21 @@ export default function MyOffersFamilyTable({ className, familyOffers, image_ser
|
||||
>
|
||||
{/* heading */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
{/* <div>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
Ready to Start?
|
||||
</h1>
|
||||
</div> */}
|
||||
<div className="">
|
||||
<CustomBreadcrumb
|
||||
title = {'Ready to Start'}
|
||||
breadcrumb={
|
||||
[
|
||||
{ link: "/", title: "Home" },
|
||||
{ link: "/pending", title: "Pending", active: true},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-3">
|
||||
<button onClick={nextHandler} type="button">
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function MyTasks({
|
||||
/>
|
||||
)}
|
||||
<div className="w-full mb-5 flex justify-between items-center gap-1">
|
||||
{userDetails.account_type == 'FULL'?
|
||||
{/* {userDetails.account_type == 'FULL'?
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
@@ -83,7 +83,7 @@ export default function MyTasks({
|
||||
My Tasks
|
||||
</span>
|
||||
</h1>
|
||||
:
|
||||
: */}
|
||||
<CustomBreadcrumb
|
||||
title = 'My Tasks'
|
||||
breadcrumb={
|
||||
@@ -93,7 +93,7 @@ export default function MyTasks({
|
||||
]
|
||||
}
|
||||
/>
|
||||
}
|
||||
{/* } */}
|
||||
|
||||
{ActiveJobList?.data?.length > 0 && userDetails.account_type == 'FAMILY' &&
|
||||
<button
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import WalletItemCard from "./WalletItemCard";
|
||||
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.
|
||||
*/
|
||||
export default function FamilyWalletBox({ wallet, payment }) {
|
||||
// const { loading, data } = wallet;
|
||||
|
||||
// const { userDetails } = useSelector((state) => state.userDetails);
|
||||
// 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 (
|
||||
<div className="w-full">
|
||||
<div className="my-wallet-wrapper w-full">
|
||||
<div className="main-wrapper w-full mb-10">
|
||||
<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">
|
||||
<LoadingSpinner size="16" color="sky-blue" height='min-h-[240px]' />
|
||||
</div>
|
||||
: wallet?.data.length > 0 ?
|
||||
<>
|
||||
{wallet?.data?.length > 1 &&
|
||||
<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 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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 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>
|
||||
// ))
|
||||
@@ -0,0 +1,81 @@
|
||||
import React, { Suspense, lazy, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import usersService from "../../services/UsersService";
|
||||
import Layout from "../Partials/Layout";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
|
||||
const FamilyWalletBox = lazy(() => import("./FamilyWalletBox"));
|
||||
|
||||
const FamilyWalletCon = () => {
|
||||
const apiCall = new usersService();
|
||||
// const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
|
||||
const { walletTable } = useSelector((state) => state.tableReload);
|
||||
|
||||
const [paymentHistory, setPaymentHistory] = useState({
|
||||
loading: true,
|
||||
data: [],
|
||||
});
|
||||
|
||||
const [familyWalletBal, setFamilyWalletBal] = useState({
|
||||
loading: true,
|
||||
data: []
|
||||
});
|
||||
|
||||
const getFamilyWalletBal = () => {
|
||||
setFamilyWalletBal({loading:true, data: []})
|
||||
apiCall.getFamilyWallet({family_uid: localStorage.getItem("uid")}).then(res => {
|
||||
setFamilyWalletBal({loading:false, data: res?.data?.result_list})
|
||||
}).catch(error => {
|
||||
setFamilyWalletBal({loading:false, data: []})
|
||||
})
|
||||
};
|
||||
|
||||
const getPaymentHistory = () => {
|
||||
apiCall
|
||||
.getPaymentHx()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
setPaymentHistory({ loading: false, data: [] });
|
||||
} else {
|
||||
setPaymentHistory({ loading: false, data: res.data?.result_list });
|
||||
// console.log('Hist', res.data?.result_list)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setPaymentHistory({ loading: false, data: [] });
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getPaymentHistory();
|
||||
getFamilyWalletBal()
|
||||
}, [walletTable]);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className='mb-4'>
|
||||
<CustomBreadcrumb
|
||||
title={'Wallet'}
|
||||
breadcrumb = {
|
||||
[
|
||||
{ link: "/", title: "Home" },
|
||||
{ link: '/family-wallet', title: 'Wallet', active: true},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Suspense fallback={
|
||||
<div className="bg-white rounded-2xl">
|
||||
<LoadingSpinner size="16" color="sky-blue" height='h-[30rem]' />
|
||||
</div>
|
||||
}>
|
||||
<FamilyWalletBox
|
||||
wallet={familyWalletBal}
|
||||
payment={paymentHistory}
|
||||
/>
|
||||
</Suspense>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -15,21 +15,6 @@ export default function WalletBox({ wallet, payment, countries }) {
|
||||
return (
|
||||
<div className="my-wallet-wrapper w-full mb-10">
|
||||
<div className="main-wrapper w-full">
|
||||
{accountType ?
|
||||
<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">
|
||||
{loading ? (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
data.length > 0 && data.map((item) => (
|
||||
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
|
||||
<WalletItemCardFamily walletItem={item} payment={payment} countries={countries} />
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
:
|
||||
<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">
|
||||
{loading ? (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
@@ -43,7 +28,6 @@ export default function WalletBox({ wallet, payment, countries }) {
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,8 +7,11 @@ import Icons from "../Helpers/Icons";
|
||||
import Accordion from "../Helpers/Accordion";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export default function WalletHeader(props) {
|
||||
|
||||
const {userDetails: { account_type }} = useSelector((state) => state?.userDetails);
|
||||
// debugger;
|
||||
//props.myWalletList.result_list
|
||||
let { pathname } = useLocation();
|
||||
@@ -21,187 +24,196 @@ export default function WalletHeader(props) {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="lg:flex hidden user-balance cursor-pointer lg:w-[152px] w-[150px] h-[48px] items-center rounded-full relative bg-sky-blue pr-1.5 pl-4">
|
||||
<div
|
||||
onClick={() => props.handlerBalance()}
|
||||
className="flex items-center lg:justify-between justify-center w-full h-full"
|
||||
>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="wallet" />
|
||||
</span>
|
||||
<p className="lg:text-xl text-lg font-bold text-white">Wallet</p>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="deep-plus" />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={`balance-dropdown w-96 z-30 bg-white dark:bg-dark-white absolute -left-24 rounded-lg cursor-pointer ${
|
||||
props.balanceDropdown ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="heading border-b dark:border-[#5356fb29] border-light-purple px-7 py-6">
|
||||
<h3 className="text-xl font-bold text-dark-gray dark:text-white">
|
||||
Wallet
|
||||
</h3>
|
||||
{account_type == 'FULL' ?
|
||||
<div className="lg:flex hidden user-balance cursor-pointer lg:w-[152px] w-[150px] h-[48px] items-center rounded-full relative bg-sky-blue pr-1.5 pl-4">
|
||||
<div
|
||||
onClick={() => props.handlerBalance()}
|
||||
className="flex items-center lg:justify-between justify-center w-full h-full"
|
||||
>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="wallet" />
|
||||
</span>
|
||||
<p className="lg:text-xl text-lg font-bold text-white">Wallet</p>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="deep-plus" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="content px-7 pb-7">
|
||||
<ul>
|
||||
{props.myWalletList &&
|
||||
props.myWalletList?.length > 0 &&
|
||||
props.myWalletList.map((value, index) =>
|
||||
{
|
||||
let image = value.code ? `${value.code.toLocaleLowerCase()}.svg` : 'default.png'
|
||||
return(
|
||||
<li
|
||||
key={index}
|
||||
className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple"
|
||||
onClick={onWalletClick}
|
||||
>
|
||||
<div className="sm:flex justify-between items-center">
|
||||
<div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">
|
||||
<div className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">
|
||||
<img src={localImgLoad(`images/currency/${image}`)} className="w-14 h-14" alt="" />
|
||||
<div
|
||||
className={`balance-dropdown w-96 z-30 bg-white dark:bg-dark-white absolute -left-24 rounded-lg cursor-pointer ${
|
||||
props.balanceDropdown ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="heading border-b dark:border-[#5356fb29] border-light-purple px-7 py-6">
|
||||
<h3 className="text-xl font-bold text-dark-gray dark:text-white">
|
||||
Wallet
|
||||
</h3>
|
||||
</div>
|
||||
<div className="content px-7 pb-7">
|
||||
<ul>
|
||||
{props.myWalletList &&
|
||||
props.myWalletList?.length > 0 &&
|
||||
props.myWalletList.map((value, index) =>
|
||||
{
|
||||
let image = value.code ? `${value.code.toLocaleLowerCase()}.svg` : 'default.png'
|
||||
return(
|
||||
<li
|
||||
key={index}
|
||||
className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple"
|
||||
onClick={onWalletClick}
|
||||
>
|
||||
<div className="sm:flex justify-between items-center">
|
||||
<div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">
|
||||
<div className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">
|
||||
<img src={localImgLoad(`images/currency/${image}`)} className="w-14 h-14" alt="" />
|
||||
</div>
|
||||
<div className="name">
|
||||
<p className="text-2xl font-bold text-dark-gray dark:text-white">
|
||||
{value.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="name">
|
||||
<p className="text-2xl font-bold text-dark-gray dark:text-white">
|
||||
{value.description}
|
||||
<div>
|
||||
<p className="eth text-xl font-bold text-purple">
|
||||
{PriceFormatter(value.amount * 0.01, value.code)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="eth text-xl font-bold text-purple">
|
||||
{PriceFormatter(value.amount * 0.01, value.code)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
)}
|
||||
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank1} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* MetaMask*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 75,320 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank2} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* Coinbase Wallet*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 56,124 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank3} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* Bitski*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 99,123 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-5">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank4} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* WalletConnect*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 43,728 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
</ul>
|
||||
<div className="add-money-btn flex justify-center items-center mt-3">
|
||||
{/* <button
|
||||
onClick={() => {
|
||||
if(pathname == '/my-wallet') props.setBalanceDropdown.toggle()
|
||||
else navigate('/my-wallet', {replace: true})
|
||||
}}
|
||||
type="button"
|
||||
className="w-[122px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</button> */}
|
||||
<Link
|
||||
to="/my-wallet"
|
||||
onClick={onWalletClick}
|
||||
className="w-[122px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</Link>
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank1} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* MetaMask*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 75,320 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank2} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* Coinbase Wallet*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 56,124 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank3} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* Bitski*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 99,123 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
{/*<li className="content-item py-5">*/}
|
||||
{/* <div className="sm:flex justify-between items-center">*/}
|
||||
{/* <div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">*/}
|
||||
{/* <div*/}
|
||||
{/* className="icon w-14 h-14 transition duration-300 ease-in-out rounded-full flex justify-center items-center bg-light-purple dark:bg-dark-light-purple ">*/}
|
||||
{/* <img src={bank4} alt=""/>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="name">*/}
|
||||
{/* <p className="text-base text-dark-gray dark:text-white font-medium">*/}
|
||||
{/* WalletConnect*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div>*/}
|
||||
{/* <p className="eth text-xl font-bold text-purple">*/}
|
||||
{/* 43,728 ETH*/}
|
||||
{/* </p>*/}
|
||||
{/* <p className="usd text-base text-thin-light-gray text-right">*/}
|
||||
{/* (773.69 USD)*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</li>*/}
|
||||
</ul>
|
||||
<div className="add-money-btn flex justify-center items-center mt-3">
|
||||
{/* <button
|
||||
onClick={() => {
|
||||
if(pathname == '/my-wallet') props.setBalanceDropdown.toggle()
|
||||
else navigate('/my-wallet', {replace: true})
|
||||
}}
|
||||
type="button"
|
||||
className="w-[122px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</button> */}
|
||||
<Link
|
||||
to="/my-wallet"
|
||||
onClick={onWalletClick}
|
||||
className="w-[122px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*<div*/}
|
||||
{/* className="lg:hidden flex user-balance cursor-pointer lg:w-[252px] w-[150px] h-[48px] items-center rounded-full relative bg-purple">*/}
|
||||
{/* <div className="flex items-center lg:justify-between justify-center w-full h-full">*/}
|
||||
{/* <p className="lg:text-xl text-lg font-bold text-white">*/}
|
||||
{/* $ 234,435.34*/}
|
||||
{/* </p>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
:
|
||||
<div className="lg:flex hidden user-balance cursor-pointer lg:w-[152px] w-[150px] h-[48px] items-center rounded-full relative bg-sky-blue pr-1.5 pl-4">
|
||||
<div
|
||||
onClick={() => navigate("/family-wallet", { replace: true })}
|
||||
className="flex items-center lg:justify-between justify-center w-full h-full"
|
||||
>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="wallet" />
|
||||
</span>
|
||||
<p className="lg:text-xl text-lg font-bold text-white">Wallet</p>
|
||||
<span className="lg:block hidden">
|
||||
<Icons name="deep-plus" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="lg:hidden block"></div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -34,9 +34,7 @@ export default function WalletItemCard({ walletItem, payment, countries }) {
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
};
|
||||
|
||||
const currentWalletCurrency = countries
|
||||
// .map((country) => country)
|
||||
.filter((country) => country.code === walletItem.country);
|
||||
const currentWalletCurrency = countries?.filter((country) => country.code === walletItem.country);
|
||||
|
||||
const image = walletItem.code
|
||||
? `${walletItem.code.toLowerCase()}.svg`
|
||||
|
||||
@@ -4,7 +4,6 @@ import background from "../../assets/images/bg-sky-blue.jpg"; //shape/balance-bg
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
import { tableReload } from "../../store/TableReloads";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import CreditPopup from "./Popup/CreditPopup";
|
||||
import WalletAction from "./WalletAction";
|
||||
|
||||
/**
|
||||
@@ -13,30 +12,17 @@ import WalletAction from "./WalletAction";
|
||||
export default function WalletItemCardFamily({ walletItem, payment, countries }) {
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [creditPopup, setCreditPopup] = useState({ show: false, data: {} });
|
||||
|
||||
/**
|
||||
* Opens the credit popup.
|
||||
* @param {Object} value - The value object.
|
||||
*/
|
||||
const openPopUp = (value) => {
|
||||
setCreditPopup({
|
||||
show: true,
|
||||
data: { ...value },
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the credit popup and dispatches a table reload action.
|
||||
*/
|
||||
const closePopUp = () => {
|
||||
setCreditPopup({ show: false, data: {} });
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
};
|
||||
|
||||
const currentWalletCurrency = countries
|
||||
// .map((country) => country)
|
||||
.filter((country) => country.code === walletItem.country);
|
||||
const currentWalletCurrency = countries?.filter((country) => country.code === walletItem.country);
|
||||
|
||||
const image = walletItem.code
|
||||
? `${walletItem.code.toLowerCase()}.svg`
|
||||
@@ -45,10 +31,10 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="current-balance-widget w-full h-full rounded-2xl overflow-hidden flex flex-col items-center gap-2 p-8 justify-between"
|
||||
style={{
|
||||
background: `url(${background}) 0% 0% / cover no-repeat`,
|
||||
}}
|
||||
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={{
|
||||
// background: `url(${background}) 0% 0% / cover no-repeat`,
|
||||
// }}
|
||||
>
|
||||
<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">
|
||||
@@ -74,24 +60,7 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="my-2 w-full h-[1px] bg-white"></div>
|
||||
|
||||
{/* <WalletAction
|
||||
walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
|
||||
payment={payment}
|
||||
openPopUp={openPopUp}
|
||||
/> */}
|
||||
</div>
|
||||
|
||||
{creditPopup.show && (
|
||||
<CreditPopup
|
||||
details={creditPopup.data}
|
||||
walletItem={walletItem}
|
||||
onClose={closePopUp}
|
||||
situation={openPopUp}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import TimeDifference from "../Helpers/TimeDifference";
|
||||
const DEFAULT_PROFILE_IMAGE = require("../../assets/images/profile.jpg");
|
||||
|
||||
export default function Header({ logoutModalHandler, sidebarHandler }) {
|
||||
|
||||
const {userDetails: { account_type }} = useSelector((state) => state?.userDetails);
|
||||
|
||||
const [balanceDropdown, setbalanceValue] = useToggle(false);
|
||||
const [notificationDropdown, setNotificationValue] = useToggle(false);
|
||||
const [userProfileDropdown, setProfileDropdown] = useToggle(false);
|
||||
@@ -402,7 +405,7 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
|
||||
</li>
|
||||
)}
|
||||
<li className="content-item my-2 hover:bg-slate-100 transition duration-500 rounded-lg">
|
||||
<Link to="/my-wallet" className="notifications">
|
||||
<Link to={ account_type == "FULL" ? "/my-wallet" : "/family-wallet"} className="notifications">
|
||||
<div className="name">
|
||||
<p className="text-sm py-2 px-4 text-dark-gray dark:text-white hover:text-sky-blue transition font-medium">
|
||||
My Wallet
|
||||
|
||||
@@ -20,10 +20,7 @@ export default function Layout({ children }) {
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
const logOut = () => {
|
||||
localStorage.removeItem("session_token");
|
||||
localStorage.removeItem("member_id");
|
||||
localStorage.removeItem("uid");
|
||||
sessionStorage.removeItem("family_uid");
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
// toast.success("Come Back Soon", {
|
||||
// icon: `🙂`,
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import RecomendedSliders from "./RecomendedSliders";
|
||||
|
||||
export default function CommonHead({ className, commonHeadData }) {
|
||||
export default function CommonHead({ className = "", commonHeadData = [] }) {
|
||||
return (
|
||||
<div
|
||||
className={`create-nft w-full lg:h-[140px] shadow lg:flex rounded-lg justify-between items-center md:p-2 p-2 bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] -2 border-pink mb-10 ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
{commonHeadData?.length > 0 && (
|
||||
<RecomendedSliders bannerData={commonHeadData} />
|
||||
<>
|
||||
{process.env.REACT_APP_SHOW_SLIDER_BANNERS === "1" && (
|
||||
<div
|
||||
className={`create-nft w-full lg:h-[140px] shadow lg:flex rounded-lg justify-between items-center md:p-2 p-2 bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] -2 border-pink mb-10 ${className}`}
|
||||
>
|
||||
{commonHeadData?.length > 0 && (
|
||||
<RecomendedSliders bannerData={commonHeadData} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/*<div className="lg:w-8/12 w-full mb-8 lg:mb-0">*/}
|
||||
{/* /!*<h1 className="text-2xl text-dark-gray dark:text-white font-bold mb-2">*!/*/}
|
||||
{/* /!* This is common head which will appear as needed , will take many shape*!/*/}
|
||||
{/* /!*</h1>*!/*/}
|
||||
{/* /!*<p className="text-base text-thin-light-gray tracking-wide">*!/*/}
|
||||
{/* /!* some space for extra texts here*!/*/}
|
||||
{/* /!*</p>*!/*/}
|
||||
{/* */}
|
||||
{/*</div>*/}
|
||||
{/*<div className="flex-1 flex lg:justify-end">*/}
|
||||
{/* <div className="flex items-center space-x-5">*/}
|
||||
{/* <Link*/}
|
||||
{/* to="/mytask"*/}
|
||||
{/* className="w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"*/}
|
||||
{/* >*/}
|
||||
{/* View Task*/}
|
||||
{/* </Link>*/}
|
||||
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ const LoadedPage = ({reloader}) => {
|
||||
const { loading, data, error } = GetMyPageLoad(reloader);
|
||||
|
||||
return (
|
||||
<div className="w-full border border-gray-400 rounded-md p-4 flex flex-col h-72 gap-2 overflow-y-auto">
|
||||
<div className="w-full border border-gray-400 rounded-md p-4 flex flex-col h-72 gap-2 overflow-y-auto dark:text-white">
|
||||
{loading ? (
|
||||
<>
|
||||
<h1 className="text-xl font-bold tracking-wide">...</h1>
|
||||
|
||||
@@ -8,6 +8,7 @@ const YourPageForm = ({ values, onChange, onSubmit, loading, msg }) => (
|
||||
fieldClass="px-4"
|
||||
parentClass="flex items-center gap-1 justify-between"
|
||||
labelClass="flex-[0.2] mb-0 font-semibold"
|
||||
labalClass="dark:text-white"
|
||||
inputClass="flex-[0.8]"
|
||||
inputBg="bg-slate-100"
|
||||
label="Introduction: "
|
||||
@@ -24,7 +25,7 @@ const YourPageForm = ({ values, onChange, onSubmit, loading, msg }) => (
|
||||
</label>
|
||||
<textarea
|
||||
style={{ resize: "none" }}
|
||||
className="text-base px-4 py-2 rounded-md min-h-[100px] text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none flex-[0.8]"
|
||||
className="text-base px-4 py-2 rounded-[36px] min-h-[100px] text-dark-gray dark:text-white w-full bg-slate-100 focus:ring-0 focus:outline-none flex-[0.8]"
|
||||
name="description"
|
||||
cols="30"
|
||||
rows="2"
|
||||
|
||||
@@ -13,12 +13,39 @@ const YourPage = () => {
|
||||
const handleChange = ({ target: { name, value } }) =>
|
||||
setPageValues((prev) => ({ ...prev, [name]: value }));
|
||||
|
||||
const updateYourPageDetails = updateYourPage(
|
||||
pageValues,
|
||||
setResponse,
|
||||
setPageValues,
|
||||
setReloader
|
||||
);
|
||||
const updateYourPageDetails = async () => {
|
||||
if (!pageValues.intro || !pageValues.description) return;
|
||||
|
||||
try {
|
||||
setResponse({ loading: true, error: "", msg: "" });
|
||||
|
||||
let api = new usersService();
|
||||
const res = await api.MyPageIntro(pageValues);
|
||||
|
||||
setTimeout(() => {
|
||||
setResponse({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
msg: "Update Complete",
|
||||
});
|
||||
|
||||
setReloader((prev) => !prev);
|
||||
}, 1000);
|
||||
|
||||
setTimeout(() => {
|
||||
setResponse({ msg: "" });
|
||||
// Clear form after successful update
|
||||
setPageValues({ intro: "", description: "" });
|
||||
}, 3000);
|
||||
} catch (error) {
|
||||
return setResponse({
|
||||
loading: false,
|
||||
data: {},
|
||||
error: "Error updating page",
|
||||
msg: "",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
@@ -57,39 +84,3 @@ const responseInitialValues = {
|
||||
error: "",
|
||||
msg: "",
|
||||
};
|
||||
|
||||
function updateYourPage(pageValues, setResponse, setPageValues, setReloader) {
|
||||
return async () => {
|
||||
if (!pageValues.intro || !pageValues.description) return;
|
||||
|
||||
try {
|
||||
setResponse({ loading: true, error: "", msg: "" });
|
||||
|
||||
let api = new usersService();
|
||||
const res = await api.MyPageIntro(pageValues);
|
||||
|
||||
setTimeout(() => {
|
||||
setResponse({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
msg: "Update Complete",
|
||||
});
|
||||
|
||||
setReloader((prev) => !prev);
|
||||
}, 1000);
|
||||
|
||||
setTimeout(() => {
|
||||
setResponse({ msg: "" });
|
||||
// Clear form after successful update
|
||||
setPageValues({ intro: "", description: "" });
|
||||
}, 3000);
|
||||
} catch (error) {
|
||||
return setResponse({
|
||||
loading: false,
|
||||
data: {},
|
||||
error: "Error updating page",
|
||||
msg: "",
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import InputCom from "../Helpers/Inputs/InputCom/index";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import Detail from "./popoutcomponent/Detail";
|
||||
import { SocketValues } from "../Contexts/SocketIOContext";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
family: Yup.string().required("This is required "),
|
||||
@@ -29,6 +30,9 @@ function JobListPopout({
|
||||
openWallet,
|
||||
setWalletItem,
|
||||
}) {
|
||||
|
||||
let {marketUpdate} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState("public");
|
||||
const tabs = ["public", "individual", "group"];
|
||||
|
||||
@@ -201,7 +205,9 @@ function JobListPopout({
|
||||
setRequestStatus({ message: "", status: false });
|
||||
}, 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 });
|
||||
setTimeout(() => {
|
||||
setLoader({ jobFields: false });
|
||||
@@ -224,6 +230,12 @@ function JobListPopout({
|
||||
members: [],
|
||||
});
|
||||
|
||||
const DetailsSection = ({ label, value }) => (
|
||||
<div className="my-3 md:flex">
|
||||
<Detail label={label} value={value} />
|
||||
</div>
|
||||
);
|
||||
|
||||
// FUNCTION TO POPULATE USER GROUP LIST
|
||||
useEffect(() => {
|
||||
// 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 detailsArray = [
|
||||
{ label: "Description", value: details.description },
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react'
|
||||
function Detail({label, value, bg,}) {
|
||||
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>
|
||||
</>
|
||||
)
|
||||
|
||||
+7
-2
@@ -52,9 +52,8 @@
|
||||
}
|
||||
.job-action {
|
||||
background-color: #4687ba;
|
||||
height: 100px;
|
||||
border-radius: 15px;
|
||||
padding: 5px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.msg_box {
|
||||
@@ -153,6 +152,12 @@
|
||||
--toastify-color-success: #f539f8;
|
||||
}
|
||||
|
||||
@layer components{
|
||||
.job-label{
|
||||
@apply text-slate-900 dark:text-white tracking-wide font-semibold
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== EXTRA ===================== */
|
||||
.bottomMargin {
|
||||
margin-bottom: 15px;
|
||||
|
||||
@@ -13,8 +13,13 @@ import { updateUserJobList } from "../store/userJobList";
|
||||
import { updateWalletDetails } from "../store/walletDetails";
|
||||
import { familyBannersList } from "../store/FamilyBannerList";
|
||||
import { familyResources } from "../store/FamilyResources";
|
||||
import {familyWalletRedeemOptList} from '../store/FamilyWalletRedeemOpt'
|
||||
import { SocketValues } from "../components/Contexts/SocketIOContext";
|
||||
|
||||
const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
|
||||
let {joinRoom} = SocketValues() // destructures 'SEND MESSAGE' and 'JOIN ROOM' FUNCTIONS FROM SOCKET
|
||||
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
const dispatch = useDispatch();
|
||||
const [lastActivityTime, setLastActivityTime] = useState(Date.now());
|
||||
@@ -22,23 +27,20 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
const [loadProfileDetails, setLoadProfileDetails] = useState([]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { jobListTable, walletTable, familyBannersListTable } = useSelector(
|
||||
const { jobListTable, marketTableList, walletTable, familyBannersListTable } = useSelector(
|
||||
(state) => state.tableReload
|
||||
);
|
||||
|
||||
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
|
||||
|
||||
let loggedIn = username && session && uid ? true : false; // variable to determine if user is logged in
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
//Removing Data stored at localStorage after session expires
|
||||
const expireSession = () => {
|
||||
localStorage.removeItem("uid");
|
||||
localStorage.removeItem("member_id");
|
||||
localStorage.removeItem("session_token");
|
||||
sessionStorage.removeItem("family_uid");
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
navigate("/login", { replace: true }); // redirects user to login page after session expires
|
||||
};
|
||||
@@ -104,6 +106,8 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
});
|
||||
};
|
||||
loadProfile();
|
||||
}else{
|
||||
setIsLogin({ loading: false, status: true });
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -188,6 +192,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
}, [jobListTable, isLogin.status]);
|
||||
|
||||
useEffect(() => {
|
||||
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
|
||||
return
|
||||
}
|
||||
const getMyWalletList = async () => {
|
||||
dispatch(updateWalletDetails({ loading: true, data: [] }));
|
||||
try {
|
||||
@@ -202,7 +209,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
}
|
||||
};
|
||||
getMyWalletList();
|
||||
}, [walletTable]);
|
||||
}, [walletTable, isLogin.status]);
|
||||
|
||||
useEffect(() => {
|
||||
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();
|
||||
}, [apiCall, dispatch, jobListTable, isLogin.status]);
|
||||
}, [apiCall, dispatch, marketTableList, isLogin.status]);
|
||||
|
||||
//FUNCTION TO GET COMMON HEAD DATA
|
||||
useEffect(() => {
|
||||
@@ -228,7 +235,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
apiCall
|
||||
.getHeroJBanners()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 0) {
|
||||
if (res.data?.internal_return < 0) {
|
||||
return;
|
||||
}
|
||||
dispatch(commonHeadBanner(res.data));
|
||||
@@ -240,6 +247,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
|
||||
//FUNCTION TO GET COMMON HEAD DATA
|
||||
useEffect(() => {
|
||||
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
|
||||
return
|
||||
}
|
||||
apiCall
|
||||
.getRecentActivitiedData()
|
||||
.then((res) => {
|
||||
@@ -252,7 +262,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
.catch((error) => {
|
||||
console.log("ERROR ", error);
|
||||
});
|
||||
}, []);
|
||||
}, [isLogin.status]);
|
||||
|
||||
|
||||
//FUNCTION TO GET FAMILY BANNERS
|
||||
@@ -291,6 +301,34 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
|
||||
}, [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
|
||||
return isLogin.loading && !loggedIn ? (
|
||||
<LoadingSpinner size="32" color="sky-blue" height="h-screen" />
|
||||
|
||||
@@ -388,13 +388,26 @@ class usersService {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
action: apiConst.WRENCHBOARD_JOB_CREATEJOB,
|
||||
action: apiConst.WRENCHBOARD_JOB_CREATEJOB || apiConst.WRENCHBOARD_FAMILY_LIST,
|
||||
limit: 30,
|
||||
offset: 0,
|
||||
};
|
||||
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() {
|
||||
var postData = {
|
||||
uuid: localStorage.getItem("uid"),
|
||||
@@ -1292,6 +1305,19 @@ class usersService {
|
||||
};
|
||||
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)
|
||||
|
||||
@@ -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;
|
||||
@@ -9,6 +9,9 @@ const initialState = {
|
||||
walletTable: false,
|
||||
uploadsTable: false,
|
||||
familyBannersListTable: false,
|
||||
chatMessageList: false,
|
||||
marketTableList: false,
|
||||
familyOfferList: false,
|
||||
};
|
||||
|
||||
export const tableReloadSlice = createSlice({
|
||||
@@ -41,6 +44,15 @@ export const tableReloadSlice = createSlice({
|
||||
case "FAMILYBANNERSLIST":
|
||||
state.familyBannersListTable = !state.familyBannersListTable;
|
||||
return;
|
||||
case "CHATMESSAGELIST":
|
||||
state.chatMessageList = !state.chatMessageList;
|
||||
return;
|
||||
case "MARKETTABLELIST":
|
||||
state.marketTableList = !state.marketTableList;
|
||||
return;
|
||||
case "FAMILYOFFERLIST":
|
||||
state.familyOfferList = !state.familyOfferList;
|
||||
return;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
+3
-1
@@ -10,6 +10,7 @@ import userJobListReducer from "./userJobList";
|
||||
import walletDetails from "./walletDetails";
|
||||
import familyBannerListReducer from "./FamilyBannerList"
|
||||
import familyResourcesReducer from './FamilyResources'
|
||||
import familyWalletRedeemOptListReducer from './FamilyWalletRedeemOpt'
|
||||
|
||||
export default configureStore({
|
||||
reducer: {
|
||||
@@ -22,6 +23,7 @@ export default configureStore({
|
||||
notifications: notificationsReducer,
|
||||
walletDetails: walletDetails,
|
||||
familyBannersList: familyBannerListReducer,
|
||||
familyResources: familyResourcesReducer
|
||||
familyResources: familyResourcesReducer,
|
||||
familyWalletRedeemOptList: familyWalletRedeemOptListReducer
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import FamilyActivities from "../components/FamilyAcc/FamilyActivities";
|
||||
|
||||
const FamilyActivitiesPage = () => {
|
||||
return (
|
||||
<>
|
||||
<FamilyActivities />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FamilyActivitiesPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import FamilyWalletCon from "../components/MyWallet/FamilyWalletCon";
|
||||
|
||||
export default function FamilyWalletPage() {
|
||||
return <FamilyWalletCon />;
|
||||
}
|
||||
@@ -2,12 +2,17 @@ import React, { useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
|
||||
import usersService from "../services/UsersService";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
/**
|
||||
* This code defines a React functional component called `ManageActiveJobs`.
|
||||
* It fetches a list of active job messages and renders the `ActiveJobs` component with the necessary props.
|
||||
*/
|
||||
function ManageActiveJobs() {
|
||||
const { chatMessageList } = useSelector(
|
||||
(state) => state.tableReload
|
||||
);
|
||||
|
||||
const ApiCall = new usersService();
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -54,7 +59,7 @@ function ManageActiveJobs() {
|
||||
}
|
||||
setDetails(state);
|
||||
getActiveJobMesList();
|
||||
}, [activeJobMesListReload]);
|
||||
}, [activeJobMesListReload, chatMessageList]);
|
||||
|
||||
return (
|
||||
<ActiveJobs
|
||||
|
||||
@@ -23,6 +23,9 @@ module.exports = {
|
||||
screens:{
|
||||
xxs: '400px',
|
||||
xxl:'1900px'
|
||||
},
|
||||
backgroundImage: {
|
||||
'family-header-bg': "linear-gradient(90deg, rgba(45,126,241,1) 0%, rgba(58,143,195,1) 0%, rgba(11,100,119,1) 100%)",
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user