Compare commits

...

145 Commits

Author SHA1 Message Date
victorAnumudu 3d150f7a6b array length bug fixed 2024-03-01 15:18:20 +01:00
tokslaw bbd100d04e Merge branch 'resources-linking' of WrenchBoard/Users-Wrench into master 2024-03-01 00:35:21 +00:00
victorAnumudu fcb340007c linked family resources 2024-02-29 21:52:11 +01:00
ameye 95a10cf795 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-29 19:48:34 +00:00
Ebube 5b5a083987 Added Home Img on Home btn 2024-02-29 20:06:18 +01:00
ameye 1564f29a4c Merge branch 'family-home-offerlist' of WrenchBoard/Users-Wrench into master 2024-02-29 17:35:02 +00:00
ameye 2b73191741 Merge branch 'parent-waiting-page' of WrenchBoard/Users-Wrench into master 2024-02-29 17:34:57 +00:00
victorAnumudu fee5c20fe2 removed offerlist from family home page 2024-02-29 17:09:47 +01:00
victorAnumudu 2d2b184291 parent waiting page top brought to top 2024-02-29 16:40:13 +01:00
ameye 5abd3665d1 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-29 15:01:45 +00:00
Ebube a603a9eaff Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-02-29 15:54:35 +01:00
Ebube 5bd74b3ca4 Added new stuff 2024-02-29 15:54:11 +01:00
Ebube 60cc290004 reduced component 2024-02-29 13:05:44 +01:00
ameye 12f30ec1e8 Merge branch 'banner-pages' of WrenchBoard/Users-Wrench into master 2024-02-29 11:46:56 +00:00
victorAnumudu 2521fbc1d8 more pages created for family banner links 2024-02-29 12:38:35 +01:00
ameye 29812e9265 Merge branch 'family-banner-linking' of WrenchBoard/Users-Wrench into master 2024-02-29 09:35:47 +00:00
victorAnumudu 271180932c linked banner to page 2024-02-29 10:32:27 +01:00
ameye 0a2e291013 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-28 18:00:00 +00:00
ameye 8be09a9f9f Merge branch 'parent-waiting' of WrenchBoard/Users-Wrench into master 2024-02-28 17:59:53 +00:00
Ebube 78aa4fe58b Added padding 2024-02-28 18:38:52 +01:00
victorAnumudu 154ea29504 added parent waiting page 2024-02-28 18:38:19 +01:00
ameye 4f670fa3ba Merge branch 'resources-banner-fix' of WrenchBoard/Users-Wrench into master 2024-02-28 16:49:51 +00:00
victorAnumudu 8d48435705 reduced family resources banner 2024-02-28 17:40:32 +01:00
ameye 76109dc458 Merge branch 'implemented-breadcrumb' of WrenchBoard/Users-Wrench into master 2024-02-28 16:00:09 +00:00
victorAnumudu 05a7b3ec12 added breadcrumb to my task page 2024-02-28 16:54:54 +01:00
ameye 0a3805ddf8 Merge branch 'family-banner-fix' of WrenchBoard/Users-Wrench into master 2024-02-28 15:20:57 +00:00
victorAnumudu 059fdaf294 family banner img height reduced 2024-02-28 15:48:59 +01:00
ameye 353c372284 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-28 11:18:52 +00:00
ameye 26e5248a0f Merge branch 'family-button-reduction' of WrenchBoard/Users-Wrench into master 2024-02-28 11:18:47 +00:00
ameye ae6a677b25 Merge branch 'market-date-format' of WrenchBoard/Users-Wrench into master 2024-02-28 11:18:43 +00:00
Ebube cab5debfb7 Added icon toggler 2024-02-28 11:41:17 +01:00
Ebube c4c1bf6ca1 added dark mode feature to right sidebar 2024-02-28 11:20:29 +01:00
Ebube fc2a78dde7 changed the background 2024-02-28 11:05:58 +01:00
victorAnumudu 1249685c41 reduced family banner button 2024-02-28 10:26:13 +01:00
victorAnumudu 3c422d9036 formatted date style 2024-02-28 10:08:26 +01:00
Ebube 264511dfb2 adjusted home dash sizes 2024-02-28 08:30:43 +01:00
Ebube d8c5b3ff07 home_dash board sizing 2024-02-28 07:49:57 +01:00
Ebube 624f97df8d Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-02-28 07:48:31 +01:00
Ebube 4dfb442a80 responsiveness check 2024-02-28 07:47:23 +01:00
ameye 50f675e82b Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-28 04:52:03 +00:00
CHIEFSOFT\ameye a0584a26fe show new dash 2024-02-27 20:50:54 -05:00
Ebube 0d3025c4d0 Reduced fonts 2024-02-27 21:47:10 +01:00
ameye ed24fea513 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-27 19:57:44 +00:00
ameye e6d83be4d9 Merge branch 'job-link-hidden' of WrenchBoard/Users-Wrench into master 2024-02-27 19:57:38 +00:00
Ebube 36e3154933 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-02-27 19:36:19 +01:00
Ebube 5d59ff1b30 Reduced component height 2024-02-27 19:35:53 +01:00
victorAnumudu 33832fdd96 made quick job link hidden in family account 2024-02-27 18:57:16 +01:00
ameye 9f02395214 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-27 17:38:03 +00:00
ameye 9cc88eebf6 Merge branch 'family-resources' of WrenchBoard/Users-Wrench into master 2024-02-27 17:37:45 +00:00
Ebube 2390670d8c added top banner 2024-02-27 18:35:49 +01:00
victorAnumudu d908b1e10e added family resources API 2024-02-27 18:10:54 +01:00
ameye d91a3bf9f0 Merge branch 'banner-match' of WrenchBoard/Users-Wrench into master 2024-02-27 12:39:53 +00:00
victorAnumudu 880c223834 matched the image height in family banner to full member banner 2024-02-27 13:27:32 +01:00
ameye e7bf07d09e Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-27 10:47:10 +00:00
ameye e1de701ea6 Merge branch 'family-header' of WrenchBoard/Users-Wrench into master 2024-02-27 10:47:03 +00:00
Ebube 3403210fe8 Populated the lower component 2024-02-27 11:36:53 +01:00
victorAnumudu 03a897829c changed family header bg color 2024-02-27 10:24:23 +01:00
victorAnumudu d884b2a43d added header on family home page 2024-02-27 10:15:13 +01:00
ameye 3b86c6cd0e Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-26 23:43:47 +00:00
Ebube 2b5de9c95f Added the first 3 banners 2024-02-27 00:39:51 +01:00
ameye 3a8a980660 Merge branch 'banner-api-caching' of WrenchBoard/Users-Wrench into master 2024-02-26 17:26:16 +00:00
victorAnumudu 06186b3c0f cache banner API using redux 2024-02-26 18:07:58 +01:00
ameye bddbe6ceb4 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-26 15:46:14 +00:00
Ebube dd802ab22e increase size of dots 2024-02-26 16:38:57 +01:00
Ebube 8c363765ae Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-02-26 16:34:58 +01:00
Ebube f597c207fa Banner Area Layout 2024-02-26 16:34:08 +01:00
ameye dc07cff959 Merge branch 'asidebar-link' of WrenchBoard/Users-Wrench into master 2024-02-26 14:35:12 +00:00
victorAnumudu 38766c9cb7 changed Dashboard aside link name to Home 2024-02-26 15:30:30 +01:00
ameye fc04855d3f Merge branch 'banner-card' of WrenchBoard/Users-Wrench into master 2024-02-26 13:17:11 +00:00
victorAnumudu 56cb956482 adjusted banner card design 2024-02-26 14:07:15 +01:00
ameye 2f5abc8931 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-26 10:39:34 +00:00
ameye 026dbb1a0a Merge branch 'family-banner-bug' of WrenchBoard/Users-Wrench into master 2024-02-26 10:39:23 +00:00
Ebube efd464ba8a Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into home-banners-dashboard 2024-02-26 02:49:58 +01:00
Ebube 8c400c7ce1 fixed market bug, fixed key issue and added texts fork the cards 2024-02-26 02:49:35 +01:00
victorAnumudu d3d2b3cb5a changed to three cards banner 2024-02-26 02:40:25 +01:00
victorAnumudu 3054a5eb9a remove unused API from family login 2024-02-26 01:55:52 +01:00
Ebube 670f4bbf1a Added color to component and toggler to the env 2024-02-26 00:12:29 +01:00
ameye ae73f10c42 Merge branch 'family-banners' of WrenchBoard/Users-Wrench into master 2024-02-25 22:14:19 +00:00
victorAnumudu de477f32ed added banner to family dashboard banner list 2024-02-25 21:16:38 +01:00
ameye 2c6e36aea9 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-23 20:12:12 +00:00
ameye dc3aa1470e Merge branch 'family_new_dashboard' of WrenchBoard/Users-Wrench into master 2024-02-23 20:12:07 +00:00
victorAnumudu 9029953432 added familybanners API 2024-02-23 17:29:18 +01:00
Ebube fa47de7292 Added empty component to the dashboard 2024-02-23 17:19:41 +01:00
victorAnumudu d0a2b804b9 configured family new dashboard to show only on dev 2024-02-23 16:27:17 +01:00
victorAnumudu aa48529dca configured family new dashboard to show only on dev 2024-02-23 16:15:46 +01:00
ameye ad2745dfce Merge branch 'section-addition' of WrenchBoard/Users-Wrench into master 2024-02-19 17:37:50 +00:00
victorAnumudu b6ab3a6ee7 added new section to family acct dashboard 2024-02-19 14:09:20 +01:00
ameye f968cc5a50 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-17 16:41:08 +00:00
Ebube 1ddb2fd903 remove mypage component from family 2024-02-17 16:27:09 +01:00
ameye 70f6ac4e24 Merge branch 'failedtopup-alert' of WrenchBoard/Users-Wrench into master 2024-02-15 18:50:06 +00:00
victorAnumudu 3d30481852 displays failed popout box for failed top up transaction 2024-02-15 13:49:05 +01:00
ameye 63c0b07f61 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-03 23:31:58 +00:00
ameye 60568c42e8 Merge branch 'number-fix' of WrenchBoard/Users-Wrench into master 2024-02-03 23:31:51 +00:00
Ebube 77ac52820d added the email and offed the autocomplete attr for the component 2024-02-04 00:29:09 +01:00
victorAnumudu 240e075305 assign offer message updated 2024-02-03 22:49:15 +01:00
victorAnumudu bea41d8181 group count fixed 2024-02-03 22:09:25 +01:00
ameye 6268d68b67 Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-02-03 20:31:19 +00:00
Ebube f96b16b373 Added the number identifier for job list 2024-02-03 21:18:49 +01:00
ameye 9fb6a4db86 Merge branch 'download-app-links' of WrenchBoard/Users-Wrench into master 2024-02-02 11:26:36 +00:00
victorAnumudu 1aa3c79666 added download app links to signup page 2024-02-02 09:42:51 +01:00
ameye ecc2360dc4 Merge branch 'app-download-link' of WrenchBoard/Users-Wrench into master 2024-02-01 20:49:27 +00:00
victorAnumudu ca9bb1c211 changed class to classname 2024-02-01 19:43:36 +01:00
victorAnumudu 2f756d189a added app download links on login page 2024-02-01 19:34:01 +01:00
ameye d7acea769c Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-01-30 17:58:31 +00:00
Ebube 7ff5e2b6e0 . 2024-01-30 17:10:39 +01:00
Ebube 2f90c4a6c2 Different dashboards for Home Banner 2024-01-30 17:10:30 +01:00
ameye 29e0345e1c Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-27 00:26:56 +00:00
Ebube 129cdc8cba Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into Jobs-Manager-Side 2024-01-26 19:17:58 +01:00
Ebube 9d42ebebab added sidebar menu 2024-01-26 19:17:28 +01:00
ameye 6193f0b492 Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-26 18:03:56 +00:00
Ebube 1d86465812 Changed my pending jobs to offers and changed its routes 2024-01-26 17:44:24 +01:00
CHIEFSOFT\ameye 7a6f43ad20 Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench 2024-01-26 10:31:56 -05:00
CHIEFSOFT\ameye 37b94a68ca new layout 2024-01-26 10:31:45 -05:00
ameye a1b63c5d0c Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-26 14:49:22 +00:00
Ebube e5162a2aaf refactored some things 2024-01-26 01:46:56 +01:00
Ebube 6ee9c7e7d8 added .toFixed(2)} 2024-01-26 01:08:07 +01:00
Ebube 5928ddb3c1 added the popup component 2024-01-26 01:07:20 +01:00
ameye 06c1e339b1 Merge branch 'login-box-fix' of WrenchBoard/Users-Wrench into master 2024-01-25 22:18:49 +00:00
victorAnumudu 29cec58122 login box adjustment 2024-01-25 21:54:31 +01:00
ameye d258158a13 Merge branch 'bg-change' of WrenchBoard/Users-Wrench into master 2024-01-25 18:01:41 +00:00
victorAnumudu 1c47fa283a Merge branch 'master' into bg-change 2024-01-25 18:57:08 +01:00
victorAnumudu d1b07e6e66 added background based on country 2024-01-25 18:55:51 +01:00
ameye 648f228e45 Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-25 15:50:17 +00:00
Ebube 551a302ede added the amount checker 2024-01-25 16:39:13 +01:00
ameye 108c82b2f8 Merge branch 'family-type' of WrenchBoard/Users-Wrench into master 2024-01-25 12:44:16 +00:00
victorAnumudu f46713ef00 Merge branch 'master' into family-type 2024-01-25 08:17:59 +01:00
victorAnumudu 992993b710 family type dropdown added 2024-01-25 08:16:55 +01:00
ameye 617df4200e Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-24 21:57:28 +00:00
Ebube a47e398e87 Added background color to the group list component 2024-01-24 20:41:25 +01:00
ameye 281c4c7ab7 Merge branch 'relative-list' of WrenchBoard/Users-Wrench into master 2024-01-24 13:12:48 +00:00
victorAnumudu 3c901e5d0d fixed relative list 2024-01-24 13:43:12 +01:00
ameye 3bcbaae4c3 Merge branch 'add-relative' of WrenchBoard/Users-Wrench into master 2024-01-24 12:19:30 +00:00
ameye 17e972d603 Merge branch 'Jobs-Manager-Side' of WrenchBoard/Users-Wrench into master 2024-01-24 12:19:23 +00:00
victorAnumudu dbc821a804 added relative list 2024-01-24 10:12:06 +01:00
Ebube 0e4b1af1ce Jobs Manager Side task done 2024-01-24 01:11:49 +01:00
CHIEFSOFT\ameye ec88f304ab remove grp icon 2024-01-23 08:20:35 -05:00
ameye 8d795a29b4 Merge branch 'actions-variables' of WrenchBoard/Users-Wrench into master 2024-01-23 12:24:14 +00:00
ameye da12f5905c Merge branch 'link-icons' of WrenchBoard/Users-Wrench into master 2024-01-23 12:24:09 +00:00
victorAnumudu 99d4301588 added link icons 2024-01-23 10:32:29 +01:00
Ebube 8139fbb090 added third 2024-01-23 09:33:56 +01:00
Ebube 926837c656 added second batch 2024-01-23 09:00:30 +01:00
Ebube 14c894da6c first batch 2024-01-23 07:33:57 +01:00
CHIEFSOFT\ameye dbdc028ed4 api const 2024-01-22 11:49:49 -05:00
CHIEFSOFT\ameye c3a5a2fe34 left image 2024-01-18 11:31:35 -05:00
ameye eed2e62f62 Merge branch 'new-layout' of WrenchBoard/Users-Wrench into master 2024-01-18 14:34:53 +00:00
110 changed files with 4795 additions and 2244 deletions
+11 -1
View File
@@ -98,4 +98,14 @@ REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
#CHANGE LOGIN LAYOUT
REACT_APP_NEW_LOGIN_LAYOUT=1
REACT_APP_NEW_LOGIN_LAYOUT=1
#APP DOWNLOAD LINKS
REACT_APP_ANDROID_APP='https://play.google.com/store/apps/details?id=com.wrenchboard.users'
REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls=1&mt=8'
# Displays the new family dashboard with boxes
REACT_APP_SHOW_NEW_FAMILY_DASH=1
# Displays the account dashboard
REACT_APP_SHOW_ACCOUNT_DASH=1
+11 -1
View File
@@ -66,4 +66,14 @@ REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
#CHANGE LOGIN LAYOUT
REACT_APP_NEW_LOGIN_LAYOUT=1
REACT_APP_NEW_LOGIN_LAYOUT=1
#APP DOWNLOAD LINKS
REACT_APP_ANDROID_APP='https://play.google.com/store/apps/details?id=com.wrenchboard.users'
REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls=1&mt=8'
# Displays the new family dashboard with boxes
REACT_APP_SHOW_NEW_FAMILY_DASH=1
# Displays the account dashboard
REACT_APP_SHOW_ACCOUNT_DASH=1
+11 -1
View File
@@ -72,4 +72,14 @@ REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
#CHANGE LOGIN LAYOUT
REACT_APP_NEW_LOGIN_LAYOUT=0
REACT_APP_NEW_LOGIN_LAYOUT=1
#APP DOWNLOAD LINKS
REACT_APP_ANDROID_APP='https://play.google.com/store/apps/details?id=com.wrenchboard.users'
REACT_APP_APPLE_APP='https://itunes.apple.com/us/app/wrenchboard/id1435718367?ls=1&mt=8'
# Displays the new family dashboard with boxes
REACT_APP_SHOW_NEW_FAMILY_DASH=1
# Displays the account dashboard
REACT_APP_SHOW_ACCOUNT_DASH=1
+3
View File
@@ -17,6 +17,9 @@
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>WrenchBoard</title>
<!-- FONT AWESOME -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.5.1/css/all.css"/>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
+16 -16
View File
@@ -1,22 +1,22 @@
import Toaster from "./components/Helpers/Toaster";
import Routers from "./Routers";
import Default from "./components/Partials/Default";
import { Navigate, useLocation } from "react-router-dom";
import Routers from "./Routers";
import Toaster from "./components/Helpers/Toaster";
import Default from "./components/Partials/Default";
function App() {
const {pathname} = useLocation()
return (
<Default>
<>
{pathname.startsWith('/@') ?
<Navigate to="/app" replace={true} />
:
<Routers />
}
<Toaster />
</>
</Default>
);
const { pathname } = useLocation();
return (
<Default>
<>
{pathname.startsWith("/@") ? (
<Navigate to="/app" replace={true} />
) : (
<Routers />
)}
<Toaster />
</>
</Default>
);
}
export default App;
+117 -76
View File
@@ -1,97 +1,112 @@
import { Route, Routes } from "react-router-dom";
import FourZeroFour from "./components/FourZeroFour";
import ScrollToTop from "./components/Helpers/ScrollToTop";
import MyCollection from "./components/MyCollection";
import StartJob from "./components/MyJobs/StartJob";
import Notification from "./components/Notification";
import AuthRoute from "./middleware/AuthRoute";
import AcitveBidsPage from "./views/AcitveBidsPage";
import AppDownloadPage from "./views/AppDownloadPage";
import AppleRedirectPage from "./views/AppleRedirectPage";
import AuthProfilePage from "./views/AuthProfilePage";
import AuthRedirect from "./views/AuthRedirect";
import BlogPage from "./views/BlogPage";
import CalendarPage from "./views/CalendarPage";
import CollectionItemPage from "./views/CollectionItemPage";
import FacebookRedirect from "./views/FacebookRedirect";
import FamilyAccPage from "./views/FamilyAccPage";
import FamilyManagePage from "./views/FamilyManagePage";
import FamilyMarketPage from "./views/FamilyMarketPage";
import FamilySettingsPage from "./views/FamilySettingsPage";
import ForgotPasswordPages from "./views/ForgotPasswordPages";
import ForgotPasswordPagesTwo from "./views/ForgotPasswordPagesTwo";
import HistoryPage from "./views/HistoryPage";
import HomePages from "./views/HomePages";
import JobGroupsPage from "./views/JobGroupsPage";
import LndPage from "./views/LndPage";
import LoginPage from "./views/LoginPage";
import LoginPageTwo from "./views/LoginPageTwo";
import ManageActiveJobs from "./views/ManageActiveJobs";
import ManageInterestOfferPage from "./views/ManageInterestOfferPage";
import MarketPlacePage from "./views/MarketPlacePage";
import MyActiveJobsPage from "./views/MyActiveJobsPage";
import MyCouponPage from "./views/MyCouponPage";
import MyJobsPage from "./views/MyJobsPage";
import MyOffersPage from "./views/MyOffersPage";
import MyPastDueJobsPage from "./views/MyPastDueJobsPage";
import MyReviewDueJobsPage from "./views/MyReviewDueJobsPage";
import MyTaskPage from "./views/MyTaskPage";
import MyWaitingJobsPage from "./views/MyWaitingJobsPage";
import MyWalletPage from "./views/MyWalletPage";
import OffersInterestPage from "./views/OffersInterestPage";
import ReferralPage from "./views/ReferralPage";
import RemindersPage from "./views/RemindersPage";
import ResourcePage from "./views/ResourcePage";
import SavedPage from "./views/SavedPage";
import SellPage from "./views/SellPage";
import SettingsPage from "./views/SettingsPage";
import ShopDetailsPage from "./views/ShopDetailsPage";
import SignupPage from "./views/SignupPage";
import SignupPageTwo from "./views/SignupPageTwo";
import TrackingPage from "./views/TrackingPage";
import UpdatePasswordPages from "./views/UpdatePasswordPages";
import UpdatePasswordPagesTwo from "./views/UpdatePasswordPagesTwo";
import UploadProductPage from "./views/UploadProductPage";
import UserProfilePage from "./views/UserProfilePage";
import VerifyYouPages from "./views/VerifyYouPages";
import VerifyYouPagesTwo from "./views/VerifyYouPagesTwo";
import VerifyPasswordPages from "./views/VerifyPasswordPages";
import VerifyPasswordPagesTwo from "./views/VerifyPasswordPagesTwo";
import RemindersPage from './views/RemindersPage';
import TrackingPage from "./views/TrackingPage";
import CalendarPage from "./views/CalendarPage";
import ResourcePage from "./views/ResourcePage";
import MyTaskPage from "./views/MyTaskPage";
import MyJobsPage from "./views/MyJobsPage";
import ReferralPage from "./views/ReferralPage";
import VerifyLinkPages from "./views/VerifyLinkPages";
import VerifyLinkPagesTwo from "./views/VerifyLinkPagesTwo";
import MyActiveJobsPage from "./views/MyActiveJobsPage";
import FamilyAccPage from "./views/FamilyAccPage";
import StartJob from "./components/MyJobs/StartJob";
import AddJobPage from "./views/AddJobPage";
import MyPendingJobsPage from "./views/MyPendingJobsPage";
import ManageActiveJobs from "./views/ManageActiveJobs";
import FamilyManagePage from "./views/FamilyManagePage";
import MyCouponPage from "./views/MyCouponPage";
import AuthRedirect from "./views/AuthRedirect";
import MyPastDueJobsPage from "./views/MyPastDueJobsPage";
import BlogPage from "./views/BlogPage";
import MyReviewDueJobsPage from "./views/MyReviewDueJobsPage";
import OffersInterestPage from "./views/OffersInterestPage";
import ManageInterestOfferPage from './views/ManageInterestOfferPage'
import MyWaitingJobsPage from "./views/MyWaitingJobsPage";
import FamilyMarketPage from "./views/FamilyMarketPage";
import FacebookRedirect from "./views/FacebookRedirect";
import AppleRedirectPage from "./views/AppleRedirectPage";
import LndPage from "./views/LndPage";
import FamilySettingsPage from "./views/FamilySettingsPage";
import AppDownloadPage from "./views/AppDownloadPage";
import JobGroupsPage from "./views/JobGroupsPage";
import VerifyPasswordPages from "./views/VerifyPasswordPages";
import VerifyPasswordPagesTwo from "./views/VerifyPasswordPagesTwo";
import VerifyYouPages from "./views/VerifyYouPages";
import VerifyYouPagesTwo from "./views/VerifyYouPagesTwo";
import YourPages from "./views/YourPage_";
import ParentWaitingPage from "./views/ParentWaitingPage";
import FamilyPendingOfferPage from "./views/FamilyPendingOfferPage";
import FamilyPastDuePage from "./views/FamilyPastDuePage";
export default function Routers() {
return (
<ScrollToTop>
<Routes>
{/* guest routes */}
{process.env.REACT_APP_NEW_LOGIN_LAYOUT == 1 ?
<>
<Route exact path="/login" element={<LoginPageTwo />} />
<Route exact path="/signup" element={<SignupPageTwo />} />
<Route exact path="/forgot-password" element={<ForgotPasswordPagesTwo />} />
<Route exact path="/update-password" element={<UpdatePasswordPagesTwo />} />
<Route path="/vemail" element={<VerifyLinkPagesTwo />} />
<Route path="/complereset" element={<VerifyPasswordPagesTwo />} />
<Route exact path="/outmessage" element={<VerifyYouPagesTwo />} />
<Route exact path="/eoffer" element={<LoginPageTwo />} />
<Route exact path="/invite" element={<LoginPageTwo />} />
</>
:
<>
<Route exact path="/login" element={<LoginPage />} />
<Route exact path="/signup" element={<SignupPage />} />
<Route exact path="/forgot-password" element={<ForgotPasswordPages />} />
<Route exact path="/update-password" element={<UpdatePasswordPages />} />
<Route path="/vemail" element={<VerifyLinkPages />} />
<Route path="/complereset" element={<VerifyPasswordPages />} />
<Route exact path="/outmessage" element={<VerifyYouPages />} />
<Route exact path="/eoffer" element={<LoginPage />} />
<Route exact path="/invite" element={<LoginPage />} />
</>
}
{process.env.REACT_APP_NEW_LOGIN_LAYOUT == 1 ? (
<>
<Route exact path="/login" element={<LoginPageTwo />} />
<Route exact path="/signup" element={<SignupPageTwo />} />
<Route
exact
path="/forgot-password"
element={<ForgotPasswordPagesTwo />}
/>
<Route
exact
path="/update-password"
element={<UpdatePasswordPagesTwo />}
/>
<Route path="/vemail" element={<VerifyLinkPagesTwo />} />
<Route path="/complereset" element={<VerifyPasswordPagesTwo />} />
<Route exact path="/outmessage" element={<VerifyYouPagesTwo />} />
<Route exact path="/eoffer" element={<LoginPageTwo />} />
<Route exact path="/invite" element={<LoginPageTwo />} />
</>
) : (
<>
<Route exact path="/login" element={<LoginPage />} />
<Route exact path="/signup" element={<SignupPage />} />
<Route
exact
path="/forgot-password"
element={<ForgotPasswordPages />}
/>
<Route
exact
path="/update-password"
element={<UpdatePasswordPages />}
/>
<Route path="/vemail" element={<VerifyLinkPages />} />
<Route path="/complereset" element={<VerifyPasswordPages />} />
<Route exact path="/outmessage" element={<VerifyYouPages />} />
<Route exact path="/eoffer" element={<LoginPage />} />
<Route exact path="/invite" element={<LoginPage />} />
</>
)}
<Route exact path="/login/auth" element={<AuthRedirect />} />
<Route exact path="/login/auth/flogin" element={<FacebookRedirect />} />
<Route exact path="/login/auth/apple" element={<AppleRedirectPage />} />
@@ -117,25 +132,51 @@ export default function Routers() {
<Route exact path="/market-place" element={<MarketPlacePage />} />
<Route exact path="/market" element={<MarketPlacePage />} />
<Route exact path="/familymarket" element={<FamilyMarketPage />} />
<Route exact path="/familysettings" element={<FamilySettingsPage />} />
<Route exact path="/suggested" element={<ParentWaitingPage />} />
<Route exact path="/pastdue" element={<FamilyPastDuePage />} />
<Route exact path="/pending" element={<FamilyPendingOfferPage />} />
<Route
exact
path="/familysettings"
element={<FamilySettingsPage />}
/>
<Route exact path="/notification" element={<Notification />} />
<Route exact path="/mytask" element={<MyTaskPage />} />
<Route exact path="/myjobs" element={<MyJobsPage />} />
{/* <Route exact path="/add-job" element={<AddJobPage />} /> */}
<Route exact path="/my-active-jobs" element={<MyActiveJobsPage />} />
<Route exact path="/my-pastdue-jobs" element={<MyPastDueJobsPage />} />
<Route exact path="/my-pending-jobs" element={<MyPendingJobsPage />} />
<Route exact path="/pend-interest" element={<MyWaitingJobsPage />} />
<Route exact path="/my-review-jobs" element={<MyReviewDueJobsPage />} />
<Route exact path="/acc-family" element={<FamilyAccPage />} />
<Route exact path="/manage-family" element={<FamilyManagePage />} />
<Route exact path="/start-job" element={<StartJob />} />
<Route exact path="/yourpage" element={<YourPages />} />
<Route exact path="/manage-active-job" element={<ManageActiveJobs />} />
<Route exact path="/blog-page" element={<BlogPage />} />
<Route exact path="/offer-interest" element={<OffersInterestPage />} />
<Route exact path="/manage-offer" element={<ManageInterestOfferPage />} />
<Route exact path="/my-active-jobs" element={<MyActiveJobsPage />} />
<Route
exact
path="/my-pastdue-jobs"
element={<MyPastDueJobsPage />}
/>
<Route exact path="/my-offers" element={<MyOffersPage />} />
<Route exact path="/pend-interest" element={<MyWaitingJobsPage />} />
<Route
exact
path="/my-review-jobs"
element={<MyReviewDueJobsPage />}
/>
<Route exact path="/acc-family" element={<FamilyAccPage />} />
<Route exact path="/manage-family" element={<FamilyManagePage />} />
<Route exact path="/start-job" element={<StartJob />} />
<Route exact path="/yourpage" element={<YourPages />} />
<Route
exact
path="/manage-active-job"
element={<ManageActiveJobs />}
/>
<Route exact path="/blog-page" element={<BlogPage />} />
<Route
exact
path="/offer-interest"
element={<OffersInterestPage />}
/>
<Route
exact
path="/manage-offer"
element={<ManageInterestOfferPage />}
/>
<Route
exact
@@ -1,4 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 0H2.5C1.12125 0 0 1.12125 0 2.5V17.5C0 18.8787 1.12125 20 2.5 20H17.5C18.8787 20 20 18.8787 20 17.5V2.5C20 1.12125 18.8787 0 17.5 0Z" fill="#1976D2"/>
<path d="M16.875 10H13.75V7.5C13.75 6.81 14.31 6.875 15 6.875H16.25V3.75H13.75C11.6788 3.75 10 5.42875 10 7.5V10H7.5V13.125H10V20H13.75V13.125H15.625L16.875 10Z" fill="#FAFAFA"/>
</svg>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 0H2.5C1.12125 0 0 1.12125 0 2.5V17.5C0 18.8787 1.12125 20 2.5 20H17.5C18.8787 20 20 18.8787 20 17.5V2.5C20 1.12125 18.8787 0 17.5 0Z" fill="#1976D2"/>
<path d="M16.875 10H13.75V7.5C13.75 6.81 14.31 6.875 15 6.875H16.25V3.75H13.75C11.6788 3.75 10 5.42875 10 7.5V10H7.5V13.125H10V20H13.75V13.125H15.625L16.875 10Z" fill="#FAFAFA"/>
</svg>

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 448 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 32 28" viewBox="0 0 32 28" id="List"><circle cx="2" cy="2" r="2" fill="#767fad" class="color4e4e50 svgShape"></circle><path fill="#767fad" d="M8 0h24v4H8z" class="color4e4e50 svgShape"></path><circle cx="10" cy="10" r="2" fill="#767fad" class="color4e4e50 svgShape"></circle><path fill="#767fad" d="M16 8h16v4H16z" class="color4e4e50 svgShape"></path><circle cx="10" cy="26" r="2" fill="#767fad" class="color4e4e50 svgShape"></circle><path fill="#767fad" d="M16 24h16v4H16z" class="color4e4e50 svgShape"></path><circle cx="18" cy="18" r="2" fill="#767fad" class="color4e4e50 svgShape"></circle><path fill="#767fad" d="M24 16h8v4h-8z" class="color4e4e50 svgShape"></path></svg>

After

Width:  |  Height:  |  Size: 743 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="Group" x="0" y="0" version="1.1" viewBox="0 0 52 52" xml:space="preserve"><path d="M26.003 13.05c2.44 0 4.43-1.99 4.43-4.43a4.44 4.44 0 0 0-4.43-4.44c-2.45 0-4.44 1.99-4.44 4.44a4.44 4.44 0 0 0 4.44 4.43zM11.293 38.77c2.44 0 4.43-1.99 4.43-4.43a4.44 4.44 0 0 0-4.43-4.44c-2.45 0-4.43 1.99-4.43 4.44 0 2.44 1.98 4.43 4.43 4.43z" fill="#4687ba" class="color000000 svgShape"></path><path d="M49.493 41.93a10.091 10.091 0 0 0-3.643-3.739 6.418 6.418 0 0 1-5.138 2.58 6.392 6.392 0 0 1-4.371-1.737.975.975 0 0 0-.158-.258l-9.184-9.903V22.1h4.344c1.41 0 2.68-.73 3.4-1.94.72-1.23.73-2.7.04-3.95a10.09 10.09 0 0 0-3.643-3.739 6.418 6.418 0 0 1-5.138 2.579 6.43 6.43 0 0 1-5.144-2.58 10.085 10.085 0 0 0-3.645 3.74c-.69 1.25-.67 2.72.05 3.95a3.9 3.9 0 0 0 3.39 1.94h4.346v6.624c-.01.022-.016.044-.025.066l-9.22 9.941a.978.978 0 0 0-.22.42 6.378 6.378 0 0 1-4.242 1.62 6.417 6.417 0 0 1-5.14-2.584 10.086 10.086 0 0 0-3.65 3.743c-.69 1.25-.67 2.72.05 3.95a3.9 3.9 0 0 0 3.39 1.94h10.69c1.41 0 2.68-.73 3.4-1.94.72-1.23.73-2.7.04-3.95a10.03 10.03 0 0 0-2.134-2.612l8.01-8.636 8.055 8.685c-.815.73-1.53 1.58-2.08 2.563-.69 1.25-.67 2.72.05 3.95a3.9 3.9 0 0 0 3.39 1.94h10.69c1.41 0 2.68-.73 3.4-1.94.72-1.23.73-2.7.04-3.95z" fill="#4687ba" class="color000000 svgShape"></path><path d="M40.713 38.77c2.44 0 4.43-1.99 4.43-4.43a4.44 4.44 0 0 0-4.43-4.44c-2.45 0-4.44 1.99-4.44 4.44a4.44 4.44 0 0 0 4.44 4.43z" fill="#4687ba" class="color000000 svgShape"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" id="List"><switch><g fill="#767fad" class="color000000 svgShape"><g fill="#4687ba" class="color0ac5ab svgShape"><path d="M20 0H8a8 8 0 00-8 8v12a8 8 0 008 8h12a8 8 0 008-8V8a8 8 0 00-8-8zM56 0H44a8 8 0 00-8 8v12a8 8 0 008 8h12a8 8 0 008-8V8a8 8 0 00-8-8zM20 36H8a8 8 0 00-8 8v12a8 8 0 008 8h12a8 8 0 008-8V44a8 8 0 00-8-8zM56 36H44a8 8 0 00-8 8v12a8 8 0 008 8h12a8 8 0 008-8V44a8 8 0 00-8-8z" fill="#767fad" class="color000000 svgShape"></path></g></g></switch></svg>

After

Width:  |  Height:  |  Size: 527 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8" id="List"><path d="M0 0v3h3V0H0zm4 0v1h4V0H4zm0 2v1h3V2H4zM0 4v3h3V4H0zm4 0v1h4V4H4zm0 2v1h3V6H4z" fill="#b22b7d" class="color000000 svgShape"></path></svg>

After

Width:  |  Height:  |  Size: 214 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="List"><path d="M9 3a6 6 0 1 0 6 6A6 6 0 0 0 9 3zM9 13a4 4 0 1 1 4-4A4 4 0 0 1 9 13zM17 9H28a1 1 0 0 0 0-2H17a1 1 0 0 0 0 2zM17 13h6a1 1 0 0 0 0-2H17a1 1 0 0 0 0 2zM9 17a6 6 0 1 0 6 6A6 6 0 0 0 9 17zM9 27a4 4 0 1 1 4-4A4 4 0 0 1 9 27zM28 21H17a1 1 0 0 0 0 2H28a1 1 0 0 0 0-2zM23 25H17a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2z" fill="#4687ba" class="color000000 svgShape"></path></svg>

After

Width:  |  Height:  |  Size: 437 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 64 64" id="delete"><path d="M44.41 19.59a2 2 0 0 0-2.83 0L32 29.18l-9.59-9.59a2 2 0 0 0-2.83 2.83L29.17 32l-9.59 9.59a2 2 0 1 0 2.83 2.83L32 34.83l9.59 9.59a2 2 0 0 0 2.83-2.83L34.83 32l9.59-9.59a2 2 0 0 0-.01-2.82Z" fill="#b22b7d" class="color000000 svgShape"></path><path d="M32 3a29 29 0 1 0 29 29A29 29 0 0 0 32 3Zm0 54a25 25 0 1 1 25-25 25 25 0 0 1-25 25Z" fill="#b22b7d" class="color000000 svgShape"></path></svg>

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

+46 -33
View File
@@ -1,54 +1,67 @@
import React, { lazy } from "react";
import React, { useContext } from "react";
import { Link } from "react-router-dom";
import { localImgLoad } from "../../lib";
import DarkModeContext from "../Contexts/DarkModeContext";
export default function LoginLayout({ slogan, children }) {
const bgImg = localImgLoad('images/left-myft.jpg')
const bgImg = localImgLoad("images/left-wrenchboard.jpg");
const bgImgNig = localImgLoad("images/wrench-home-back-nigeria.jpg");
const bgImgCom = localImgLoad("images/wrench-home-back-common.jpg");
const { countryMode } = useContext(DarkModeContext);
return (
<div className={`layout-wrapper login`}>
<div className={`w-full min-h-screen overflow-y-auto lg:grid grid-cols-2`}>
<div
<div
className={`h-screen overflow-y-auto bg-cover bg-center`}
style={{
backgroundImage: `url(${countryMode == "NG" ? bgImgNig : bgImgCom})`,
}}
>
<div className={`w-full grid grid-cols-1 lg:grid-cols-2`}>
{/* <div
className={`auth-bg hidden lg:block bg-blue-50 relative bg-cover bg-no-repeat border-0 after:content-[''] after:absolute after:inset-0`}
style={{backgroundImage: `url(${bgImg})`}}
>
</div>
<div className="p-5 sm:p-7 flex place-content-center">
<div className="py-10 w-11/12 h-full flex flex-col justify-between items-center content-wrapper login shadow-md xl:bg-white dark:bg-dark-white rounded-[0.475rem]">
</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="w-full flex justify-center items-center">
{children && children}
</div>
<div className="w-full flex flex-col justify-center items-center px-10">
<div className="w-full flex justify-center items-center pt-5">
<div className="flex items-center">
<a
href="https://www.wrenchboard.com/about-us"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
About
</a>
<a
href="https://www.wrenchboard.com/service"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
Services
</a>
<a
href="https://www.wrenchboard.com/contact"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
Contact Us
</a>
<a
href="https://www.wrenchboard.com/about-us"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
About
</a>
<a
href="https://www.wrenchboard.com/service"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
Services
</a>
<a
href="https://www.wrenchboard.com/contact"
className="text-[#a1a5b7] text-[15px] px-2 font-medium hover:text-[#009ef7]"
target="_blank"
rel="noreferrer"
>
Contact Us
</a>
</div>
</div>
<p className="py-1 text-black text-[15px] px-2 font-medium flex items-center gap-1">
<span className="">&copy; {new Date().getFullYear()} -</span>
<span className="dark:text-white">
&copy; {new Date().getFullYear()} -
</span>
<Link to="/" className="text-[#009ef7] ml-1">
WrenchBoard
</Link>{" "}
@@ -59,7 +59,7 @@ export default function ForgotPassword() {
}
if (email !== "" && checked) {
const reqData = { email, action:11013 };
const reqData = { email };
setResetLoading(true);
try {
const res = await userApi.StartResetPassword(reqData);
@@ -59,7 +59,7 @@ export default function ForgotPassword() {
}
if (email !== "" && checked) {
const reqData = { email, action:11013 };
const reqData = { email };
setResetLoading(true);
try {
const res = await userApi.StartResetPassword(reqData);
@@ -99,7 +99,7 @@ export default function ForgotPassword() {
</Link>
</div>
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[400px]">
<div className="w-10/12">
{msgSuccess == null ?
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
+1 -3
View File
@@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import linkedInLogo from "../../../assets/images/Linkedin.png";
import appleLogo from "../../../assets/images/apple-black.svg";
import facebookLogo from "../../../assets/images/facebook-4.svg";
import facebookLogo from "../../../assets/images/facebook.svg";
import googleLogo from "../../../assets/images/google-logo.svg";
import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png";
import usersService from "../../../services/UsersService";
@@ -98,7 +98,6 @@ export default function Login() {
password: password,
sessionid: "STARTING",
login_mode: 1100,
action: 11025,
};
} else if (name == "family") {
// Post Data Info for family Login
@@ -107,7 +106,6 @@ export default function Login() {
pin: password,
sessionid: "20067A92714",
login_mode: 1105,
action: 11025,
};
} else {
setLoginLoading(false);
+58 -20
View File
@@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import linkedInLogo from "../../../assets/images/Linkedin.png";
import appleLogo from "../../../assets/images/apple-black.svg";
import facebookLogo from "../../../assets/images/facebook-4.svg";
import facebookLogo from "../../../assets/images/facebook.svg";
import googleLogo from "../../../assets/images/google-logo.svg";
import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png";
import usersService from "../../../services/UsersService";
@@ -24,7 +24,9 @@ export default function Login() {
const dispatch = useDispatch();
const { state } = useLocation();
const [sessionExpired, setSessionExpired] = useState(queryParams.get("sessionExpired"))
const [sessionExpired, setSessionExpired] = useState(
queryParams.get("sessionExpired")
);
const [validCaptcha, setValidCaptcha] = useState({ show: false, valid: "" }); // FOR CAPTCHA
@@ -98,7 +100,6 @@ export default function Login() {
password: password,
sessionid: "STARTING",
login_mode: 1100,
action: 11025,
};
} else if (name == "family") {
// Post Data Info for family Login
@@ -107,7 +108,6 @@ export default function Login() {
pin: password,
sessionid: "20067A92714",
login_mode: 1105,
action: 11025,
};
} else {
setLoginLoading(false);
@@ -237,19 +237,18 @@ export default function Login() {
setPassword("");
}, [loginType]);
// EFFECT TO CLEAR SESSION EXPIRY IF IT EXISTS AFTER SOME SECONDS
useEffect(()=>{
useEffect(() => {
let timer;
if(sessionExpired == "true"){
timer = setTimeout(()=>{
setSessionExpired(false)
},5000)
if (sessionExpired == "true") {
timer = setTimeout(() => {
setSessionExpired(false);
}, 5000);
}
return () => {
clearTimeout(timer)
}
}, [])
clearTimeout(timer);
};
}, []);
return (
<>
@@ -266,7 +265,7 @@ export default function Login() {
</div>
{/* <div className="content-wrapper login shadow-md w-10/12 mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5"> */}
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[530px]">
<div className="w-10/12">
{/* HIDES THIS IF USER SESSION HAS EXPIRED */}
{sessionExpired != "true" && (
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
@@ -522,11 +521,50 @@ export default function Login() {
}
{/* END of login component */}
{loginType == "full" && (
<div className="pt-5 text-[#181c32] text-center font-semibold text-[13.975px] leading-[20.9625px]">
This site is protected by a Captcha. Our Privacy Policy and
Terms of Service apply.
{/* APP DOWNLOAD STORE */}
<div className="w-full mt-4">
<div className="w-full flex justify-center items-center gap-4">
<div className="w-28 lg:w-32">
<a
className="px-1 py-1 lg:py-2 flex justify-center items-center gap-1 w-full rounded-md bg-black text-white hover:text-slate-500 hover:shadow-lg transition-all duration-300"
target="_blank"
rel="noreferrer"
href={process.env.REACT_APP_APPLE_APP}
>
<i className="fa-brands fa-apple text-3xl"></i>
<div className="flex flex-col">
<span className="text-[11px]">Available on the</span>
<span className="text-[12px] lg:text-base">
App Store
</span>
</div>
</a>
</div>
<div className="w-28 lg:w-32">
<a
className="px-1 py-1 lg:py-2 flex justify-center items-center gap-1 w-full rounded-md bg-black text-white hover:text-slate-500 hover:shadow-lg transition-all duration-300"
target="_blank"
rel="noreferrer"
href={process.env.REACT_APP_ANDROID_APP}
>
<i className="fa-brands fa-google-play text-2xl"></i>
<div className="flex flex-col">
<span className="text-[11px]">Available on the</span>
<span className="text-[12px] lg:text-base">
Google Play
</span>
</div>
</a>
</div>
</div>
</div>
{loginType == "full" && (
<>
<div className="pt-5 text-[#181c32] text-center font-semibold text-[13.975px] leading-[20.9625px]">
This site is protected by a Captcha. Our Privacy Policy and
Terms of Service apply.
</div>
</>
)}
</div>
</div>
@@ -567,7 +605,7 @@ const BrandBtn = ({
{isAnchor ? (
<a
href={link}
className="w-full border border-light-purple dark:border-[#5356fb29] rounded-[0.475rem] h-[48px] flex justify-center bg-[#FAFAFA] hover:bg-[#eff2f5] hover:text-[#7e8299] transition duration-300 dark:bg-[#11131F] items-center font-medium cursor-pointer"
className="w-full border border-light-purple rounded-[0.475rem] h-[48px] flex justify-center bg-[#FAFAFA] hover:bg-[#eff2f5] hover:text-[#7e8299] transition duration-300 items-center font-medium cursor-pointer"
>
<img className="mr-3 h-6" src={imgSrc} alt="logo-icon(s)" />
<span className="text-lg text-thin-light-gray font-normal text-[15px]">
@@ -578,7 +616,7 @@ const BrandBtn = ({
<button
onClick={onClick}
// href="#dd"
className="w-full border border-light-purple dark:border-[#5356fb29] rounded-[0.475rem] h-[48px] flex justify-center bg-[#FAFAFA] hover:bg-[#eff2f5] hover:text-[#7e8299] transition duration-300 dark:bg-[#11131F] items-center font-medium cursor-pointer"
className="w-full border border-light-purple rounded-[0.475rem] h-[48px] flex justify-center bg-[#FAFAFA] hover:bg-[#eff2f5] hover:text-[#7e8299] transition duration-300 items-center font-medium cursor-pointer"
>
<img className="mr-3 h-6" src={imgSrc} alt="logo-icon(s)" />
<span className="text-lg text-thin-light-gray font-normal text-[15px]">
+81 -41
View File
@@ -9,19 +9,21 @@ export default function SignUp() {
// eslint-disable-next-line no-restricted-globals
const queryParams = new URLSearchParams(location?.search);
const country = queryParams.get("cnt")?.toUpperCase();
const {pathname} = useLocation()
const currentPath = country ? `${pathname}?cnt=${country.toLowerCase()}`:pathname // Determines the new pathname is country query params exist
const { pathname } = useLocation();
const currentPath = country
? `${pathname}?cnt=${country.toLowerCase()}`
: pathname; // Determines the new pathname is country query params exist
const [signUpLoading, setSignUpLoading] = useState(false);
const [checked, setValue] = useState(false);
// for the catch error
const [msgError, setMsgError] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [countries, setCountries] = useState({loading:true, data:[]});
const [countries, setCountries] = useState({ loading: true, data: [] });
const [formData, setFormData] = useState({
country: country? country : "",
country: country ? country : "",
first_name: "",
last_name: "",
email: "",
@@ -47,22 +49,23 @@ export default function SignUp() {
// Get Country Api
const getCountryList = useCallback(async () => {
try {
const res = await userApi.getSignupCountryData();
if (res.status === 200 && res.data.internal_return >= 0) {
const { result_list } = await res.data;
if(country){ // IF LINK/PATHNAME HAS CNT QUERY VALUE
let cnt = result_list.filter(item => item.code == country) // test to see country passed in query param exist from list of countries supplied by API
if(!cnt.length){ // IF CNT EMPTY, SET FORMDATA COUNTRY BACK TO EMPTY STRING: RE: THIS IS BCOS WE INITAIL SET COUNTRY VALUE IN FORMDATA, IF COUNTRY PARAM IS PRESENT IN LINK
setFormData(prev => ({...prev, country: ''}))
return setCountries({loading: false, data: result_list});
if (country) {
// IF LINK/PATHNAME HAS CNT QUERY VALUE
let cnt = result_list.filter((item) => item.code == country); // test to see country passed in query param exist from list of countries supplied by API
if (!cnt.length) {
// IF CNT EMPTY, SET FORMDATA COUNTRY BACK TO EMPTY STRING: RE: THIS IS BCOS WE INITAIL SET COUNTRY VALUE IN FORMDATA, IF COUNTRY PARAM IS PRESENT IN LINK
setFormData((prev) => ({ ...prev, country: "" }));
return setCountries({ loading: false, data: result_list });
}
return setCountries({loading: false, data: cnt});
return setCountries({ loading: false, data: cnt });
}
setCountries({loading: false, data:result_list});
setCountries({ loading: false, data: result_list });
} else if (res.data.result !== 100) {
setCountries({loading: false, data:[]});
setCountries({ loading: false, data: [] });
}
} catch (error) {
throw new Error(error);
@@ -113,9 +116,7 @@ export default function SignUp() {
if (res.status === 200) {
const { data } = res;
if (data && data.acc === "DULPICATE") {
setMsgError(
"Unable to use this username. Please try another username."
);
setMsgError("Duplicate username. Please try another email.");
setSignUpLoading(false);
}
if (data && data.status === "1") {
@@ -124,6 +125,11 @@ export default function SignUp() {
setSignUpLoading(false);
}, 2000);
}
if (data && data.status === "5") {
setMsgError("Something went wrong. Please try another email.");
setSignUpLoading(false);
}
} else {
setSignUpLoading(false);
setMsgError("An error occurred");
@@ -158,7 +164,7 @@ export default function SignUp() {
</Link>
</div>
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[530px]">
<div className="w-10/12">
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Create Account
@@ -187,7 +193,9 @@ export default function SignUp() {
name="country"
value={formData.country}
inputHandler={handleInputChange}
disable={country && countries?.data?.length <= 1 ? true : false}
disable={
country && countries?.data?.length <= 1 ? true : false
}
/>
<div className="input-fl-name mb-4 sm:flex w-full sm:space-x-6 ">
<div className="input-item sm:w-1/2 w-full mb-4 sm:mb-0">
@@ -325,7 +333,7 @@ export default function SignUp() {
disabled={countries.loading}
type="button"
onClick={handleSignUp}
className={`rounded-full mb-6 text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center h-[42px] py-[0.8875rem] px-[1.81rem] text-[14.95px] btn-login`}
className={`rounded-full text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center h-[42px] py-[0.8875rem] px-[1.81rem] text-[14.95px] btn-login`}
>
{signUpLoading ? (
<div className="signup btn-loader"></div>
@@ -335,6 +343,44 @@ export default function SignUp() {
</button>
</div>
</div>
{/* APP DOWNLOAD STORE */}
<div className="w-full mt-4">
<div className="w-full flex justify-center items-center gap-4">
<div className="w-28 lg:w-32">
<a
className="px-1 py-1 lg:py-2 flex justify-center items-center gap-1 w-full rounded-md bg-black text-white hover:text-slate-500 hover:shadow-lg transition-all duration-300"
target="_blank"
href={process.env.REACT_APP_APPLE_APP}
rel="noreferrer"
>
<i className="fa-brands fa-apple text-3xl"></i>
<div className="flex flex-col">
<span className="text-[11px]">Available on the</span>
<span className="text-[12px] lg:text-base">
App Store
</span>
</div>
</a>
</div>
<div className="w-28 lg:w-32">
<a
className="px-1 py-1 lg:py-2 flex justify-center items-center gap-1 w-full rounded-md bg-black text-white hover:text-slate-500 hover:shadow-lg transition-all duration-300"
target="_blank"
href={process.env.REACT_APP_ANDROID_APP}
rel="noreferrer"
>
<i className="fa-brands fa-google-play text-2xl"></i>
<div className="flex flex-col">
<span className="text-[11px]">Available on the</span>
<span className="text-[12px] lg:text-base">
Google Play
</span>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -350,7 +396,7 @@ const SelectOption = ({
inputHandler,
value,
data, // passing the data from parent
disable
disable,
}) => {
return (
<div className="input-com mb-7">
@@ -364,39 +410,33 @@ const SelectOption = ({
</div>
<div>
<select
disabled={disable}
disabled={disable}
name={name}
id={name}
className="input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-full rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] text-base focus-visible:border-transparent focus-visible:outline-0 focus-visible:ring-transparent "
onChange={inputHandler}
value={value}
>
{data?.data?.length > 1 ?
{data?.data?.length > 1 ? (
<>
<option value={""}>Select your Country</option>
{data?.data?.map((item) => (
<option value={item.code} key={item.uid}>
{item.country}
</option>
))}
<option value={""}>Select your Country</option>
{data?.data?.map((item) => (
<option value={item.code} key={item.uid}>
{item.country}
</option>
))}
</>
:
data?.data?.length == 1 ?
) : data?.data?.length == 1 ? (
data?.data?.map((item) => (
<option value={item.code} key={item.uid}>
{item.country}
</option>
))
:
data?.data?.length < 1 && data.loading ?
<option value=''>
Loading...
</option>
:
<option value=''>
No Country Found!
</option>
}
) : data?.data?.length < 1 && data.loading ? (
<option value="">Loading...</option>
) : (
<option value="">No Country Found!</option>
)}
</select>
</div>
</div>
@@ -19,7 +19,7 @@ export default function UpdatePassword() {
<AuthLayout slogan="Welcome to myFit">
{updated === false ? (
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[600px]">
<div className="w-10/12">
<div className="title-area relative flex flex-col justify-center items-center mb-7">
<h1 className="sm:text-5xl text-4xl font-bold leading-[74px] text-dark-gray dark:text-white">
Update Password
+59 -58
View File
@@ -36,10 +36,7 @@ export default function VerifyLink() {
var postData = {
username: email,
password: password,
login_mode: 100,
sessionid: "STARTER-NOTREAL",
verify_link: token,
action: 11012,
};
const res = await userApi?.CompleteSignUp(postData);
@@ -54,8 +51,7 @@ export default function VerifyLink() {
localStorage.setItem("member_id", `${data?.member_id}`);
localStorage.setItem("session_token", `${data?.session}`);
localStorage.setItem("session", `${data?.session}`);
localStorage.setItem("uid", data?.uid)
localStorage.setItem("uid", data?.uid);
navigate("/", { replace: true });
setLinkLoader(false);
@@ -83,19 +79,19 @@ export default function VerifyLink() {
};
// for verifying the incoming verification link and render the correct component
const verifyEmail = useCallback(async (code) => {
const verifyEmail = async (code) => {
try {
const verifyRes = await userApi.verifyEmail(code);
if (verifyRes.status === 200) {
let { data } = verifyRes;
console.log('TESTING VERIFY',data)
console.log("TESTING VERIFY", data);
if (
data &&
data.internal_return >= 0 &&
data.status == 0 &&
data.pending_id != '' &&
data.pending_uid != '' &&
data.username != '' &&
data.internal_return >= 0 &&
data.status == 0 &&
data.pending_id != "" &&
data.pending_uid != "" &&
data.username != "" &&
data.status_text === "Link Verified"
) {
setPageLoader(false);
@@ -109,12 +105,13 @@ export default function VerifyLink() {
setLinkSuccess(false);
throw new Error(error);
}
}, []);
};
// delay verify requests by 10000ms
const debouncedEmail = debounce(verifyEmail, 1000);
useEffect(() => {
setEmail("")
debouncedEmail(token);
}, []);
@@ -174,53 +171,57 @@ const SuccessfulComponent = ({
handleEmail,
msgErr,
loader,
}) => (
<div className="input-area">
{/* INPUT */}
<div className="mb-5">
<InputCom
fieldClass="px-6"
value={email}
inputHandler={handleEmail}
placeholder="support@mermsemr.com"
label="Email"
name="email"
type="email"
iconName="message"
/>
</div>
<div className="mb-5">
<InputCom
fieldClass="px-6"
value={password}
inputHandler={handlePassword}
placeholder="● ● ● ● ● ●"
label="Password"
name="password"
type="password"
iconName="password"
/>
</div>
{msgErr && (
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">
{msgErr}
}) => {
return (
<div className="input-area">
{/* INPUT */}
<div className="mb-5">
<InputCom
fieldClass="px-6"
value={email}
inputHandler={handleEmail}
placeholder="support@mermsemr.com"
label="Email"
name="email"
type="email"
iconName="message"
autoComplete="off"
/>
</div>
<div className="mb-5">
<InputCom
fieldClass="px-6"
value={password}
inputHandler={handlePassword}
placeholder="● ● ● ● ● ●"
label="Password"
name="password"
type="password"
iconName="password"
autoComplete="off"
/>
</div>
{msgErr && (
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">
{msgErr}
</div>
)}
<div className="signin-area mb-3.5">
<button
onClick={onSubmit}
type="button"
className={`btn-login rounded-[0.475rem] mb-6 text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
>
{loader ? (
<div className="signup btn-loader"></div>
) : (
<span>Continue</span>
)}
</button>
</div>
)}
<div className="signin-area mb-3.5">
<button
onClick={onSubmit}
type="button"
className={`btn-login rounded-[0.475rem] mb-6 text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
>
{loader ? (
<div className="signup btn-loader"></div>
) : (
<span>Continue</span>
)}
</button>
</div>
</div>
);
);
};
const ErrorComponent = ({ onClick }) => (
<div className="input-area">
+11 -12
View File
@@ -36,10 +36,7 @@ export default function VerifyLink() {
var postData = {
username: email,
password: password,
login_mode: 100,
sessionid: "STARTER-NOTREAL",
verify_link: token,
action: 11012,
};
const res = await userApi?.CompleteSignUp(postData);
@@ -54,8 +51,7 @@ export default function VerifyLink() {
localStorage.setItem("member_id", `${data?.member_id}`);
localStorage.setItem("session_token", `${data?.session}`);
localStorage.setItem("session", `${data?.session}`);
localStorage.setItem("uid", data?.uid)
localStorage.setItem("uid", data?.uid);
navigate("/", { replace: true });
setLinkLoader(false);
@@ -88,16 +84,17 @@ export default function VerifyLink() {
const verifyRes = await userApi.verifyEmail(code);
if (verifyRes.status === 200) {
let { data } = verifyRes;
console.log('TESTING VERIFY',data)
console.log("TESTING VERIFY", data);
if (
data &&
data.internal_return >= 0 &&
data.status == 0 &&
data.pending_id != '' &&
data.pending_uid != '' &&
data.username != '' &&
data.internal_return >= 0 &&
data.status == 0 &&
data.pending_id != "" &&
data.pending_uid != "" &&
data.username != "" &&
data.status_text === "Link Verified"
) {
setEmail(data.username);
setPageLoader(false);
} else {
setPageLoader(false);
@@ -135,7 +132,7 @@ export default function VerifyLink() {
</Link>
</div>
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[500px]">
<div className="w-10/12">
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
{linkSuccess
@@ -187,6 +184,7 @@ const SuccessfulComponent = ({
name="email"
type="email"
iconName="message"
autoComplete="off"
/>
</div>
<div className="mb-5">
@@ -199,6 +197,7 @@ const SuccessfulComponent = ({
name="password"
type="password"
iconName="password"
autoComplete="off"
/>
</div>
{msgErr && (
+124 -105
View File
@@ -11,7 +11,11 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
const VerifyPassword = () => {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [requestStatus, setRequestStatus] = useState({loading: true, status:false, data: []})
const [requestStatus, setRequestStatus] = useState({
loading: true,
status: false,
data: [],
});
const [msgError, setMsgError] = useState("");
const [linkLoader, setLinkLoader] = useState(false);
const [linkSuccess, setLinkSuccess] = useState(null);
@@ -35,60 +39,64 @@ const VerifyPassword = () => {
};
const completeReset = async () => {
if(!password || !confirmPassword){ // CHECKS IF PASSWORD IS EMPTY
if (!password || !confirmPassword) {
// CHECKS IF PASSWORD IS EMPTY
setMsgError("Please fill in fields");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password != confirmPassword){ // CHECKS IF PASSWORD EQUALS CONFIRM PASSWORD
if (password != confirmPassword) {
// CHECKS IF PASSWORD EQUALS CONFIRM PASSWORD
setMsgError("Passwords does not match");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password.length < 6){ // CHECKS IF PASSWORD LENGTH IS UPTO 6 CHARACTERS
if (password.length < 6) {
// CHECKS IF PASSWORD LENGTH IS UPTO 6 CHARACTERS
setMsgError("Password must be upto six characters");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(!PasswordValidator(password)){ // CHECKS IF PASSWORD IS VALID
setMsgError("Password must contain alphanumeric, uppercase and special character: eg: Password1@");
if (!PasswordValidator(password)) {
// CHECKS IF PASSWORD IS VALID
setMsgError(
"Password must contain alphanumeric, uppercase and special character: eg: Password1@"
);
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
try {
setLinkLoader(true);
var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY",
reset_link: token,
newpass: password,
m_uid: requestStatus.data?.m_uid || '',
reset_uid: requestStatus.data?.reset_uid || '',
step: 300,
action: 730,
};
const res = await userApi?.CompleteResetPassword(reqData);
setLinkLoader(true);
var reqData = {
reset_link: token,
newpass: password,
m_uid: requestStatus.data?.m_uid || "",
reset_uid: requestStatus.data?.reset_uid || "",
step: 300,
};
const res = await userApi?.CompleteResetPassword(reqData);
if (res.status == 200) {
const { data } = res;
if (data?.internal_return >= 0) {
// setTimeout(() => {
// navigate("/login", { replace: true });
// setLinkLoader(false);
// }, 2000);
setLinkSuccess(true);
} else {
setLinkLoader(false);
setMsgError("An error occurred");
setLinkSuccess(false);
}
} else {
setLinkLoader(false);
setLinkSuccess(false);
}
if (res.status == 200) {
const { data } = res;
if (data?.internal_return >= 0) {
// setTimeout(() => {
// navigate("/login", { replace: true });
// setLinkLoader(false);
// }, 2000);
setLinkSuccess(true);
} else {
setLinkLoader(false);
setMsgError("An error occurred");
setLinkSuccess(false);
}
} else {
setLinkLoader(false);
setLinkSuccess(false);
}
} catch (error) {
setLinkLoader(false);
setLinkSuccess(false);
@@ -100,31 +108,33 @@ const VerifyPassword = () => {
}
};
const verifyResetPwd = () => { // FUNCTION TO VERIFY RESET PASSWORD LINK
setRequestStatus({loading: true, status:false, data: []})
const verifyResetPwd = () => {
// FUNCTION TO VERIFY RESET PASSWORD LINK
setRequestStatus({ loading: true, status: false, data: [] });
var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY",
reset_link: token,
step: 200,
action: 730,
};
userApi.CompleteResetPassword(reqData).then(res => {
if(res.status != 200 || res.data.internal_return < 0){
return setRequestStatus({loading: false, status:false, data: []})
}
setRequestStatus({loading: false, status:true, data: res.data})
}).catch(error => {
setRequestStatus({loading: false, status:false, data: []})
})
}
userApi
.CompleteResetPassword(reqData)
.then((res) => {
if (res.status != 200 || res.data.internal_return < 0) {
return setRequestStatus({ loading: false, status: false, data: [] });
}
setRequestStatus({ loading: false, status: true, data: res.data });
})
.catch((error) => {
setRequestStatus({ loading: false, status: false, data: [] });
});
};
useEffect(()=>{
useEffect(() => {
// little checker for the validity of the token
if (token==null || token?.length != 64) {
return setRequestStatus({loading: false, status:false, data: []});
}
verifyResetPwd()
},[])
if (token == null || token?.length != 64) {
return setRequestStatus({ loading: false, status: false, data: [] });
}
verifyResetPwd();
}, []);
return (
<>
<AuthLayout slogan="Welcome to WrenchBoard">
@@ -139,59 +149,68 @@ const VerifyPassword = () => {
</Link>
</div>
<div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5">
{requestStatus.loading ?
<LoadingSpinner color='sky-blue' size='16' height='h-300px' />
:
!requestStatus.loading && requestStatus.status ?
<div className="w-full">
{linkSuccess == null ?
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Password Reset
</h1>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
Enter a new password to reset
</span>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
We'll send an email to confirm reset
</span>
</div>
<div>
<p className="text-red-500 font-semibold mb-3 leading-[27.3px] text-[13px]">
Must include a special, numeric, uppercase and lowercase character
</p>
</div>
<SuccessfulComponent
password={password}
confirmPassword={confirmPassword}
handlePassword={handlePassword}
onSubmit={completeReset}
msgErr={msgError}
loader={linkLoader}
showPassword={showPassword}
onClick={togglePasswordVisibility}
navigateHandler={() => navigate("/login")}
{requestStatus.loading ? (
<LoadingSpinner color="sky-blue" size="16" height="h-300px" />
) : !requestStatus.loading && requestStatus.status ? (
<div className="w-full">
{linkSuccess == null ? (
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Password Reset
</h1>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
Enter a new password to reset
</span>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
We'll send an email to confirm reset
</span>
</div>
<div>
<p className="text-red-500 font-semibold mb-3 leading-[27.3px] text-[13px]">
Must include a special, numeric, uppercase and lowercase
character
</p>
</div>
<SuccessfulComponent
password={password}
confirmPassword={confirmPassword}
handlePassword={handlePassword}
onSubmit={completeReset}
msgErr={msgError}
loader={linkLoader}
showPassword={showPassword}
onClick={togglePasswordVisibility}
navigateHandler={() => navigate("/login")}
/>
</>
) : (
<ForgetPwdResponse
title={
linkSuccess
? "Password Reset Complete"
: "Password Reset Error"
}
message={
linkSuccess
? "Password Reset Complete. You can login now with your new credentials"
: "Password Reset Error. Please get in touch with support for further support"
}
type={linkSuccess}
/>
</>
:
<ForgetPwdResponse
title={linkSuccess? 'Password Reset Complete' : 'Password Reset Error'}
message={linkSuccess? 'Password Reset Complete. You can login now with your new credentials' : 'Password Reset Error. Please get in touch with support for further support'
}
type={linkSuccess}
/>
}
</div>
:
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<ForgetPwdResponse
title={'Forget Password'}
message={'We are unable to continue to reset process. This error is usually due to expired links. Please start all over or contact us'}
type={requestStatus.status}
/>
</div>
}
)}
</div>
) : (
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<ForgetPwdResponse
title={"Forget Password"}
message={
"We are unable to continue to reset process. This error is usually due to expired links. Please start all over or contact us"
}
type={requestStatus.status}
/>
</div>
)}
</div>
</div>
</AuthLayout>
+124 -105
View File
@@ -11,7 +11,11 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
const VerifyPassword = () => {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [requestStatus, setRequestStatus] = useState({loading: true, status:false, data: []})
const [requestStatus, setRequestStatus] = useState({
loading: true,
status: false,
data: [],
});
const [msgError, setMsgError] = useState("");
const [linkLoader, setLinkLoader] = useState(false);
const [linkSuccess, setLinkSuccess] = useState(null);
@@ -35,60 +39,64 @@ const VerifyPassword = () => {
};
const completeReset = async () => {
if(!password || !confirmPassword){ // CHECKS IF PASSWORD IS EMPTY
if (!password || !confirmPassword) {
// CHECKS IF PASSWORD IS EMPTY
setMsgError("Please fill in fields");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password != confirmPassword){ // CHECKS IF PASSWORD EQUALS CONFIRM PASSWORD
if (password != confirmPassword) {
// CHECKS IF PASSWORD EQUALS CONFIRM PASSWORD
setMsgError("Passwords does not match");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password.length < 6){ // CHECKS IF PASSWORD LENGTH IS UPTO 6 CHARACTERS
if (password.length < 6) {
// CHECKS IF PASSWORD LENGTH IS UPTO 6 CHARACTERS
setMsgError("Password must be upto six characters");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(!PasswordValidator(password)){ // CHECKS IF PASSWORD IS VALID
setMsgError("Password must contain alphanumeric, uppercase and special character: eg: Password1@");
if (!PasswordValidator(password)) {
// CHECKS IF PASSWORD IS VALID
setMsgError(
"Password must contain alphanumeric, uppercase and special character: eg: Password1@"
);
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
try {
setLinkLoader(true);
var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY",
reset_link: token,
newpass: password,
m_uid: requestStatus.data?.m_uid || '',
reset_uid: requestStatus.data?.reset_uid || '',
step: 300,
action: 730,
};
const res = await userApi?.CompleteResetPassword(reqData);
setLinkLoader(true);
var reqData = {
reset_link: token,
newpass: password,
m_uid: requestStatus.data?.m_uid || "",
reset_uid: requestStatus.data?.reset_uid || "",
step: 300,
};
const res = await userApi?.CompleteResetPassword(reqData);
if (res.status == 200) {
const { data } = res;
if (data?.internal_return >= 0) {
// setTimeout(() => {
// navigate("/login", { replace: true });
// setLinkLoader(false);
// }, 2000);
setLinkSuccess(true);
} else {
setLinkLoader(false);
setMsgError("An error occurred");
setLinkSuccess(false);
}
} else {
setLinkLoader(false);
setLinkSuccess(false);
}
if (res.status == 200) {
const { data } = res;
if (data?.internal_return >= 0) {
// setTimeout(() => {
// navigate("/login", { replace: true });
// setLinkLoader(false);
// }, 2000);
setLinkSuccess(true);
} else {
setLinkLoader(false);
setMsgError("An error occurred");
setLinkSuccess(false);
}
} else {
setLinkLoader(false);
setLinkSuccess(false);
}
} catch (error) {
setLinkLoader(false);
setLinkSuccess(false);
@@ -100,31 +108,33 @@ const VerifyPassword = () => {
}
};
const verifyResetPwd = () => { // FUNCTION TO VERIFY RESET PASSWORD LINK
setRequestStatus({loading: true, status:false, data: []})
const verifyResetPwd = () => {
// FUNCTION TO VERIFY RESET PASSWORD LINK
setRequestStatus({ loading: true, status: false, data: [] });
var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY",
reset_link: token,
step: 200,
action: 730,
};
userApi.CompleteResetPassword(reqData).then(res => {
if(res.status != 200 || res.data.internal_return < 0){
return setRequestStatus({loading: false, status:false, data: []})
}
setRequestStatus({loading: false, status:true, data: res.data})
}).catch(error => {
setRequestStatus({loading: false, status:false, data: []})
})
}
userApi
.CompleteResetPassword(reqData)
.then((res) => {
if (res.status != 200 || res.data.internal_return < 0) {
return setRequestStatus({ loading: false, status: false, data: [] });
}
setRequestStatus({ loading: false, status: true, data: res.data });
})
.catch((error) => {
setRequestStatus({ loading: false, status: false, data: [] });
});
};
useEffect(()=>{
useEffect(() => {
// little checker for the validity of the token
if (token==null || token?.length != 64) {
return setRequestStatus({loading: false, status:false, data: []});
}
verifyResetPwd()
},[])
if (token == null || token?.length != 64) {
return setRequestStatus({ loading: false, status: false, data: [] });
}
verifyResetPwd();
}, []);
return (
<>
<AuthLayout slogan="Welcome to WrenchBoard">
@@ -139,59 +149,68 @@ const VerifyPassword = () => {
</Link>
</div>
<div className="flex place-content-center">
{requestStatus.loading ?
<LoadingSpinner color='sky-blue' size='16' height='h-300px' />
:
!requestStatus.loading && requestStatus.status ?
<div className="w-11/12 sm:max-w-[500px]">
{linkSuccess == null ?
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Password Reset
</h1>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
Enter a new password to reset
</span>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
We'll send an email to confirm reset
</span>
</div>
<div>
<p className="text-red-500 font-semibold mb-3 leading-[27.3px] text-[13px]">
Must include a special, numeric, uppercase and lowercase character
</p>
</div>
<SuccessfulComponent
password={password}
confirmPassword={confirmPassword}
handlePassword={handlePassword}
onSubmit={completeReset}
msgErr={msgError}
loader={linkLoader}
showPassword={showPassword}
onClick={togglePasswordVisibility}
navigateHandler={() => navigate("/login")}
{requestStatus.loading ? (
<LoadingSpinner color="sky-blue" size="16" height="h-300px" />
) : !requestStatus.loading && requestStatus.status ? (
<div className="w-10/12">
{linkSuccess == null ? (
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Password Reset
</h1>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
Enter a new password to reset
</span>
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
We'll send an email to confirm reset
</span>
</div>
<div>
<p className="text-red-500 font-semibold mb-3 leading-[27.3px] text-[13px]">
Must include a special, numeric, uppercase and lowercase
character
</p>
</div>
<SuccessfulComponent
password={password}
confirmPassword={confirmPassword}
handlePassword={handlePassword}
onSubmit={completeReset}
msgErr={msgError}
loader={linkLoader}
showPassword={showPassword}
onClick={togglePasswordVisibility}
navigateHandler={() => navigate("/login")}
/>
</>
) : (
<ForgetPwdResponse
title={
linkSuccess
? "Password Reset Complete"
: "Password Reset Error"
}
message={
linkSuccess
? "Password Reset Complete. You can login now with your new credentials"
: "Password Reset Error. Please get in touch with support for further support"
}
type={linkSuccess}
/>
</>
:
<ForgetPwdResponse
title={linkSuccess? 'Password Reset Complete' : 'Password Reset Error'}
message={linkSuccess? 'Password Reset Complete. You can login now with your new credentials' : 'Password Reset Error. Please get in touch with support for further support'
}
type={linkSuccess}
/>
}
</div>
:
<div className="w-11/12 sm:max-w-[500px] title-area flex flex-col justify-center items-center relative text-center mb-7">
<ForgetPwdResponse
title={'Forget Password'}
message={'We are unable to continue to reset process. This error is usually due to expired links. Please start all over or contact us'}
type={requestStatus.status}
/>
</div>
}
)}
</div>
) : (
<div className="w-11/12 sm:max-w-[500px] title-area flex flex-col justify-center items-center relative text-center mb-7">
<ForgetPwdResponse
title={"Forget Password"}
message={
"We are unable to continue to reset process. This error is usually due to expired links. Please start all over or contact us"
}
type={requestStatus.status}
/>
</div>
)}
</div>
</div>
</AuthLayout>
@@ -18,7 +18,7 @@ export default function VerifyYou() {
</Link>
</div>
<div className="flex place-content-center">
<div className="w-11/12 sm:max-w-[500px]">
<div className="w-10/12">
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Let's verify your email now
@@ -0,0 +1,22 @@
import React from 'react'
import { Link } from 'react-router-dom'
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>
</div>
)
}
+13 -31
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import MarketPopUp from "../MarketPlace/PopUp/MarketPopUp";
@@ -19,10 +19,10 @@ export default function AvailableJobsCard({
datas?.currency
);
useEffect(() => {
const imagePath = require(`../../assets/images/${datas.thumbnil}`); // Replace with your directory path for local images
setImageUrl(imagePath);
}, []);
// useEffect(() => {
// const imagePath = require(`../../assets/images/${datas.thumbnil}`); // Replace with your directory path for local images
// setImageUrl(imagePath);
// }, []);
const image = localStorage.getItem("session_token")
? `${image_server}${localStorage.getItem("session_token")}/job/${
@@ -55,7 +55,7 @@ export default function AvailableJobsCard({
Added
</p>
<p className="text-base text-dark-gray dark:text-white">
{datas.offer_added}
{new Date(datas.offer_added).toLocaleDateString()}
</p>
</div>
</div>
@@ -66,7 +66,7 @@ export default function AvailableJobsCard({
Expires
</p>
<p className="text-base text-dark-gray dark:text-white text-right">
{datas.expire}
{new Date(datas.expire).toLocaleDateString()}
</p>
</div>
</div>
@@ -75,34 +75,16 @@ export default function AvailableJobsCard({
<div
className="w-full h-[236px] p-6 rounded-xl overflow-hidden bg-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('${imageUrl}')`,
backgroundImage: `url('${image}')`,
}}
>
<div className="flex justify-center">{datas.description}</div>
<div className="flex justify-center bg-slate-100 p-2 rounded-md">
{datas.description}
</div>
</div>
</div>
<div className="details-area">
<div className="product-two-options flex justify-between mb-5 relative">
{/* <div className="status">*/}
{/* {datas.isActive && (*/}
{/* <span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">*/}
{/* Active*/}
{/*</span>*/}
{/* )}*/}
{/* </div>*/}
{/*<div className=" review flex space-x-2">*/}
{/* <button*/}
{/* onClick={favoriteHandler}*/}
{/* type="button"*/}
{/* className={`w-7 h-7 bg-white rounded-full flex justify-center items-center ${*/}
{/* addFavorite ? "text-red-500" : "text-thin-light-gray"*/}
{/* }`}*/}
{/* >*/}
{/* <Icons name="star" />*/}
{/* </button>*/}
{/*</div>*/}
</div>
<div className="product-two-options flex justify-between mb-5 relative"></div>
<div className="flex justify-between">
<div className="flex items-center space-x-2">
@@ -135,7 +117,7 @@ export default function AvailableJobsCard({
</div>
</div>
) : (
<div className="card-style-two w-full p-8 my-2 flex items-center gap-4 bg-white dark:bg-dark-white rounded-2xl section-shadow">
<div className="card-style-two w-full px-4 py-[0.4rem] my-2 flex items-center gap-4 bg-white dark:bg-dark-white rounded-2xl section-shadow">
<div className="flex gap-5 items-center w-full">
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] min-w-[60px] max-w-[60px]">
<img src={image} alt="data" className="w-full h-full" />
@@ -8,7 +8,7 @@ export default function HomeBannerOffersCard(props) {
useEffect(() => {
let { banner, banner_location } = props?.itemData;
if (banner_location === "LOCAL") {
const imagePath = require(`../../assets/images/${banner}`); // Replace with your directory path for local images
const imagePath = require(`../../assets/images/${banner}`);
setImageUrl(imagePath);
} else if (banner_location === "URL") setImageUrl(banner);
else return null;
@@ -0,0 +1,204 @@
import React from "react";
import { Link } from "react-router-dom";
const AccountDashboard = ({ className, bannerList }) => {
// getting the upper three banners for the home layout
const getUpperBanner = bannerList?.filter((value, idx) => idx <= 2);
const getLowerBanner = bannerList?.filter((value, idx) => idx > 2);
let getImage = ({ banner_location, banner }) => {
if (banner_location == "LOCAL") {
return require(`../../assets/images/${banner}`);
} else {
return banner;
}
};
console.log(getLowerBanner);
return (
<div
className={`w-full min-h-[450px] flex flex-col justify-between items-center gap-4 rounded-2xl overflow-hidden ${
className || ""
}`}
>
<div className="w-full grid xxs:grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 items-center justify-center gap-2 md:gap-4">
{getUpperBanner?.map((props, idx) => {
let image = getImage(props);
let { short_title, short_description, short_button_text, link_path } =
props;
return (
<TopBanner
btn={short_button_text}
image={image}
title={short_title}
desc={short_description}
link_path={link_path}
key={idx}
/>
);
})}
</div>
<div className="w-full grid-cols-1 md:grid-cols-2 2xl::grid-cols-3 grid items-center justify-center gap-2 md:gap-4">
{getLowerBanner?.map((props, idx) => {
let image = getImage(props);
let { short_title, short_description, short_button_text, link_path } =
props;
return (
<LowerBanner
btn={short_button_text}
image={image}
title={short_title}
desc={short_description}
link_path={link_path}
key={idx}
/>
);
})}
</div>
</div>
);
};
export default AccountDashboard;
const TopBanner = ({ image, title = "", desc = "", btn, link_path, key }) => {
return (
<div className="flex flex-col shadow-md rounded-xl dark:border-[#5356fb29]" key={key}>
<Link to={link_path} className="h-[12rem] rounded-t-xl">
<img
src={image}
alt="banner-img"
loading="lazy"
className="w-full h-full rounded-t-xl object-cover"
/>
</Link>
<div className="h-[7rem] rounded-b-xl bg-white dark:bg-dark-white">
<div className="border-b border-slate-300 px-2 py-1 h-[5.4rem] flex flex-col gap-2 dark:text-white">
<Link to={link_path} className="font-bold text-lg">
{title}
</Link>
<Link to={link_path} className="text-sm">
{desc}
</Link>
</div>
<div className="flex justify-between w-full px-2 items-center pt-[0.2rem]">
<Link to={link_path} className="text-slate-300 font-semibold text-sm">
{btn}
</Link>
<button className="flex items-center justify-center gap-2">
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
</button>
</div>
</div>
</div>
);
};
const LowerBanner = ({ image, title = "", desc = "", btn, link_path, key }) => {
return (
<div
key={key}
className="flex flex-col bg-white shadow-md h-full rounded-xl dark:border-[#5356fb29] dark:bg-dark-white"
>
<div className="w-full flex justify-between border-b border-slate-300 p-2">
<div className="h-[130px] flex justify-between items-center">
<div className="px-2 flex flex-col gap-2 dark:text-white">
<Link to={link_path} className="text-lg font-bold">
{title}
</Link>
<p to={link_path} className="text-sm">
{desc}
</p>
</div>
</div>
<Link to={link_path} className="w-[150px] h-[100px]">
<img
src={image}
alt="banner-img"
loading="lazy"
className="w-full h-full rounded-xl"
/>
</Link>
</div>
<div className="flex justify-between w-full px-2 items-center">
<Link to={link_path} className="text-slate-300 font-semibold text-sm">
{btn}
</Link>
<button className="flex items-center justify-center gap-2">
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
</button>
</div>
</div>
);
};
const BannerSection = ({ banners, variant }) => {
const getImage = ({ banner_location, banner }) => {
return banner_location === "LOCAL"
? require(`../../assets/images/${banner}`)
: banner;
};
return (
<>
{banners?.map((props, idx) => {
const { short_title, short_description, short_button_text, link_path } =
props;
const image = getImage(props);
return (
<div
key={idx}
className={`flex flex-col shadow-md rounded-xl ${
variant === "top" ? "" : "bg-white"
}`}
>
<div className={`${variant === "top" ? "rounded-t-xl" : ""}`}>
<Link to={link_path}>
<img
src={image}
alt="banner-img"
className="w-full h-full rounded-t-xl object-cover"
/>
</Link>
</div>
<div
className={`${
variant === "top"
? "rounded-b-xl bg-white"
: "border-b border-slate-300"
} h-[7rem]`}
>
<div className="border-b border-slate-300 px-2 py-1 h-[5.4rem] flex flex-col gap-2">
<Link to={link_path} className="font-bold text-lg">
{short_title}
</Link>
<Link to={link_path} className="text-sm">
{short_description}
</Link>
</div>
<div className="flex justify-between w-full px-2 items-center">
<Link to={link_path} className="text-slate-300 font-semibold">
{short_button_text}
</Link>
<button className="flex items-center justify-center gap-2">
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
<div className="w-[4px] h-[4px] bg-slate-400 rounded-full"></div>
</button>
</div>
</div>
</div>
);
})}
</>
);
};
@@ -0,0 +1,83 @@
import React from "react";
import CountDown from "../Helpers/CountDown";
// import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function FamilyParentDashboard({
className,
bannerList,
nextDueTask,
}) {
const { userDetails } = useSelector((state) => state?.userDetails);
let loginDate = userDetails?.last_login.split(" ")[0];
let { firstname, lastname, email } = userDetails;
let userEmail = email.split("@")[0];
return (
<div
className={`w-full md:h-[47px] xxs:h-[74px] flex px-[1.05rem] py-[0.35rem] flex-wrap justify-between items-center gap-2 rounded-2xl overflow-hidden bg-sky-blue ${
className || ""
}`}
style={{
// background: `url(${heroBg})`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
}}
>
<div className="h-full flex flex-wrap w-full justify-between mb-5 lg:mb-0">
{/* heading */}
<div className="flex gap-8">
<h1 className="text-base font-medium text-white tracking-wide">
Welcome
</h1>
{/* user */}
<div className="flex flex-col gap-1">
<p className="text-base tracking-wide font-bold antise text-white leading-[1]">
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white leading-[1]">
@{userEmail}
</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>
</div>
</div>
);
}
@@ -0,0 +1,79 @@
import React from "react";
import CountDown from "../Helpers/CountDown";
// import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function HomeDashboard({ className, bannerList, nextDueTask }) {
const { userDetails } = useSelector((state) => state?.userDetails);
let loginDate = userDetails?.last_login.split(" ")[0];
let { firstname, lastname, email } = userDetails;
let userEmail = email.split("@")[0];
return (
<div
className={`w-full md:h-[47px] xxs:h-[74px] flex px-[1.05rem] py-[0.35rem] flex-wrap justify-between items-center gap-2 rounded-2xl overflow-hidden bg-sky-blue ${
className || ""
}`}
style={{
// background: `url(${heroBg})`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
}}
>
<div className="h-full flex flex-wrap w-full justify-between mb-5 lg:mb-0">
{/* heading */}
<div className="flex gap-8">
<h1 className="text-base font-medium text-white tracking-wide">
Welcome
</h1>
{/* user */}
<div className="flex flex-col gap-1">
<p className="text-base tracking-wide font-bold antise text-white leading-[1]">
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white leading-[1]">
@{userEmail}
</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>
</div>
</div>
);
}
@@ -0,0 +1,83 @@
import React from "react";
import CountDown from "../Helpers/CountDown";
// import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function JobOwnerDashboard({
className,
bannerList,
nextDueTask,
}) {
const { userDetails } = useSelector((state) => state?.userDetails);
let loginDate = userDetails?.last_login.split(" ")[0];
let { firstname, lastname, email } = userDetails;
let userEmail = email.split("@")[0];
return (
<div
className={`w-full md:h-[47px] xxs:h-[74px] flex px-[1.05rem] py-[0.35rem] flex-wrap justify-between items-center gap-2 rounded-2xl overflow-hidden bg-sky-blue ${
className || ""
}`}
style={{
// background: `url(${heroBg})`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
}}
>
<div className="h-full flex flex-wrap w-full justify-between mb-5 lg:mb-0">
{/* heading */}
<div className="flex gap-8">
<h1 className="text-base font-medium text-white tracking-wide">
Welcome
</h1>
{/* user */}
<div className="flex flex-col gap-1">
<p className="text-base tracking-wide font-bold antise text-white leading-[1]">
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white leading-[1]">
@{userEmail}
</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>
</div>
</div>
);
}
+103
View File
@@ -0,0 +1,103 @@
import React, { useState } 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 }) {
const settings = {
autoplay: true,
dots: true,
arrows: false,
infinite: true,
swipe: true,
};
const sildeData = null;
const { userDetails } = useSelector((state) => state?.userDetails);
let loginDate = userDetails?.last_login.split(" ")[0];
let { firstname, lastname, email, profile_pic } = userDetails;
let userEmail = email.split("@")[0];
return (
<div
className={`w-full min-h-[400px] md:grid grid-cols-2 lg:p-8 p-4 justify-between items-center gap-2 rounded-2xl overflow-hidden bg-blue-900 ${
className || ""
}`}
style={{
// background: `url(${heroBg})`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
}}
>
<div className="h-full flex flex-col justify-between mb-5 lg:mb-0">
{/* heading */}
<div>
<h1 className="lg:text-2xl text-xl font-medium text-white tracking-wide">
Welcome
</h1>
<span className="text-[18px] font-thin tracking-wide text-white">
Last Login : {loginDate}
</span>
</div>
{/* user */}
<div className="flex items-center space-x-3">
<div className="w-14 h-14 flex justify-center items-center rounded-full overflow-hidden">
<img src={profile_pic != "" ? profile_pic : heroUser} alt="" />
</div>
<div>
<p className="text-xl tracking-wide font-bold antise text-white">
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white">@{userEmail}</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>
)}
{/* action */}
<div className="flex lg:space-x-3 space-x-1 items-center">
<Link to="/mytask" className="text-white text-base">
<span className=" border-b dark:border-[#5356fb29] border-white">
{" "}
View All Task(s)
</span>
</Link>
</div>
</div>
<HomeSliders
settings={settings}
sideData={sildeData}
bannerList={bannerList}
/>
</div>
);
}
@@ -0,0 +1,83 @@
import React from "react";
import CountDown from "../Helpers/CountDown";
// import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function WorkerDashboard({
className,
bannerList,
nextDueTask,
}) {
const { userDetails } = useSelector((state) => state?.userDetails);
let loginDate = userDetails?.last_login.split(" ")[0];
let { firstname, lastname, email } = userDetails;
let userEmail = email.split("@")[0];
return (
<div
className={`w-full md:h-[47px] xxs:h-[74px] flex px-[1.05rem] py-[0.35rem] flex-wrap justify-between items-center gap-2 rounded-2xl overflow-hidden bg-sky-blue ${
className || ""
}`}
style={{
// background: `url(${heroBg})`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
}}
>
<div className="h-full flex flex-wrap w-full justify-between mb-5 lg:mb-0">
{/* heading */}
<div className="flex gap-8">
<h1 className="text-base font-medium text-white tracking-wide">
Welcome
</h1>
{/* user */}
<div className="flex flex-col gap-1">
<p className="text-base tracking-wide font-bold antise text-white leading-[1]">
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white leading-[1]">
@{userEmail}
</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>
</div>
</div>
);
}
+13
View File
@@ -0,0 +1,13 @@
import FamilyParentDashboard from "./FamilyParentDashboard";
import HomeDashboard from "./HomeDashboard";
import JobOwnerDashboard from "./JobOwnerDashboard";
import WorkerDashboard from "./WorkerDashboard";
import AccountDashboard from "./AccountDashboard";
export {
FamilyParentDashboard,
HomeDashboard,
JobOwnerDashboard,
WorkerDashboard,
AccountDashboard
};
@@ -13,6 +13,7 @@ import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
import FamilyWallet from "./Tabs/FamilyWallet";
import { apiConst } from "../../lib/apiConst";
// Lazy Imports for components
const FamilyWaitlist = lazy(() => import("./Tabs/FamilyWaitlist"));
@@ -127,7 +128,7 @@ export default function FamilyManageTabs({
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: 'FILE',
action: 11305
action: apiConst.WRENCHBOARD_PICTURE_FAMMEMBER
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
apiCall.sendFiles(reqData).then(res=>{
@@ -285,7 +286,7 @@ export default function FamilyManageTabs({
limit: 30,
offset: 0,
job_type: "FAMILY",
action: 13005,
action: apiConst.WRENCHBOARD_PICTURE_FAMMEMBER,
};
if (checkFamilyTask) {
@@ -0,0 +1,10 @@
import React from 'react'
import Layout from '../Partials/Layout'
export default function FamilyPastDue() {
return (
<Layout>
<div>Family PastDue Page Here</div>
</Layout>
)
}
@@ -0,0 +1,44 @@
import React, { useEffect, useState } from 'react'
import Layout from '../Partials/Layout'
import MyOffersFamilyTable from '../MyTasks/MyOffersFamilyTable'
import LoadingSpinner from '../Spinners/LoadingSpinner';
import usersService from '../../services/UsersService';
export default function FamilyPendingOffer() {
const userApi = new usersService();
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()
},[])
return (
<Layout>
{myOffersList.loading ?
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
:
myOffersList?.data?.result_list && myOffersList?.data?.result_list.length > 0 ?
<MyOffersFamilyTable
familyOffers={myOffersList?.data?.result_list}
image_server={myOffersList?.data?.session_image_server}
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>
}
</Layout>
)
}
@@ -1,5 +1,6 @@
import React, { useMemo, useRef, useState } from "react";
import usersService from "../../../../services/UsersService";
import { apiConst } from "../../../../lib/apiConst";
const FamilyBanner = ({ imageServer }) => {
const uploadedImage = `${imageServer}${localStorage.getItem(
@@ -65,7 +66,7 @@ const FamilyBanner = ({ imageServer }) => {
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: "FILE",
action: 11303,
action: apiConst.WRENCHBOARD_PICTURE_JOB,
};
setUploadStatus({
loading: true,
@@ -0,0 +1,275 @@
import React, { useState } from 'react'
import ModalCom from '../../../Helpers/ModalCom';
import LoadingSpinner from '../../../Spinners/LoadingSpinner';
import InputCom from '../../../Helpers/Inputs/InputCom/index';
import { Formik, Form } from 'formik';
import * as Yup from "yup";
import usersService from '../../../../services/UsersService';
const validationSchema = Yup.object().shape({
email: Yup.string()
.email("Wrong email format")
.matches(
/^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
"Invalid email format"
)
.min(3, "Minimum 3 characters")
.max(50, "Maximum 50 characters")
.required("Email is required"),
firstname: Yup.string()
.min(3, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Firstname is required"),
lastname: Yup.string()
.min(3, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Lastname is required"),
family_type: Yup.string()
.min(3, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Family Type is required"),
});
const initialValues = {
firstname: '',
lastname: '',
family_type: '',
email: ''
};
export default function InviteRelative({action, situation, setReloadRelList, relativeList}) {
const api = new usersService()
let [requestStatus, setRequestStatus] = useState({
loading: false,
status: false,
message: "",
}); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER
const handleInvite = (values) => {
setRequestStatus({loading: true, status: false, message: ""})
api.inviteFamilyRelative(values).then(response => {
let {status, data} = response
if(data?.internal_return < 0){
setRequestStatus({loading: false, status: false, message: "Unable to complete"})
return setTimeout(()=>{
setRequestStatus({ loading: false, status: false, message: ""})
},3000)
}
setRequestStatus({loading: false, status: true, message: "Relative Added"})
//RELOAD RELATIVE LSIT TABLE
setReloadRelList(prev => !prev)
setTimeout(()=>{
action()
},3000)
}).catch(error => {
setRequestStatus({loading: false, status: false, message: "Something went wrong, try again!"})
setTimeout(()=>{
setRequestStatus({ loading: false, status: false, message: ""})
},3000)
})
}
return (
<ModalCom
action={action}
situation={situation}
>
<div className="lg:w-[600px] w-11/12 lg:overflow-hidden lg:rounded-2xl bg-white dark:bg-dark-white dark:text-white">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] ">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
Invite Parent/Relative
</h1>
<button
type="button"
className="text-[#374557] 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"
>
<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>
<div className="logout-modal-body w-full flex flex-col items-center px-10 py-8">
<div className="personal-info-tab w-full flex flex-col justify-between">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleInvite}
>
{(props) => {
return (
<Form>
<div className="w-full flex flex-col-reverse sm:flex-row">
<div className="fields w-full">
{/* inputs starts here */}
{/* Email */}
<div className="field w-full mb-6">
<InputCom
fieldClass="px-6"
label="Email"
type="text"
name="email"
placeholder="Email"
value={props.values.email}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={(props.errors.email && props.touched.email) ? props.errors.email : '' }
/>
</div>
{/* first name and last name */}
<div className="md:flex md:space-x-7 mb-6">
<div className="field w-full mb-6 md:mb-0">
<InputCom
fieldClass="px-6"
label="First Name"
type="text"
name="firstname"
placeholder="First Name"
value={props.values.firstname}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={(props.errors.firstname && props.touched.firstname) ? props.errors.firstname : '' }
/>
</div>
<div className="field w-full">
<InputCom
fieldClass="px-6"
label="Last Name"
type="text"
name="lastname"
placeholder="Last Name"
value={props.values.lastname}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={(props.errors.lastname && props.touched.lastname) ? props.errors.lastname : '' }
/>
</div>
</div>
{/* Type */}
<div className="md:flex md:space-x-7 items-end mb-6">
{/* <div className="field w-full mb-6 md:mb-0">
<InputCom
fieldClass="px-6"
label="Type"
type="text"
name="family_type"
placeholder="Family Type"
value={props.values.family_type}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
error={(props.errors.family_type && props.touched.family_type) ? props.errors.family_type : '' }
/>
</div> */}
<div className="field w-full mb-6 xl:mb-0">
<label
htmlFor="family_type"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1"
>
Family Type
{props.errors.family_type && props.touched.family_type && (
<span className="text-[12px] text-red-500">
{props.errors.family_type}
</span>
)}
</label>
<select
id="family_type"
name="family_type"
value={props.values.family_type}
className={`input-field p-2 mt-3 rounded-full placeholder:text-base text-dark-gray dark:text-white w-full h-10 bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none border`}
onChange={props.handleChange}
onBlur={props.handleBlur}
>
{relativeList?.loading ? (
<option className="text-slate-500 text-lg" value="">
Loading...
</option>
) : relativeList?.family_types?.length ? (
<>
<option className="text-slate-500 text-lg" value="">
Select Family Type
</option>
{relativeList?.family_types?.map((item, index) => (
<option
key={index}
className="text-slate-500 text-lg"
value={item?.ty}
>
{item?.ty}
</option>
))}
</>
) : (
<option className="text-slate-500 text-lg" value="">
No Options Found! Try Again
</option>
)}
</select>
</div>
<div className="field w-full flex justify-end">
<div className="flex">
{requestStatus.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : (
<button
type="submit"
className={`text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full ${(requestStatus.status || requestStatus.loading) && 'opacity-50'}`}
disabled={requestStatus.status || requestStatus.loading}
>
Send Message
</button>
)}
</div>
</div>
</div>
</div>
</div>
</Form>
);
}}
</Formik>
</div>
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
{requestStatus.message != "" &&
(!requestStatus.status ? (
<div
className={`w-full relative p-4 my-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
>
{requestStatus.message}
</div>
) : (
requestStatus.status && (
<div
className={`relative p-4 my-4 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>
)
))}
{/* End of error or success display */}
</div>
</div>
</ModalCom>
)
}
@@ -0,0 +1,73 @@
import React, { useState } from 'react'
import { handlePagingFunc } from '../../../Pagination/HandlePagination';
import PaginatedList from '../../../Pagination/PaginatedList';
export default function RelativeTable({relativeList}) {
// Handle Pagination
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentRelativeList = relativeList?.slice(indexOfFirstItem, indexOfLastItem);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
return (
<div className={`w-full overflow-hidden rounded-2xl`}>
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between min-h-[400px]">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{relativeList && relativeList?.length > 0 ? (
currentRelativeList.map((value, index) => (
<tr key={value.uid || index} className="border-b dark:border-[#5356fb29] hover:bg-gray-50">
<td className='p-2'>
<div className="flex flex-col">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.firstname && value.firstname} {value.lastname && value.lastname}
</h1>
<span className="text-sm text-thin-light-gray">
{value.email && value.email}
</span>
</div>
</td>
<td className='p-2'>
{/* <span>Family Type</span> */}
<span>{value.family_type && value.family_type.toUpperCase()}</span>
</td>
<td className='p-2 text-right'>
{value.status && value.status}
</td>
</tr>
))
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">No Members Found</td>
</tr>
)}
</>
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
relativeList?.length
? true
: false
}
data={relativeList}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
</div>
);
};
@@ -1,8 +1,68 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import RelativeTable from './RelativeTable'
import InviteRelative from './InviteRelative'
import usersService from '../../../../services/UsersService'
import LoadingSpinner from '../../../Spinners/LoadingSpinner'
const Relatives = () => {
const api = new usersService()
const [reloadRelList, setReloadRelList] = useState(false)
const [invitePopout, setInvitePopout] = useState(false)
const [relativeList, setRelativeList] = useState({loading: true, result_list:[], family_types:[]})
const showInviteMemberPopout = () => {
setInvitePopout(true)
}
const getRelativeList = () => {
setRelativeList(prev => ({...prev, loading: true}))
api.getFamilyRelativeList().then(response => {
let {status, data} = response
if(status != 200 || !data){
setRelativeList({loading:false, result_list:[], family_types:[]})
return
}
setRelativeList({loading:false, result_list:data?.result_list, family_types:data?.family_types})
}).catch(error => {
setRelativeList({loading:false, result_list:[], family_types:[]})
})
}
useEffect(()=>{
getRelativeList()
},[reloadRelList])
return (
<div>Relatives</div>
<>
<div className=''>
<div className='py-4'>
<button onClick={showInviteMemberPopout} className='text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full'>Invite</button>
<div className='my-4 border-b-2'></div>
</div>
<div className='min-h-[500px]'>
{relativeList.loading ?
<LoadingSpinner size='8' height='h-full' />
:
<RelativeTable relativeList={relativeList.result_list} />
}
</div>
</div>
{/* INVITE RELATIVE POPOUT */}
{invitePopout &&
<InviteRelative
action={()=>setInvitePopout(false)}
situation={invitePopout}
setReloadRelList={setReloadRelList}
relativeList={relativeList}
/>
}
{/* END OF INVITE RELATIVE POPOUT */}
</>
)
}
@@ -62,10 +62,14 @@ const FamilySettings = () => {
<span className={``}>Family Settings</span>
</h1>
</div>
<Link to="/acc-family">Go Back</Link>
<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" />
</svg>
Family
</Link>
</div>
{/* Something Here */}
{/* <form className="logout-modal-body w-full flex flex-col items-center px-10 py-8 gap-4"></form> */}
<div className="w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow h-full ">
<div className="update-table w-full h-full p-4 bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] lg:flex lg:px-10 px-4 justify-between">
<div className="content-tab-items lg:w-[230px] w-full mr-2">
@@ -0,0 +1,12 @@
import React from 'react'
import Layout from '../Partials/Layout'
import ParentWaiting from '../MyOffers/ParentWaiting'
export default function ParentWaitingLayout() {
return (
<Layout>
<ParentWaiting />
</Layout>
)
}
@@ -55,7 +55,6 @@ export default function FamilyProfile({ familyData, className }) {
year: familyData?.year,
month: familyData?.month,
enable_traking: familyData?.enable_traking,
action: 22020,
};
// const handleChange = ({ target: { name, value } }) => {
@@ -1,15 +1,16 @@
import React, { useEffect, useState } from 'react'
import ModalCom from '../../../Helpers/ModalCom'
import InputCom from '../../../Helpers/Inputs/InputCom'
import React, { useEffect, useState } from "react";
import ModalCom from "../../../Helpers/ModalCom";
import InputCom from "../../../Helpers/Inputs/InputCom";
import { Form, Formik } from "formik";
import * as Yup from "yup";
import {AmountTo2DP} from '../../../Helpers/PriceFormatter'
import usersService from '../../../../services/UsersService';
import LoadingSpinner from '../../../Spinners/LoadingSpinner';
import { PriceFormatter } from '../../../Helpers/PriceFormatter';
import { tableReload } from '../../../../store/TableReloads';
import { useDispatch } from 'react-redux';
import { AmountTo2DP } from "../../../Helpers/PriceFormatter";
import usersService from "../../../../services/UsersService";
import LoadingSpinner from "../../../Spinners/LoadingSpinner";
import { PriceFormatter } from "../../../Helpers/PriceFormatter";
import { tableReload } from "../../../../store/TableReloads";
import { useDispatch } from "react-redux";
import { apiConst } from "../../../../lib/apiConst";
const validationSchema = Yup.object().shape({
// amount: Yup.string()
@@ -22,104 +23,149 @@ const validationSchema = Yup.object().shape({
// return true;
// })
// .required("Amount is required"),
amount: Yup.number('Please enter a number')
.min(1, "Price must be greater than 0")
.required("Amount is required"),
comment: Yup.string()
.required("Comment is required"),
amount: Yup.number("Please enter a number")
.min(1, "Price must be greater than 0")
.required("Amount is required"),
comment: Yup.string().required("Comment is required"),
});
function FamilyAddFundPopout({action, situation, wallet, familyData}) {
function FamilyAddFundPopout({ action, situation, wallet, familyData }) {
const dispatch = useDispatch();
const dispatch = useDispatch()
const apiUrl = new usersService();
const apiUrl = new usersService()
const [startTransfer, setStartTransfer] = useState({loading:true, data: {}})
const [requestStatus, setRequestStatus] = useState({loading:false, status:false, message:''})
const [startTransfer, setStartTransfer] = useState({
loading: true,
data: {},
});
const [requestStatus, setRequestStatus] = useState({
loading: false,
status: false,
message: "",
});
// initial values for formik
let initialValues = {
amount: '',
from : AmountTo2DP(startTransfer?.data?.origing_current_balance*0.01),
amount: "",
from: AmountTo2DP(startTransfer?.data?.origing_current_balance * 0.01),
to: `${familyData.firstname} ${familyData.lastname}`,
comment: ''
comment: "",
};
// FUNCTION TO PERFORM FAMILY TRANSFER
const handleAddFund = (values) => {
setRequestStatus({loading:true, status:false, message:''})
setRequestStatus({ loading: true, status: false, message: "" });
let senderBal = startTransfer?.data?.origing_current_balance || '' // SENDER'S ACCOUNT BALANCE
let senderLimit = startTransfer?.data?.origing_transfer_limit || '' // SENDER'S TRANSFER LIMIT
let senderBal = startTransfer?.data?.origing_current_balance || ""; // SENDER'S ACCOUNT BALANCE
let senderLimit = startTransfer?.data?.origing_transfer_limit || ""; // SENDER'S TRANSFER LIMIT
let reqData = { // API REQUEST DATA
family_uid : familyData.uid,
wallet_uid : wallet.wallet_uid,
origing_wallet_uid : startTransfer?.data?.origing_wallet_uid,
currency : startTransfer?.data?.currency,
amount : values.amount*100,
description : values.comment,
family_transfer_mode : 100,
action : 22014
let reqData = {
// API REQUEST DATA
family_uid: familyData.uid,
wallet_uid: wallet.wallet_uid,
origing_wallet_uid: startTransfer?.data?.origing_wallet_uid,
currency: startTransfer?.data?.currency,
amount: values.amount * 100,
description: values.comment,
family_transfer_mode: 100,
action: apiConst.WRENCHBOARD_FAMILY_TRANSFER,
};
if (!senderBal || !senderLimit) {
// RETURNS UNAUTHORIZED, IF SENDER BAL OR LIMIT IS NOT AVAILABLE
setRequestStatus({
loading: false,
status: false,
message: "Unauthorized, try again later",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if(!senderBal || !senderLimit){ // RETURNS UNAUTHORIZED, IF SENDER BAL OR LIMIT IS NOT AVAILABLE
setRequestStatus({loading:false, status:false, message:'Unauthorized, try again later'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
}, 5000)
if (values.amount > senderBal * 0.01) {
// CHECKS TO SEE IF SENDER IS SENDING MORE THAN HIS BALANCE
setRequestStatus({
loading: false,
status: false,
message: "You cannot send more than your balance",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if(values.amount > senderBal*0.01){ // CHECKS TO SEE IF SENDER IS SENDING MORE THAN HIS BALANCE
setRequestStatus({loading:false, status:false, message:'You cannot send more than your balance'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
}, 5000)
if (values.amount > senderLimit * 0.01) {
// CHECKS TO SEE IF SENDER IS SENDING MORE THAN HIS LIMIT
setRequestStatus({
loading: false,
status: false,
message: `You cannot exceed ${senderLimit * 0.01} ${
startTransfer?.data?.origing_currency.charAt(0).toUpperCase() +
startTransfer?.data?.origing_currency.slice(1).toLowerCase()
}`,
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if(values.amount > senderLimit*0.01){ // CHECKS TO SEE IF SENDER IS SENDING MORE THAN HIS LIMIT
setRequestStatus({loading:false, status:false, message:`You cannot exceed ${senderLimit*0.01} ${startTransfer?.data?.origing_currency.charAt(0).toUpperCase() + startTransfer?.data?.origing_currency.slice(1).toLowerCase()}`})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
}, 5000)
}
apiUrl.familyTransfer(reqData).then(({data}) => {
if(data.internal_return < 0 || data.credit_confirm == '' || data.pay_confirm == ''){
setRequestStatus({loading:false, status:false, message:'Transfer Failed'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
}, 5000)
}
setRequestStatus({loading:false, status:true, message:'Transfer Successful'})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
dispatch(tableReload({ type: "WALLETTABLE" })); // UPDATES PARENT WALLET ACCOUNT
action() // TO CLOSE THE MODAL
}, 5000)
}).catch(error => {
setRequestStatus({loading:false, status:false, message:'Network Error, try again'})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
}, 5000)
})
}
apiUrl
.familyTransfer(reqData)
.then(({ data }) => {
if (
data.internal_return < 0 ||
data.credit_confirm == "" ||
data.pay_confirm == ""
) {
setRequestStatus({
loading: false,
status: false,
message: "Transfer Failed",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
}
setRequestStatus({
loading: false,
status: true,
message: "Transfer Successful",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
dispatch(tableReload({ type: "WALLETTABLE" })); // UPDATES PARENT WALLET ACCOUNT
action(); // TO CLOSE THE MODAL
}, 5000);
})
.catch((error) => {
setRequestStatus({
loading: false,
status: false,
message: "Network Error, try again",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
});
};
// LOAD FAMILY START TRANSFER
useEffect(()=>{
useEffect(() => {
let reqData = {
family_uid: familyData.uid,
wallet_uid: wallet.wallet_uid,
action: 22013
}
apiUrl.familyTransferStart(reqData).then(response => {
setStartTransfer({loading:false, data:response?.data })
}).catch(err => {
setStartTransfer({loading:false, data: {}})
})
},[])
action: apiConst.WRENCHBOARD_FAMILY_TRANSFERSTART,
};
apiUrl
.familyTransferStart(reqData)
.then((response) => {
setStartTransfer({ loading: false, data: response?.data });
})
.catch((err) => {
setStartTransfer({ loading: false, data: {} });
});
}, []);
return (
<ModalCom action={action} situation={situation}>
@@ -155,116 +201,125 @@ function FamilyAddFundPopout({action, situation, wallet, familyData}) {
</button>
</div>
<div className="logout-modal-body w-full flex flex-col items-center px-10 py-8">
{startTransfer.loading && <LoadingSpinner size='16' color='sky-blue' height={'h-64'} />}
{ !startTransfer.loading &&
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleAddFund}
>
{(props) => (
<Form className="w-full">
<div className="flex flex-col-reverse sm:flex-row">
<div className="fields w-full">
{/* AMOUNT */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="0"
label={`Amount (${startTransfer?.data?.currency})`}
name="amount"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9] ${props.errors.amount && props.touched.amount ? 'border border-red-500' : ''}`}
fieldClass="px-2 text-right"
value={props.values.amount}
inputHandler={props.handleChange}
/>
</div>
{startTransfer.loading && (
<LoadingSpinner size="16" color="sky-blue" height={"h-64"} />
)}
{/* FROM */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="From"
label={`From (${startTransfer?.data?.origing_currency})`}
name="from"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9]`}
fieldClass="px-2 text-right"
value={props.values.from}
disable={true}
/>
</div>
{/* TO */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="To"
label="To:"
name="to"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9]`}
fieldClass="px-2 text-right"
value={props.values.to}
disable={true}
/>
</div>
{/* COMMENT */}
<div className="field w-full mb-[0.5rem]">
<div className="w-full">
<label
htmlFor="Job Delivery Details"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
>
Comment
{/* {props.errors.comment && props.touched.comment && <span className='text-sm text-red-500'>{' '}{props.errors.comment}</span>} */}
</label>
<textarea
// id="Job Delivery Details"
rows="2"
className={`input-field px-3 py-2 placeholder:text-base text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] border ${props.errors.comment && props.touched.comment ? 'border border-red-500' : ''}`}
style={{ resize: "none" }}
name="comment"
value={props.values.comment}
onChange={props.handleChange}
/>
{!startTransfer.loading && (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleAddFund}
>
{(props) => (
<Form className="w-full">
<div className="flex flex-col-reverse sm:flex-row">
<div className="fields w-full">
{/* AMOUNT */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="0"
label={`Amount (${startTransfer?.data?.currency})`}
name="amount"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9] ${
props.errors.amount && props.touched.amount
? "border border-red-500"
: ""
}`}
fieldClass="px-2 text-right"
value={props.values.amount}
inputHandler={props.handleChange}
/>
</div>
{/* FROM */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="From"
label={`From (${startTransfer?.data?.origing_currency})`}
name="from"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9]`}
fieldClass="px-2 text-right"
value={props.values.from}
disable={true}
/>
</div>
{/* TO */}
<div className="field w-full mb-[0.5rem]">
<InputCom
placeholder="To"
label="To:"
name="to"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.3] mb-0"
inputClass={`flex-[0.7] input-curve lg border border-[#dce4e9]`}
fieldClass="px-2 text-right"
value={props.values.to}
disable={true}
/>
</div>
{/* COMMENT */}
<div className="field w-full mb-[0.5rem]">
<div className="w-full">
<label
htmlFor="Job Delivery Details"
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
>
Comment
{/* {props.errors.comment && props.touched.comment && <span className='text-sm text-red-500'>{' '}{props.errors.comment}</span>} */}
</label>
<textarea
// id="Job Delivery Details"
rows="2"
className={`input-field px-3 py-2 placeholder:text-base text-dark-gray dark:text-white w-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] border ${
props.errors.comment && props.touched.comment
? "border border-red-500"
: ""
}`}
style={{ resize: "none" }}
name="comment"
value={props.values.comment}
onChange={props.handleChange}
/>
</div>
</div>
{/* inputs ends here */}
</div>
{/* inputs ends here */}
</div>
</div>
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
<div className="content-footer w-full">
{/* error or success display */}
{requestStatus.message != "" &&
(!requestStatus.status ? (
<div
className={`relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
// className={`pb-1 absolute bottom-0 left-1/2 -translate-x-1/2 text-[#912741] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
>
{requestStatus.message}
</div>
) : (
requestStatus.status && (
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
<div className="content-footer w-full">
{/* error or success display */}
{requestStatus.message != "" &&
(!requestStatus.status ? (
<div
className={`relative p-4 text-green-700 bg-slate-200 border-slate-800 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
// className={`pb-1 absolute bottom-0 left-1/2 -translate-x-1/2 text-green-700 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
className={`relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
// className={`pb-1 absolute bottom-0 left-1/2 -translate-x-1/2 text-[#912741] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
>
{requestStatus.message}
</div>
)
))}
{/* End of error or success display */}
) : (
requestStatus.status && (
<div
className={`relative p-4 text-green-700 bg-slate-200 border-slate-800 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
// className={`pb-1 absolute bottom-0 left-1/2 -translate-x-1/2 text-green-700 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
>
{requestStatus.message}
</div>
)
))}
{/* End of error or success display */}
<div className="pt-2 w-full border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
<div className="w-full flex justify-between gap-2 items-center">
<div className="pt-2 w-full border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
<div className="w-full flex justify-between gap-2 items-center">
<button
type="button"
onClick={action}
@@ -273,29 +328,31 @@ function FamilyAddFundPopout({action, situation, wallet, familyData}) {
Cancel
</button>
<>
{requestStatus.loading ?
<LoadingSpinner size='6' color='sky-blue' />
:
<button
type="submit"
className={`w-[150px] h-[48px] rounded-full text-base text-white bg-sky-500 hover:bg-sky-400 ${requestStatus.status ? 'opacity-50' : ''}`}
disabled={requestStatus.status}
>
Send
</button>
}
{requestStatus.loading ? (
<LoadingSpinner size="6" color="sky-blue" />
) : (
<button
type="submit"
className={`w-[150px] h-[48px] rounded-full text-base text-white bg-sky-500 hover:bg-sky-400 ${
requestStatus.status ? "opacity-50" : ""
}`}
disabled={requestStatus.status}
>
Send
</button>
)}
</>
</div>
</div>
</div>
</div>
</Form>
)}
</Formik>
}
</Form>
)}
</Formik>
)}
</div>
</div>
</ModalCom>
)
);
}
export default FamilyAddFundPopout
export default FamilyAddFundPopout;
+1 -7
View File
@@ -102,13 +102,7 @@ export default function FamilyAcc() {
const memberList = useCallback(async () => {
setLoader(true);
try {
const reqData = {
limit: 20,
offset: 0,
action: 22010,
};
const res = await apiCall.familyListings(reqData);
const res = await apiCall.familyListings();
const { data } = res;
if (data?.internal_return >= 0 && data?.status === "OK") {
const { result_list, session_image_server } = data;
+18
View File
@@ -560,6 +560,24 @@ export default function Icons({ name }) {
src={localImgLoad("images/icons/family-pin.svg")}
alt="family-pin"
/>
) : name === "pending-job" ? (
<img
className="w-[19px] h-[19px]"
src={localImgLoad("images/icons/job_pending.svg")}
alt="Pending Job"
/>
) : name === "active-job" ? (
<img
className="w-[17px] h-[17px]"
src={localImgLoad("images/icons/job_active.svg")}
alt="Active Job"
/>
) : name === "job-list" ? (
<img
className="w-[17px] h-[17px]"
src={localImgLoad("images/icons/job_list.svg")}
alt="Job List"
/>
) : (
""
)}
@@ -27,6 +27,7 @@ export default function InputCom({
direction,
tabIndex,
error,
autoComplete="on"
}) {
const inputRef = useRef(null);
// Entry Validation
@@ -52,7 +53,7 @@ export default function InputCom({
<div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
{label && (
<label
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
className="input-label text-[#181c32] text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
htmlFor={name}
>
{label}
@@ -85,7 +86,7 @@ export default function InputCom({
className={`input-wrapper w-full rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-base ${
inputClass
? inputClass
: "text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] border"
: "text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] border"
}`}
>
<input
@@ -107,6 +108,7 @@ export default function InputCom({
readOnly={disable}
onBlur={blurHandler}
dir={direction}
autoComplete={autoComplete}
/>
{iconName && (
<div className="absolute right-6 bottom-3 z-10 flex gap-2">
+160 -10
View File
@@ -1,29 +1,179 @@
import React from "react";
import ParentWaiting from "../MyPendingJobs/ParentWaiting";
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import usersService from "../../services/UsersService";
import MyOffersFamilyTable from "../MyTasks/MyOffersFamilyTable";
import FamilyActiveLSlde from "./FamilyActiveLSlde";
import { useDispatch, useSelector } from "react-redux";
import { tableReload } from "../../store/TableReloads";
import LoadingSpinner from "../Spinners/LoadingSpinner";
export default function FamilyDash({ familyOffers, MyActiveJobList }) {
export default function FamilyDash({ MyActiveJobList, serverImg }) {
// console.log("PROPS IN FAMILY DASH->", familyOffers?.result_list);
const dispatch = useDispatch();
const userApi = new usersService();
const trending = MyActiveJobList;
const { familyBannersList } = useSelector((state) => state.familyBannersList);
const { familyResources:{ tab_categories } } = useSelector((state) => state.familyResources);
const { userDetails } = useSelector((state) => state?.userDetails);
let [reloadBanner, setReloadBanner] = useState(0)
// DO NOT UNCOMMENT THE CODE BELOW
// let [familyBannersList, setFamilyBannersList] = useState({loading:false, result:{}})
// const getFamilyBanners = async () => { // FUNCTION TO GET FAMILY BANNERS
// setFamilyBannersList({loading:true, result:[]});
// try {
// const res = await userApi.getFamilyBannersList();
// setFamilyBannersList({loading:false, result:res.data});
// console.log('TEST RESPONSE', res.data)
// } catch (error) {
// setFamilyBannersList({loading:false, result:[]});
// console.log("Error getting tasks");
// }
// };
// useEffect(()=>{
// getFamilyBanners()
// },[])
useEffect(()=>{
if(reloadBanner >= 2){
dispatch(tableReload({ type: "FAMILYBANNERSLIST" })); // RELOAD FAMILY BANNERS LIST EVERY 10 MINS
setReloadBanner(0)
}
const timer = setInterval(()=>{
setReloadBanner(prev => prev+1)
},300000)
return ()=>{
clearInterval(timer)
}
},[reloadBanner])
return (
<div>
<div className="home-page-wrapper">
{/* <CommonHead commonHeadData={props.commonHeadData} /> */}
{familyOffers?.result_list && familyOffers?.result_list.length > 0 && (
{/* 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>
</div>
<div className="w-full text-sm flex justify-end items-end">
<p className="leading-4">Last Login: {`${userDetails?.last_login.split(' ')[0]}`}</p>
</div>
</div>
{process.env.REACT_APP_SHOW_NEW_FAMILY_DASH == '1' &&
<>
{familyBannersList?.loading ?
<div className="w-full bg-white rounded-2xl">
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
</div>
:
familyBannersList?.result_list && Object.keys(familyBannersList?.result_list).length > 0 ?
// Loop for Family Banners
<div className="w-full mb-4 grid grid-cols-2 md:grid-cols-3 gap-2 md:gap-4">
{Object.keys(familyBannersList?.result_list).map((item, index) => {
let content = familyBannersList?.result_list[item]
// let action = item == 'recommend' ? 'familymarket' : 'mytask'
return (
<Link key={item} to={`/${content.banner.action}`} className={`rounded-xl bg-white dark:bg-dark-white shadow-md flex justify-center items-center transition-all duration-300 hover:shadow-sm`}>
<div className="h-full w-full">
<img className="w-full h-[10rem] object-cover rounded-t-xl" src={content.banner.image} alt='banner image' />
<div className="flex flex-col justify-between">
<div className="px-2 py-2 border-b border-transparent min-h-[4rem] flex flex-col gap-1">
<h1 className="text-lg text-[#083e21] dark:text-white font-bold tracking-wide">{content.banner.text}</h1>
<p className="text-sm text-black dark:text-white">{content.banner.description}</p>
</div>
</div>
</div>
</Link>
)
})}
</div>
:
null
}
{tab_categories?.data &&
<div className="mb-4">
<h1 className="my-4 text-26 font-bold text-dark-gray dark:text-white tracking-wide">Resources</h1>
<div className="w-full grid grid-cols-2 md:grid-cols-4 gap-2 md:gap-4">
{tab_categories.data.map((item) => {
// onClick={()=>navigate('/resources', {state:{tab:'created'}})}
let resourceState = ''
switch(item?.action){
case 'fam-blog':
resourceState = 'blog'
break
case 'ai-question':
resourceState = 'onsale'
break
case 'myfiles':
resourceState = 'created'
break
case 'ai-lab':
resourceState = 'onsale'
break
default:
resourceState = 'blog'
break
}
// console.log('EX', item.enabled, item?.action, resourceState)
if(item.enabled){
return (
<Link key={item.uid} to={'/resources'} state={{tab:resourceState}} className={`group rounded-xl bg-white dark:bg-dark-white shadow-md flex justify-center items-center transition-all duration-300 hover:shadow-sm`}>
<div className="h-full w-full">
<div className="w-full h-[8rem] rounded-t-xl overflow-hidden">
<img className="w-full h-full group-hover:scale-110 object-cover transition-all duration-300" src={item?.banner} alt='banner image' />
</div>
<div className="flex flex-col justify-between">
<div className="px-2 py-1 border-b border-transparent min-h-[2rem] flex justify-between items-center gap-1">
<h1 className="text-lg text-[#083e21] dark:text-white font-bold tracking-wide">{item?.content}</h1>
<div className="flex justify-center gap-1">
<div className="w-1 h-1 bg-slate-400 rounded-full"></div>
<div className="w-1 h-1 bg-slate-400 rounded-full"></div>
<div className="w-1 h-1 bg-slate-400 rounded-full"></div>
</div>
</div>
</div>
</div>
</Link>
)}
})}
</div>
</div>
}
</>
}
{/* {familyOffers?.result_list && familyOffers?.result_list.length > 0 && (
<MyOffersFamilyTable
familyOffers={familyOffers?.result_list}
image_server={familyOffers?.session_image_server}
className="mb-10"
/>
)}
{trending && trending.length > 0 && (
<FamilyActiveLSlde trending={trending} className="mb-10" image_server={familyOffers?.session_image_server} />
)}
)} */}
{/*<TopSellerTopBuyerSliderSection className="mb-10" />*/}
<ParentWaiting className="mb-10" />
{trending && trending.length > 0 && (
<FamilyActiveLSlde
trending={trending}
className="mb-10"
image_server={serverImg}
/>
)}
</div>
</div>
);
+67 -27
View File
@@ -1,25 +1,72 @@
import { useSelector } from "react-redux";
import {
AccountDashboard,
FamilyParentDashboard,
HomeDashboard,
JobOwnerDashboard,
WorkerDashboard,
} from "../Dashboards";
import MyJobTable from "../MyTasks/MyJobTable";
import MyOffersTable from "../MyTasks/MyOffersTable";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import Hero from "./Hero";
import HomeActivities from "./HomeActivities";
export default function FullAccountDash(props) {
// console.log("PROPS IN HOME->", props);
const { userDetails } = useSelector((state) => state?.userDetails);
const renderDashboard = () => {
switch (props.dashTypes) {
case "DEFAULT_HOME_DASH":
return (
<HomeDashboard
className="mb-4"
data={userDetails}
bannerList={props.bannerList}
nextDueTask={props.nextDueTask}
/>
);
case "FAMILY_PARENT_DASH":
return (
<FamilyParentDashboard
className="mb-4"
data={userDetails}
bannerList={props.bannerList}
nextDueTask={props.nextDueTask}
/>
);
case "WORKER_HOME_DASH":
return (
<WorkerDashboard
className="mb-4"
data={userDetails}
bannerList={props.bannerList}
nextDueTask={props.nextDueTask}
/>
);
case "JOBOWNER_HOME_DASH":
return (
<JobOwnerDashboard
className="mb-4"
data={userDetails}
bannerList={props.bannerList}
nextDueTask={props.nextDueTask}
/>
);
default:
return null;
}
};
return (
<>
<div className="home-page-wrapper">
<Hero
className="mb-10"
data={userDetails}
bannerList={props.bannerList}
nextDueTask={props.nextDueTask}
/>
{props.offersList?.data?.result_list?.length ? (
{renderDashboard()}
{process.env.REACT_APP_SHOW_ACCOUNT_DASH == "1" && (
<AccountDashboard className="mb-4" bannerList={props.bannerList} />
)}
{props?.dashTypes !== "undefined" &&
props.offersList?.data?.result_list?.length ? (
<MyOffersTable
MyActiveOffersList={props.offersList?.data}
className="mb-10"
@@ -37,24 +84,17 @@ export default function FullAccountDash(props) {
imageServer={props.offersList?.data?.session_image_server}
/>
</>
) : !props.offersList?.loading && !props.MyActiveJobList?.loading ? (
<HomeActivities className="mb-10" />
) : (
<div className="w-full h-[220px] flex items-center justify-center">
<LoadingSpinner size="16" color="sky-blue" />
</div>
)}
{/*<UpdateTable className="mb-10"/>*/}
{/*<SellHistoryMarketVisitorAnalytic className="mb-10"/>*/}
{/*<TopSellerTopBuyerSliderSection className="mb-10" />*/}
{/*<HomeTaskDisplay*/}
{/* jobData={jobData}*/}
{/* className="mb-10"*/}
{/* bannerList={props.bannerList}*/}
{/*/>*/}
) : null}
</div>
</>
);
}
// : !props.offersList?.loading && !props.MyActiveJobList?.loading ? (
// <HomeActivities className="mb-10" />
// )
// : (
// <div className="w-full h-[220px] flex items-center justify-center">
// <LoadingSpinner size="16" color="sky-blue" />
// </div>
// )
+1 -1
View File
@@ -53,7 +53,7 @@ export default function HomeActivities({ className }) {
return (
<div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow relative min-h-[520px] ${
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl relative min-h-[520px] ${
className || ""
}`}
>
+6 -3
View File
@@ -60,8 +60,9 @@ export default function Home(props) {
const fetchData = async () => {
await Promise.all([getHomeDate(), getMyOffersList()]);
};
fetchData();
if(userDetails?.account_type == 'FULL'){
fetchData();
}
}, []);
useEffect(() => {
@@ -75,13 +76,15 @@ export default function Home(props) {
<FamilyDash
account={userDetails}
commonHeadData={props.bannerList}
familyOffers={MyOffersList?.data}
// familyOffers={MyOffersList?.data}
serverImg = {userDetails?.session_image_server}
MyActiveJobList={MyActiveJobList?.data}
/>
) : userDetails && userDetails?.account_type == "FULL" ? (
<FullAccountDash
nextDueTask={nextDueTask}
bannerList={props.bannerList}
dashTypes={props.dashTypes}
offersList={MyOffersList}
MyActiveJobList={MyActiveJobList}
/>
+84 -58
View File
@@ -1,69 +1,93 @@
import React, { useState } from 'react'
import React, { useState } from "react";
import ModalCom from '../Helpers/ModalCom'
import LoadingSpinner from '../Spinners/LoadingSpinner'
import InputCom from '../Helpers/Inputs/InputCom/index'
import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import InputCom from "../Helpers/Inputs/InputCom/index";
import usersService from '../../services/UsersService'
import usersService from "../../services/UsersService";
import { apiConst } from "../../lib/apiConst";
export default function AddGroup({action, situation , setUpdateList}) {
export default function AddGroup({ action, situation, setUpdateList }) {
const api = new usersService();
const api = new usersService()
const [name, setName] = useState("");
const [name, setName] = useState('')
const handleChange = ({ target: { name, value } }) => {
setName(value);
};
const handleChange = ({target:{name, value}}) =>{
setName(value)
}
let [requestStatus, setRequestStatus] = useState({
loading: false,
status: false,
message: "",
}); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER
let [requestStatus, setRequestStatus] = useState({
const addGroup = () => {
setRequestStatus({ loading: true, status: false, message: "" });
if (name == "") {
setRequestStatus({
loading: false,
status: false,
message: "",
}); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER
const addGroup = () => {
setRequestStatus({loading:true, status:false, message:''})
if(name == ''){
setRequestStatus({loading:false, status:false, message:'Please enter a group name'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
},3000)
}
if(name.length < 6){
setRequestStatus({loading:false, status:false, message:'Group name must be up to six characters'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
},3000)
}
api.jobGroupAdd({group_name:name, action:13025}).then(response => {
let {status, data} = response
if(status != 200 || data.internal_return < 0){
setRequestStatus({loading:false, status:false, message:'Unable to add Group'})
return
}
setRequestStatus({loading:false, status:true, message:'Group Added'})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
// close modal
action()
// reload group page
setUpdateList(prev => !prev)
},3000)
}).catch(error => {
setRequestStatus({loading:false, status:false, message:'Unable to add Group, try again later'})
}).finally(()=>{
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message:''})
},3000)
})
message: "Please enter a group name",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
}
if (name.length < 6) {
setRequestStatus({
loading: false,
status: false,
message: "Group name must be up to six characters",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
}
api
.jobGroupAdd({
group_name: name,
action: apiConst.WRENCHBOARD_JOB_OFFER_SYSTEM,
})
.then((response) => {
let { status, data } = response;
if (status != 200 || data.internal_return < 0) {
setRequestStatus({
loading: false,
status: false,
message: "Unable to add Group",
});
return;
}
setRequestStatus({
loading: false,
status: true,
message: "Group Added",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
// close modal
action();
// reload group page
setUpdateList((prev) => !prev);
}, 3000);
})
.catch((error) => {
setRequestStatus({
loading: false,
status: false,
message: "Unable to add Group, try again later",
});
})
.finally(() => {
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
});
};
return (
<ModalCom
action={action}
situation={situation}
>
<ModalCom action={action} situation={situation}>
<div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] ">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
@@ -98,7 +122,7 @@ export default function AddGroup({action, situation , setUpdateList}) {
<div className="logout-modal-body w-full flex flex-col items-center px-10 py-8">
<div className="mb-6 w-full">
<div className="input-item">
<InputCom
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={name}
@@ -108,7 +132,7 @@ export default function AddGroup({action, situation , setUpdateList}) {
type="text"
inputHandler={handleChange}
// iconName="message"
/>
/>
</div>
</div>
<div className="w-full flex justify-between items-center gap-4">
@@ -117,7 +141,9 @@ export default function AddGroup({action, situation , setUpdateList}) {
type="button"
className="text-base text-light-red tracking-wide "
>
<span className="border-b dark:border-[#5356fb29] border-light-red">Cancel</span>
<span className="border-b dark:border-[#5356fb29] border-light-red">
Cancel
</span>
</button>
{requestStatus.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
@@ -153,5 +179,5 @@ export default function AddGroup({action, situation , setUpdateList}) {
</div>
</div>
</ModalCom>
)
);
}
+1 -1
View File
@@ -73,7 +73,7 @@ export default function DeleteGroup({action, situation, details}) {
</div>
<div className="mb-6">
<p className="text-xl text-center tracking-wide text-dark-gray dark:text-white">
Are you sure, you want to delete <br /> <span>'{details?.group_name}'</span>
Are you sure, you want to delete <br /> <span>'{details?.group_name}'</span> group?
</p>
</div>
<div className="flex space-x-2.5">
+3 -3
View File
@@ -23,7 +23,7 @@ export default function DeleteMember({action, situation, details}) {
<div className="logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="logout-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b border-light-purple dark:border-[#5356fb29] ">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
Delete Member
Remove Member
</h1>
<button
type="button"
@@ -73,7 +73,7 @@ export default function DeleteMember({action, situation, details}) {
</div>
<div className="mb-6">
<p className="text-xl text-center tracking-wide text-dark-gray dark:text-white">
Are you sure, you want to delete <br /> <span>'{details?.firstname} {details.lastname}'</span>
Are you sure, you want to remove <br /> <span>'{details?.firstname} {details.lastname}'</span>
</p>
</div>
<div className="flex space-x-2.5">
@@ -92,7 +92,7 @@ export default function DeleteMember({action, situation, details}) {
type="button"
className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full"
>
Confirm Delete
Remove
</button>
)}
</div>
+92 -60
View File
@@ -1,72 +1,104 @@
import React, { useState } from 'react'
import React, { useState } from "react";
import InputCom from '../../components/Helpers/Inputs/InputCom/index'
import DeleteGroup from './DeleteGroup'
import AddGroup from './AddGroup'
import AddGroup from "./AddGroup";
import DeleteGroup from "./DeleteGroup";
import { localImgLoad } from "../../lib";
export default function GroupList({groupList, selectedGroup, changeSelectedGroup, setUpdateList}) {
export default function GroupList({
groupList,
selectedGroup,
changeSelectedGroup,
setUpdateList,
}) {
const [deletePopout, setDeletePopout] = useState({
status: false,
data: {},
});
const [deletePopout, setDeletePopout] = useState({
status: false,
data: {}
})
const [addGroupPopout, setAddGroupPopout] = useState(false);
const [addGroupPopout, setAddGroupPopout] = useState(false)
const handleAddGroup = () => {
setAddGroupPopout(true)
}
const handleDeleteGroup = (item) => {
setDeletePopout({
status: true,
data: {...item}
})
}
const handleAddGroup = () => {
setAddGroupPopout(true);
};
const handleDeleteGroup = (item) => {
setDeletePopout({
status: true,
data: { ...item },
});
};
return (
<>
<div className='p-5 w-full lg:w-[400px] min-h-[300px] bg-sky-100 dark:bg-dark-gray rounded-2xl'>
{/* <h1 className='mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100'>Jobs Groups</h1> */}
<div className='flex justify-end items-center'>
<button onClick={handleAddGroup} className='py-2 px-4 flex justify-center items-center bg-sky-blue hover:bg-sky-600 text-base rounded-full text-white font-bold'>Add Group</button>
</div>
{groupList && groupList.length < 1 ?
<h1 className='my-5 text-lg tracking-wide text-slate-900 dark:text-slate-100'>No Group Found!</h1>
:
<div className='my-4 max-h-[400px] overflow-y-auto'>
<div className='flex flex-col'>
{groupList.map(item=> (
<div key={item.group_uid} className='p-2 flex gap-2 items-center justify-between w-full'>
<div className='flex gap-2 items-center'>
<input type='radio' name='grouplist' value={item.group_id} checked={selectedGroup?.id == item?.group_id} onChange={changeSelectedGroup} className='w-[20px] h-[20px] outline-none' />
<p className='text-sm lg:text-base text-slate-900 dark:text-slate-100'>{item.group_name}</p>
</div>
<button onClick={()=>{handleDeleteGroup(item)}} className='rounded-lg text-sm bg-red-500 hover:bg-red-400 text-white font-bold py-1 px-2.5 flex justify-center items-center'>X</button>
</div>
))}
</div>
</div>
}
<div className="p-5 w-full lg:w-[400px] min-h-[300px] bg-sky-100 dark:bg-dark-gray rounded-2xl flex flex-col">
{/* <h1 className='mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100'>Jobs Groups</h1> */}
<div className="flex justify-end items-center">
<button
onClick={handleAddGroup}
className="py-2 px-4 flex justify-center items-center bg-sky-blue hover:bg-sky-600 text-base rounded-full text-white font-bold"
>
Add Group
</button>
</div>
{deletePopout.status &&
<DeleteGroup
action={()=>setDeletePopout({status:false, data:{}})}
situation={deletePopout.status}
details={deletePopout.data}
/>
}
{addGroupPopout &&
<AddGroup
action={()=>setAddGroupPopout(false)}
situation={addGroupPopout}
setUpdateList={setUpdateList}
/>
}
{groupList && groupList.length < 1 ? (
<h1 className="my-5 text-lg tracking-wide text-slate-900 dark:text-slate-100">
No Group Found!
</h1>
) : (
<div className="my-4 max-h-[596px] bg-[#fffef6] rounded overflow-y-auto flex-1">
<div className="flex flex-col">
{groupList.map((item) => (
<div
key={item.group_uid}
className="p-2 flex gap-2 items-center justify-between w-full"
>
<div className="flex gap-2 items-center">
<input
type="radio"
name="grouplist"
value={item.group_id}
checked={selectedGroup?.id == item?.group_id}
onChange={changeSelectedGroup}
className="w-[20px] h-[20px] outline-none"
/>
<p className="text-sm lg:text-base text-slate-900 dark:text-slate-100">
{item.group_name}
</p>
</div>
<button
onClick={() => {
handleDeleteGroup(item);
}}
className="flex relative items-center justify-center border-0 w-6 h-6"
>
<img
src={localImgLoad("images/icons/remove_grp.svg")}
alt="remove-icon"
/>
</button>
</div>
))}
</div>
</div>
)}
</div>
{deletePopout.status && (
<DeleteGroup
action={() => setDeletePopout({ status: false, data: {} })}
situation={deletePopout.status}
details={deletePopout.data}
/>
)}
{addGroupPopout && (
<AddGroup
action={() => setAddGroupPopout(false)}
situation={addGroupPopout}
setUpdateList={setUpdateList}
/>
)}
</>
)
);
}
+109 -89
View File
@@ -1,98 +1,118 @@
import React, { useState } from 'react'
import { handlePagingFunc } from '../Pagination/HandlePagination';
import PaginatedList from '../Pagination/PaginatedList';
import DeleteMember from './DeleteMember';
import React, { useState } from "react";
import { handlePagingFunc } from "../Pagination/HandlePagination";
import PaginatedList from "../Pagination/PaginatedList";
import DeleteMember from "./DeleteMember";
import { localImgLoad } from "../../lib";
export default function GroupMemberTable({selectedList}) {
// Handle Pagination
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
export default function GroupMemberTable({ selectedList }) {
// Handle Pagination
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentSelectedList = selectedList?.slice(indexOfFirstItem, indexOfLastItem);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
const currentSelectedList = selectedList?.slice(
indexOfFirstItem,
indexOfLastItem
);
const [deletePopout, setDeletePopout] = useState({
status: false,
data: {}
})
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
const handleDeleteMember = (item) => {
setDeletePopout({
status: true,
data: {...item}
})
}
return (
<div className={`w-full p-8 bg-white dark:bg-dark-gray overflow-hidden rounded-2xl section-shadow`}>
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between min-h-[400px]">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{selectedList && selectedList?.length > 0 ? (
currentSelectedList.map((value, index) => (
<tr key={value.uid} className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
{/* <td className="p-1">{value?.firstname}</td>
const [deletePopout, setDeletePopout] = useState({
status: false,
data: {},
});
const handleDeleteMember = (item) => {
setDeletePopout({
status: true,
data: { ...item },
});
};
return (
<div
className={`w-full p-8 dark:bg-dark-gray overflow-hidden rounded-2xl section-shado bg-[#fffef6]`}
>
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between min-h-[400px]">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{selectedList && selectedList?.length > 0 ? (
currentSelectedList.map((value, index) => (
<tr
key={value.uid}
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
>
{/* <td className="p-1">{value?.firstname}</td>
<td className="p-1">{value?.lastname}</td>
<td className="p-1">{value?.email}</td>
<td className="p-1 text-right">
<button onClick={()=>{handleDeleteMember(value)}} className='rounded-lg text-sm bg-red-500 hover:bg-red-400 text-white font-bold py-1 px-2.5'>X</button>
</td> */}
<td className='py-2'>
<div className="flex flex-col">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.firstname && value.firstname} {value.lastname && value.lastname}
</h1>
<span className="text-sm text-thin-light-gray">
{value.email && value.email}
</span>
</div>
</td>
<td className='py-2 text-right'>
<button onClick={()=>{handleDeleteMember(value)}} className='rounded-lg text-sm bg-red-500 hover:bg-red-400 text-white font-bold py-1 px-2.5'>X</button>
</td>
</tr>
))
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">No Members Found</td>
</tr>
)}
</>
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
selectedList?.length
? true
: false
}
data={selectedList}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
{/* DELETE MEMBER POPOUT */}
{deletePopout.status &&
<DeleteMember
action={()=>setDeletePopout({status:false, data:{}})}
situation={deletePopout.status}
details={deletePopout.data}
/>
}
{/* END OF DELETE MEMBER POPOUT */}
</div>
);
};
<td className="py-2">
<div className="flex flex-col">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.firstname && value.firstname}{" "}
{value.lastname && value.lastname}
</h1>
<span className="text-sm text-thin-light-gray">
{value.email && value.email}
</span>
</div>
</td>
<td className="py-2 text-right">
<button
onClick={() => {
handleDeleteMember(value);
}}
className="flex relative items-center justify-center border-0 w-8 h-8"
>
<img
src={localImgLoad("images/icons/remove_grp.svg")}
alt="remove-icon"
/>
</button>
</td>
</tr>
))
) : (
<tr className="font-semibold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">No Members Found. Please add</td>
</tr>
)}
</>
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
selectedList?.length
? true
: false
}
data={selectedList}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
{/* DELETE MEMBER POPOUT */}
{deletePopout.status && (
<DeleteMember
action={() => setDeletePopout({ status: false, data: {} })}
situation={deletePopout.status}
details={deletePopout.data}
/>
)}
{/* END OF DELETE MEMBER POPOUT */}
</div>
);
}
+105 -65
View File
@@ -1,79 +1,119 @@
import React, { useEffect, useState } from 'react'
import Layout from '../Partials/Layout'
import React, { useEffect, useState } from "react";
import Layout from "../Partials/Layout";
import GroupList from './GroupList'
import MemberList from './MemberList'
import LoadingSpinner from '../Spinners/LoadingSpinner'
import GroupList from "./GroupList";
import MemberList from "./MemberList";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import usersService from '../../services/UsersService'
import usersService from "../../services/UsersService";
export default function JobGroups() {
const userApi = new usersService();
const userApi = new usersService();
const [updateList, setUpdateList] = useState(false);
const [updateList, setUpdateList] = useState(false)
const [groupList, setGroupList] = useState({
loading: true,
groups: [],
members: [],
});
const [groupList, setGroupList] = useState({
loading:true,
groups: [],
members: []
})
const [selectedGroup, setSelectedGroup] = useState({
id: "",
name: "",
data: [],
});
const [selectedGroup, setSelectedGroup] = useState({id:'', name:'', data: []})
const changeSelectedGroup = (e) => {
let groupID = e.target.value;
const activeMembers = groupList?.members?.filter(
(item) => item.group_id == groupID
);
const activeGroup = groupList?.groups?.filter(
(item) => item.group_id == groupID
);
setSelectedGroup({
id: groupID,
name: activeGroup[0]?.group_name,
data: activeMembers,
});
};
const changeSelectedGroup = (e) => {
let groupID = e.target.value
const activeMembers = groupList?.members?.filter(item => item.group_id == groupID)
const activeGroup = groupList?.groups?.filter(item => item.group_id == groupID)
setSelectedGroup({id: groupID, name:activeGroup[0]?.group_name, data:activeMembers})
}
useEffect(()=>{
setGroupList({loading: true, groups: [], members: []})
userApi.jobGroupList({}).then(res => {
const {status, data} = res
if(status != 200 || data?.internal_return < 0){
setGroupList({loading: false, groups: [], members: []})
return
}
if(data.result_list.length < 0){
setGroupList({loading: false, groups: [], members: []})
return
}
setGroupList({loading: false, groups: data.result_list, members: data.result_list_member})
if(selectedGroup.id == ''){
let activeGroupId = data.result_list[0].group_id
let activeGroup = data.result_list[0].group_name
let activeMembers = data.result_list_member?.filter(item => item.group_id == activeGroupId)
setSelectedGroup({id: activeGroupId, name:activeGroup, data:activeMembers})
}else{
let activeMembers = data.result_list_member?.filter(item => item.group_id == selectedGroup?.id)
setSelectedGroup({id: selectedGroup?.id, name:selectedGroup?.name, data:activeMembers})
}
}).catch(error => {
setGroupList({loading: false, groups: [], members: []})
console.log(error)
})
},[updateList])
useEffect(() => {
setGroupList({ loading: true, groups: [], members: [] });
userApi
.jobGroupList({})
.then((res) => {
const { status, data } = res;
if (status != 200 || data?.internal_return < 0) {
setGroupList({ loading: false, groups: [], members: [] });
return;
}
if (data.result_list.length < 0) {
setGroupList({ loading: false, groups: [], members: [] });
return;
}
setGroupList({
loading: false,
groups: data.result_list,
members: data.result_list_member,
});
if (selectedGroup.id == "") {
let activeGroupId = data.result_list[0].group_id;
let activeGroup = data.result_list[0].group_name;
let activeMembers = data.result_list_member?.filter(
(item) => item.group_id == activeGroupId
);
setSelectedGroup({
id: activeGroupId,
name: activeGroup,
data: activeMembers,
});
} else {
let activeMembers = data.result_list_member?.filter(
(item) => item.group_id == selectedGroup?.id
);
setSelectedGroup({
id: selectedGroup?.id,
name: selectedGroup?.name,
data: activeMembers,
});
}
})
.catch((error) => {
setGroupList({ loading: false, groups: [], members: [] });
console.log(error);
});
}, [updateList]);
return (
<Layout>
<div>
<h1 className='mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100'>Jobs Groups</h1>
</div>
<div className='p-5 w-full min-h-[400px] flex flex-col lg:flex-row gap-3 lg:gap-6 rounded-lg shadow-md bg-white dark:bg-dark-white'>
{groupList.loading ?
<div className='w-full h-[400px] flex justify-center items-center'>
<LoadingSpinner size='16' />
</div>
:
<>
<GroupList groupList={groupList?.groups} selectedGroup={selectedGroup} changeSelectedGroup={changeSelectedGroup} setUpdateList={setUpdateList} />
<MemberList groupList={groupList?.groups} selectedGroup={selectedGroup} setUpdateList={setUpdateList} />
</>
}
</div>
<div>
<h1 className="mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100">
Job Groups
</h1>
</div>
<div className="p-5 w-full min-h-[400px] flex flex-col lg:flex-row gap-3 lg:gap-6 rounded-lg shadow-md bg-white dark:bg-dark-white">
{groupList.loading ? (
<div className="w-full h-[400px] flex justify-center items-center">
<LoadingSpinner size="16" />
</div>
) : (
<>
<GroupList
groupList={groupList?.groups}
selectedGroup={selectedGroup}
changeSelectedGroup={changeSelectedGroup}
setUpdateList={setUpdateList}
/>
<MemberList
groupList={groupList?.groups}
selectedGroup={selectedGroup}
setUpdateList={setUpdateList}
/>
</>
)}
</div>
</Layout>
)
);
}
+276 -243
View File
@@ -1,262 +1,295 @@
import React, { useState } from 'react'
import React, { useState } from "react";
import InputCom from '../../components/Helpers/Inputs/InputCom/index'
import LoadingSpinner from '../Spinners/LoadingSpinner'
import GroupMemberTable from './GroupMemberTable'
import InputCom from "../../components/Helpers/Inputs/InputCom/index";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import GroupMemberTable from "./GroupMemberTable";
import EmailValidator from '../../lib/EmailValidator'
import EmailValidator from "../../lib/EmailValidator";
import usersService from '../../services/UsersService'
import { apiConst } from "../../lib/apiConst";
import usersService from "../../services/UsersService";
export default function MemberList({groupList, selectedGroup, setUpdateList}) {
export default function MemberList({
groupList,
selectedGroup,
setUpdateList,
}) {
const api = new usersService();
const api = new usersService()
const [fields, setFields] = useState({
firstname: "",
lastname: "",
email: "",
});
const [fields, setFields] = useState({
firstname: '',
lastname: '',
email: ''
})
const handleFieldsChange = ({ target: { name, value } }) => {
setFields((prev) => ({ ...prev, [name]: value }));
// let error = requestState?.errors?.indexOf(name) //// checks if the input field was in error array and removes it when the input changes
// if(error >= 0){
// let oldErrorArr = requestState.errors
// let newErrorArr = oldErrorArr.splice(error, 1)
// setRequestState(prev => ({...prev, errors:oldErrorArr}))
// }
const handleFieldsChange = ({target:{name, value}}) => {
setFields(prev => ({...prev, [name]:value}))
// let error = requestState?.errors?.indexOf(name) //// checks if the input field was in error array and removes it when the input changes
// if(error >= 0){
// let oldErrorArr = requestState.errors
// let newErrorArr = oldErrorArr.splice(error, 1)
// setRequestState(prev => ({...prev, errors:oldErrorArr}))
// }
if(value == ''){
setRequestState({
loading: false,
status: false,
message: '',
data: [],
errors: [name]
})
}else{
let error = requestState?.errors?.indexOf(name) //// checks if the input field was in error array and removes it when the input changes
if(error >= 0){
let oldErrorArr = requestState.errors
let newErrorArr = oldErrorArr.splice(error, 1)
setRequestState(prev => ({...prev, errors:oldErrorArr}))
}
}
if(name == 'email'){
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (!EmailValidator(value)) {
setRequestState({
loading: false,
status: false,
message: '',
data: [],
errors: ['email']
})
}
}
}
const [requestState, setRequestState] = useState({
if (value == "") {
setRequestState({
loading: false,
status: false,
message: '',
message: "",
data: [],
errors: ['email', 'firstname', 'lastname']
})
const addMember = () => {
// let errors = Object.keys(fields).filter((item) => { // CHECKS FOR EMPTY STRINGS
// if(typeof item == 'string' && fields[item] === ''){
// return item
// }
// })
// if(errors.length){
// setRequestState({
// loading: false,
// status: false,
// message: '',
// data: [],
// errors: [...errors]
// })
// return
// }
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (!EmailValidator(fields.email)) {
setRequestState({
loading: false,
status: false,
message: 'Email is invalid',
data: [],
errors: []
})
return setTimeout(()=>{
setRequestState({
loading: false,
status: false,
message: '',
data: [],
errors: []
})
},3000)
}
setRequestState({
loading: true,
status: false,
message: '',
data: [],
errors: []
})
const requestData = {
firstname:fields.firstname,lastname:fields.lastname, email:fields.email, group_id: selectedGroup?.id, action:13015
}
api.groupMemberAdd(requestData).then(response => {
let {status, data} = response
if(status != 200 || data?.internal_return < 0){
setRequestState({
loading: false,
status: false,
message: 'Unable to add member',
data: [],
errors: []
})
return
}
setRequestState({
loading: false,
status: true,
message: 'Member added',
data: [],
errors: []
})
setTimeout(()=>{
// trigger group page reload
setUpdateList(prev => !prev)
setRequestState({
loading: false,
status: false,
message: '',
data: [],
errors: []
})
}, 3000)
}).catch(error=>{
setRequestState({
loading: false,
status: false,
message: 'Something went wrong, try again',
data: [],
errors: []
})
}).finally(()=>{
setTimeout(()=>{
setRequestState({
loading: false,
status: false,
message: '',
data: [],
errors: []
})
setFields({
firstname: '',
lastname: '',
email: ''
})
}, 3000)
})
errors: [name],
});
} else {
let error = requestState?.errors?.indexOf(name); //// checks if the input field was in error array and removes it when the input changes
if (error >= 0) {
let oldErrorArr = requestState.errors;
let newErrorArr = oldErrorArr.splice(error, 1);
setRequestState((prev) => ({ ...prev, errors: oldErrorArr }));
}
}
if (name == "email") {
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (!EmailValidator(value)) {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: ["email"],
});
}
}
};
const [requestState, setRequestState] = useState({
loading: false,
status: false,
message: "",
data: [],
errors: ["email", "firstname", "lastname"],
});
const addMember = () => {
// let errors = Object.keys(fields).filter((item) => { // CHECKS FOR EMPTY STRINGS
// if(typeof item == 'string' && fields[item] === ''){
// return item
// }
// })
// if(errors.length){
// setRequestState({
// loading: false,
// status: false,
// message: '',
// data: [],
// errors: [...errors]
// })
// return
// }
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (!EmailValidator(fields.email)) {
setRequestState({
loading: false,
status: false,
message: "Email is invalid",
data: [],
errors: [],
});
return setTimeout(() => {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
}, 3000);
}
setRequestState({
loading: true,
status: false,
message: "",
data: [],
errors: [],
});
const requestData = {
firstname: fields.firstname,
lastname: fields.lastname,
email: fields.email,
group_id: selectedGroup?.id,
action: apiConst.WRENCHBOARD_JOB_GROUP_MEMBER,
};
api
.groupMemberAdd(requestData)
.then((response) => {
let { status, data } = response;
if (status != 200 || data?.internal_return < 0) {
setRequestState({
loading: false,
status: false,
message: "Unable to add member",
data: [],
errors: [],
});
return;
}
setRequestState({
loading: false,
status: true,
message: "Member added",
data: [],
errors: [],
});
setTimeout(() => {
// trigger group page reload
setUpdateList((prev) => !prev);
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
}, 3000);
})
.catch((error) => {
setRequestState({
loading: false,
status: false,
message: "Something went wrong, try again",
data: [],
errors: [],
});
})
.finally(() => {
setTimeout(() => {
setRequestState({
loading: false,
status: false,
message: "",
data: [],
errors: [],
});
setFields({
firstname: "",
lastname: "",
email: "",
});
}, 3000);
});
};
return (
<>
<div className='p-5 w-full min-h-[600px] overflow-y-auto'>
{groupList && groupList.length < 1 ?
<>
<h1 className='my-5 text-lg lg:text-xl tracking-wide text-slate-900 dark:text-slate-100'>You Currently Do not have any Group, Please Add Group</h1>
</>
:
<>
<h1 className='mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100'>{selectedGroup?.name}</h1>
<div className='w-full flex flex-col-reverse lg:flex-col'>
<div className='py-3 w-full'>
<div className='relative grid grid-cols-1 sm:grid-cols-2 gap-2 place-content-center'>
<div className="input-item">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.firstname}
inputHandler={handleFieldsChange}
placeholder="First Name"
// label="Firstname"
name="firstname"
type="text"
// iconName="message"
/>
</div>
<div className="input-item">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.lastname}
inputHandler={handleFieldsChange}
placeholder="Last Name"
// label="Lastname"
name="lastname"
type="text"
// iconName="message"
/>
</div>
<div className="input-item w-full sm:w-[150%]">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.email}
inputHandler={handleFieldsChange}
placeholder="Email"
// label="Email"
name="email"
type="email"
// iconName="message"
/>
</div>
<div className='flex justify-end items-end'>
{requestState.loading ?
<LoadingSpinner size='8' color='sky-blue' />
:
<button
onClick={addMember}
disabled={requestState.loading || requestState.status || requestState.errors.length}
className={`py-2 px-4 h-[42px] flex justify-center items-center text-base rounded-full text-white font-bold transition-all duration-500 ${requestState.loading || requestState.status || requestState.errors.length ? 'bg-sky-blue/50' : 'bg-sky-blue hover:bg-sky-600'} `}
>
Add Member
</button>
}
</div>
{!requestState.loading && requestState.message &&
<p className={`text-lg absolute -bottom-7 left-0 ${requestState.status ? 'text-green-500' : 'text-red-500'}`}>{requestState.message}</p>
<div className="p-5 w-full min-h-[600px] overflow-y-auto">
{groupList && groupList.length < 1 ? (
<>
<h1 className="my-5 text-lg lg:text-xl tracking-wide text-slate-900 dark:text-slate-100">
You Currently Do not have any Group, Please Add Group
</h1>
</>
) : (
<>
<h1 className="mb-5 text-lg lg:text-2xl tracking-wide font-bold text-slate-900 dark:text-slate-100">
{selectedGroup?.name}
</h1>
<div className="w-full flex flex-col-reverse lg:flex-col">
<div className="py-3 w-full">
<div className="relative grid grid-cols-1 sm:grid-cols-2 gap-2 place-content-center">
<div className="input-item">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.firstname}
inputHandler={handleFieldsChange}
placeholder="First Name"
// label="Firstname"
name="firstname"
type="text"
// iconName="message"
/>
</div>
<div className="input-item">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.lastname}
inputHandler={handleFieldsChange}
placeholder="Last Name"
// label="Lastname"
name="lastname"
type="text"
// iconName="message"
/>
</div>
<div className="input-item w-full sm:w-[150%]">
<InputCom
labelClass="tracking-wider"
fieldClass="sm:px-6 px-2"
value={fields.email}
inputHandler={handleFieldsChange}
placeholder="Email"
// label="Email"
name="email"
type="email"
// iconName="message"
/>
</div>
<div className="flex justify-end items-end">
{requestState.loading ? (
<LoadingSpinner size="8" color="sky-blue" />
) : (
<button
onClick={addMember}
disabled={
requestState.loading ||
requestState.status ||
requestState.errors.length
}
</div>
</div>
<div className='my-2 flex flex-col min-h-[300px]'>
{selectedGroup?.data?.length < 1 ?
<h1 className='my-5 text-lg lg:text-xl tracking-wide text-slate-900 dark:text-slate-100'>No Member Found, Please Add</h1>
:
<GroupMemberTable selectedList={selectedGroup?.data} />
}
className={`py-2 px-4 h-[42px] flex justify-center items-center text-base rounded-full text-white font-bold transition-all duration-500 ${
requestState.loading ||
requestState.status ||
requestState.errors.length
? "bg-sky-blue/50"
: "bg-sky-blue hover:bg-sky-600"
} `}
>
Add Member
</button>
)}
</div>
{!requestState.loading && requestState.message && (
<p
className={`text-lg absolute -bottom-7 left-0 ${
requestState.status ? "text-green-500" : "text-red-500"
}`}
>
{requestState.message}
</p>
)}
</div>
</div>
<div className="my-2 flex flex-col min-h-[300px] h-full">
{selectedGroup?.data?.length < 1 ? (
<h1 className="my-5 text-lg lg:text-xl tracking-wide text-slate-900 dark:text-slate-100">
No Member Found, Please Add
</h1>
) : (
<GroupMemberTable selectedList={selectedGroup?.data} />
)}
</div>
</div>
</>
}
</div>
</>
)}
</div>
</>
)
);
}
+7 -6
View File
@@ -109,12 +109,13 @@ export default function MainSection({
endLength={products?.length}
>
{({ datas }) => (
<AvailableJobsCard
contentDisplay={contentDisplay}
image_server={image_server}
key={datas.id}
datas={datas}
/>
<div key={datas.job_uid}>
<AvailableJobsCard
contentDisplay={contentDisplay}
image_server={image_server}
datas={datas}
/>
</div>
)}
</DataIteration>
</div>
@@ -1,12 +1,10 @@
import React, { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import localImgLoad from "../../lib/localImgLoad";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import { handlePagingFunc } from "../Pagination/HandlePagination";
import PaginatedList from "../Pagination/PaginatedList";
export default function MyActiveJobTable({ MyJobList, className }) {
const navigate = useNavigate();
let { pathname } = useLocation();
@@ -45,7 +43,11 @@ export default function MyActiveJobTable({ MyJobList, className }) {
value?.currency_code,
value?.currency
);
let image = `${MyJobList.session_image_server}${localStorage.getItem('session_token')}/job/${value.job_uid}`
let image = `${
MyJobList.session_image_server
}${localStorage.getItem("session_token")}/job/${
value.job_uid
}`;
return (
<tr
key={index}
@@ -112,7 +114,7 @@ export default function MyActiveJobTable({ MyJobList, className }) {
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{value.owner_status == "OWNER"
? "Manage"
? "Review"
: "Send Updates"}
</button>
</div>
+202 -124
View File
@@ -1,21 +1,23 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import dataImage2 from "../../assets/images/data-table-user-2.png";
import SelectBox from "../Helpers/SelectBox";
import DeleteJobPopout from "../jobPopout/DeleteJobPopout";
import JobListPopout from "../jobPopout/JobListPopout";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import usersService from "../../services/UsersService";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import SelectBox from "../Helpers/SelectBox";
import { handlePagingFunc } from "../Pagination/HandlePagination";
import PaginatedList from "../Pagination/PaginatedList";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import DeleteJobPopout from "../jobPopout/DeleteJobPopout";
import EditJobPopOut from "../jobPopout/EditJobPopout";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import EditIcon from "../../assets/images/icon-edit.svg";
import DeleteIcon from "../../assets/images/icon-delete.svg";
import localImgLoad from "../../lib/localImgLoad";
import EditIcon from "../../assets/images/icon-edit.svg";
import { tableReload } from "../AddJob/settings";
import CreditPopup from "../MyWallet/Popup/CreditPopup";
import JobListPopout from "../jobPopout/JobListPopout";
export default function MyJobTable({ MyJobList, reloadJobList, className }) {
const dispatch = useDispatch();
// Getting the categories
const currentJobCart = MyJobList?.data?.categories;
// DropDown Box
@@ -25,24 +27,46 @@ export default function MyJobTable({ MyJobList, reloadJobList, className }) {
Object.keys(filterCategories)[0]
);
let [jobPopout, setJobPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW
const [jobPopout, setJobPopout] = useState({ show: false, data: {} });
let [deleteJobPopout, setDeleteJobPopout] = useState({
const [deleteJobPopout, setDeleteJobPopout] = useState({
show: false,
data: {},
}); // STATE TO HOLD THE VALUE OF THE ITEM DETAILS TO DELETE AND DETERMINE WHEN TO SHOW
});
const [editJob, setEditJob] = useState({ show: false, data: {} });
const [myCountry, setCountries] = useState("");
const {
userDetails: { country },
} = useSelector((state) => state?.userDetails);
const userApi = useMemo(() => new usersService(), []);
const [creditPopup, setCreditPopup] = useState({ show: false, data: {} });
const [walletItem, setWalletItem] = useState(null);
/**
* 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" }));
};
// Get Country Api
const getCountryList = useCallback(async () => {
try {
const res = await userApi.getSignupCountryData();
if (res.status === 200 && res.data.internal_return >= 0) {
@@ -59,7 +83,7 @@ export default function MyJobTable({ MyJobList, reloadJobList, className }) {
throw new Error(error);
}
}, [userApi, country]);
console.log('MY COUNTRY', myCountry)
useEffect(() => {
getCountryList();
}, [getCountryList]);
@@ -101,6 +125,121 @@ export default function MyJobTable({ MyJobList, reloadJobList, className }) {
}
};
const { MyJobListHeader, MyJobListTable } = myJobTableFeatures(
filterCategories,
selectedCategory,
handleSetCategory,
setDeleteJobPopout,
setEditJob,
setJobPopout,
MyJobList,
filteredCurrentJobList,
handlePagination,
currentPage,
currentJobList,
indexOfFirstItem,
indexOfLastItem
);
return (
<div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
className || ""
}`}
>
<MyJobListHeader />
{MyJobList?.loading ? (
<LoadingSpinner size="16" color="sky-blue" />
) : (
<MyJobListTable />
)}
{/* Job List Popout */}
{jobPopout.show && (
<JobListPopout
details={jobPopout.data}
onClose={() => {
setJobPopout({ show: false, data: {} });
}}
setWalletItem={setWalletItem}
openWallet={openPopUp}
situation={jobPopout.show}
/>
)}
{/* End of Job List Popout */}
{/* Delete Job Popout */}
{deleteJobPopout.show && (
<DeleteJobPopout
details={deleteJobPopout.data}
onClose={() => {
setDeleteJobPopout({ show: false, data: {} });
}}
reloadJobList={reloadJobList}
situation={deleteJobPopout.show}
/>
)}
{/* END of Delete Job Popout */}
{editJob.show && (
<EditJobPopOut
details={editJob.data}
onClose={() => {
setEditJob({
show: false,
data: {},
});
}}
situation={editJob.show}
country={myCountry}
categories={currentJobCart}
/>
)}
{creditPopup.show && (
<CreditPopup
details={creditPopup.data}
walletItem={walletItem}
onClose={closePopUp}
situation={openPopUp}
/>
)}
</div>
);
}
function myJobTableFeatures(
filterCategories,
selectedCategory,
handleSetCategory,
setDeleteJobPopout,
setEditJob,
setJobPopout,
MyJobList,
filteredCurrentJobList,
handlePagination,
currentPage,
currentJobList,
indexOfFirstItem,
indexOfLastItem
) {
// List of job table features
const MyJobListHeader = () => (
<div className="header w-full flex justify-between items-center mb-5">
<div className="flex space-x-2 items-center">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-wide">
{filterCategories[selectedCategory]} Jobs
</h1>
</div>
<SelectBox
action={handleSetCategory}
datas={Object.values(filterCategories)}
className="Update-table-dropdown"
contentBodyClasses="w-auto min-w-max"
/>
</div>
);
const JobListItem = ({ value, index, image_server }) => {
let thePrice = PriceFormatter(
value?.price * 0.01,
@@ -190,7 +329,10 @@ export default function MyJobTable({ MyJobList, reloadJobList, className }) {
<button
type="button"
onClick={() => {
setJobPopout({ show: true, data: { thePrice, ...value } });
setJobPopout({
show: true,
data: { thePrice, ...value },
});
}}
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
@@ -201,117 +343,53 @@ export default function MyJobTable({ MyJobList, reloadJobList, className }) {
);
};
return (
<div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
className || ""
}`}
>
<div className="header w-full flex justify-between items-center mb-5">
<div className="flex space-x-2 items-center">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-wide">
{filterCategories[selectedCategory]} Jobs
</h1>
</div>
<SelectBox
action={handleSetCategory}
datas={Object.values(filterCategories)}
className="Update-table-dropdown"
contentBodyClasses="w-auto min-w-max"
/>
</div>
{MyJobList?.loading ? (
<LoadingSpinner size="16" color="sky-blue" />
) : (
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between min-h-[520px]">
<table className="table-auto min-w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{MyJobList &&
MyJobList?.data?.result_list &&
MyJobList.data?.result_list.length > 0 ? (
filteredCurrentJobList?.length ? (
filteredCurrentJobList.map((value, index) => (
<JobListItem
index={index}
key={index}
value={value}
image_server={MyJobList?.data.session_image_server}
/>
))
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">
No Jobs Available In This Category!
</td>
</tr>
)
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">No Jobs Avaliable!</td>
</tr>
)}
</>
</tbody>
</table>
const NoJobsRow = ({ text }) => (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">{text}</td>
</tr>
);
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
currentJobList?.length
? true
: false
}
data={currentJobList}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
)}
const MyJobListTable = () => (
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between min-h-[520px]">
<table className="table-auto min-w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{MyJobList?.data?.result_list?.length > 0 ? (
filteredCurrentJobList.length > 0 ? (
filteredCurrentJobList.map((value, index) => (
<JobListItem
key={index}
index={index}
value={value}
image_server={MyJobList.data.session_image_server}
/>
))
) : (
<NoJobsRow text="No Jobs Available In This Category!" />
)
) : (
<NoJobsRow text="No Jobs Available!" />
)}
</>
</tbody>
</table>
{/* Job List Popout */}
{jobPopout.show && (
<JobListPopout
details={jobPopout.data}
onClose={() => {
setJobPopout({ show: false, data: {} });
}}
situation={jobPopout.show}
/>
)}
{/* End of Job List Popout */}
{/* Delete Job Popout */}
{deleteJobPopout.show && (
<DeleteJobPopout
details={deleteJobPopout.data}
onClose={() => {
setDeleteJobPopout({ show: false, data: {} });
}}
reloadJobList={reloadJobList}
situation={deleteJobPopout.show}
/>
)}
{/* END of Delete Job Popout */}
{editJob.show && (
<EditJobPopOut
details={editJob.data}
onClose={() => {
setEditJob({
show: false,
data: {},
});
}}
situation={editJob.show}
country={myCountry}
categories={currentJobCart}
/>
)}
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
currentJobList?.length
? true
: false
}
data={currentJobList}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
);
return { MyJobListHeader, MyJobListTable };
}
@@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom";
import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import { useDispatch } from "react-redux";
import { apiConst } from "../../lib/apiConst";
function DeleteTaskModal({ details, onClose, situation, setReloadList }) {
let dispatch = useDispatch();
@@ -19,34 +19,50 @@ function DeleteTaskModal({ details, onClose, situation, setReloadList }) {
// FUNCTION TO DELETE TASK
const deleteTask = () => {
setRequestStatus({loading:true, status:false, message: ''})
setRequestStatus({ loading: true, status: false, message: "" });
let reqData = { // REQUEST PAYLOAD
let reqData = {
// REQUEST PAYLOAD
suggest_uid: details.uid,
suggest_action: 555,
offset: 0
}
ApiCall.suggestStatus(reqData).then((response)=>{ // API CALL TO DELETE SUGGESTED TASK
let {data} = response
if(data.internal_return < 0){
setRequestStatus({loading:false, status:false, message: 'Unable to delete, Try again'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
},3000)
}
setRequestStatus({loading:false, status:true, message: 'Family Suggest Deleted'})
setReloadList(prev => !prev) // RELOADS THE FAMILY SUGGEST LIST TABLE
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
onClose()
},3000)
}).catch(error => {
setRequestStatus({loading:false, status:false, message: 'Unable to delete, Try again'})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
},3000)
})
}
suggest_action: apiConst.WRENCHBOARD_COMPLETE_SENDMONEY_INTERSW,
offset: 0,
};
ApiCall.suggestStatus(reqData)
.then((response) => {
// API CALL TO DELETE SUGGESTED TASK
let { data } = response;
if (data.internal_return < 0) {
setRequestStatus({
loading: false,
status: false,
message: "Unable to delete, Try again",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
}
setRequestStatus({
loading: false,
status: true,
message: "Family Suggest Deleted",
});
setReloadList((prev) => !prev); // RELOADS THE FAMILY SUGGEST LIST TABLE
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
onClose();
}, 3000);
})
.catch((error) => {
setRequestStatus({
loading: false,
status: false,
message: "Unable to delete, Try again",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
});
};
return (
<ModalCom action={onClose} situation={situation}>
@@ -6,9 +6,7 @@ import PendingJobsPopout from "../jobPopout/PendingJobsPopout";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import localImgLoad from "../../lib/localImgLoad";
export default function MyPendingJobTable({ MyJobList, className }) {
let [jobPopout, setJobPopout] = useState({ show: false, data: {} }); // STATE TO HOLD THE VALUE OF THE ALERT DETAILS AND DETERMINE WHEN TO SHOW
const [currentPage, setCurrentPage] = useState(0);
@@ -19,7 +17,7 @@ export default function MyPendingJobTable({ MyJobList, className }) {
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
@@ -46,7 +44,11 @@ export default function MyPendingJobTable({ MyJobList, className }) {
value?.currency_code,
value?.currency
);
let image = `${MyJobList.session_image_server}${localStorage.getItem('session_token')}/job/${value.job_uid}`
let image = `${
MyJobList.session_image_server
}${localStorage.getItem("session_token")}/job/${
value.job_uid
}`;
return (
<tr
key={index}
@@ -107,7 +109,9 @@ export default function MyPendingJobTable({ MyJobList, className }) {
}}
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{value.owner_status == 'OWNER' ? 'Manage' : 'Send Updates'}
{value.owner_status == "OWNER"
? "Manage"
: "View"}
</button>
</td>
</tr>
+49
View File
@@ -0,0 +1,49 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";
import activeAidsBanner from "../../assets/images/kids-waiting.jpg";
import ParentWaitingTable from "./ParentWaitingTable";
export default function ParentWaiting({ className }) {
const [addFavorite, setValue] = useState(false);
const favoriteHandler = () => {
if (!addFavorite) {
setValue(true);
toast.success("Added to Favorite List");
} else {
setValue(false);
toast.warn("Remove to Favorite List");
}
};
return (
<>
<div className={`overview-section w-full ${className || ""}`}>
<div className="w-full mb-3 flex justify-between items-center gap-1">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
Waiting for Parent to Get Started...
</h1>
<Link
to='/familymarket'
className="px-4 h-10 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
More Task
</Link>
</div>
{/* <div className="overview-section-wrapper py-2 min-h-[450px] lg:flex lg:space-x-2 flex-1 lg:gap-8"> */}
<div className="overview-section-wrapper py-2 min-h-[400px] lg:grid grid-cols-2 gap-4">
<div className="overview-countdown mb-10 lg:mb-0 h-full w-full flex flex-col justify-between p-4 rounded-2xl bg-white dark:bg-dark-white">
{<ParentWaitingTable />}
</div>
<div className="h-full w-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">
<img
src={activeAidsBanner}
alt="banner"
className="w-full h-full"
/>
</div>
</div>
</div>
</>
);
}
@@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom";
import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import { useDispatch } from "react-redux";
import { apiConst } from "../../lib/apiConst";
function SendReminderModal({ details, onClose, situation, setReloadList }) {
let dispatch = useDispatch();
@@ -19,34 +19,50 @@ function SendReminderModal({ details, onClose, situation, setReloadList }) {
// FUNCTION TO SEND REMINDER
const sendReminder = () => {
setRequestStatus({loading:true, status:false, message: ''})
setRequestStatus({ loading: true, status: false, message: "" });
let reqData = { // REQUEST PAYLOAD
let reqData = {
// REQUEST PAYLOAD
suggest_uid: details.uid,
suggest_action: 222,
offset: 0
}
ApiCall.suggestStatus(reqData).then((response)=>{ // API CALL TO DELETE SUGGESTED TASK
let {data} = response
if(data.internal_return < 0){
setRequestStatus({loading:false, status:false, message: 'Unable to send reminder, Try again1111'})
return setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
},3000)
}
setRequestStatus({loading:false, status:true, message: 'Reminder Sent'})
setReloadList(prev => !prev) // RELOADS THE FAMILY SUGGEST LIST TABLE
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
onClose()
},3000)
}).catch(error => {
setRequestStatus({loading:false, status:false, message: 'Unable to send reminder, Try againNETWORK'})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, message: ''})
},3000)
})
}
suggest_action: apiConst.OFFER_CANCEL,
offset: 0,
};
ApiCall.suggestStatus(reqData)
.then((response) => {
// API CALL TO DELETE SUGGESTED TASK
let { data } = response;
if (data.internal_return < 0) {
setRequestStatus({
loading: false,
status: false,
message: "Unable to send reminder, Try again1111",
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
}
setRequestStatus({
loading: false,
status: true,
message: "Reminder Sent",
});
setReloadList((prev) => !prev); // RELOADS THE FAMILY SUGGEST LIST TABLE
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
onClose();
}, 3000);
})
.catch((error) => {
setRequestStatus({
loading: false,
status: false,
message: "Unable to send reminder, Try againNETWORK",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 3000);
});
};
return (
<ModalCom action={onClose} situation={situation}>
@@ -82,27 +98,32 @@ function SendReminderModal({ details, onClose, situation, setReloadList }) {
</button>
</div>
<div className="logout-modal-body w-full flex flex-col items-center p-8">
<div className="mb-6 w-full flex gap-4 items-center">
<div className="mb-6 w-full flex gap-4 items-center">
<div className="icon max-w-[150px] min-w-[150px] max-h-[150px] min-h-[150px] flex justify-center items-center">
<img src={require(`../../assets/images/family/${details.banner || "default.jpg"}`)} alt="" className="w-full h-full" />
<img
src={require(`../../assets/images/family/${
details.banner || "default.jpg"
}`)}
alt=""
className="w-full h-full"
/>
</div>
<div className="w-full">
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
{details.title}
</p>
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
{details.title}
</p>
<p className="text-sm mb-2 text-thin-light-gray font-medium">
{details.description}
</p>
{
details.remind &&
<p className="text-sm mb-2 text-thin-light-gray font-medium">
{details.description}
</p>
{details.remind && (
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
Last Remind: {new Date(details.remind).toLocaleString().split(',')[0]}
Last Remind:{" "}
{new Date(details.remind).toLocaleString().split(",")[0]}
</p>
}
)}
</div>
</div>
</div>
<div className="w-full flex justify-end">
{/* <button
@@ -1,11 +1,10 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import CommonHead from "../UserHeader/CommonHead";
import MyPendingJobTable from "./MyPendingJobTable";
import LoadingSpinner from "../Spinners/LoadingSpinner";
export default function MyPendingJobs(props) {
export default function MyOffers(props) {
const [selectTab, setValue] = useState("today");
const filterHandler = (value) => {
setValue(value);
@@ -13,9 +12,7 @@ export default function MyPendingJobs(props) {
// console.log("AMEYE LOC1", props.MyJobList);
return (
<Layout>
<CommonHead
commonHeadData={props.commonHeadData}
/>
<CommonHead commonHeadData={props.commonHeadData} />
<div className="notification-page w-full mb-10">
<div className="notification-wrapper w-full">
{/* heading */}
@@ -25,7 +22,7 @@ export default function MyPendingJobs(props) {
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
Pending Job(s)
Pending Offers
</span>
</h1>
</div>
@@ -36,13 +33,17 @@ export default function MyPendingJobs(props) {
></div>
</div>
</div>
{props.MyJobList.loading ?
<div className="bg-white">
<LoadingSpinner size='16' color='sky-blue' height='min-h-[300px]' />
</div>
:
<MyPendingJobTable MyJobList={props.MyJobList.data} />
}
{props.MyJobList.loading ? (
<div className="bg-white">
<LoadingSpinner
size="16"
color="sky-blue"
height="min-h-[300px]"
/>
</div>
) : (
<MyPendingJobTable MyJobList={props.MyJobList.data} />
)}
</div>
</div>
</Layout>
@@ -1,72 +0,0 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";
import activeAidsBanner from "../../assets/images/kids-waiting.jpg";
import ParentWaitingTable from "./ParentWaitingTable";
export default function ParentWaiting({ className }) {
const [addFavorite, setValue] = useState(false);
const favoriteHandler = () => {
if (!addFavorite) {
setValue(true);
toast.success("Added to Favorite List");
} else {
setValue(false);
toast.warn("Remove to Favorite List");
}
};
return (
<>
<div className={`overview-section w-full ${className || ""}`}>
<div className="w-full mb-3 flex justify-between items-center gap-1">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
Waiting for Parent to Get Started...
</h1>
<Link
to='/familymarket'
className="px-4 h-10 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
More Task
</Link>
</div>
{/* <div className="overview-section-wrapper py-2 min-h-[450px] lg:flex lg:space-x-2 flex-1 lg:gap-8"> */}
<div className="overview-section-wrapper py-2 min-h-[400px] lg:grid grid-cols-2 gap-4">
<div className="mb-10 lg:mb-0 h-full w-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">
<img
src={activeAidsBanner}
alt="banner"
className="w-full h-full"
/>
</div>
<div className="overview-countdown h-full w-full flex flex-col justify-between p-4 rounded-2xl bg-white dark:bg-dark-white">
{<ParentWaitingTable />}
{/* <div className="lg:mb-0 mb-3">*/}
{/* <h1 className="text-2xl font-bold text-dark-gray dark:text-white tracking-wide">*/}
{/* Lock and Lob x Fiesta Spurs*/}
{/* </h1>*/}
{/* <span className="text-[18px] font-thin tracking-wide text-dark-gray dark:text-white">*/}
{/* ID : 2320382*/}
{/*</span>*/}
{/* </div>*/}
{/* /!* user *!/*/}
{/* <div className="flex items-center space-x-3 lg:mb-0 mb-3">*/}
{/* <div className="w-14 h-14 flex justify-center items-center rounded-full overflow-hidden">*/}
{/* <img src={HeroUser} alt="" />*/}
{/* </div>*/}
{/* <div>*/}
{/* <p className="text-xl tracking-wide font-bold antise text-dark-gray dark:text-white">*/}
{/* Brokln Simons*/}
{/* </p>*/}
{/* <p className="text-sm tracking-wide text-dark-gray dark:text-white">*/}
{/* @broklinslam_75*/}
{/* </p>*/}
{/* </div>*/}
{/* </div>*/}
</div>
</div>
</div>
</>
);
}
+21 -7
View File
@@ -6,6 +6,7 @@ import CommonHead from "../UserHeader/CommonHead";
import MyOffersTable from "./MyOffersTable";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function MyTasks({
MyActiveOffersList,
@@ -74,13 +75,25 @@ export default function MyTasks({
/>
)}
<div className="w-full mb-5 flex justify-between items-center gap-1">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
My Tasks
</span>
</h1>
{userDetails.account_type == 'FULL'?
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
My Tasks
</span>
</h1>
:
<CustomBreadcrumb
title = 'My Tasks'
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/mytask", title: "My Tasks", active: true},
]
}
/>
}
{ActiveJobList?.data?.length > 0 && userDetails.account_type == 'FAMILY' &&
<button
@@ -94,6 +107,7 @@ export default function MyTasks({
</button>
}
</div>
<MyJobTable ActiveJobList={ActiveJobList} Account={userDetails} imageServer={MyActiveOffersList.session_image_server} />
</div>
</div>
@@ -66,6 +66,8 @@ const initialValues = {
function AddFundDollars(props) {
let MaxNoOfCards = process.env.REACT_APP_MAX_CREDIT_CARDS; // HOLDS THE VALUE OF THE MAX NUMBER OF CARDS USER CAN ADD
let [loadingState, setLoadingState] = useState(false)
const apiCall = new usersService();
let countryWallet = props.walletItem.country;
const [selectedOption, setSelectedOption] = useState("previous");
@@ -162,10 +164,11 @@ function AddFundDollars(props) {
}
}
props.setConfirmCredit((prev) => ({
...prev,
show: { awaitConfirm: { loader: true } },
}));
// props.setConfirmCredit((prev) => ({
// ...prev,
// show: { awaitConfirm: { loader: true } },
// }));
setLoadingState(true)
// Extracting card_uid from the previous card details
const paymentCardValue = prevCardDetails["payment-card"];
@@ -193,6 +196,18 @@ function AddFundDollars(props) {
if (res.data.internal_return < 0) {
props.setInputError("An Error Occurred");
throw new Error("An Error Occurred");
// use commented code when you when to display pop for failed start credit API
// props.setConfirmCredit((prev) => ({
// ...prev,
// show: {
// awaitConfirm: { loader: false, state: false },
// acceptConfirm: { loader: false, state: true },
// },
// data: {internal_return: -1}
// }));
setLoadingState(false)
return
}
const _response = res.data;
@@ -204,6 +219,7 @@ function AddFundDollars(props) {
stateData = { ...stateData, ..._response };
setTimeout(() => {
setLoadingState(false)
props.setConfirmCredit({
show: {
awaitConfirm: { loader: false, state: true },
@@ -213,6 +229,7 @@ function AddFundDollars(props) {
});
}, 1500);
} catch (error) {
setLoadingState(false)
props.setInputError(error.message);
setTimeout(() => props.setInputError(""), 5000);
props.setConfirmCredit((prev) => ({
@@ -582,7 +599,7 @@ function AddFundDollars(props) {
type="submit"
className="px-4 py-1 h-11 max-w-[115px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{props.confirmCredit?.show?.awaitConfirm?.loader ? (
{loadingState ? (
<LoadingSpinner size="6" color="sky-blue" />
) : (
<>
@@ -616,7 +633,7 @@ function AddFundDollars(props) {
type="button"
className="px-4 py-1 h-11 max-w-[115px] w-full flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{props.confirmCredit?.show?.awaitConfirm?.loader ? (
{loadingState ? (
<LoadingSpinner size="6" color="sky-blue" />
) : (
<span className="text-white">Continue</span>
@@ -86,6 +86,16 @@ function AddFundPop({
}));
setInputError("An Error Occurred");
setTimeout(() => setInputError(""), 5000);
// use commented code when you when to display pop for failed start credit API
// setConfirmCredit((prev) => ({
// ...prev,
// show: {
// awaitConfirm: { loader: false, state: false },
// acceptConfirm: { loader: false, state: true },
// },
// data: {internal_return: -1}
// }));
return;
}
@@ -70,7 +70,8 @@ function CompleteConfirmCredit({ onClose, confirmCredit }) {
}`}
</span>
</div>
{data?.curr_balance &&
<div className="flex items-center gap-8">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
Wallet Balance
@@ -79,6 +80,7 @@ function CompleteConfirmCredit({ onClose, confirmCredit }) {
{data?.curr_balance * 0.01}
</span>
</div>
}
{isSuccess && (
<div className="flex items-center gap-8">
@@ -239,7 +239,8 @@ function ConfirmAddFund({
setConfirmCredit((prev) => ({
...prev,
show: {
acceptConfirm: { loader: false },
awaitConfirm: { loader: false, state: false },
acceptConfirm: { loader: false, state: true },
},
}));
return;
@@ -261,7 +262,8 @@ function ConfirmAddFund({
setConfirmCredit((prev) => ({
...prev,
show: {
acceptConfirm: { loader: false },
awaitConfirm: { loader: false, state: false },
acceptConfirm: { loader: false, state: true },
},
}));
console.log(error);
@@ -333,7 +335,8 @@ function ConfirmAddFund({
setConfirmCredit((prev) => ({
...prev,
show: {
acceptConfirm: { loader: false },
awaitConfirm: { loader: false, state: false },
acceptConfirm: { loader: false, state: true },
},
}));
setTimeout(() => onClose, 10000);
@@ -79,7 +79,7 @@ const CreditPopup = ({ details, onClose, situation, walletItem }) => {
<ConfirmAddFund
confirmCredit={confirmCredit}
setConfirmCredit={setConfirmCredit}
walletItem={walletItem}
walletItem={walletItem || details}
onClose={onClose}
/>
) : confirmCredit?.show?.acceptConfirm?.state ? (
+1 -1
View File
@@ -47,7 +47,7 @@ const WalletRoutes = () => {
}
setAllCountries((prev) => ({
loading: false,
data: res.data.result_list,
data: res?.data?.result_list,
}));
})
.catch((error) => {
+16 -1
View File
@@ -5,6 +5,13 @@ function Default({ children }) {
// dark mode setup
const [theme, setTheme] = useState(null);
// country mode setup
const [countryMode, setCountryMode] = useState(localStorage.getItem('cnt') ? localStorage.getItem('cnt')?.toUpperCase() : '')
const queryParams = new URLSearchParams(location?.search);
const country = queryParams.get("cnt")?.toUpperCase();
useEffect(() => {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
setTheme("dark");
@@ -24,9 +31,17 @@ function Default({ children }) {
const handleThemeSwitch = () => {
setTheme(theme === "dark" ? "light" : "dark");
};
useEffect(()=>{
if(country){
setCountryMode(country)
localStorage.setItem('cnt', country)
}
},[countryMode])
return (
<>
<DarkModeContext.Provider value={{ theme, handleThemeSwitch }}>
<DarkModeContext.Provider value={{ theme, handleThemeSwitch, countryMode }}>
{children && children}
</DarkModeContext.Provider>
</>
+62 -46
View File
@@ -1,18 +1,17 @@
import React, { useContext, useMemo, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import React, { useContext } from "react";
import { Link, useLocation } from "react-router-dom";
import bank1 from "../../assets/images/bank-1.png";
import bank2 from "../../assets/images/bank-2.png";
import bank3 from "../../assets/images/bank-3.png";
import bank4 from "../../assets/images/bank-4.png";
import profileImg from "../../assets/images/profile.jpg";
import useToggle from "../../hooks/useToggle";
import usersService from "../../services/UsersService";
import DarkModeContext from "../Contexts/DarkModeContext";
import Icons from "../Helpers/Icons";
import ModalCom from "../Helpers/ModalCom";
import WalletHeader from "../MyWallet/WalletHeader";
import { useDispatch, useSelector } from "react-redux";
import { useSelector } from "react-redux";
import Flag from "../../assets/images/united-states.svg";
import siteLogo from "../../assets/images/wrenchboard-logo-text.png";
// import { updateWalletDetails } from "../../store/walletDetails";
@@ -27,11 +26,6 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const [moneyPopup, setPopup] = useToggle(false);
const darkMode = useContext(DarkModeContext);
const { userDetails } = useSelector((state) => state?.userDetails);
const { walletTable } = useSelector((state) => state.tableReload); // DETERMINES WHEN WALLET RELOADS
const [myWalletList, setMyWalletList] = useState([]);
const api = useMemo(() => new usersService(), []);
const dispatch = useDispatch();
const navigate = useNavigate();
const { notifications } = useSelector((state) => state?.notifications); // NOTIFICATION STORE
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
@@ -157,15 +151,16 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
</defs>
</svg>
</button>
{/* search bar */}
<div className="search-bar lg:block hidden w-[376px]">
{/*<SearchCom />*/}
<div className="search-bar xl:hidden justify-center items-center w-[376px]">
{/* Home */}
<HomeButton />
</div>
{/* user info */}
<div className="user-info flex items-center justify-end w-full xl:space-x-7 space-x-2 z-10 ">
{/* dark mode */}
<button
{/* <button
onClick={darkMode.handleThemeSwitch}
type="button"
className="xl:w-[176px] w-[52px] h-[52px] dark:bg-white bg-dark-gray border border-pink rounded-full flex justify-center items-center"
@@ -236,11 +231,11 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
{darkMode.theme === "light" ? "Dark" : "Light"} Mode
</span>
</div>
</button>
</button> */}
{/* balance */}
{/* My Page Button */}
<PageButton />
{userDetails.account_type === "FULL" ? <PageButton /> : null}
{/*<div className="lg:hidden block"></div>*/}
<WalletHeader
@@ -505,15 +500,6 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
</div>
</div>
</div>
{/* <div className="for-mobile-profile lg:hidden block">
<div
// to="/profile"
onClick={() => handlerProfile()}
className="lg:w-[62px] lg:h-[62px] w-[50px] h-[50px] rounded-full overflow-hidden block"
>
<img src={profileImg} alt="profile" className="w-full h-full" />
</div>
</div> */}
</div>
</div>
</div>
@@ -671,28 +657,58 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
);
}
const PageButton = () => {
return (
<Link to="/yourpage" 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
className="flex items-center lg:justify-between justify-center w-full h-full"
>
<span className="lg:block hidden w-[25px]">
<Link
to="/yourpage"
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 className="flex items-center lg:justify-between justify-center w-full h-full">
<span className="lg:block hidden w-[25px]">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 50" id="Page">
<path
fillRule="evenodd"
d="M0 13V2a2 2 0 0 1 2-2h64a2 2 0 0 1 2 2v11H0Zm0 4v31a2 2 0 0 0 2 2h20V17H0Zm26 33h40a2 2 0 0 0 2-2V17H26v33Z"
fill="#ffffff"
className="color000000 svgShape"
></path>
</svg>
</span>
<p className="lg:text-xl text-lg font-bold text-white">My Page</p>
<span className="lg:block hidden">
{/* <Icons name="deep-plus" /> */}
</span>
</div>
<path
fillRule="evenodd"
d="M0 13V2a2 2 0 0 1 2-2h64a2 2 0 0 1 2 2v11H0Zm0 4v31a2 2 0 0 0 2 2h20V17H0Zm26 33h40a2 2 0 0 0 2-2V17H26v33Z"
fill="#ffffff"
className="color000000 svgShape"
></path>
</svg>
</span>
<p className="lg:text-xl text-lg font-bold text-white">My Page</p>
<span className="lg:block hidden">
{/* <Icons name="deep-plus" /> */}
</span>
</div>
</Link>
)
}
);
};
const HomeButton = () => {
return (
<Link
to="/"
className="flex user-balance cursor-pointer w-[110px] h-[48px] items-center rounded-full relative bg-sky-blue pr-1.5 pl-4"
>
<div className="flex items-center lg:justify-between justify-center w-full h-full">
<span className="">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-7 h-7 stroke-white fill-white"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"
/>
</svg>
</span>
<p className="lg:text-xl text-lg font-bold text-white">Home</p>
<span className=""></span>
</div>
</Link>
);
};
+1 -1
View File
@@ -24,7 +24,7 @@ export default function Layout({ children }) {
localStorage.removeItem("member_id");
localStorage.removeItem("uid");
sessionStorage.removeItem("family_uid");
// localStorage.clear();
localStorage.clear();
// toast.success("Come Back Soon", {
// icon: `🙂`,
// });
+11 -6
View File
@@ -89,7 +89,7 @@ export default function MobileSidebar({
<ul className="flex flex-col space-y-6">
{/* Using mini component reduces the bulk amount of html */}
<ListItem
title="Dashboard"
title= {userDetails?.account_type == "FULL" ? "Dashboard" : "Home"}
route="/"
sidebar={sidebar}
iconName="new-dashboard"
@@ -190,16 +190,21 @@ export default function MobileSidebar({
<div className="items">
<ul className="flex flex-col space-y-6">
{[
{ name: "List", path: "/myjobs", iconName: "people-two" },
{ name: "List", path: "/myjobs", iconName: "job-list" },
{
name: "Pending",
path: "/my-pending-jobs",
iconName: "people-two",
name: "Offers",
path: "/my-offers",
iconName: "pending-job",
},
{
name: "Waiting",
path: "/pend-interest",
iconName: "pending-job",
},
{
name: "Active",
path: "/my-active-jobs",
iconName: "people-two",
iconName: "active-job",
},
].map(({ name, path, iconName }, idx) => (
<ListItem
+141 -127
View File
@@ -1,9 +1,11 @@
import React, { useState } from "react";
import React, { useContext, useState } from "react";
import { useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
//import SideStatistics from "./SideStatistics";
import { localImgLoad } from "../../lib";
import DarkModeContext from "../Contexts/DarkModeContext";
export default function RightSideBar({myJobList}) {
export default function RightSideBar({ myJobList }) {
const filterDatas = ["Last 15 days", "Last Month", "Last 6 month"];
const [filterDataSet, setFilterDataSet] = useState([10, 30, 20, 40]);
const dataSetHandler = (value) => {
@@ -15,6 +17,7 @@ export default function RightSideBar({myJobList}) {
setFilterDataSet([8, 15, 40, 30]);
}
};
const darkMode = useContext(DarkModeContext);
const [selectedRate, setSelectedRate] = useState("ETH");
const [rateStaticsDropdown, setRateStaticsDropdown] = useState(false);
@@ -152,118 +155,150 @@ export default function RightSideBar({myJobList}) {
</p>
</div>
</div>
{/* dark mode */}
<div
onClick={darkMode.handleThemeSwitch}
className="item flex space-x-5 items-center mb-4 cursor-pointer"
>
<span className="dark:text-dark-gray text-white">
{darkMode.theme === "light" ? (
<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 fill-black"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z"
/>
</svg>
) : (
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="fill-current w-6 h-6"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.3065 16.3771C18.1572 16.6304 17.986 16.8743 17.7937 17.1062C17.7118 17.2044 17.7247 17.3515 17.8228 17.4339C17.9208 17.5163 18.0665 17.5028 18.1484 17.4046C18.3569 17.1532 18.5419 16.8897 18.7043 16.6155C18.7695 16.5051 18.7334 16.3622 18.6238 16.2966C18.5142 16.2304 18.3722 16.2668 18.3065 16.3771ZM18.9591 14.722C18.8948 15.0116 18.8078 15.2975 18.6982 15.5759C18.6511 15.6955 18.7093 15.831 18.8282 15.878C18.9466 15.9255 19.0812 15.8668 19.1283 15.7477C19.2472 15.446 19.3411 15.1368 19.4104 14.8231C19.4382 14.6978 19.3596 14.5735 19.2347 14.5456C19.1103 14.5176 18.9864 14.5968 18.9591 14.722ZM19.0673 12.944C19.0955 13.2411 19.1006 13.5395 19.0825 13.8375C19.0747 13.9655 19.1718 14.0763 19.2994 14.0837C19.4266 14.0917 19.5362 13.9939 19.5441 13.8659C19.564 13.5437 19.5584 13.2206 19.5274 12.8994C19.5154 12.7713 19.4021 12.6777 19.2754 12.6899C19.1482 12.702 19.0548 12.816 19.0673 12.944ZM18.6229 11.2201C18.7422 11.4948 18.8388 11.7769 18.9128 12.0641C18.9447 12.1884 19.071 12.2629 19.1949 12.2308C19.3184 12.1987 19.3924 12.0716 19.3605 11.9473C19.2805 11.6363 19.1755 11.3304 19.0465 11.0334C18.9951 10.9156 18.8587 10.8616 18.7417 10.9133C18.6247 10.9649 18.5715 11.1023 18.6229 11.2201ZM17.6651 9.72283C17.8653 9.94816 18.0448 10.1856 18.2034 10.4333C18.2723 10.5413 18.4157 10.5725 18.523 10.5026C18.6303 10.4333 18.6612 10.2889 18.5919 10.1809C18.4208 9.91324 18.2265 9.65578 18.0092 9.4123C17.9241 9.31639 17.7779 9.30848 17.6827 9.39414C17.5879 9.4798 17.58 9.62738 17.6651 9.72283Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M13.4409 5.61267C9.08757 5.61267 5.55359 9.14665 5.55359 13.5C5.55359 17.8533 9.08757 21.3873 13.4409 21.3873C17.7942 21.3873 21.3282 17.8533 21.3282 13.5C21.3282 9.14665 17.7942 5.61267 13.4409 5.61267ZM13.9049 6.5559C17.5298 6.79484 20.4003 9.81475 20.4003 13.5C20.4003 17.1852 17.5298 20.2051 13.9049 20.4441V6.5559Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.1116 1.32213V3.46343C12.1116 4.19318 12.7072 4.78556 13.4409 4.78556C14.1746 4.78556 14.7702 4.19318 14.7702 3.46343V1.32213C14.7702 0.592374 14.1746 0 13.4409 0C12.7072 0 12.1116 0.592374 12.1116 1.32213Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M21.0877 4.01472L19.5511 5.5513C19.0274 6.07499 19.0274 6.92528 19.5511 7.44898C20.0748 7.97267 20.9251 7.97267 21.4488 7.44898L22.9854 5.9124C23.509 5.38871 23.509 4.53841 22.9854 4.01472C22.4617 3.49102 21.6114 3.49102 21.0877 4.01472Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M25.6581 12.3649H23.4849C22.7443 12.3649 22.1431 12.9661 22.1431 13.7068C22.1431 14.4474 22.7443 15.0486 23.4849 15.0486H25.6581C26.3988 15.0486 27 14.4474 27 13.7068C27 12.9661 26.3988 12.3649 25.6581 12.3649Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M22.9854 21.5012L21.4488 19.9646C20.9251 19.4409 20.0748 19.4409 19.5511 19.9646C19.0274 20.4883 19.0274 21.3386 19.5511 21.8623L21.0877 23.3989C21.6114 23.9226 22.4617 23.9226 22.9854 23.3989C23.509 22.8752 23.509 22.0249 22.9854 21.5012Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M14.7702 25.6778V23.5365C14.7702 22.8068 14.1746 22.2144 13.4409 22.2144C12.7072 22.2144 12.1116 22.8068 12.1116 23.5365V25.6778C12.1116 26.4076 12.7072 27 13.4409 27C14.1746 27 14.7702 26.4076 14.7702 25.6778Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.78958 23.0647L7.29553 21.5372C7.80878 21.0166 7.80878 20.1714 7.29553 19.6508C6.78228 19.1302 5.94893 19.1302 5.43568 19.6508L3.92974 21.1783C3.41649 21.6989 3.41649 22.5441 3.92974 23.0647C4.44299 23.5853 5.27633 23.5853 5.78958 23.0647Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.32213 14.8293H3.46343C4.19318 14.8293 4.78556 14.2337 4.78556 13.5C4.78556 12.7663 4.19318 12.1707 3.46343 12.1707H1.32213C0.592374 12.1707 0 12.7663 0 13.5C0 14.2337 0.592374 14.8293 1.32213 14.8293Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.92974 5.82165L5.43568 7.34911C5.94893 7.86969 6.78228 7.86969 7.29553 7.34911C7.80878 6.82853 7.80878 5.98328 7.29553 5.46269L5.78958 3.93524C5.27633 3.41465 4.44299 3.41465 3.92974 3.93524C3.41649 4.45582 3.41649 5.30107 3.92974 5.82165Z"
/>
</svg>
)}
</span>
<p className="text-thin-light-gray text-base font-medium">
{darkMode.theme === "light" ? "Dark" : "Light"} Mode
</p>
</div>
</div>
</div>
{/*JOB LINKS*/}
{myJobList?.data?.result_list?.length > 0 &&
<div className="top-platform mt-6 bg-white dark:bg-dark-white rounded-2xl py-8 2xl:w-[268px] w-full 2xl:mb-10 2xl:border-none border ">
{/* heading */}
<div className="px-8 heading flex justify-between items-center mb-3.5">
<h3 className="text-xl font-bold text-dark-gray dark:text-white">
Job Links
</h3>
<div></div>
</div>
<div className="platform-list">
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 rounded-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
id="history"
>
<g data-name="14">
<circle cx="9" cy="14" r="7" fill="#ffd54f"></circle>
<path
fill="#ef6c00"
d="M21 9H17a1 1 0 0 1 0-2h4a1 1 0 0 1 0 2zM21 5H3A1 1 0 0 1 3 3H21a1 1 0 0 1 0 2zM21 13H19a1 1 0 0 1 0-2h2a1 1 0 0 1 0 2zM21 17H19a1 1 0 0 1 0-2h2a1 1 0 0 1 0 2zM21 21H17a1 1 0 0 1 0-2h4a1 1 0 0 1 0 2z"
></path>
<path
fill="#ff8f00"
d="M10,10a1,1,0,0,0-2,0v3.59L6.29,15.29a1,1,0,1,0,1.41,1.41l2-2A1,1,0,0,0,10,14Z"
></path>
</g>
</svg>
</div>
{/* name */}
<div>
<p className="text-thin-light-gray text-base font-medium">
<NavLink to="/my-active-jobs">Active Task</NavLink>
</p>
</div>
{/* action */}
{userDetails?.account_type !== "FAMILY" &&
myJobList?.data?.result_list?.length > 0 && (
<div className="top-platform mt-6 bg-white dark:bg-dark-white rounded-2xl py-8 2xl:w-[268px] w-full 2xl:mb-10 2xl:border-none border ">
{/* heading */}
<div className="px-8 heading flex justify-between items-center mb-3.5">
<h3 className="text-xl font-bold text-dark-gray dark:text-white">
Job Links
</h3>
<div></div>
</div>
{/* {userDetails && userDetails?.account_type !== "FAMILY" && (
<>
</>
)} */}
<div className="platform-list">
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 rounded-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
id="add-user"
>
<path
fill="#9bcb5b"
d="M12 13.4c-2 0-3.7-1.6-3.7-3.6s1.6-3.7 3.6-3.7 3.7 1.6 3.7 3.6-1.6 3.6-3.6 3.7zm0-6.2c-1.4 0-2.6 1.1-2.6 2.6 0 1.4 1.1 2.6 2.6 2.6s2.6-1.1 2.6-2.6c-.1-1.5-1.2-2.6-2.6-2.6z"
></path>
<path
fill="#9bcb5b"
d="M16.6 17.9c-.3 0-.5-.2-.6-.5 0-2.2-1.8-4-4-4s-4 1.8-4 4c0 .3-.3.5-.6.5-.2 0-.4-.2-.5-.5 0-2.8 2.3-5.1 5.1-5.1s5.1 2.3 5.1 5.1c0 .3-.2.5-.5.5z"
></path>
<path
fill="#0376bc"
d="M12 23.7C5.5 23.7.3 18.4.3 12 .3 5.5 5.6.3 12 .3c2.6 0 5.1.9 7.2 2.5.2.2.2.6 0 .8-.2.2-.4.2-.7.1-1.9-1.4-4.1-2.2-6.5-2.2C6.2 1.4 1.4 6.2 1.4 12S6.2 22.6 12 22.6 22.6 17.8 22.6 12c0-2.4-.8-4.6-2.2-6.5-.2-.3-.1-.6.2-.8.2-.1.5-.1.7.1 1.6 2 2.5 4.6 2.4 7.2 0 6.4-5.3 11.7-11.7 11.7z"
></path>
<circle cx="20.2" cy="20.3" r="2.4" fill="#fff"></circle>
<path
fill="#9bcb5b"
d="M18 18.1c.6-.6 1.4-.9 2.2-.9.8 0 1.6.3 2.2.9s1 1.4.9 2.2c0 .8-.3 1.6-.9 2.2s-1.4 1-2.2.9c-.8 0-1.6-.3-2.2-.9s-1-1.4-.9-2.2c-.1-.8.3-1.7.9-2.2zm3.8 2.5V20h-1.3v-1.3h-.6V20h-1.3v.6h1.3v1.3h.6v-1.3h1.3z"
></path>
</svg>
<div className="w-8 h-8 p-[4px] rounded-full">
<img
src={localImgLoad("images/icons/job_active.svg")}
className="w-full h-full"
alt="Active Task"
/>
</div>
{/* name */}
<div>
<p className="text-thin-light-gray text-base font-medium">
<NavLink to="/my-review-jobs">Review Pending</NavLink>
<NavLink to="/my-active-jobs">Active Task</NavLink>
</p>
</div>
{/* action */}
</div>
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 p-[4px] rounded-full">
<img
src={localImgLoad("images/icons/job_pending.svg")}
className="w-full h-full"
alt="Review Task"
/>
</div>
{/* name */}
<div>
<p className="text-thin-light-gray text-base font-medium">
<NavLink to="/my-review-jobs">Review</NavLink>
</p>
</div>
</div>
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 rounded-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
id="InternationalUser"
>
<path
fill="#e6e7f9"
d="M38.5 31.1c2.1-1.1 3.9-2.5 5.4-4.4h-3.2c-.6 1.6-1.3 3.1-2.2 4.4zm-5.8 1.4c2-.7 3.7-2.8 4.9-5.8h-4.9v5.8zm8.8-8.6h4.2c.9-1.8 1.5-3.7 1.7-5.8h-5.1c-.1 2-.4 4-.8 5.8zm2.4-17.3c-1.5-1.8-3.3-3.3-5.4-4.4.8 1.2 1.6 2.7 2.2 4.4h3.2zm-5.3 2.9h-5.9v5.8h6.7c-.1-2.1-.4-4.1-.8-5.8zm3.7 5.8h5.1c-.2-2.1-.8-4-1.7-5.8h-4.2c.4 1.8.7 3.7.8 5.8zM32.7.8v5.8h4.9c-1.2-2.9-2.9-5.1-4.9-5.8zm6.7 17.3h-6.7v5.8h5.9c.4-1.8.7-3.8.8-5.8zM25 6.6h4.9V.8c-2 .7-3.7 2.9-4.9 5.8zm-1.8 8.7h6.7V9.5H24c-.4 1.7-.7 3.7-.8 5.8zm6.7 17.2v-5.8H25c1.2 3 2.9 5.1 4.9 5.8zM24.1 2.3c-2.1 1.1-3.9 2.5-5.4 4.4H22c.5-1.7 1.3-3.2 2.1-4.4zM24 23.9h5.9v-5.8h-6.7c.1 2 .4 4 .8 5.8z"
className="colorc1e5ff svgShape"
></path>
<path
fill="#ff6699"
d="M3.7 44.7c0 1.6 1.2 2.8 2.8 2.8 1.3 0 2.4-.9 2.7-2.2.3 1.3 1.4 2.2 2.7 2.2 1.5 0 2.8-1.3 2.8-2.8V30.1h3.1V18.8c0-4.2-3.3-7.5-7.4-7.5H8c-4.1 0-7.4 3.4-7.4 7.5v11.3h3.1v14.6z"
className="colorff99b0 svgShape"
></path>
<path
fill="#998da0"
d="M9.2 10.3c2.4 0 4.4-2.2 4.4-4.9S11.6.5 9.2.5C6.8.5 4.8 2.7 4.8 5.4s2 4.9 4.4 4.9z"
className="colorffd499 svgShape"
></path>
<path
fill="#e6e7f9"
d="M16.9 9.5c-.3.6-.5 1.2-.8 1.8 1.3 1 2.3 2.4 2.9 4h1.3c.1-2 .3-4 .8-5.8h-4.2zm2.9 9.3v5.1h1.4c-.4-1.8-.7-3.8-.8-5.8h-.6c-.1.2 0 .4 0 .7zm2.2 7.9h-2.2v1.2c1.3 1.3 2.7 2.4 4.4 3.2-.9-1.3-1.7-2.8-2.2-4.4z"
className="colorc1e5ff svgShape"
></path>
</svg>
<div className="w-8 h-8 p-[4px] rounded-full">
<img
src={localImgLoad("images/icons/job_past_due.svg")}
className="w-full h-full"
alt="Past Due Task"
/>
</div>
{/* name */}
<div>
@@ -278,33 +313,12 @@ export default function RightSideBar({myJobList}) {
<div className="px-8 item flex space-x-3 items-center mb-4">
{/* image */}
<div className="w-8 h-8 rounded-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
id="InternationalUser"
>
<path
fill="#e6e7f9"
d="M38.5 31.1c2.1-1.1 3.9-2.5 5.4-4.4h-3.2c-.6 1.6-1.3 3.1-2.2 4.4zm-5.8 1.4c2-.7 3.7-2.8 4.9-5.8h-4.9v5.8zm8.8-8.6h4.2c.9-1.8 1.5-3.7 1.7-5.8h-5.1c-.1 2-.4 4-.8 5.8zm2.4-17.3c-1.5-1.8-3.3-3.3-5.4-4.4.8 1.2 1.6 2.7 2.2 4.4h3.2zm-5.3 2.9h-5.9v5.8h6.7c-.1-2.1-.4-4.1-.8-5.8zm3.7 5.8h5.1c-.2-2.1-.8-4-1.7-5.8h-4.2c.4 1.8.7 3.7.8 5.8zM32.7.8v5.8h4.9c-1.2-2.9-2.9-5.1-4.9-5.8zm6.7 17.3h-6.7v5.8h5.9c.4-1.8.7-3.8.8-5.8zM25 6.6h4.9V.8c-2 .7-3.7 2.9-4.9 5.8zm-1.8 8.7h6.7V9.5H24c-.4 1.7-.7 3.7-.8 5.8zm6.7 17.2v-5.8H25c1.2 3 2.9 5.1 4.9 5.8zM24.1 2.3c-2.1 1.1-3.9 2.5-5.4 4.4H22c.5-1.7 1.3-3.2 2.1-4.4zM24 23.9h5.9v-5.8h-6.7c.1 2 .4 4 .8 5.8z"
className="colorc1e5ff svgShape"
></path>
<path
fill="#ff6699"
d="M3.7 44.7c0 1.6 1.2 2.8 2.8 2.8 1.3 0 2.4-.9 2.7-2.2.3 1.3 1.4 2.2 2.7 2.2 1.5 0 2.8-1.3 2.8-2.8V30.1h3.1V18.8c0-4.2-3.3-7.5-7.4-7.5H8c-4.1 0-7.4 3.4-7.4 7.5v11.3h3.1v14.6z"
className="colorff99b0 svgShape"
></path>
<path
fill="#998da0"
d="M9.2 10.3c2.4 0 4.4-2.2 4.4-4.9S11.6.5 9.2.5C6.8.5 4.8 2.7 4.8 5.4s2 4.9 4.4 4.9z"
className="colorffd499 svgShape"
></path>
<path
fill="#e6e7f9"
d="M16.9 9.5c-.3.6-.5 1.2-.8 1.8 1.3 1 2.3 2.4 2.9 4h1.3c.1-2 .3-4 .8-5.8h-4.2zm2.9 9.3v5.1h1.4c-.4-1.8-.7-3.8-.8-5.8h-.6c-.1.2 0 .4 0 .7zm2.2 7.9h-2.2v1.2c1.3 1.3 2.7 2.4 4.4 3.2-.9-1.3-1.7-2.8-2.2-4.4z"
className="colorc1e5ff svgShape"
></path>
</svg>
<div className="w-8 h-8 p-[4px] rounded-full">
<img
src={localImgLoad("images/icons/job_group.svg")}
className="w-full h-full"
alt="Job Groups"
/>
</div>
{/* name */}
<div>
@@ -313,9 +327,9 @@ export default function RightSideBar({myJobList}) {
</p>
</div>
</div>
</div>
</div>
}
</div>
</div>
)}
</div>
</>
);
+13 -9
View File
@@ -8,14 +8,13 @@ import {
import DarkModeContext from "../Contexts/DarkModeContext";
import Icons from "../Helpers/Icons";
export default function Sidebar({
sidebar,
action,
logoutModalHandler,
myJobList,
}) {
const darkMode = useContext(DarkModeContext);
const darkMode = useContext(DarkModeContext);
let { userDetails } = useSelector((state) => state.userDetails);
//const jobLists = getJobList(); // pass from upper - we need in a lot of places
@@ -111,7 +110,7 @@ export default function Sidebar({
<ul className="flex flex-col space-y-6">
{/* Using mini component reduces the bulk amount of html */}
<ListItem
title="Dashboard"
title={userDetails?.account_type == "FULL" ? "Dashboard" : "Home"}
route="/"
sidebar={sidebar}
iconName="new-dashboard"
@@ -215,17 +214,22 @@ export default function Sidebar({
{
name: "List",
path: "/myjobs",
iconName: "people-two",
iconName: "job-list",
},
{
name: "Pending",
path: "/my-pending-jobs",
iconName: "people-two",
name: "Waiting",
path: "/pend-interest",
iconName: "pending-job",
},
{
name: "Offers",
path: "/my-offers",
iconName: "pending-job",
},
{
name: "Active",
path: "/my-active-jobs",
iconName: "people-two",
iconName: "active-job",
},
].map(({ name, path, iconName }, idx) => (
<ListItem
@@ -291,7 +295,7 @@ export default function Sidebar({
className="signout-btn w-full flex items-center justify-center"
>
<span className="p-[1px] w-[40px] h-[40px] border border-purple rounded-full">
<Icons name='new-logout' />
<Icons name="new-logout" />
</span>
</button>
)}
+20 -8
View File
@@ -33,6 +33,9 @@ export default function Resources(props) {
const CreatedBits = __resources?.productdata?.datas;
const blogItems = __resources?.blogdata?.payload;
console.log(__resources);
console.log("Blog data >> ", blogItems);
// My Items Data
const [uploadedFiles, setUploadedFiles] = useState({
loading: false,
@@ -63,7 +66,7 @@ export default function Resources(props) {
loading: false,
msg: "success",
data: res?.result_list,
image:res?.session_image_server
image: res?.session_image_server,
}));
} catch (error) {
setUploadedFiles((prev) => ({
@@ -79,7 +82,13 @@ export default function Resources(props) {
}, [uploadsTable]);
// const [tab, setTab] = useState(tab_categories ? tab_categories[0]?.name : "");
const [tab, setTab] = useState(props.activeTab? props.activeTab : tab_categories ? tab_categories[0]?.name : "");
const [tab, setTab] = useState(
props.activeTab
? props.activeTab
: tab_categories
? tab_categories[0]?.name
: ""
);
const tabHandler = (value) => {
setTab(value);
@@ -105,8 +114,12 @@ export default function Resources(props) {
// const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
const defaultTabComponent = props.activeTab ? tabComponents[props.activeTab] : <BlogTab blogdata={blogItems} />;
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
const defaultTabComponent = props.activeTab ? (
tabComponents[props.activeTab]
) : (
<BlogTab blogdata={blogItems} />
);
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
// Tab Item Component
const TabItem = ({ tabValue, isActive }) => {
@@ -160,17 +173,16 @@ export default function Resources(props) {
<ul className="lg:flex lg:space-x-14 space-x-8">
{tabCategories?.length > 0 &&
tabCategories?.map((tabValue, idx) => {
if(tabValue.enabled){
if (tabValue.enabled) {
return (
<TabItem
key={tabValue.id}
tabValue={tabValue}
isActive={tab === tabValue.name || (idx === 0 && tab === "")}
/>
)
);
}
}
)}
})}
</ul>
);
};
@@ -134,7 +134,7 @@ export default function MyUploadedFiles({ uploadedFiles }) {
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
uploadedFiles?.data.length
uploadedFiles?.data?.length
? true
: false
}
@@ -11,6 +11,7 @@ import profileImage from "../../../assets/images/profile.jpg";
import { Form, Formik } from "formik";
import * as Yup from "yup";
import { apiConst } from "../../../lib/apiConst";
const validationSchema = Yup.object().shape({
email: Yup.string()
@@ -147,7 +148,7 @@ export default function PersonalInfoTab({
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: "FILE",
action: 11300,
action: apiConst.WRENCHBOARD_PICTURE_PROFILE,
};
setUploadStatus({
@@ -0,0 +1,12 @@
import React from "react";
import HomeActivities from "../../Home/HomeActivities";
const RecentActivitiesTab = () => {
return (
<div className="recent-activity-tab w-full">
<HomeActivities />
</div>
);
};
export default RecentActivitiesTab;
+2
View File
@@ -5,6 +5,7 @@ import NotificationSettingTab from "./NotificationSettingTab";
import PaymentMathodsTab from "./PaymentMathodsTab";
import PersonalInfoTab from "./PersonalInfoTab";
import PrivacyPolicyTab from "./PrivacyPolicyTab";
import RecentActivitiesTab from "./RecentActivitiesTab";
import TermsConditionTab from "./TermsConditionTab";
export {
@@ -15,5 +16,6 @@ export {
PaymentMathodsTab,
PersonalInfoTab,
PrivacyPolicyTab,
RecentActivitiesTab,
TermsConditionTab,
};
+12 -10
View File
@@ -1,10 +1,4 @@
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import usersService from "../../services/UsersService";
import Icons from "../Helpers/Icons";
@@ -17,6 +11,7 @@ import {
PaymentMathodsTab,
PersonalInfoTab,
PrivacyPolicyTab,
RecentActivitiesTab,
TermsConditionTab,
} from "./Tabs";
import RecipientAccountTab from "./Tabs/RecipientAccountTab";
@@ -102,24 +97,30 @@ export default function Settings({ faq }) {
},
{
id: 6,
name: "recent_activities",
title: "Recent Activities",
iconName: "login-activity",
},
{
id: 7,
name: "password",
title: "Change Password",
iconName: "password-hover",
},
{
id: 7,
id: 8,
name: "faq",
title: "FAQ",
iconName: "block-question",
},
{
id: 8,
id: 9,
name: "privacy",
title: "Privacy Policy",
iconName: "page-right",
},
{
id: 9,
id: 10,
name: "terms",
title: "Terms and Conditions",
iconName: "page-right",
@@ -166,6 +167,7 @@ export default function Settings({ faq }) {
</div>
),
login_activity: <LoginActivityTab />,
recent_activities: <RecentActivitiesTab />,
password: <ChangePasswordTab />,
faq: <FaqTab datas={faq} />,
privacy: <PrivacyPolicyTab />,
+2 -1
View File
@@ -8,6 +8,7 @@ import ProductUploadField from "./ProductUploadField";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import usersService from "../../services/UsersService";
import { useNavigate } from "react-router-dom";
import { apiConst } from "../../lib/apiConst";
export default function UploadProduct({uploadTypes}) {
const apiCall = new usersService()
@@ -152,7 +153,7 @@ export default function UploadProduct({uploadTypes}) {
title: itemName,
description: description,
msg_type: 'FILE',
action: 11307
action: apiConst.WRENCHBOARD_RESOURCE_MYFILES
}
if(!isValidFile(imgDetails, uploadTypes?.data)){ // FUNCTION TO CHECK IF FILE TYPE IS VALID
+2 -1
View File
@@ -8,6 +8,7 @@ import { tableReload } from "../../store/TableReloads";
import InputCom from "../Helpers/Inputs/InputCom";
import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import { apiConst } from "../../lib/apiConst";
const validationSchema = Yup.object().shape({
country: Yup.string()
@@ -162,7 +163,7 @@ const EditJobPopOut = ({
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: "FILE",
action: 11303,
action: apiConst.WRENCHBOARD_PICTURE_JOB,
};
setUploadStatus({
loading: true,
+380 -290
View File
@@ -1,13 +1,13 @@
import { Field, Form, Formik } from "formik";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import * as Yup from "yup";
import usersService from "../../services/UsersService";
import { tableReload } from "../../store/TableReloads";
import InputCom from "../Helpers/Inputs/InputCom/index";
import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import Detail from "./popoutcomponent/Detail";
import { tableReload } from "../../store/TableReloads";
import { useDispatch } from "react-redux";
const validationSchema = Yup.object().shape({
family: Yup.string().required("This is required "),
@@ -22,14 +22,22 @@ const validationSchema = Yup.object().shape({
group: Yup.string(),
});
function JobListPopout({ details, onClose, situation }) {
function JobListPopout({
details,
onClose,
situation,
openWallet,
setWalletItem,
}) {
const [selectedTab, setSelectedTab] = useState("public");
const tabs = ["public", "individual", "group"];
const [selectedTab, setSelectedTab] = useState('public')
const tabs = ['public', 'individual', 'group']
const dispatch = useDispatch();
const dispatch = useDispatch()
const [requestStatus, setRequestStatus] = useState({message:'', status:false})
const [requestStatus, setRequestStatus] = useState({
message: "",
status: false,
});
const [familyList, setFamilyList] = useState([]);
let [loader, setLoader] = useState({
@@ -43,18 +51,36 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
});
const apiCall = useMemo(() => new usersService(), []);
const { walletDetails } = useSelector((state) => state.walletDetails);
const getWalletDetail = (currency) => {
// A FUNCTION TO GET USER BALANCE BASED ON TASK CURRENCY
const walletChecker = walletDetails?.data.find(
(item) => item.description === currency
);
return walletChecker
? {
description: walletChecker.description,
country: walletChecker.country,
code: walletChecker.code,
amount: walletChecker.amount,
}
: 0;
};
const taskWalletSelector = getWalletDetail(details?.currency);
const openCreditPopup = () => {
onClose();
setWalletItem(taskWalletSelector);
openWallet();
};
// member listing
const memberList = useCallback(async () => {
setLoader({ member: true, jobFields: false });
try {
let reqData = {
limit: 20,
offset: 0,
action: 22010,
};
let res = await apiCall.familyListings(reqData);
let res = await apiCall.familyListings();
const { data } = res;
if (data?.internal_return >= 0 && data?.status == "OK") {
let { result_list } = data;
@@ -123,6 +149,7 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
job_uid,
job_description: textArea,
};
let reqData;
// for family input
@@ -130,7 +157,6 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
reqData = {
...jobReq,
family_uid: values?.family,
action: 13025,
assign_mode: 110011,
};
setLoader({ jobFields: { family: true } });
@@ -139,7 +165,6 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
reqData = {
...jobReq,
duration: Number(values?.public),
action: 13025,
assign_mode: 110022,
};
setLoader({ jobFields: { public: true } });
@@ -148,7 +173,6 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
reqData = {
...jobReq,
email: values?.individual,
action: 13025,
assign_mode: 110033,
};
setLoader({ jobFields: { individual: true } });
@@ -156,9 +180,8 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
// for group input
reqData = {
...jobReq,
email: '',
email: "",
group_id: values?.group,
action: 13025,
assign_mode: 110044,
duration: details?.timeline_days,
// duration: 0,
@@ -171,52 +194,106 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
try {
const res = await apiCall.assignJobTask(reqData);
let { status, data } = await res;
if(status != 200 || data.internal_return < 0){
setRequestStatus({message:'Unable to complete', status:false})
return setTimeout(()=>{
if (status != 200 || data.internal_return < 0) {
setRequestStatus({ message: data?.status ? data?.status : "Unable to assign offer", status: false });
return setTimeout(() => {
setLoader({ jobFields: false });
setRequestStatus({message:'', status:false})
},3000)
setRequestStatus({ message: "", status: false });
}, 3000);
}
dispatch(tableReload({ type: "JOBTABLE" }));
setRequestStatus({message:'Successful', status:true})
setTimeout(()=>{
setRequestStatus({ message: data?.status_msg ? data?.status_msg : "Offer Assigned Successful", status: true });
setTimeout(() => {
setLoader({ jobFields: false });
onClose();
throw new Response(data);
},3000)
// throw new Response(data);
}, 3000);
} catch (error) {
setRequestStatus({message:'Unable to complete', status:false})
setTimeout(()=>{
setRequestStatus({message:'', status:false})
setRequestStatus({ message: "Unable to complete", status: false });
setTimeout(() => {
setRequestStatus({ message: "", status: false });
setLoader({ jobFields: false });
throw new Error(error);
},3000)
}, 3000);
}
};
const [groupList, setGroupList] = useState({loading: true, groups: [], members: []})
const [groupList, setGroupList] = useState({
loading: true,
groups: [],
members: [],
});
// FUNCTION TO POPULATE USER GROUP LIST
useEffect(()=>{
useEffect(() => {
// setGroupList({loading: true, groups: [], members: []})
apiCall.jobGroupList({}).then(res => {
const {status, data} = res
if(status != 200 || data?.internal_return < 0){
setGroupList({loading: false, groups: [], members: []})
return
apiCall
.jobGroupList({})
.then((res) => {
const { status, data } = res;
if (status != 200 || data?.internal_return < 0) {
setGroupList({ loading: false, groups: [], members: [] });
return;
}
if(data.result_list.length < 0){
setGroupList({loading: false, groups: [], members: []})
return
if (data.result_list.length < 0) {
setGroupList({ loading: false, groups: [], members: [] });
return;
}
setGroupList({loading: false, groups: data.result_list, members: data.result_list_member})
}).catch(error => {
setGroupList({loading: false, groups: [], members: []})
})
},[])
setGroupList({
loading: false,
groups: data.result_list,
members: data.result_list_member,
});
})
.catch((error) => {
setGroupList({ loading: false, groups: [], members: [] });
});
}, []);
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 },
{ label: "Price", value: details.thePrice },
{ label: "Timeline", value: `${details.timeline_days} day(s)` },
{ label: "Created", value: new Date(details?.created).toDateString() },
];
return (
<div className="px-4 pb-3 w-full md:border-r-2">
{/* <p className='text-lg font-semibold text-slate-900 tracking-wide'>{details.title}</p> */}
{/* INPUT SECTION */}
{detailsArray.map((detail, index) => (
<DetailsSection
key={index}
label={detail.label}
value={detail.value}
/>
))}
<div className="">
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
Delivery Detail
</label>
<textarea
className={`p-2 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
rows="7"
style={{ resize: "none" }}
value={textArea}
onChange={handleInputChange}
/>
<p>{errMsg.deliveryDetail}</p>
</div>
</div>
);
};
// console.log("Job List P >> ", details)
return (
<ModalCom action={onClose} situation={situation} className="">
<div className="logout-modal-wrapper w-[90%] md:w-[768px] bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
@@ -250,211 +327,185 @@ const [requestStatus, setRequestStatus] = useState({message:'', status:false})
</svg>
</button>
</div>
<div className="md:grid grid-cols-2 bg-white dark:bg-dark-white rounded-lg shadow-lg">
<div className="p-4 pb-3 w-full md:border-r-2">
{/* <p className='text-lg font-semibold text-slate-900 tracking-wide'>{details.title}</p> */}
<DetailsComponent />
<>
{/* ACTION SECTION */}
{+taskWalletSelector.amount > +details.price ? (
<div className="px-4 pb-3 w-full flex flex-col justify-between">
<h1 className="text-lg mt-3 font-medium tracking-wide text-black dark:text-white">
Send this Task to:
</h1>
<div className="flex flex-col grow">
<div className="grid grid-cols-3 mt-4">
{tabs.map((item) => (
<TabButton
key={item}
item={item}
selectedTab={selectedTab}
setSelectedTab={setSelectedTab}
/>
))}
</div>
<div className="grow flex flex-col bg-red-50 dark:bg-[#D85A5A] rounded-b-2xl">
{selectedTab == "family" && (
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.family}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="hidden">
{/* Assign to Family */}
<JobFieldInput
label="Assign to family"
select={true}
inputName="family"
value={props?.values.family}
data={familyList}
btnText="Assign to family"
optionText="Select Family"
loader={loader?.jobFields?.family}
errorHandler={errorHandler}
parentClass="w-full flex flex-col gap-4"
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values?.family === "" && (
<span>{errMsg?.jobFields?.family}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
)}
{/* INPUT SECTION */}
<div className="my-3 md:flex">
<Detail label="Description" value={details.description} />
</div>
{selectedTab == "public" && (
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.public}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to public input */}
<JobFieldInput
label="Offer this job to public"
select={true}
inputName="public"
value={props?.values.public}
data={publicArray}
btnText="Show Task to Public"
optionText="Select Duration"
loader={loader?.jobFields?.public}
errorHandler={errorHandler}
parentClass="w-full flex flex-col gap-4"
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.public === "" && (
<span>{errMsg?.jobFields?.public}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
)}
<div className="my-3 md:flex">
<Detail label="Price" value={details.thePrice} />
</div>
{selectedTab == "individual" && (
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.individual}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to individual input */}
<JobFieldInput
label="Offer this job to individual"
input={true}
inputName="individual"
value={props?.values.individual}
placeholder="Enter email of individual"
inputHandler={props?.handleChange}
btnText="Send Offer to Individual"
loader={loader?.jobFields?.individual}
errorHandler={errorHandler}
parentClass="w-full flex flex-col gap-4"
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.individual === "" && (
<span>{errMsg?.jobFields?.individual}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
)}
<div className="my-3 md:flex">
<Detail
label="Timeline"
value={`${details.timeline_days} day(s)`}
/>
</div>
<div className="my-3 md:flex">
<Detail
label="Created"
value={new Date(details?.created).toDateString()}
/>
</div>
<div className="">
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
Delivery Detail
</label>
<textarea
className={`p-2 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
rows="7"
style={{ resize: "none" }}
value={textArea}
onChange={handleInputChange}
/>
<p>{errMsg.deliveryDetail}</p>
</div>
</div>
{/* ACTION SECTION */}
<div className="p-4 w-ful flex flex-col justify-between">
<h1 className="text-lg mt-3 font-medium tracking-wide text-black dark:text-white">Send this Task to:</h1>
<div className="flex flex-col grow">
<div className="grid grid-cols-3 mt-4">
{tabs.map(item => (
<button
// className={`px-4 py-1 rounded-t-2xl ${selectedTab == item ? 'btn-gradient border-[2px] text-white' : 'bg-white text-[#000] border-t-[2px]'}`}
className={`px-4 py-1 rounded-t-2xl border-t-[2px] transition-all duration-200 flex flex-col justify-center items-center ${selectedTab == item ? 'bg-red-50 dark:bg-[#D85A5A] text-slate-600 font-extrabold' : 'bg-white text-[#000]'}`}
value={item}
name={item}
onClick={()=>setSelectedTab(item)}
>
<div className={`mb-[1px] h-6 w-6 border-4 rounded-full transition-all duration-200 ${selectedTab == item ? 'border-white bg-emerald-500' : 'border-red-50 dark:border-[#D85A5A] bg-white'}`}></div>
{item[0].toUpperCase() + item.slice(1)}
</button>
))}
{/* { process.env.REACT_APP_SHOW_OFFER_GROUP_JOB != 0 && } */}
{selectedTab == "group" && (
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.group}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to your group input */}
<JobFieldInput
label="Offer this job to your Group"
select={true}
inputName="group"
value={props?.values.group}
btnText="Send Order to Group"
optionText="Select Group"
loader={loader?.jobFields?.group}
errorHandler={errorHandler}
data={groupList}
parentClass="w-full flex flex-col gap-4"
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.group === "" && (
<span>{errMsg?.jobFields?.group}</span>
)}
</p>
</Form>
);
}}
</Formik>
)}
<p
className={`text-center w-full text-lg ${
requestStatus.status
? "text-emerald-600"
: "text-red-600"
}`}
>
{requestStatus.message && requestStatus.message}
</p>
</div>
</div>
</div>
<div className="grow flex flex-col bg-red-50 dark:bg-[#D85A5A] rounded-b-2xl">
{selectedTab == 'family' &&
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.family}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="hidden">
{/* Assign to Family */}
<JobFieldInput
label="Assign to family"
select={true}
inputName="family"
value={props?.values.family}
data={familyList}
btnText="Assign to family"
optionText="Select Family"
loader={loader?.jobFields?.family}
errorHandler={errorHandler}
parentClass='w-full flex flex-col gap-4'
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values?.family === "" && (
<span>{errMsg?.jobFields?.family}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
}
{selectedTab == 'public' &&
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.public}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to public input */}
<JobFieldInput
label="Offer this job to public"
select={true}
inputName="public"
value={props?.values.public}
data={publicArray}
btnText="Show Task to Public"
optionText="Select Duration"
loader={loader?.jobFields?.public}
errorHandler={errorHandler}
parentClass='w-full flex flex-col gap-4'
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.public === "" && (
<span>{errMsg?.jobFields?.public}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
}
) : (
<ZeroBalanceChecker
{...taskWalletSelector}
openCreditPopup={openCreditPopup}
/>
)}
{selectedTab == 'individual' &&
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.individual}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to individual input */}
<JobFieldInput
label="Offer this job to individual"
input={true}
inputName="individual"
value={props?.values.individual}
placeholder="Enter email of individual"
inputHandler={props?.handleChange}
btnText="Send Offer to Individual"
loader={loader?.jobFields?.individual}
errorHandler={errorHandler}
parentClass='w-full flex flex-col gap-4'
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.individual === "" && (
<span>{errMsg?.jobFields?.individual}</span>
)}
</p>{" "}
</Form>
);
}}
</Formik>
}
{/* { process.env.REACT_APP_SHOW_OFFER_GROUP_JOB != 0 && } */}
{selectedTab == 'group' &&
<Formik
initialValues={initialValues}
validationSchema={validationSchema.fields.group}
onSubmit={jobFieldHandler}
>
{(props) => {
return (
<Form className="">
{/* Offer this job to your group input */}
<JobFieldInput
label="Offer this job to your Group"
select={true}
inputName="group"
value={props?.values.group}
btnText="Send Order to Group"
optionText="Select Group"
loader={loader?.jobFields?.group}
errorHandler={errorHandler}
data={groupList}
parentClass='w-full flex flex-col gap-4'
/>
<p className="h-4 text-[13px] font-light italic text-red-600 tracking-wide">
{" "}
{props?.values.group === "" && (
<span>{errMsg?.jobFields?.group}</span>
)}
</p>
</Form>
);
}}
</Formik>
}
</div>
</div>
{requestStatus.message &&
<p className={`mt-4 w-full text-lg ${requestStatus.status ? 'text-emerald-600' : 'text-red-600'}`}>{requestStatus.message}</p>
}
</div>
{/* END OF ACTION SECTION */}
{/* END OF ACTION SECTION */}
</>
</div>
</div>
</ModalCom>
@@ -490,7 +541,7 @@ const JobFieldInput = ({
>
{label && (
<label
className="input-label border-2 w-full border-sky-700 py-4 px-2 text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block tracking-wide"
className="input-label border-2 w-full border-sky-700 rounded py-4 px-2 text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block tracking-wide"
htmlFor={inputName}
>
{label}
@@ -507,51 +558,49 @@ const JobFieldInput = ({
value={value}
>
{/* <option value="">{optionText}</option> */}
{(inputName == 'family' || inputName == 'public') &&
Array.isArray(data) &&
<>
<option value="">{optionText}</option>
{ data?.map((item, idx) => (
<React.Fragment key={idx}>
{inputName === "family" && item?.last_login !== "" && (
<option value={item?.family_uid} key={idx}>
{`${item?.firstname} ${item?.lastname}`}
</option>
)}
{inputName === "public" && (
<option value={item?.duration} key={idx}>
{item?.name}
</option>
)}
{/* {inputName === "group" && (
<option value={item?.group_id} key={idx}>
{item?.group_name}
</option>
)} */}
</React.Fragment>
))}
</>
}
{(inputName == 'group') &&
<>
{data.loading ?
<option value={''}>
Loading...
</option>
: data?.groups?.length > 0 ?
{(inputName == "family" || inputName == "public") &&
Array.isArray(data) && (
<>
<option value="">{optionText}</option>
{ data?.groups?.map((item, index)=>(
<option value={item?.group_id} key={index}>
{item?.group_name}
</option>
{data?.map((item, idx) => (
<React.Fragment key={idx}>
{inputName === "family" &&
item?.last_login !== "" && (
<option value={item?.family_uid} key={idx}>
{`${item?.firstname} ${item?.lastname}`}
</option>
)}
{inputName === "public" && (
<option value={item?.duration} key={idx}>
{item?.name}
</option>
)}
</React.Fragment>
))}
</>
:
<option value="">No Group Found</option>
}
</>
}
)}
{inputName == "group" && (
<>
{data.loading ? (
<option value={""}>Loading...</option>
) : data?.groups?.length > 0 ? (
<>
<option value="">{optionText}</option>
{data?.groups?.map((item, index) => (
<option value={item?.group_id} key={index}>
{`${item?.group_name} (${
item?.member_count == null
? "0"
: ' ' + item.member_count + ' '
})`}
</option>
))}
</>
) : (
<option value="">No Group Found</option>
)}
</>
)}
</Field>
</div>
</div>
@@ -607,3 +656,44 @@ const publicArray = [
{ duration: 21, name: "3 weeks" },
{ duration: 28, name: "4 weeks" },
];
const ZeroBalanceChecker = ({ amount, code, country, openCreditPopup }) => {
return (
<div className="px-4 pb-3 w-full flex flex-col gap-5 items-center">
<h1 className="text-lg mt-3 font-medium tracking-wide text-black dark:text-white">
Wallet Balance:{` ${code} ${(+amount * 0.01).toFixed(2)}`}
</h1>
<p className="font-semibold text-center text-red-500 text-lg">
You do not have sufficient balance to assign this task
</p>
<button
onClick={openCreditPopup}
className="btn-gradient w-48 h-[46px] text-white rounded-full text-base bg-pink flex justify-center items-center"
>
Add Credit to Wallet
</button>
</div>
);
};
const TabButton = ({ item, selectedTab, setSelectedTab }) => (
<button
className={`px-4 py-1 rounded-t-2xl border-t-[2px] transition-all duration-200 flex flex-col justify-center items-center ${
selectedTab === item
? "bg-red-50 dark:bg-[#D85A5A] text-slate-600 font-extrabold"
: "bg-white text-[#000]"
}`}
value={item}
name={item}
onClick={() => setSelectedTab(item)}
>
<div
className={`mb-[1px] h-6 w-6 border-4 rounded-full transition-all duration-200 ${
selectedTab === item
? "border-white bg-emerald-500"
: "border-red-50 dark:border-[#D85A5A] bg-white"
}`}
></div>
{item[0].toUpperCase() + item.slice(1)}
</button>
);
+1 -1
View File
@@ -180,7 +180,7 @@ html {
.primary-home {
/*background: linear-gradient(134.38deg, #f539f8 0%, #284f64 43.55%, #1a3544 104.51%); */
background-image: url("./assets/images/left-myft.jpg");
background-image: url("./assets/images/left-wrenchboard.jpg");
background-repeat: no-repeat;
background-size: cover;
}
+274
View File
@@ -0,0 +1,274 @@
export const apiConst = {
LOGIN_MODE_GENERAL: 1100,
LOGIN_MODE_FAMILY: 1105,
ADD_JOB: 10010,
UPDATE_JOB: 10020,
PHP_API_OK: 0,
PHP_LOGIN_OK: 100,
PHP_CREATED_OK: 10,
PHP_API_BAD_PARAM: -1,
PHP_INVALID_SESSION: -9999,
SESSION_TIMEOUT_LOGOUT:6000,
MOBILE_LOGIN: 1101,
SUPPORT_PHONE:'+234 (818)-3866434',
UPLOAD_FILE_SIZE:1,
OFFER_ACCEPT:100,
OFFER_REJECT:333,
OFFER_CANCEL:222,
OFFER_EXPIRE:444,
JOB_INTEREST_ACCEPT:100,
JOB_INTEREST_REJECT:200,
JOB_INTEREST_CANCEL:300,
SMONEY_PROCC_MANUAL:100,
SMONEY_PROCC_AUTO:200,
SMONEY_PROCC_INTERSWITCH:300,
ACCOUNT_AGREE_JOBS:100,
ACCOUNT_AGREE_REFER:200,
WRENCHBOARD_SESSION_CHECK: 299,
WRENCHBOARD_USER_LOGIN: 300,
WRENCHBOARD_USER_LOGOUT: 301,
WRENCHBOARD_CREATE_ACCOUNT: 320,
CONTRACT_CANCEL_CONTRACT: 7,
CONTRACT_EXTEND_TIMELINE: 9,
CONTRACT_NOTIFY_COMPLETE: 4,
CONTRACT_REQUEST_CANCEL: 3,
CONTRACT_REQUEST_TIMELINE: 2,
CONTRACT_ACCEPT_COMPLETE: 5,
CONTRACT_REJECT_COMPLETE: 1,
WRENCHBOARD_SIGNUP_COUNTRY : 648,
WRENCHBOARD_GET_MEDIA: 650,
WRENCHBOARD_SAVE_MEDIA: 652,
WRENCH_FILE_PROFILE: 100,
WRENCH_FILE_MYFILE: 200,
WRENCH_FILE_CONTRACTS: 300,
WRENCH_FILE_FAMILY: 400,
WRENCH_FILE_FAMILYBANNER: 410,
WRENCH_FILE_JOB : 500,
WRENCHBOARD_BKO_START: 10000,
WRENCHBOARD_BKO_LOGIN: 10010,
WRENCHBOARD_BKO_CREATEUSER: 10015,
WRENCHBOARD_BKO_UPDATEUSER: 10020,
WRENCHBOARD_BKO_END: 10999,
WRENCHBOARD_ACCOUNT_START: 11000,
WRENCHBOARD_PROFILE_RESETPASS: 11005,
WRENCHBOARD_ACCOUNT_TESTEMAIL: 11001,
WRENCHBOARD_ACCOUNT_PENDING: 11010,
WRENCHBOARD_CREATE_MOBILEUSER: 11011,
WRENCHBOARD_COMPLETE_MOBILEUSER: 11012,
WRENCHBOARD_RESET_PASSWORD: 11013 ,
WRENCHBOARD_ACCOUNT_JOBLIST:11014 ,
WRENCHBOARD_VERIFY_PENDING_LINK: 11015,
WRENCHBOARD_ACCOUNT_RESETPASS: 11016,
WRENCHBOARD_ACCOUNT_SETPASSWD: 11017,
WRENCHBOARD_DELETE_PENDING_LINK: 11018,
WRENCHBOARD_RESEND_PENDING_LINK: 11019,
LOGIN_GOOGLE: 990010,
LOGIN_FACEBOOK: 990011,
LOGIN_APPLE: 990012,
WRENCHBOARD_ACCOUNT_DASHRECENT: 11206,
WRENCHBOARD_ACCOUNT_QRLOGIN: 11022,
WRENCHBOARD_ACCOUNT_CREATEACC: 11020,
WRENCHBOARD_ACCOUNT_AUXSTART: 11023,
WRENCHBOARD_ACCOUNT_AUXLOGIN: 11024,
WRENCHBOARD_ACCOUNT_LOGIN: 11025,
WRENCHBOARD_FACEBOOK_LOGIN: 11026,
WRENCHBOARD_GOOGLE_LOGIN: 11027,
WRENCHBOARD_APPLE_LOGIN: 11031,
WRENCHBOARD_START_JOBLIST: 11028,
WRENCHBOARD_ACCOUNT_DASHDATA: 11029,
WRENCHBOARD_SEND_CONTACTUS: 11030,
WRENCHBOARD_ACCOUNT_SENDREFER: 11032,
WRENCHBOARD_ACCOUNT_REFERLINK: 11033,
WRENCHBOARD_SESSION_VERIFY: 11034,
WRENCHBOARD_UPDATE_PROFILE: 11035,
WRENCHBOARD_ACCOUNT_TERMS: 11036,
WRENCHBOARD_ACCOUNT_MDESCRIPTION:11037,
WRENCHBOARD_ACCOUNT_SAVESKILL: 11038,
WRENCHBOARD_ACCOUNT_DELSKILL: 11039,
WRENCHBOARD_LOG_MEMBER: 11040,
WRENCHBOARD_DELETE_RECACC: 11041,
WRENCHBOARD_SAVE_GALLERY: 11042,
WRENCHBOARD_ACCOUNT_PENDJOB: 11043,
WRENCHBOARD_ACCT_NOTIFICATIONS: 11046,
WRENCHBOARD_ACCT_HELPITEMS: 11047,
WRECNH_CREDIT_HOOKS_FULUTTER: 11045,
WRENCHBOARD_USER_GETBANKLIST: 11050,
WRENCHBOARD_USER_SENDMONEY: 11051,
WRENCHBOARD_USER_SENDJOBINT: 11052,
WRENCHBOARD_USER_STARTCREDIT: 11053,
WRENCHBOARD_USER_ADNEWCC: 11054,
WRENCHBOARD_USER_CARDLIST: 11055,
WRENCHBOARD_USER_USESAVEDCC: 11056,
WRENCHBOARD_USER_CARDREMV: 11057,
WRENCHBOARD_USER_SETTINGS: 11058,
WRENCHBOARD_GETUSER_SETTINGS: 11059,
WRENCHBOARD_ACCOUNT_WALLETS: 11060,
WRENCHBOARD_ACCOUNT_TOPUP_RESULT: 11061,
WRENCHBOARD_ACCOUNT_PREPARE_TOPUP: 11062,
WRENCHBOARD_ACCOUNT_COMPLETE_TOPUP: 11063,
WRENCHBOARD_ACCOUNT_REFFERHX: 11064,
WRENCHBOARD_ACCOUNT_PREFERENCES: 11065,
WRENCHBOARD_ACCOUNT_MYPAGE: 11070,
WRENCHBOARD_ACCOUNT_PAGEINTRO: 11071,
WRENCHBOARD_ACCOUNT_PRICE_COMBO: 11171,
WRENCHBOARD_ACCOUNT_JOBPOST_DURATION: 11173,
WRENCHBOARD_ACCOUNT_USER_RECIPIENT: 11175,
WRENCHBOARD_ACCOUNT_ADD_RECIPIENT: 11176,
WRENCHBOARD_ACCOUNT_ACCOUNT_TYPES: 11177,
WRENCHBOARD_ACCOUNT_COUNTRY_COMBO: 11179,
WRENCHBOARD_ACCOUNT_JOB_COUNTRY: 11181,
WRENCHBOARD_ACCOUNT_COUNTRY_BANKS: 11183,
WRENCHBOARD_ACCOUNT_HOMEBANNERS: 11200,
WRENCHBOARD_ACCOUNT_PLAYGROUND: 11201,
WRENCHBOARD_ACCOUNT_FAMILY_BANNERS: 22005,
WRENCHBOARD_ACCOUNT_FAMILY_RESOURCES: 22017,
WRENCHBOARD_ACCOUNT_RECENTS: 11202,
WRENCHBOARD_ACCOUNT_NOTIFICATIONS: 11205,
WRENCHBOARD_PICTURE_PROFILE: 11300,
WRENCHBOARD_PICTURE_JOB: 11303,
WRENCHBOARD_PICTURE_FAMBANNER: 11304,
WRENCHBOARD_PICTURE_FAMMEMBER: 11305,
WRENCHBOARD_RESOURCE_MYFILES: 11307,
WRENCHBOARD_MYFILES_LIST: 11309,
WRENCHBOARD_RELATIVE_LIST: 22032,
WRENCHBOARD_RELATIVE_INVITE: 22031,
WRENCHBOARD_USER_DELETEACC: 11990,
WRENCHBOARD_ACCOUNT_END: 11999,
WRENCHBOARD_JOB_POSTAGREE: 13002,
WRENCHBOARD_JOB_LISTJOBS: 13005,
WRENCHBOARD_JOB_OFFERS: 13006,
WRENCHBOARD_JOB_ACTIVE: 13008,
WRENCHBOARD_JOB_USERACTIVE: 13009,
WRENCHBOARD_JOB_CREATEJOB: 13010 ,
WRENCHBOARD_JOB_DELETEJOB: 13011 ,
WRENCHBOARD_JOB_GROUP_MEMBER: 13015,
WRENCHBOARD_JOB_DELETE_GROUPMEMBER:13017,
WRENCHBOARD_JOB_CREATE_GROUP: 13020,
WRENCHBOARD_JOB_DELETE_GROUP:13023,
WRENCHBOARD_JOB_OFFER_INTLIST: 13024,
WRENCHBOARD_JOB_OFFER_SYSTEM: 13025,
WRENCHBOARD_JOB_OFFER_FAMILY: 13029,
WRENCHBOARD_JOB_OFFER_INDVI:13030,
WRENCHBOARD_JOB_OFFER_GROUP:13031,
WRENCHBOARD_JOB_OFFER_PUBLIC:13032,
WRENCHBOARD_JOB_SEND_INTEREST:13033,
WRENCHBOARD_JOB_PROC_INTEREST:13034,
WRENCHBOARD_JOB_OFFER_CONCLUDE:13035,
WRENCHBOARD_JOB_SEND_QUESTION:13036,
WRENCHBOARD_JOB_MRKTINT_QUEST:13037,
WRENCHBOARD_JOB_REPLY_QUESTION:13038,
WRENCHBOARD_JOB_INT_QUESTLST: 13039,
WRENCHBOARD_JOB_WAITING_INT: 13040,
WRENCHBOARD_JOB_EXTEND_EXPIRE: 13041,
WRENCHBOARD_JOB_RESEND_MESSAGE: 13042,
WRENCHBOARD_JOB_CANCEL_OFFER: 13043,
WRENCHBOARD_JOB_JOBGROUPS: 13045,
WRENCHBOARD_JOB_JOBGROUPADD: 13046,
WRENCHBOARD_JOB_REPORT: 13047,
WRENCHBOARD_GROUP_START: 12000,
WRENCHBOARD_GROUP_CREATEGROUP: 12010,
WRENCHBOARD_GROUP_INVITEGROUP: 12015,
WRENCHBOARD_GROUP_ACCEPTGROUP: 12020,
WRENCHBOARD_CONTRACT_MESSAGE: 14010,
WRENCHBOARD_CONTRACT_MSGLIST: 14011,
WRENCHBOARD_CONTRACT_STATUS: 14015,
WRENCHBOARD_MOBILE_OFFERSLIST: 15010,
WRENCHBOARD_MOBILE_OFFERSRESP: 15012,
WRENCHBOARD_MOBILE_ACTIVEJOB: 15020,
WRENCHBOARD_MOBILE_LOADPROFILE: 15030,
WRENCHBOARD_MOBILE_UPDATEPROFILE:15031,
WRENCHBOARD_MOBILE_ACCOUNT: 15040,
WRENCHBOARD_MOBILE_JOB_MESSAGE: 15044,
WRENCHBOARD_MOBILE_MESSAGE: 15045,
WRENCHBOARD_MOBILE_PAYMENTHX: 15046,
WRENCHBOARD_MOBILE_TASKMESSAGE: 15047,
WRENCHBOARD_MOBILE_SENDTASKMESSAGE: 15048,
WRENCHBOARD_MOBILE_PURCHASEHX: 15049,
WRENCHBOARD_FAMILY_LIST: 22010,
WRENCHBOARD_FAMILY_TRANSFERHX: 22011,
WRENCHBOARD_FAMILY_WALLET: 22012,
WRENCHBOARD_FAMILY_TRANSFERSTART: 22013,
WRENCHBOARD_FAMILY_TRANSFER: 22014,
WRENCHBOARD_FAMILY_ADD: 22015,
WRENCHBOARD_FAMILY_UPDATE: 22020,
WRENCHBOARD_FAMILY_MANAGE: 22025,
WRENCHBOARD_FAMILY_SGGESTSTATUS: 22026,
WRENCHBOARD_FAMILY_SAMPLETASKS: 22027,
WRENCHBOARD_FAMILY_SGGESTTASKS: 22028,
WRENCHBOARD_FAMILY_SGGESTLIST: 22029,
WRENCHBOARD_FAMILY_SGGESTWAITING: 22030,
WRENCHBOARD_FAMILY_RELINVITE: 22031,
WRENCHBOARD_SMONEY_ADDRECIPIENT: 33010,
WRENCHBOARD_SMONEY_MEMBER: 33020,
WRENCHBOARD_SMONEY_PROCFEE: 33025,
WRENCHBOARD_SMONEY_BKOPROC: 33030 ,
WRENCHBOARD_LOGIN_SHOP: 50501,
WRENCHBOARD_LOGIN_ADMIN: 50502,
WRENCHBOARD_LOGIN_MANAGER: 50503,
WRENCHBOARD_SURVEY_DATA: 55000,
WRENCHBOARD_ADD_SURVEY: 55050,
WRENCHBOARD_LOAD_SURVEY: 55055,
WRENCHBOARD_COMPLETE_SENDMONEY_INTERSW: 555,
WRENCHBOARD_GETBILLER_INTERSW: 556,
WRENCHBOARD_BILL_PAYMENT_ADVICE_INTERSW: 557,
WRENCHBOARD_INTERSW_GETBILLER: 556,
WRENCHBOARD_INTERSW_BILL_PAYMENT_ADVICE: 557,
WRENCHBOARD_INTERSW_GETBILLERPAYMENTINTEMS: 558,
WRENCHBOARD_INTERSW_GETBILLERCATEGORIES: 559,
WRENCHBOARD_INTERSW_DO_TRANSFER: 560,
WRENCHBOARD_INTERSW_QUERY_TRANSACTION: 561,
WRENCHBOARD_ADD_MONEYRECIPIENT: 600,
WRENCHBOARD_CREATE_USER_ACCOUNT: 700,
WRENCHBOARD_USER_ACCOUNT_LOGIN: 710,
WRENCHBOARD_START_PASSWORDRESET: 720,
WRENCHBOARD_VERIFY_PASSWD_RESETLINK: 725,
WRENCHBOARD_COMPLETE_PASSWORDRESET: 730,
WRENCHBOARD_CARDS_GETCARDLIST: 40010,
WRENCHBOARD_CARDS_UPDATECARD: 40015 ,
WRENCHBOARD_COUPON_REDEEM: 85020,
WRENCHBOARD_COUPON_MEMLIST: 85025,
WRENCHBOARD_COUPON_PENDLIST: 85030,
WRENCHBOARD_ADD_MOBILE_TOPUPNUM: 900,
WRENCHBOARD_PROMO_CALL: 990,
WRENCHBOARD_STOREFACE_GET_ACCOUNT_BALANCE: 891,
WRENCHBOARD_LOG_ENTRY: 900000,
WRENCHBOARD_CREDIT_TOPUP: 900010,
WRENCHBOARD_TOPUP_ORDER: 900020,
WRENCHBOARD_TOPUP_ORDER_PURCHASE: 900030,
WRENCHBOARD_PAYPAL_IPNMSG: 900090,
WRENCHBOARD_BULKTOPUP_ORDER: 700010,
WRENCHBOARD_BULKTOPUP_ITEM: 700020,
WRENCHBOARD_BULKTOPUP_ITEMUPDATE: 700030,
WRENCHBOARD_BULKTOPUP_DELIVER: 700040,
WRENCHBOARD_BALANCE_TOPUP_ORDER: 800020,
WRENCHBOARD_BALANCE_TOPUP_PURCHASE: 800030,
WRENCHBOARD_BALANCE_TOPUP_PAYMENT: 800040,
VIRTUAL_AIRTOPUP: 70011,
PAY_MODE_BALANCE: 0,
PAY_MODE_CCARD: 1,
PAY_MODE_BONUS: 9,
APPROVED_BALANCE: 5,
DISAPROVE_BALANCE: 3
};
+66 -19
View File
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Navigate, Outlet, useNavigate } from "react-router-dom";
import LoadingSpinner from "../components/Spinners/LoadingSpinner";
import { formattedDate } from "../lib";
import usersService from "../services/UsersService";
import { commonHeadBanner } from "../store/CommonHeadBanner";
import { recentActivitiesData } from "../store/RecentActivitiesData";
@@ -10,8 +11,8 @@ import { updateJobs } from "../store/jobLists";
import { updateNotifications } from "../store/notifications";
import { updateUserJobList } from "../store/userJobList";
import { updateWalletDetails } from "../store/walletDetails";
import { formattedDate } from "../lib";
import { tableReload } from "../store/TableReloads";
import { familyBannersList } from "../store/FamilyBannerList";
import { familyResources } from "../store/FamilyResources";
const AuthRoute = ({ redirectPath = "/login", children }) => {
const apiCall = useMemo(() => new usersService(), []);
@@ -21,12 +22,12 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
const [loadProfileDetails, setLoadProfileDetails] = useState([]);
const navigate = useNavigate();
const { jobListTable, walletTable } = useSelector(
const { jobListTable, walletTable, familyBannersListTable } = useSelector(
(state) => state.tableReload
);
const {
userDetails: { username, uid, session},
userDetails: { username, uid, session, account_type },
} = 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
@@ -38,6 +39,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
localStorage.removeItem("member_id");
localStorage.removeItem("session_token");
sessionStorage.removeItem("family_uid");
localStorage.clear();
navigate("/login", { replace: true }); // redirects user to login page after session expires
};
@@ -166,6 +168,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}, []);
useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
return
}
const getMyJobList = async () => {
dispatch(updateUserJobList({ loading: true, data: [] }));
try {
@@ -180,7 +185,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}
};
getMyJobList();
}, [jobListTable]);
}, [jobListTable, isLogin.status]);
useEffect(() => {
const getMyWalletList = async () => {
@@ -200,6 +205,9 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}, [walletTable]);
useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
return
}
// Getting market data
const getMarketActiveJobList = async () => {
try {
@@ -210,23 +218,26 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}
};
getMarketActiveJobList();
}, [apiCall, dispatch, jobListTable]);
}, [apiCall, dispatch, jobListTable, isLogin.status]);
//FUNCTION TO GET COMMON HEAD DATA
useEffect(() => {
apiCall
.getHeroJBanners()
.then((res) => {
if (res.data.internal_return < 0) {
return;
}
dispatch(commonHeadBanner(res.data));
})
.catch((error) => {
console.log("ERROR ", error);
});
}, []);
//
if((!loggedIn && !isLogin.status) || account_type == 'FAMILY'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FAMILY
return
}
apiCall
.getHeroJBanners()
.then((res) => {
if (res.data.internal_return < 0) {
return;
}
dispatch(commonHeadBanner(res.data));
})
.catch((error) => {
console.log("ERROR ", error);
});
}, [isLogin.status]);
//FUNCTION TO GET COMMON HEAD DATA
useEffect(() => {
apiCall
@@ -243,6 +254,42 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
});
}, []);
//FUNCTION TO GET FAMILY BANNERS
useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FULL'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
return
}
const getFamilyBanners = async () => { // FUNCTION TO GET FAMILY BANNERS
// setFamilyBannersList({loading:true, result:[]});
try {
const res = await apiCall.getFamilyBannersList();
dispatch(familyBannersList({...res.data, loading:false}))
} catch (error) {
dispatch(familyBannersList({loading:false}))
console.log("Error getting tasks");
}
};
getFamilyBanners()
}, [isLogin.status, familyBannersListTable]);
//FUNCTION TO GET FAMILY RESOURCES
useEffect(() => {
if((!loggedIn && !isLogin.status) || account_type == 'FULL'){ // DO NOT CALL THIS, IF USER ACCOUNT TYPE IS FULL
return
}
const getFamilyResourcesList = async () => { // FUNCTION TO GET FAMILY BANNERS
try {
const res = await apiCall.getFamilyResources();
dispatch(familyResources(res?.data?.result_list))
// console.log('RESPONSE', res?.data?.result_list)
} catch (error) {
console.log("Error getting tasks");
}
};
getFamilyResourcesList()
}, [isLogin.status, familyBannersListTable]);
// useEffect(() => {
// apiCall
// .getHeroJBanners()
+2 -1
View File
@@ -1,4 +1,5 @@
import Axios from "axios";
import { apiConst } from "../lib/apiConst";
class SiteService {
constructor() {
@@ -32,7 +33,7 @@ class SiteService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22015,
action: apiConst.WRENCHBOARD_FAMILY_ADD,
...reqData,
};
return this.postAuxEnd("/familyadd", postData);
+175 -96
View File
@@ -1,4 +1,5 @@
import Axios from "axios";
import { apiConst } from "../lib/apiConst";
class usersService {
constructor() {
@@ -10,7 +11,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData
...reqData,
};
return this.postAuxEnd("/mypageintro", postData);
}
@@ -20,7 +21,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11070
action: apiConst.WRENCHBOARD_ACCOUNT_MYPAGE,
};
return this.postAuxEnd("/mypageload", postData);
}
@@ -30,12 +31,23 @@ class usersService {
return this.postAuxEnd("/createuser", reqData);
}
blogData() {
return this.getAuxEnd("/blogdata", null);
}
CompleteOauthLogin(reqData) {
localStorage.setItem("session_token", ``);
return this.postAuxEnd("/authlogin", reqData);
}
CompleteSignUp(reqData) {
CompleteSignUp(postData) {
localStorage.setItem("session_token", ``);
var reqData = {
login_mode: 100,
sessionid: "STARTER-NOTREAL",
action: apiConst.WRENCHBOARD_COMPLETE_MOBILEUSER,
...postData,
};
return this.postAuxEnd("/completesignuplink", reqData);
}
@@ -44,6 +56,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_JOB_OFFER_SYSTEM,
...reqData,
};
return this.postAuxEnd("/assigntask", postData);
@@ -65,13 +78,18 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11202,
action: apiConst.WRENCHBOARD_ACCOUNT_RECENTS,
};
return this.postAuxEnd("/recentactivities", postData);
}
logInUser(reqData) {
logInUser(postData) {
localStorage.setItem("session_token", ``);
var reqData = {
action: apiConst.WRENCHBOARD_ACCOUNT_LOGIN,
...postData,
};
return this.postAuxEnd("/userlogin", reqData);
}
@@ -133,7 +151,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 1,
limit: 20,
action: 11309,
action: apiConst.WRENCHBOARD_MYFILES_LIST,
};
return this.postAuxEnd("/myfiles", postData);
}
@@ -250,7 +268,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 1,
limit: 20,
action: 11175,
action: apiConst.WRENCHBOARD_ACCOUNT_USER_RECIPIENT,
};
return this.postAuxEnd("/recipients", postData);
}
@@ -273,7 +291,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
amount,
action: 33025,
action: apiConst.WRENCHBOARD_SMONEY_PROCFEE,
};
return this.postAuxEnd("/sendmoneyfee", postData);
}
@@ -284,7 +302,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11053,
action: apiConst.WRENCHBOARD_USER_STARTCREDIT,
...value,
};
return this.postAuxEnd("/startcredit", postData);
@@ -296,7 +314,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11056,
action: apiConst.WRENCHBOARD_USER_USESAVEDCC,
...value,
};
return this.postAuxEnd("/payprevcard", postData);
@@ -308,7 +326,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11054,
action: apiConst.WRENCHBOARD_USER_ADNEWCC,
...value,
};
return this.postAuxEnd("/paynewcard", postData);
@@ -321,7 +339,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
limit: 30,
offset: 0,
action: 22027,
action: apiConst.WRENCHBOARD_FAMILY_SAMPLETASKS,
};
return this.postAuxEnd("/familysampletasks", postData);
}
@@ -331,7 +349,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13010,
action: apiConst.WRENCHBOARD_JOB_CREATEJOB,
...reqData,
};
return this.postAuxEnd("/familysuggesttasks", postData);
@@ -343,7 +361,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22025,
action: apiConst.WRENCHBOARD_FAMILY_MANAGE,
...reqData,
};
return this.postAuxEnd("/familymanage", postData);
@@ -358,7 +376,7 @@ class usersService {
job_mode: "ACTIVE",
limit: 30,
offset: 0,
action: 13008,
action: apiConst.WRENCHBOARD_JOB_ACTIVE,
...reqData,
};
return this.postAuxEnd("/jobmanageractive", postData);
@@ -370,7 +388,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13010,
action: apiConst.WRENCHBOARD_JOB_CREATEJOB,
limit: 30,
offset: 0,
};
@@ -471,7 +489,7 @@ class usersService {
uuid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22010,
action: apiConst.WRENCHBOARD_FAMILY_LIST,
...reqData,
};
return this.postAuxEnd("/askresources", postData);
@@ -509,7 +527,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 1,
limit: 20,
action: 85025,
action: apiConst.WRENCHBOARD_COUPON_MEMLIST,
};
return this.postAuxEnd("/couponhx", postData);
}
@@ -521,7 +539,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 1,
limit: 20,
action: 15049,
action: apiConst.WRENCHBOARD_MOBILE_PURCHASEHX,
};
return this.postAuxEnd("/purchasehx", postData);
}
@@ -534,7 +552,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
offset: 1,
limit: 20,
action: 22011,
action: apiConst.WRENCHBOARD_FAMILY_TRANSFERHX,
};
return this.postAuxEnd("/familyrewardhx", postData);
}
@@ -547,7 +565,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 1,
limit: 20,
action: 15046,
action: apiConst.WRENCHBOARD_MOBILE_PAYMENTHX,
};
return this.postAuxEnd("/paymenthx", postData);
}
@@ -558,7 +576,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 33020,
action: apiConst.WRENCHBOARD_SMONEY_MEMBER,
...reqData,
};
return this.postAuxEnd("/sendmoney", postData);
@@ -572,7 +590,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
offset: 1,
limit: 100,
action: 11064,
action: apiConst.WRENCHBOARD_ACCOUNT_REFFERHX,
};
return this.postAuxEnd("/refferhx", postData);
}
@@ -583,7 +601,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 5031,
action: apiConst.WRENCHBOARD_MOBILE_UPDATEPROFILE,
...post,
};
return this.postAuxEnd("/updateprofile", postData);
@@ -628,6 +646,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
page: 0,
limit: 100,
action: apiConst.WRENCHBOARD_FAMILY_UPDATE,
...reqdata,
};
return this.postAuxEnd("/familyupdate", postData);
@@ -663,10 +682,10 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: Number(localStorage.getItem("member_id")),
sessionid: localStorage.getItem("session_token"),
action: 11061,
action: apiConst.WRENCHBOARD_ACCOUNT_TOPUP_RESULT,
...post,
};
console.log("topupresult", postData);
// console.log("topupresult", postData);
return this.postAuxEnd("/topupresult", postData);
}
@@ -676,17 +695,26 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11032,
action: apiConst.WRENCHBOARD_ACCOUNT_SENDREFER,
...postData,
};
return this.postAuxEnd("/sendreferral", reqData);
}
StartResetPassword(reqData) {
StartResetPassword(postData) {
var reqData = {
action: apiConst.WRENCHBOARD_RESET_PASSWORD,
...postData,
};
return this.postAuxEnd("/startresetpasword", reqData);
}
CompleteResetPassword(reqData) {
CompleteResetPassword(postData) {
var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY",
action: apiConst.WRENCHBOARD_COMPLETE_PASSWORDRESET,
...postData,
};
return this.postAuxEnd("/stepresetpass", reqData);
}
@@ -695,7 +723,7 @@ class usersService {
uuid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 85020,
action: apiConst.WRENCHBOARD_COUPON_REDEEM,
...reqData,
};
return this.postAuxEnd("/couponredeem", postData);
@@ -712,7 +740,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11183,
action: apiConst.WRENCHBOARD_ACCOUNT_COUNTRY_BANKS,
...value,
};
return this.postAuxEnd("/countrybanks", postData);
@@ -724,7 +752,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11177,
action: apiConst.WRENCHBOARD_ACCOUNT_ACCOUNT_TYPES,
};
return this.postAuxEnd("/accounttypes", postData);
}
@@ -736,7 +764,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
msg_type: "JOB",
action: 13033,
action: apiConst.WRENCHBOARD_JOB_SEND_INTEREST,
...reqData,
};
return this.postAuxEnd("/marketinterest", postData);
@@ -748,7 +776,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
msg_type: "JOB",
action: 13036,
action: apiConst.WRENCHBOARD_JOB_SEND_QUESTION,
...reqData,
};
return this.postAuxEnd("/marketmessage", postData);
@@ -760,7 +788,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13002,
action: apiConst.WRENCHBOARD_JOB_POSTAGREE,
};
return this.postAuxEnd("/jobmanageragree", postData);
}
@@ -771,7 +799,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13010,
action: apiConst.WRENCHBOARD_JOB_CREATEJOB,
...reqData,
};
return this.postAuxEnd("/jobmanagercreatejob", postData);
@@ -782,7 +810,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13010,
action: apiConst.WRENCHBOARD_JOB_CREATEJOB,
...reqData,
};
return this.postAuxEnd("/jobmanagerupdatejob", postData);
@@ -794,7 +822,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
extend_days: 7,
action: 13041,
action: apiConst.WRENCHBOARD_JOB_EXTEND_EXPIRE,
...reqData,
};
return this.postAuxEnd("/pendingjobextend", postData);
@@ -806,7 +834,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
mode: 200,
action: 13042,
action: apiConst.WRENCHBOARD_JOB_RESEND_MESSAGE,
...reqData,
};
return this.postAuxEnd("/pendingjobsendtome", postData);
@@ -817,7 +845,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13043,
action: apiConst.WRENCHBOARD_JOB_CANCEL_OFFER,
...reqData,
};
return this.postAuxEnd("/pendingjobcancel", postData);
@@ -830,7 +858,7 @@ class usersService {
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
limit: 30,
action: 14011,
action: apiConst.WRENCHBOARD_CONTRACT_MSGLIST,
offset: 0,
...reqData,
};
@@ -843,7 +871,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 14010,
action: apiConst.WRENCHBOARD_CONTRACT_MESSAGE,
...reqData,
};
return this.postAuxEnd("/sendtaskmessage", postData);
@@ -855,10 +883,10 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 14010,
action: apiConst.WRENCHBOARD_CONTRACT_MESSAGE,
...reqData,
};
const formData = new FormData();
for (let data in postData) {
formData.append(data, postData[data]);
@@ -873,7 +901,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13011,
action: apiConst.WRENCHBOARD_JOB_DELETEJOB,
...reqData,
};
return this.postAuxEnd("/jobmanagerdeletejob", postData);
@@ -882,7 +910,7 @@ class usersService {
verifyEmail(code) {
const reqData = {
verify_link: code,
action: 11015,
action: apiConst.WRENCHBOARD_VERIFY_PENDING_LINK,
};
return this.postAuxEnd("/verifysignuplink", reqData);
}
@@ -893,7 +921,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 15012,
action: apiConst.WRENCHBOARD_MOBILE_OFFERSRESP,
...reqData,
};
return this.postAuxEnd("/offersresponse", postData);
@@ -905,7 +933,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13024,
action: apiConst.WRENCHBOARD_JOB_OFFER_INTLIST,
limit: 30,
offset: 0,
};
@@ -918,7 +946,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13034,
action: apiConst.WRENCHBOARD_JOB_OFFER_INTLIST,
...reqData,
};
return this.postAuxEnd("/offersinterestproc", postData);
@@ -930,7 +958,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 14015,
action: apiConst.WRENCHBOARD_CONTRACT_STATUS,
...reqData,
};
return this.postAuxEnd("/activetaskstatus", postData);
@@ -942,7 +970,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 14015,
action: apiConst.WRENCHBOARD_CONTRACT_STATUS,
...reqData,
};
return this.postAuxEnd("/activejobstatus", postData);
@@ -963,7 +991,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
limit: 30,
offset: 0,
action: 11205,
action: apiConst.WRENCHBOARD_ACCOUNT_NOTIFICATIONS,
};
return this.postAuxEnd("/mynotifications", postData);
}
@@ -974,7 +1002,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11055,
action: apiConst.WRENCHBOARD_USER_CARDLIST,
};
return this.postAuxEnd("/paylistcard", postData);
}
@@ -985,7 +1013,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13037,
action: apiConst.WRENCHBOARD_JOB_MRKTINT_QUEST,
...reqData,
};
return this.postAuxEnd("/offerinterestmsg", postData);
@@ -997,7 +1025,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13037,
action: apiConst.WRENCHBOARD_JOB_MRKTINT_QUEST,
...reqData,
};
return this.postAuxEnd("/offerinterestlistmsg", postData);
@@ -1019,7 +1047,9 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
limit: 20,
offset: 0,
action: apiConst.WRENCHBOARD_FAMILY_LIST,
};
return this.postAuxEnd("/familylist", postData);
}
@@ -1030,7 +1060,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13025,
action: apiConst.WRENCHBOARD_JOB_OFFER_SYSTEM,
...reqData,
};
return this.postAuxEnd("/assigntask", postData);
@@ -1044,7 +1074,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
limit: 30,
offset: 0,
action: 13010,
action: apiConst.WRENCHBOARD_JOB_OFFER_SYSTEM,
};
return this.postAuxEnd("/familysuggestlist", postData);
}
@@ -1055,7 +1085,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11005,
action: apiConst.WRENCHBOARD_PROFILE_RESETPASS,
...reqData,
};
return this.postAuxEnd("/profilepasschange", postData);
@@ -1067,7 +1097,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11059,
action: apiConst.WRENCHBOARD_GETUSER_SETTINGS,
};
return this.postAuxEnd("/getaccsettings", postData);
}
@@ -1078,7 +1108,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11058,
action: apiConst.WRENCHBOARD_USER_SETTINGS,
...reqdata,
};
return this.postAuxEnd("/setaccsettings", postData);
@@ -1090,7 +1120,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 11057,
action: apiConst.WRENCHBOARD_USER_CARDREMV,
...reqData,
};
return this.postAuxEnd("/payremcard", postData);
@@ -1103,7 +1133,7 @@ class usersService {
sessionid: localStorage.getItem("session_token"),
limit: 30,
offset: 0,
action: 11202,
action: apiConst.WRENCHBOARD_ACCOUNT_RECENTS,
};
return this.postAuxEnd("/recentactivities", postData);
}
@@ -1125,7 +1155,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22026,
action: apiConst.WRENCHBOARD_FAMILY_SGGESTSTATUS,
...reqData,
};
return this.postAuxEnd("/suggeststatus", postData);
@@ -1137,7 +1167,7 @@ class usersService {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22012,
action: apiConst.WRENCHBOARD_FAMILY_WALLET,
...reqData,
};
return this.postAuxEnd("/familywallet", postData);
@@ -1165,41 +1195,90 @@ class usersService {
return this.postAuxEnd("/familytransfer", postData);
}
// FUNCTION GET JOB GROUP LIST
jobGroupList(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_JOB_JOBGROUPS,
...reqData,
};
return this.postAuxEnd("/jobgrouplist", postData);
}
// FUNCTION GET JOB GROUP LIST
jobGroupList(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 13045,
...reqData,
};
return this.postAuxEnd("/jobgrouplist", postData);
}
// FUNCTION TO ADD JOB GROUP
jobGroupAdd(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/jobgroupadd", postData);
}
// FUNCTION TO ADD JOB GROUP
jobGroupAdd(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/jobgroupadd", postData);
}
// FUNCTION TO ADD JOB GROUP MEMBER
groupMemberAdd(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/groupmemberadd", postData);
}
// FUNCTION TO ADD JOB GROUP MEMBER
groupMemberAdd(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/groupmemberadd", postData);
}
// API FUNCTION TO GET FAMILY RELATIVE
getFamilyRelativeList() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
offset: 1,
limit: 20,
action: apiConst.WRENCHBOARD_RELATIVE_LIST,
};
return this.postAuxEnd("/familyrellist", postData);
}
// API FUNCTION TO ADD/INVITE FAMILY RELATIVE
inviteFamilyRelative(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_RELATIVE_INVITE,
...reqData,
};
return this.postAuxEnd("/familyrelinvite", postData);
}
// API FUNCTION TO FAMILY BANNERS
getFamilyBannersList() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_ACCOUNT_FAMILY_BANNERS,
limit: 20,
offset: 1,
};
return this.postAuxEnd("/familybanners", postData);
}
// API FUNCTION TO FAMILY RESOURCES
getFamilyResources() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: apiConst.WRENCHBOARD_ACCOUNT_FAMILY_RESOURCES,
limit: 20,
offset: 1,
};
return this.postAuxEnd("/familyresources", postData);
}
/*
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username)
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password)

Some files were not shown because too many files have changed in this diff Show More