Compare commits

...

93 Commits

Author SHA1 Message Date
victorAnumudu 436498bef9 added background image to error page 2023-10-31 19:51:36 +01:00
victorAnumudu 086b1202a4 error 404 page adjusted 2023-10-31 16:59:02 +01:00
ameye a81ccdc4d7 Merge branch 'reward-tab-cleanup' of WrenchBoard/Users-Wrench into master 2023-10-31 12:57:55 +00:00
victorAnumudu 33abbbcd2b adjusted reward component contents 2023-10-31 13:53:02 +01:00
ameye 04844af733 Merge branch 'lastname-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-31 12:42:42 +00:00
victorAnumudu 46d919090d lastname bug fixed 2023-10-31 13:36:53 +01:00
ameye 8e67892f16 Merge branch 'rewards-tab' of WrenchBoard/Users-Wrench into master 2023-10-31 12:21:17 +00:00
victorAnumudu a67d2b7bb4 reward tab clean up 2023-10-31 13:16:33 +01:00
victorAnumudu 99c0c24489 Merge master into rewards-tab 2023-10-31 13:15:22 +01:00
victorAnumudu 1a1d59a8c7 rewards API implemented 2023-10-31 13:13:58 +01:00
ameye 31dcfcfd0b Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-31 11:45:48 +00:00
Chief Bube e9aa58f2f5 Added tracking text color 2023-10-31 04:42:50 -07:00
victorAnumudu 55fe2bf6d2 Merge master into rewards-tab 2023-10-31 04:23:42 +01:00
victorAnumudu 738eb1589e rewards tab added 2023-10-31 04:22:50 +01:00
ameye 139e0c2827 Merge branch 'send-btn-disable' of WrenchBoard/Users-Wrench into master 2023-10-30 17:43:22 +00:00
victorAnumudu 30642bba14 disabled send btn on successful transfer 2023-10-30 16:29:45 +01:00
ameye f5921612b8 Merge branch 'balance-bug' of WrenchBoard/Users-Wrench into master 2023-10-30 14:43:49 +00:00
victorAnumudu 38afece043 Merge master into balance-bug 2023-10-30 15:40:34 +01:00
victorAnumudu d44447c6b3 returned balance to 2 decimal places 2023-10-30 15:39:38 +01:00
ameye d942c6641a Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-30 14:12:06 +00:00
Chief Bube beed565ba0 Updated Transaction popup layout 2023-10-30 07:04:01 -07:00
ameye 329e27b83d Merge branch 'family-transfer-bug' of WrenchBoard/Users-Wrench into master 2023-10-28 22:42:25 +00:00
victorAnumudu 3145656d80 checked that required parameters are not empty before outputting success message 2023-10-28 23:39:11 +01:00
victorAnumudu 5098a45bd5 fixed family transfer bug 2023-10-28 23:06:53 +01:00
ameye 9e65a6e7d5 Merge branch 'family-transfer' of WrenchBoard/Users-Wrench into master 2023-10-28 21:33:04 +00:00
victorAnumudu 83ac1087f3 Merge master into family-transfer 2023-10-28 17:48:42 +01:00
victorAnumudu 55b2bccdf0 family transfer API added 2023-10-28 17:47:36 +01:00
ameye 0c51474dd2 Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-28 12:38:17 +00:00
CHIEFSOFT\ameye 8c7ffb52a5 captcha text 2023-10-28 08:30:28 -04:00
Chief Bube 6c698bc399 fixed array list 2023-10-27 20:37:25 -07:00
ameye 540ad6f9ad Merge branch 'family-start-transfer' of WrenchBoard/Users-Wrench into master 2023-10-27 19:55:00 +00:00
victorAnumudu 11342c32c6 Family start transfer API added 2023-10-27 19:22:54 +01:00
ameye 356c11d029 Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-26 20:17:15 +00:00
Chief Bube 934d95e822 Added Tracking to Family Profile 2023-10-26 10:25:00 -07:00
ameye 0aa49b49a9 Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-26 08:22:30 +00:00
Chief Bube be52792271 fixed height issues 2023-10-25 13:51:39 -07:00
ameye c23e61e06b Merge branch 'family-add-fund-modal' of WrenchBoard/Users-Wrench into master 2023-10-25 20:20:19 +00:00
victorAnumudu 24b9a0e348 made amount to align right 2023-10-25 19:37:36 +01:00
victorAnumudu fcb154ba49 request message removed 2023-10-25 19:27:08 +01:00
victorAnumudu c0065ed569 Merge master into family-add-fund-modal 2023-10-25 19:23:06 +01:00
victorAnumudu 05a2ebec61 added family add fund modal 2023-10-25 19:19:55 +01:00
ameye 63f7deaa2b Merge branch 'job-increse-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-25 14:47:55 +00:00
Chief Bube d762ef42e8 Fixed positioning 2023-10-25 07:43:47 -07:00
ameye 3e34c81789 Merge branch 'job-increse-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-25 09:15:19 +00:00
Chief Bube a2340af314 tiny bug fix and checker added 2023-10-24 19:09:09 -07:00
Chief Bube 2a445fd2d4 tiny feature added 2023-10-24 18:55:37 -07:00
Chief Bube b5e52fb34e Fixed button position 2023-10-24 18:48:17 -07:00
ameye 87512bbc23 Merge branch 'family-balance' of WrenchBoard/Users-Wrench into master 2023-10-24 18:07:43 +00:00
victorAnumudu 1e59059394 Merge master into family-balance 2023-10-24 17:47:13 +01:00
victorAnumudu e59c83d216 made balance container take whole width 2023-10-24 17:45:10 +01:00
ameye 395569dab5 Merge branch 'job-increse-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-24 15:47:03 +00:00
Chief Bube 25a537c5bc changed duplicate 2023-10-24 08:25:52 -07:00
Chief Bube 5244a2875e Interest Popup Fix 2023-10-24 08:18:32 -07:00
victorAnumudu 54560b3fec Merge master into family-balance 2023-10-24 15:27:23 +01:00
victorAnumudu 078d26317f family balance added 2023-10-24 15:26:24 +01:00
ameye 8dbf638c7f Merge branch 'interest-popout-size' of WrenchBoard/Users-Wrench into master 2023-10-24 11:39:09 +00:00
CHIEFSOFT\ameye a68af7c3a4 cooment 2023-10-24 06:38:38 -04:00
CHIEFSOFT\ameye 905d48ceb7 package json lock 2023-10-24 06:34:30 -04:00
victorAnumudu 1e5dac0104 adjusted interest popout style 2023-10-24 11:22:51 +01:00
ameye 11e52a02f6 Merge branch 'family-wallet' of WrenchBoard/Users-Wrench into master 2023-10-24 08:51:02 +00:00
ameye 4e74198ae5 Merge branch 'job-increse-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-24 08:50:55 +00:00
ameye 5d673a630c Merge branch 'banner-fix' of WrenchBoard/Users-Wrench into master 2023-10-24 08:50:47 +00:00
victorAnumudu adcb33764b added family wallet icon 2023-10-24 07:26:27 +01:00
Chief Bube 305bff1167 Job count increase - bug fixed 2023-10-23 22:51:47 -07:00
victorAnumudu 1ebe9fe12b Fixed banner image 2023-10-23 20:37:10 +01:00
ameye 3fbaf6b78a Merge branch 'update-family-validation' of WrenchBoard/Users-Wrench into master 2023-10-23 16:37:19 +00:00
victorAnumudu 421a24c185 added validation to update family component 2023-10-23 17:23:43 +01:00
ameye 6386fbcda6 Merge branch 'family-update' of WrenchBoard/Users-Wrench into master 2023-10-23 11:34:35 +00:00
victorAnumudu 2e09d77597 bug fix 2023-10-23 12:27:54 +01:00
victorAnumudu 10dae9193c added family update component 2023-10-23 12:17:32 +01:00
ameye 3f487337f4 Merge branch 'interest-style-fix' of WrenchBoard/Users-Wrench into master 2023-10-22 18:08:02 +00:00
victorAnumudu 7eabee8855 updated interest popout btn and font style 2023-10-22 19:04:14 +01:00
ameye 360f0500a9 Merge branch 'btn-customization' of WrenchBoard/Users-Wrench into master 2023-10-22 12:16:34 +00:00
victorAnumudu 9b6c5b72ad changed cancel btn style 2023-10-22 05:52:47 +01:00
ameye afc5e25cfc Merge branch 'login-captcha' of WrenchBoard/Users-Wrench into master 2023-10-17 17:40:06 +00:00
victorAnumudu 58fe5eb82c captcha added in login page 2023-10-17 18:26:46 +01:00
CHIEFSOFT\ameye 2f3fdc0695 google captach settings 2023-10-17 07:01:05 -04:00
ameye 0a465fceb0 Merge branch 'btn-height-adjustment' of WrenchBoard/Users-Wrench into master 2023-10-16 20:26:23 +00:00
victorAnumudu 5e968db2f5 adjusted btn height 2023-10-16 21:08:06 +01:00
ameye 1916bc1a65 Merge branch 'btn-rename' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:55 +00:00
ameye 1103127cae Merge branch 'btn-customized' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:47 +00:00
ameye 751369071c Merge branch 'family-task-reload' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:39 +00:00
ameye 4cc8f27c14 Merge branch 'profile-upload-revert' of WrenchBoard/Users-Wrench into master 2023-10-16 18:41:07 +00:00
ameye aab455c2c3 Merge branch 'Changed-Naira-Wallet-Country-Display' of WrenchBoard/Users-Wrench into master 2023-10-16 13:52:03 +00:00
Ebube 21843c4bc7 Changed Naira Wallet Country Display 2023-10-16 13:43:48 +01:00
Ebube 8702728ffa Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into Recent-Activities 2023-10-16 13:12:24 +01:00
victorAnumudu 79dcd0f2b5 btn style customized 2023-10-16 11:49:03 +01:00
ameye 47b25f3dfe Merge branch 'google-recaptcha' of WrenchBoard/Users-Wrench into master 2023-10-16 00:30:06 +00:00
victorAnumudu a8416a8433 made family page to reload after adding a task 2023-10-10 10:17:22 +01:00
victorAnumudu 70c9d1778c renamed edit job btn to save 2023-10-10 07:02:52 +01:00
Ebube 930559c96b Family Picture 2023-10-09 13:32:07 +01:00
victorAnumudu c4af2dfcc8 changed timeout duration 2023-10-09 11:29:11 +01:00
victorAnumudu b186549b8d added profile upload API 2023-10-09 11:22:38 +01:00
42 changed files with 1424 additions and 167 deletions
+6 -1
View File
@@ -90,4 +90,9 @@ REACT_APP_SHOW_OFFER_GROUP_JOB=0
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
#FAMILY MEMBER MINIMUM AGE
REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
+6 -1
View File
@@ -58,4 +58,9 @@ REACT_APP_SHOW_OFFER_GROUP_JOB=0
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
#FAMILY MEMBER MINIMUM AGE
REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
+6 -1
View File
@@ -64,4 +64,9 @@ REACT_APP_SHOW_OFFER_GROUP_JOB=0
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
#GOOGLE RECAPTCHA SITEKEY
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
REACT_APP_GOOGLE_RECAPTCHA_SITEKEY=6Ld_qKooAAAAADNL1TPzRLmcBA8vlpvx__39Rj39
#6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
#FAMILY MEMBER MINIMUM AGE
REACT_APP_FAMILY_MINIMUM_AGE=4
REACT_APP_FAMILY_MAXIMUM_AGE=18
+2
View File
@@ -19,6 +19,8 @@
.env.test.local
.env.production.local
#package-lock.json
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+74
View File
@@ -22,13 +22,17 @@
"flutterwave-react-v3": "^1.3.0",
"formik": "^2.2.9",
"react": "^18.2.0",
"react-apple-login": "^1.1.6",
"react-chartjs-2": "^4.1.0",
"react-countup": "^6.2.0",
"react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-qr-code": "^2.0.11",
"react-redux": "^8.0.5",
"react-router-dom": "^6.0.2",
"react-scripts": "5.0.1",
"react-slick": "^0.29.0",
"react-to-print": "^2.14.12",
"react-toastify": "^9.0.1",
"redux": "^4.2.0",
"slick-carousel": "^1.8.1",
@@ -14801,6 +14805,11 @@
"teleport": ">=0.2.0"
}
},
"node_modules/qr.js": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
"integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ=="
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
@@ -14944,6 +14953,32 @@
"url": "https://opencollective.com/core-js"
}
},
"node_modules/react-apple-login": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/react-apple-login/-/react-apple-login-1.1.6.tgz",
"integrity": "sha512-ySV6ax0aB+ksA7lKzhr4MvsgjwSH068VtdHJXS+7rL380IJnNQNl14SszR31k3UqB8q8C1H1oyjJFGq4MyO6tw==",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"peerDependencies": {
"prop-types": "^15.5.4",
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-async-script": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
"dependencies": {
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.5.0"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-chartjs-2": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz",
@@ -15044,11 +15079,41 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
},
"node_modules/react-google-recaptcha": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
"integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==",
"dependencies": {
"prop-types": "^15.5.0",
"react-async-script": "^1.2.0"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-qr-code": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.12.tgz",
"integrity": "sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==",
"dependencies": {
"prop-types": "^15.8.1",
"qr.js": "0.0.0"
},
"peerDependencies": {
"react": "^16.x || ^17.x || ^18.x",
"react-native-svg": "*"
},
"peerDependenciesMeta": {
"react-native-svg": {
"optional": true
}
}
},
"node_modules/react-redux": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
@@ -15218,6 +15283,15 @@
"react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-to-print": {
"version": "2.14.15",
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.15.tgz",
"integrity": "sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w==",
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-toastify": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.1.tgz",
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

+10
View File
@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 64 64" viewBox="0 0 64 64" id="wallet"><path d="M60.94,33.76H59.6V19.85c0-1.69-1.37-3.06-3.06-3.06h-1.61l-0.47-6.54c-0.12-1.67-1.57-2.94-3.27-2.84l-7.3,0.52
l-0.18-2.48c-0.12-1.67-1.57-2.95-3.27-2.84L7.83,4.93c-0.82,0.06-1.56,0.43-2.1,1.05C5.19,6.6,4.93,7.39,4.99,8.2l0.61,8.59H3.06
C1.37,16.79,0,18.17,0,19.85v38.48c0,1.69,1.37,3.06,3.06,3.06h53.48c1.69,0,3.06-1.37,3.06-3.06V44.43h1.33
c1.69,0,3.06-1.37,3.06-3.06v-4.55C64,35.13,62.63,33.76,60.94,33.76z M51.42,9.94c0.27,0,0.51,0.22,0.53,0.49l0.45,6.36H18.55
l-0.28-3.97c-0.01-0.19,0.07-0.32,0.13-0.38c0.05-0.06,0.17-0.17,0.36-0.18L51.42,9.94z M7.65,7.64C7.7,7.58,7.82,7.47,8.01,7.46
l32.66-2.32c0.27,0,0.51,0.22,0.53,0.49l0.18,2.48L18.58,9.73c-0.82,0.06-1.56,0.43-2.1,1.05c-0.54,0.62-0.8,1.41-0.74,2.22
l0.27,3.79H8.14L7.52,8.02C7.5,7.83,7.59,7.7,7.65,7.64z M57.07,58.34c0,0.28-0.24,0.53-0.53,0.53H3.06
c-0.28,0-0.53-0.24-0.53-0.53V19.85c0-0.29,0.24-0.53,0.53-0.53h53.48c0.28,0,0.53,0.24,0.53,0.53v13.91h-4.43
c-1.69,0-3.06,1.37-3.06,3.06v4.55c0,1.69,1.37,3.06,3.06,3.06h4.43V58.34z M61.47,41.37c0,0.28-0.24,0.53-0.53,0.53h-8.3
c-0.28,0-0.53-0.24-0.53-0.53v-4.55c0-0.28,0.24-0.53,0.53-0.53h8.3c0.29,0,0.53,0.24,0.53,0.53V41.37z"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

@@ -24,7 +24,7 @@ const ForgetPwdResponse = ({title, message, type}) => {
<button
type="button"
onClick={() => navigate("/login")}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
>
<span>Home</span>
</button>
@@ -172,11 +172,18 @@ export default function ForgotPassword() {
</div>
)}
<div className="signin-area mb-3.5">
<div className="flex justify-center items-center gap-2">
<div className="flex justify-center items-center gap-4">
<button
type="button"
onClick={() => navigate("/login")}
className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white hover:text-white flex justify-center bg-red-500 hover:bg-red-600 transition-all duration-300 items-center py-[0.8875rem] px-[1.8125rem] `}
>
Cancel
</button>
<button
type="button"
onClick={resetHandler}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
className={`h-[48px] rounded-full mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
>
{resetLoading ? (
<div className="signup btn-loader"></div>
@@ -184,13 +191,6 @@ export default function ForgotPassword() {
<span>Send Code</span>
)}
</button>
<button
type="button"
onClick={() => navigate("/login")}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-[#009ef7] hover:text-white flex justify-center bg-[#f1faff] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.8125rem] `}
>
Cancel
</button>
</div>
</div>
</div>
+36 -4
View File
@@ -14,10 +14,14 @@ import { useGoogleLogin } from "@react-oauth/google";
import { useDispatch } from "react-redux";
import { updateUserDetails } from "../../../store/UserDetails";
import ReCAPTCHA from "react-google-recaptcha";
export default function Login() {
const dispatch = useDispatch();
const { state } = useLocation();
const [validCaptcha, setValidCaptcha] = useState({show: false, valid:''}); // FOR CAPTCHA
let [loginType, setLoginType] = useState("");
const [loginLoading, setLoginLoading] = useState(false);
@@ -107,6 +111,14 @@ export default function Login() {
}, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT));
return;
}
if(name == "full" && !validCaptcha.valid && validCaptcha.show){ // RUNS AND DISPLAYS CAPTCHA, IF ERROR OCCURED DURING LOGIN FOR FULL LOGIN ALONE
setMsgError("Please Verify Captcha");
setLoginLoading(false);
setTimeout(() => {
setMsgError("");
}, Number(process.env.REACT_APP_LOGIN_ERROR_TIMEOUT));
return;
}
userApi
.logInUser(postData)
.then((res) => {
@@ -120,6 +132,7 @@ export default function Login() {
// setMsgError("Wrong, email/password");
setLoginError(true);
setLoginLoading(false);
setValidCaptcha(prev => ({...prev, show:true})) // DISPLAYS CAPTCHA IF ERROR
return;
}
localStorage.setItem("member_id", `${res.data.member_id}`);
@@ -135,6 +148,7 @@ export default function Login() {
.catch((error) => {
setMsgError("Unable to login, try again");
setLoginLoading(false);
setValidCaptcha(prev => ({...prev, show:true})) // DISPLAYS CAPTCHA IF ERROR
})
.finally(() => {
setTimeout(() => {
@@ -145,6 +159,14 @@ export default function Login() {
});
};
function captchaChecker(value) { // FUNCTION TO VALIDATE CAPTCHA
if(value){
setValidCaptcha({show: true, valid:value})
}else{
setValidCaptcha({show: true, valid:''})
}
}
const googleLogin = useGoogleLogin({
flow: "auth-code",
ux_mode: "redirect",
@@ -296,6 +318,17 @@ export default function Login() {
forgotPassword
/>
</div>
{/* hCaptha clone for the time being */}
{validCaptcha.show &&
<div className="mb-5 flex justify-center w-full">
<ReCAPTCHA
sitekey={process.env.REACT_APP_GOOGLE_RECAPTCHA_SITEKEY}
onChange={captchaChecker}
/>
</div>
}
{loginError && (
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-thin leading-[19.5px] text-[13px]">
Invalid username or password- Please{" "}
@@ -320,7 +353,7 @@ export default function Login() {
onClick={doLogin}
type="button"
disabled={loginLoading}
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]`}
className={`btn-login rounded-full mb-6 text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
>
{loginLoading ? (
<div className="signup btn-loader"></div>
@@ -433,7 +466,7 @@ export default function Login() {
onClick={doLogin}
disabled={loginLoading}
type="button"
className={`btn-login rounded-[0.475rem] text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
className={`btn-login rounded-full text-xl text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center text-[15px]`}
>
{loginLoading ? (
<div className="signup btn-loader"></div>
@@ -451,8 +484,7 @@ export default function Login() {
{loginType == "full" && (
<div className="pt-5 text-[#181c32] text-center font-semibold text-[13.975px] leading-[20.9625px]">
This site is protected by hCaptcha and the our Privacy Policy
and Terms of Service apply.
This site is protected by a Captcha. Our Privacy Policy and Terms of Service apply.
</div>
)}
</div>
+1 -1
View File
@@ -325,7 +325,7 @@ export default function SignUp() {
disabled={countries.loading}
type="button"
onClick={handleSignUp}
className={`rounded-[0.475rem] 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 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`}
>
{signUpLoading ? (
<div className="signup btn-loader"></div>
+1 -1
View File
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import dataImage2 from "../../assets/images/data-table-user-2.png";
import dataImage2 from "../../assets/images/taskbanners/default.jpg";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import MarketPopUp from "../MarketPlace/PopUp/MarketPopUp";
+44 -13
View File
@@ -7,11 +7,12 @@ import React, {
useState,
} from "react";
import { useReactToPrint } from "react-to-print";
import profile from "../../assets/images/profile-info-profile.png";
import profile from "../../assets/images/icons/family.svg";
import localImgLoad from "../../lib/localImgLoad";
import usersService from "../../services/UsersService";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
import FamilyWallet from "./Tabs/FamilyWallet";
// Lazy Imports for components
const FamilyWaitlist = lazy(() => import("./Tabs/FamilyWaitlist"));
@@ -51,6 +52,8 @@ export default function FamilyManageTabs({
});
};
const [updatePage, setUpdatePage] = useState(false) // State to determine when to update the page
// State for family task data
const [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
@@ -82,14 +85,29 @@ export default function FamilyManageTabs({
profileImgInput.current.click();
};
// Function to handle changes in the profile image input
/**
* Handles the change event of the profile image input field.
* Checks if the selected file exceeds the maximum file size limit and displays an alert if it does.
* If the file is within the size limit, it reads the file using the FileReader API and sets the profile image state with the result.
*/
const profileImgChangeHandler = (e) => {
if (e.target.value !== "") {
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const file = e.target.files[0];
if (file && file.size > MAX_FILE_SIZE) {
alert("File size exceeds the limit.");
return;
}
if (file) {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setProfileImg(event.target.result);
imgReader.onload = () => {
const imageDataUrl = imgReader.result;
// Set the profile image
setProfileImg(imageDataUrl);
};
imgReader.readAsDataURL(e.target.files[0]);
imgReader.readAsDataURL(file);
}
};
@@ -148,7 +166,8 @@ export default function FamilyManageTabs({
handlePrint={useHandlePrint}
/>
),
Profile: <FamilyProfile />,
Profile: <FamilyProfile familyData={details.familyDetails.data} />,
wallet: <FamilyWallet familyData={details.familyDetails.data} />,
};
// Default tab component
@@ -220,7 +239,7 @@ export default function FamilyManageTabs({
// Invoke the manageFamily function when the component mounts
manageFamily();
}, []);
}, [updatePage]);
// Effect to manage family tasks
useEffect(() => {
@@ -280,17 +299,17 @@ export default function FamilyManageTabs({
browseProfileImg={browseProfileImg}
accountDetails={accountDetails}
/>
<div className="mt-4 flex justify-start items-center gap-2">
<div className="mt-4 flex flex-col justify-center items-center gap-2 lg:flex-row lg:justify-center lg:items-center xl:flex-col xl:justify-center xl:items-center 2xl:flex-row 2xl:justify-center 2xl:items-center 2xl:gap-[2px]">
<button
onClick={() => tabHandler("Account")}
className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center max-w-[65px] w-full"
>
<img
src={localImgLoad("images/icons/account.svg")}
className="max-w-[30px] w-full"
className="max-w-[30px]"
alt="Settings-Icon"
/>
<p className="text-lg text-sky-blue">Acc.</p>
<p className="text-[16px] text-sky-blue">Acc.</p>
</button>
<button
onClick={() => tabHandler("Profile")}
@@ -298,10 +317,21 @@ export default function FamilyManageTabs({
>
<img
src={localImgLoad("images/icons/profile.svg")}
className="max-w-[30px] w-full"
className="max-w-[30px]"
alt="Settings-Icon"
/>
<p className="text-lg text-sky-blue">Profile</p>
<p className="text-[16px] text-sky-blue">Profile</p>
</button>
<button
onClick={() => tabHandler("wallet")}
className="family-icon p-2 border-2 border-sky-blue rounded-2xl flex flex-col justify-between items-center max-w-[65px] w-full"
>
<img
src={localImgLoad("images/icons/wallet.svg")}
className="max-w-[30px]"
alt="Settings-Icon"
/>
<p className="text-[16px] text-sky-blue">Wallet</p>
</button>
</div>
</div>
@@ -356,6 +386,7 @@ export default function FamilyManageTabs({
setActiveTask={setActiveTask}
activeTask={activeTask}
familyDetailsData={details.familyDetails.data}
setUpdatePage={setUpdatePage}
/>
)}
</div>
@@ -15,6 +15,7 @@ const AssignTaskPopout = React.memo(
familyTask,
activeTask,
setActiveTask,
setUpdatePage
}) => {
const apiCall = new usersService();
@@ -143,6 +144,7 @@ const AssignTaskPopout = React.memo(
status: true,
message: "action successful",
});
setUpdatePage(prev => !prev) // Updates family task page by calling the useeffect hook
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
action(); // FUNCTION THAT CLOSES THE MODAL BOX
+30 -4
View File
@@ -52,15 +52,20 @@ export default function FamilyTable({
task_count,
family_uid,
banner,
enable_traking,
}) => {
// Check for valid dates
const addedDate = added ? added.split(" ")[0] : "N/A";
const loginDate = last_login ? formatDateString(last_login) : "N/A";
const key = `family-${family_uid}`; // Assign a unique key
const trackingStatus =
enable_traking === "0" ? "Stopped" : enable_traking === "100" ? "Active" : "";
return (
<tr
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
key={family_uid}
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
key={key}
>
<td className="py-4">
<div className="flex space-x-2 items-center w-full">
@@ -85,6 +90,23 @@ export default function FamilyTable({
</div>
</div>
</td>
<td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center">
<span
className={`text-base font-medium whitespace-nowrap ${
enable_traking === "0"
? "text-[#FF0000] dark:text-[#FF6666]"
: enable_traking === "100"
? "text-[#00A000] dark:text-[#00FF00]"
: "text-dark-gray dark:text-white"
}`}
>
{trackingStatus}
</span>
</div>
</td>
<td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center">
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
@@ -92,6 +114,7 @@ export default function FamilyTable({
</span>
</div>
</td>
<td className="text-right py-4 px-2 flex items-center justify-center">
<button
onClick={() =>
@@ -116,6 +139,8 @@ export default function FamilyTable({
);
};
console.log(currentFamilyList);
return (
<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] flex flex-col justify-between ${
@@ -134,13 +159,14 @@ export default function FamilyTable({
<thead className="sticky top-0">
<tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-bottom ">
<th className="py-4">Name</th>
<th className="py-4 text-center">Tracking</th>
<th className="py-4 text-center">No of Tasks</th>
<th className="py-4 text-right"></th>
</tr>
</thead>
<tbody className="h-full">
{currentFamilyList?.map((familyMember) => {
return <FamilyRow {...familyMember} />;
{currentFamilyList?.map((familyMember, index) => {
return <FamilyRow key={index} {...familyMember} />;
})}
</tbody>
</table>
+300 -3
View File
@@ -1,11 +1,308 @@
export default function FamilyProfile({ className }) {
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom";
import LoadingSpinner from "../../Spinners/LoadingSpinner";
import { Form, Formik } from "formik";
import * as Yup from "yup";
export default function FamilyProfile({ familyData, className }) {
const validationSchema = Yup.object().shape({
firstname: Yup.string().required("Firstname is required"),
lastname: Yup.string()
// .min(3, "Minimum 3 characters")
// .max(25, "Maximum 25 characters")
.required("Lastname is required"),
year: Yup.number()
.required("Year is required")
.min(
new Date().getFullYear() - process.env.REACT_APP_FAMILY_MAXIMUM_AGE,
`Age must be within ${process.env.REACT_APP_FAMILY_MINIMUM_AGE} to ${process.env.REACT_APP_FAMILY_MAXIMUM_AGE} years`
)
.max(
new Date().getFullYear() - process.env.REACT_APP_FAMILY_MINIMUM_AGE,
`Age must be within ${process.env.REACT_APP_FAMILY_MINIMUM_AGE} to ${process.env.REACT_APP_FAMILY_MAXIMUM_AGE} years`
),
month: Yup.number()
.required("Month is required")
.min(1, "Month is required"),
});
const navigate = useNavigate();
const api = new usersService();
let [requestStatus, setRequestStatus] = useState({
loading: false,
status: false,
message: "",
});
// let [updateDetails, setUpdateDetails] = useState({
// family_uid: familyData.uid,
// firstname: familyData.firstname,
// lastname: familyData.lastname,
// year: familyData.year,
// month: familyData.month,
// action: 22020
// })
// initial values for formik
let initialValues = {
family_uid: familyData.uid,
firstname: familyData.firstname,
lastname: familyData.lastname,
year: familyData.year,
month: familyData.month,
enable_traking: familyData.enable_traking,
action: 22020,
};
// const handleChange = ({ target: { name, value } }) => {
// setUpdateDetails((prev) => ({ ...prev, [name]: value }));
// };
const updateFamily = (values, helpers) => {
setRequestStatus({ loading: true, status: false, message: "" });
// let {firstname, lastname, year, month} = updateDetails
// if(!firstname || !lastname || year == 0 || month == 0) {
// setRequestStatus({loading:false, status:false, message: 'Please fill all fields'})
// return setTimeout(()=>{
// setRequestStatus({loading:false, status:false, message: ''})
// }, 5000)
// }
api
.getFamilyUpdate(values)
.then((res) => {
if (res.data.internal_return < 0) {
return setRequestStatus({
loading: false,
status: false,
message: "Failed, try again!",
});
}
setRequestStatus({
loading: false,
status: true,
message: "Family account updated",
});
setTimeout(() => {
navigate("/acc-family", { replace: true });
}, 5000);
})
.catch((error) => {
setRequestStatus({
loading: false,
status: false,
message: "Unable to update, try again!",
});
})
.finally(() => {
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 5000);
});
};
return (
<div
className={`update-table w-full bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow lg:min-h-[538px] p-3 ${
className={`w-full bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow lg:min-h-[538px] p-3 ${
className || ""
}`}
>
<h1>Profile</h1>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={updateFamily}
>
{(props) => {
return (
<Form className="logout-modal-body w-full lg:w-[500px] lg:mx-auto flex flex-col items-center px-10 py-8 gap-4">
<InputCom
placeholder="Firstname"
label="First Name:"
name="firstname"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.2] mb-0"
inputClass={`flex-[0.8] input-curve lg border border-[#dce4e9] ${
props.errors.firstname && props.touched.firstname
? "border border-red-500"
: ""
}`}
fieldClass="px-2"
value={props.values.firstname}
inputHandler={props.handleChange}
/>
<InputCom
placeholder="Lastname"
label="Last Name:"
name="lastname"
type="text"
parentClass="flex items-center gap-1 w-full"
labelClass="flex-[0.2] mb-0"
inputClass={`flex-[0.8] input-curve lg border border-[#dce4e9] ${
props.errors.lastname && props.touched.lastname
? "border border-red-500"
: ""
}`}
fieldClass="px-2"
value={props.values?.lastname}
inputHandler={props.handleChange}
/>
<div className="input-com flex flex-col gap-1 w-full">
{/* Age dropdown */}
<div className="">
<label
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
htmlFor="age-selection"
>
Birthday: (Year/Month)
</label>
{((props.errors.year && props.touched.year) ||
(props.errors.month && props.touched.month)) && (
<span className="text-[12px] text-red-500">
{" "}
{props.errors.year || props.errors.month}
</span>
)}
</div>
<div className="flex max-w-[330px] w-full self-end gap-4">
<select
name="year"
id="yearDropdown"
value={props.values.year}
onChange={props.handleChange}
className={`input-wrapper border border-[#f5f8fa] ${
props.errors.year && props.touched.year
? "border border-red-500"
: ""
} dark:border-[#5e6278] w-56 rounded-[35px] h-10 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 px-4`}
>
<option value="">Select a Year</option>
{years.map((year) => (
<option key={year} value={year}>
{year}
</option>
))}
</select>
<select
name="month"
id="monthDropdown"
// value={(months.filter(month => month.id == selectedMonth)[0]?.id) || ''}
value={
months.filter(
(month) => month.id == props.values.month
)[0]?.id || 0
}
onChange={props.handleChange}
className={`input-wrapper border border-[#f5f8fa] ${
props.errors.month && props.touched.month
? "border border-red-500"
: ""
} dark:border-[#5e6278] w-56 rounded-[35px] h-10 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 px-4`}
>
<option value="">Select a Month</option>
{months.map(({ id, name }) => (
<option key={id} value={id}>
{name}
</option>
))}
</select>
</div>
</div>
<div className="input-com mb-7 flex flex-col gap-1 w-full">
{/* Location dropdown */}
<div className="">
<label
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
htmlFor="age-selection"
>
Location Tracking
</label>
{/* {((props.errors.year && props.touched.year) ||
(props.errors.month && props.touched.month)) && (
<span className="text-[12px] text-red-500">
{" "}
{props.errors.year || props.errors.month}
</span>
)} */}
</div>
<div className="flex max-w-[330px] w-full self-end gap-4">
<select
name="enable_traking"
id="enable_traking"
value={props.values.enable_traking}
onChange={props.handleChange}
className={`input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-56 rounded-[35px] h-10 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 px-4`}
>
<option value={+0}>Disabled</option>
<option value={+100}>Enabled</option>
</select>
</div>
</div>
{requestStatus.message && (
<div
className={`relative p-2 ${
!requestStatus.status
? "text-[#912741] bg-[#fcd9e2] border-[#fbc6d3]"
: "text-green-700"
} mb-2 rounded-[0.475rem] text-xs font-light leading-[19.5px]`}
>
{requestStatus.message}
</div>
)}
<div className="flex justify-end w-full">
{requestStatus.loading ? (
<>
<div className="signup btn-loader"></div>
<LoadingSpinner size="4" />
</>
) : (
<button
type="submit"
// onClick={updateFamily}
// className={`rounded-[0.475rem] 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="text-white btn-gradient text-lg tracking-wide px-6 py-2 rounded-full"
>
Update
</button>
)}
</div>
</Form>
);
}}
</Formik>
</div>
);
}
// Get the current year
// const currentYear = new Date().getFullYear() - process.env.REACT_APP_FAMILY_MINIMUM_AGE;
// Calculate the current year and the year 3 years before the current year
const currentYear = new Date().getFullYear();
const startYear = currentYear - 3;
// Generate an array of years from 4 years before the current year to 18 years before the current year
const years = Array.from({ length: 15 }, (_, index) => startYear - index).reverse();
// const latestYears = years.slice(0, process.env.REACT_APP_FAMILY_YEAR_RANGE);
const months = [
{ id: "1", name: "January" },
{ id: "2", name: "February" },
{ id: "3", name: "March" },
{ id: "4", name: "April" },
{ id: "5", name: "May" },
{ id: "6", name: "June" },
{ id: "7", name: "July" },
{ id: "8", name: "August" },
{ id: "9", name: "September" },
{ id: "10", name: "October" },
{ id: "11", name: "November" },
{ id: "12", name: "December" },
];
@@ -0,0 +1,45 @@
import React, { useEffect, useState } from 'react'
import usersService from '../../../services/UsersService'
import LoadingSpinner from '../../Spinners/LoadingSpinner'
import background from '../../../assets/images/bg-sky-blue.jpg'
import Wallet from './wallet/Wallet'
function FamilyWallet({familyData}) {
const apiUrl = new usersService()
let [familyWallet, setFamilyWallet] = useState({loading:true, data: []})
let [familyWalletReload, setFamilyWalletReload] = useState(false) // STATE TO DETERMINE WHEN TO RELOAD FAMILY WALLET TAB/PAGE
useEffect(()=>{
setFamilyWallet({loading:true, data: []})
apiUrl.getFamilyWallet({family_uid:familyData?.uid}).then(res => {
setFamilyWallet({loading:false, data: res?.data?.result_list || []})
}).catch(error => {
setFamilyWallet({loading:false, data: []})
})
},[familyWalletReload])
return (
<div className='p-3 w-full h-full bg-white dark:bg-dark-white flex flex-col justify-start items-start'>
{familyWallet.loading ?
<div className='w-full h-20 flex justify-center items-center'>
<LoadingSpinner size='8' color='sky-blue' />
</div>
:
familyWallet?.data?.length > 0 ?
<div className='w-full p-4 flex flex-col gap-2'>
{familyWallet?.data?.map((wallet, index)=>(
<Wallet key={index} wallet={wallet} familyData={familyData} setFamilyWalletReload={setFamilyWalletReload} />
))}
</div>
:
<p className='text-lg text-gray-500 dark:text-gray-400'>No Wallet Found!</p>
}
</div>
)
}
export default FamilyWallet
+10 -5
View File
@@ -1,26 +1,31 @@
import React from "react";
import localImgLoad from "../../../lib/localImgLoad";
export default function ProfileInfo({
profileImg,
profileImgInput,
profileImgChangHandler,
profileImgChangeHandler,
browseProfileImg,
accountDetails,
}) {
// console.log(accountDetails.banner)
return (
<div className="flex flex-col items-center gap-4">
<div className="flex justify-center">
<div className="w-full relative">
<img
src={localImgLoad(`images/icons/${accountDetails.banner}`)}
alt=""
src={
profileImg
? profileImg
: localImgLoad(`images/icons/${accountDetails.banner}`)
}
alt="profile"
className="sm:w-[180px] sm:h-[180px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover"
/>
<input
ref={profileImgInput}
onChange={(e) => profileImgChangHandler(e)}
accept="image/*"
onChange={profileImgChangeHandler}
type="file"
className="hidden"
/>
@@ -0,0 +1,301 @@
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';
const validationSchema = Yup.object().shape({
// amount: Yup.string()
// .typeError("Invalid number")
// .min(1, "Price must be greater than 0")
// .test("no-e", "Invalid number", (value) => {
// if (value && /\d+e/.test(value)) {
// return false;
// }
// 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"),
});
function FamilyAddFundPopout({action, situation, wallet, familyData}) {
const dispatch = useDispatch()
const apiUrl = new usersService()
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),
to: `${familyData.firstname} ${familyData.lastname}`,
comment: ''
};
// FUNCTION TO PERFORM FAMILY TRANSFER
const handleAddFund = (values) => {
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 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
}
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 > 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)
})
}
// LOAD FAMILY START TRANSFER
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: {}})
})
},[])
return (
<ModalCom action={action} situation={situation}>
<div className="relative logout-modal-wrapper lg:w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
<div className="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">
Add Fund
</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">
{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>
{/* 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>
</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 && (
<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">
<button
type="button"
onClick={action}
className="w-[150px] h-[48px] rounded-full text-base text-white bg-red-600 hover:bg-red-500"
>
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>
}
</>
</div>
</div>
</div>
</Form>
)}
</Formik>
}
</div>
</div>
</ModalCom>
)
}
export default FamilyAddFundPopout
@@ -0,0 +1,77 @@
import React, { useState } from 'react'
import { localImgLoad } from '../../../../lib'
import { PriceFormatter } from '../../../Helpers/PriceFormatter'
import FamilyAddFundPopout from './FamilyAddFundPopout'
function Wallet({wallet, familyData, setFamilyWalletReload}) {
const [addFundPopout, setAddFundPopout] = useState({ show: false, data: {} })
return (
<div className='w-full p-4 bg-[aliceblue] rounded-lg'
// style={{
// background: `url(${background}) 0% 0% / cover no-repeat`,
// }}
>
<div className="w-full flex justify-start items-center gap-3">
<div className="min-w-[50px] min-h-[50px] max-w-min md:max-w-[80px] max-h-min md:max-h-[80px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
<img
src={localImgLoad(`images/currency/${(wallet.code).toLowerCase()}.svg`)}
className="w-full h-full"
alt="currency-icon"
/>
</div>
<div className="w-full flex flex-col">
<div className="w-full flex gap-2">
<p className="text-base md:text-lg text-thin-light-gray tracking-wide">
Balance:
</p>
<p
className="text-base md:text-lg font-bold text-purple tracking-wide leading-10"
// className="text-[44px] lg:text-[62px] font-bold text-white tracking-wide leading-10 xxs:scale-100 lg:scale-100 xl:scale-125"
>
{PriceFormatter(
Number(wallet.amount) * 0.01,
wallet.code,
wallet.country,
""
)}
</p>
</div>
{/* BTN */}
<div className='mt-1 flex justify-end items-center gap-2'>
<button
className="w-[150px] h-[48px] rounded-full text-base text-white bg-sky-500 hover:bg-sky-400"
name="add"
onClick={()=>{
setAddFundPopout({ show: true, data: {} });
}}
>
Add Money
</button>
<button
className="w-[150px] h-[48px] rounded-full text-base text-white bg-[#4687ba] hover:bg-[#009ef7]"
name="plan"
// onClick={onClose}
>
Plan Wallet
</button>
</div>
</div>
</div>
{/* MODAL TO ADD FUND */}
{addFundPopout.show &&
<FamilyAddFundPopout
action={() => {
setAddFundPopout({ show: false, data: {} });
setFamilyWalletReload(prev => !prev) // TO RELOAD FAMILY WALLET // DETERMINES WHEN TO RELOAD FAMILY WALLET TAB/PAGE
}}
situation={addFundPopout.show}
wallet={wallet}
familyData={familyData}
/>
}
</div>
)
}
export default Wallet
+12 -5
View File
@@ -2,6 +2,8 @@ import React from "react";
// import Lottie from "react-lottie";
import { useNavigate } from "react-router-dom";
import * as animationData from "../../assets/images/Lotties/77618-website-404-error-animation.json";
import { localImgLoad } from "../../lib";
// import BgError from '../../assets/images/wrench-page-notfound.jpg'
export default function FourZeroFour() {
const navigate = useNavigate();
@@ -14,16 +16,21 @@ export default function FourZeroFour() {
},
};
return (
<div className="flex justify-center items-center w-full h-screen bg-[#232247]">
<div>
<div className={`my-custom-bg-class flex justify-center items-center w-full h-screen before:content-[''] before:absolute before:inset-0 before:bg-[#cdcdcd]/[.8]`}>
<div className="relative pt-32 max-w-3xl">
{/* <Lottie options={defaultOptions} width={600} height={600} /> */}
<div className="flex justify-center">
<div className="px-16 md:px-24 flex flex-col items-center justify-center gap-4">
<img src={localImgLoad('images/404.png')} className="w-72" alt='404 Image' />
<p className="mt-8 text-red-600 font-black text-4xl md:text-5xl tracking-wider text-center">Sorry!</p>
<h1 className="text-black text-4xl md:text-5xl font-black tracking-wide text-center leading-tight">The page cant be found.</h1>
<p className="px-2 md:px-8 text-slate-700 text-base md:text-lg text-center">The page you're looking for isn't available. Use the go back button below</p>
<button
onClick={() => navigate(-1)}
type="button"
className="btn-gradient text-white text-lg w-[150px] h-[50px] rounded-full"
className="px-4 md:px-8 border-2 border-[#2b70fa] rounded-lg text-[#007bff] text-base md:text-lg h-[48px] flex justify-center items-center gap-1"
>
Go Back
<span>Go Back</span>
<span className="pb-1">&rarr;</span>
</button>
</div>
</div>
+26
View File
@@ -50,3 +50,29 @@ export const PriceFormatter = (
</span>
);
};
// FUNCTION TO RETURN AMOUNT TO TWO DECIMAL PLACES
export const AmountTo2DP = (
amount = "00",
) => {
// Convert the number to a string
let numStr = String(amount);
// Split the string into integer and decimal parts
let parts = numStr.split(".");
let integerPart = parts[0] || "";
let decimalPart = parts[1] || "";
// Add thousands separators to the integer part
let formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// Truncate or pad the decimal part to two decimal points
let formattedDecimal = decimalPart.slice(0, 2).padEnd(2, "0");
// Combine the formatted integer and decimal parts
let formattedNumber = formattedInteger + '.' + formattedDecimal;
// return formattedNumber;
return formattedNumber;
};
+114
View File
@@ -0,0 +1,114 @@
import React, {useEffect, useState} from 'react'
import Image from '../../assets/images/taskbanners/default.jpg'
import usersService from '../../services/UsersService';
import { handlePagingFunc } from '../../components/Pagination/HandlePagination';
import PaginatedList from '../../components/Pagination/PaginatedList';
import LoadingSpinner from '../Spinners/LoadingSpinner';
import { AmountTo2DP } from '../Helpers/PriceFormatter';
function RewardsTable() {
const apiCall = new usersService()
let [familyRewardHistory, setFamilyRewardHistory] = useState({ // FOR PURCHASE HISTORY
loading: true,
data: [],
error: false
})
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem = Number(indexOfFirstItem)+Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentReward = familyRewardHistory?.data?.slice(indexOfFirstItem, indexOfLastItem);
const handlePagination = (e) => {
handlePagingFunc(e,setCurrentPage)
}
//FUNCTION TO GET FAMILY REWARD HISTORY
const getFamilyRewardHistory = ()=>{
apiCall.getFamilyRewardHx().then((res)=>{
if(res.data.internal_return < 0){ // success but no data
setFamilyRewardHistory(prev => ({...prev, loading: false}))
return
}
setFamilyRewardHistory(prev => ({...prev, loading: false, data: res.data.result_list}))
}).catch((error)=>{
setFamilyRewardHistory(prev => ({...prev, loading: false, error: true}))
})
}
useEffect(()=>{
getFamilyRewardHistory()
}, [])
return (
<div className='flex flex-col justify-between min-h-[500px]'>
{familyRewardHistory.loading ?
<LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
:
<table className="wallet-activity w-full table-auto border-collapse text-left">
<thead className='border-b-2'>
<tr className='text-slate-600'>
<th className="p-2"></th>
<th className="p-2">Amount</th>
<th className="p-2">Date</th>
<th className="p-2">Confirmation</th>
</tr>
</thead>
{familyRewardHistory.data.length ?
(
<tbody>
{currentReward.map((item, index) => {
let date = new Date(item.added).toLocaleDateString()
return (
<tr key={index} className='text-slate-500'>
<td className="p-2">
<div className='flex items-center gap-2'>
<img src={item.icon} className='min-w-[60px] max-w-[60px] min-h-[60px] max-h-[60px] rounded-full bg-slate-500' alt='Reward Logo' />
<div className='flex flex-col'>
<h1 className='text-lg font-bold'>Reward to {item.rec_firstname} {item.rec_lastname}</h1>
<p className='text-sm'>{item.description}</p>
</div>
</div>
</td>
<td className="p-2">{AmountTo2DP(item.amount*0.01)} {item.currency}</td>
<td className="p-2">{date}</td>
<td className="p-2">{item.confirmation}</td>
</tr>
)
}
)}
</tbody>
)
:
familyRewardHistory.error ?
(
<tbody>
<tr className='text-slate-500'>
<td className="p-2" colSpan={4}>Opps! an error occurred. Please try again!</td>
</tr>
</tbody>
)
:
<tbody>
<tr className='text-slate-500'>
<td className="p-2" colSpan={4}>No Rewards History 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) >= familyRewardHistory?.data?.length ? true : false} data={familyRewardHistory?.data} start={indexOfFirstItem} stop={indexOfLastItem} />
{/* END OF PAGINATION BUTTON */}
</div>
)
}
export default RewardsTable
+21
View File
@@ -10,6 +10,7 @@ import usersService from "../../services/UsersService";
import PurchasesTable from "../MyWallet/WalletComponent/PurchasesTable";
import RecentActivityTable from "../MyWallet/WalletComponent/RecentActivityTable";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import RewardsTable from "./RewardsTable";
export default function History() {
@@ -58,6 +59,9 @@ export default function History() {
useEffect(()=>{
getPaymentHistory()
}, [])
useEffect(()=>{
getPurchaseHistory()
}, [])
@@ -236,6 +240,15 @@ export default function History() {
>
Recent Activity
</button>
<button
name="reward"
onClick={(e) => setTab(e.target.name)}
className={`px-4 py-1 rounded-t-2xl ${
tab == "reward" ? "bg-[#4687ba] border-[2px] border-[#4687ba] text-white" : "bg-white text-[#000] border-t-[2px]"
}`}
>
Rewards
</button>
</div>
{/* END OF switch button */}
<div className="history-tables w-full">
@@ -265,6 +278,14 @@ export default function History() {
</div>
}
{/* END OF RECENT ACTIVITY SECTION */}
{/* REWARD SECTION */}
{tab == 'reward' &&
<div className="wallet w-full border-t">
<RewardsTable />
</div>
}
{/* END OF REWARD SECTION */}
</div>
</div>
{/*<HistoryTable />*/}
@@ -7,6 +7,10 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
const [textValue, setTextValue] = useState("");
const [errMsg, setErrMsg] = useState({
market: false,
manage: false,
});
const apiCall = useMemo(() => new usersService(), []);
const handleInputChange = ({ target: { value } }) => {
@@ -48,20 +52,17 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
return;
}
toast.success("Message sent", {
autoClose: 2500,
hideProgressBar: true,
});
setMarketMsg({ data: marketMessageRes, state: true });
setTimeout(() => onClose(), 2000);
} catch (error) {
setErrMsg({ market: true });
setMarketMsg({ loading: false, state: false });
throw new Error(error);
} finally {
setTextValue("");
setTimeout(() => {
setTextValue("");
setMarketMsg({ loading: false });
}, 2000);
setMarketMsg({ loading: false, state: false });
setErrMsg({ market: false });
}, 5000);
}
};
@@ -117,7 +118,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
return (
<ModalCom action={onClose} situation={situation} className="edit-popup">
<div className="logout-modal-wrapper md:w-[750px] md:h-[660px] h-full bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
<div className="logout-modal-wrapper md:w-[650px] md:h-[580px] h-full bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
<div className="logout-modal-header w-full flex items-center justify-between lg:p-6 px-[30px] py-[23px]">
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
{details.offer_code}
@@ -127,7 +128,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<div className="md:flex bg-white dark:bg-dark-white text-slate-900 dark:text-white rounded-lg">
<div className="p-4 w-full md:w-[75%] md:border-r-1">
<div className="min-h-[263px]">
<div className="max-h-[240px] h-full">
<h2 className="font-semibold text-slate-900 dark:text-white tracking-wide">
{details?.title}
</h2>
@@ -158,9 +159,9 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
<div
className={`w-full md:w-3/4 text-slate-900 dark:text-white market-pop ${
name !== "Delivery Detail"
? " h-full max-h-28 flex items-center"
: " overflow-y-auto max-h-[100px]"
}`}
? " h-full flex items-center"
: " overflow-y-auto max-h-[80px]"
} ${name === "Description" && "max-h-14 h-full overflow-auto"}`}
>
{danger ? (
<p
@@ -195,40 +196,46 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
))}
</div>
<hr />
<div className="my-3 w-full flex flex-col gap-3">
<div className="w-full flex flex-col gap-3">
<div className="w-full">
<label className="w-full text-slate-900 dark:text-white tracking-wide">
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
If you have any questions about this task:
</label>
<textarea
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
rows="5"
className={`p-1 w-full text-sm text-slate-900 dark:text-white ${
marketMsg.loading && "italic text-[#9CA3AF]"
} bg-transparent outline-none border-2 border-slate-300 rounded-md`}
rows="3"
style={{ resize: "none" }}
placeholder="Enter message here ..."
value={textValue}
value={marketMsg.loading ? "Sending..." : textValue}
onChange={handleInputChange}
/>
</div>
<button
className="self-end w-[150px] h-[52px] rounded-md text-base bg-yellow-500 text-white"
name="market-message"
onClick={MarketDetail}
>
{marketMsg.loading ? (
<LoadingSpinner size={5} color="white" />
) : !marketMsg.state ? (
"Send Message"
) : (
"Message Sent"
)}
</button>
<div className="relative flex w-full justify-end ">
<span className="text-sm text-[#57cd89] absolute left-[8rem] top-4">
{marketMsg.state && "Message Sent!"}
{errMsg.market && "Something went wrong"}
</span>
<button
className="self-end w-[150px] h-[48px] rounded-full text-base bg-yellow-500 text-white"
name="market-message"
onClick={MarketDetail}
>
{marketMsg.loading ? (
<LoadingSpinner size={5} color="white" />
) : (
"Send Message"
)}
</button>
</div>
</div>
</div>
<div className="w-full md:w-[23%] h-full ">
<div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] p-4 rounded-md md:min-h-[498px] flex flex-col justify-between">
<div className="w-full flex flex-col justify-center py-4 gap-2">
<p className="w-full text-slate-900 tracking-wide my-1">
<div className="w-full md:w-[23%] h-full flex flex-col">
<div className="mx-auto bg-[#f1f8ff] dark:bg-[#C2C8D3] px-4 rounded-md md:min-h-[420px] flex flex-col justify-between">
<div className="w-full flex flex-col justify-center pb-4 gap-2">
<p className="w-full text-slate-900 tracking-wide my-1 font-semibold">
Interested in the task?
</p>
<hr />
@@ -270,7 +277,7 @@ const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
</div>
</div>
<button
className="self-end w-[150px] mt-2 h-[52px] rounded-md text-base bg-transparent border border-red-500 text-red-500 mx-auto"
className="self-center w-[150px] mt-2 h-[48px] rounded-full text-base bg-transparent border border-red-500 text-red-500 mx-auto"
name="cancel"
onClick={onClose}
>
@@ -118,7 +118,11 @@ function PastDueJobAction({jobDetails}) {
<tr>
<td>
<div className="flex justify-center items-center">
<button type="button" onClick={popUpHandler} className="w-[180px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
<button
type="button"
onClick={popUpHandler}
className="px-4 h-[48px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
Cancel or Extend Timeline
</button>
</div>
@@ -230,8 +234,12 @@ function PastDueJobAction({jobDetails}) {
{/* cancel btn */}
<div className='flex justify-end items-center'>
<button onClick={popUpHandler} type="button" className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white">
<span className='text-gradient'>Cancel</span>
<button onClick={popUpHandler} type="button"
// className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white"
className='w-[150px] mt-2 h-[48px] rounded-full text-base bg-transparent border border-red-500 text-red-500'
>
Cancel
{/* <span className='text-gradient'>Cancel</span> */}
</button>
</div>
</div>
@@ -80,14 +80,16 @@ function CompleteConfirmCredit({ onClose, confirmCredit }) {
</span>
</div>
<div className="flex items-center gap-8">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
Confirmation Number
</h1>
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
{data?.confirmation}
</span>
</div>
{isSuccess && (
<div className="flex items-center gap-8">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
Confirmation Number
</h1>
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
{data?.confirmation}
</span>
</div>
)}
</>
)}
</div>
@@ -17,7 +17,7 @@ const CreditPopup = ({ details, onClose, situation, walletItem }) => {
const getTitle = () => {
if (confirmCredit?.show?.acceptConfirm?.state) {
if (confirmCredit?.data?.internal_return < 0) {
if (confirmCredit?.data?.internal_return <= 0) {
return "Credit Unsuccessful";
} else {
return "Credit Add Completed";
+44 -52
View File
@@ -12,8 +12,7 @@ function NairaWithdraw({
state,
setShowConfirmNairaWithdraw,
}) {
let MaxNoOfBanks = process.env.REACT_APP_MAX_CREDIT_BANK_ACCOUNT // HOLDS THE VALUE OF THE MAX NUMBER OF BANKS USER CAN ADD
let MaxNoOfBanks = process.env.REACT_APP_MAX_CREDIT_BANK_ACCOUNT; // HOLDS THE VALUE OF THE MAX NUMBER OF BANKS USER CAN ADD
const apiCall = new usersService();
const [tab, setTab] = useState("previous");
let [requestStatus, setRequestStatus] = useState(false);
@@ -25,7 +24,9 @@ function NairaWithdraw({
recipientID: state?.previousAccount?.recipientID || "",
},
newAccount: {
country: state?.newAccount?.amount || "",
country: wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country,
bank: state?.newAccount?.amount || "",
accountNumber: state?.newAccount?.amount || "",
accountType: state?.newAccount?.amount || "",
@@ -67,10 +68,14 @@ function NairaWithdraw({
// Handling card change
const handleBankOptions = (event) => {
const { value } = event.target;
let bankCountry = wallet.walletCountry
? wallet.walletCountry[0][0]
: wallet.country
setBankName((prev) => ({ loading: true, data: [] }));
apiCall
.getCountryBank({ country: value })
.getCountryBank({
country: bankCountry
})
.then((res) => {
if (res.data.internal_return < 0) {
setBankName((prev) => ({ loading: false, data: [] }));
@@ -140,6 +145,7 @@ function NairaWithdraw({
};
useEffect(() => {
handleBankOptions()
getCountry(); // TO LOAD LIST COUNTRY
getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
}, []);
@@ -226,7 +232,7 @@ function NairaWithdraw({
setShowConfirmNairaWithdraw({ show: true, state: stateData });
}, 1000);
}
if (tab === "new") {
const { accountNumber, accountType, bank, city, country, state } =
values?.newAccount;
@@ -281,6 +287,8 @@ function NairaWithdraw({
getRecipients();
}, []);
console.log("Testing Wallet Country", wallet?.walletCountry[0][0]);
return (
<ModalCom action={action} situation={situation} className="edit-popup">
<div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
@@ -424,7 +432,11 @@ function NairaWithdraw({
<label
onClick={() => setTab("new")}
htmlFor="new"
className={`cursor-pointer flex items-center gap-1 ${recipients.data.length >= MaxNoOfBanks ? 'pointer-events-none':''}`}
className={`cursor-pointer flex items-center gap-1 ${
recipients.data.length >= MaxNoOfBanks
? "pointer-events-none"
: ""
}`}
>
<input
id="new"
@@ -436,7 +448,12 @@ function NairaWithdraw({
tab == "new" ? "" : ""
} tracking-wide transition duration-200`}
/>
New Account{" "} {recipients.data.length >= MaxNoOfBanks && <span className="text-[14px] text-red-500">Max Reached</span>}
New Account{" "}
{recipients.data.length >= MaxNoOfBanks && (
<span className="text-[14px] text-red-500">
Max Reached
</span>
)}
</label>
</div>
</div>
@@ -523,12 +540,12 @@ function NairaWithdraw({
</>
)}
{tab == "new" && (
recipients.loading ?
{tab == "new" &&
(recipients.loading ? (
<div className="mt-3 flex flex-col w-full h-[188px] justify-center items-center">
<LoadingSpinner size='10' color='sky-blue' />
<LoadingSpinner size="10" color="sky-blue" />
</div>
:recipients.data.length < MaxNoOfBanks ?
) : recipients.data.length < MaxNoOfBanks ? (
<div className="w-full mt-3 rounded-md bg-slate-100">
<div className="relative fields w-full flex flex-col p-4">
<div className="flex flex-[2] min-h-[52px]">
@@ -541,7 +558,12 @@ function NairaWithdraw({
Country{" "}
<span className="text-red-500">*</span>
</label>
<select
<div className="w-full text-base p-2 text-dark-gray dark:text-white border border-slate-300 outline-0 flex-[0.6] rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding tracking-[1.5px] flex items-center pointer-events-none">
<span className="text-slate-500 text-lg italic">
{wallet.walletCountry[0][1]}
</span>
</div>
{/* <select
className="w-full text-base p-2 text-dark-gray dark:text-white border border-slate-300 outline-0 flex-[0.6] rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding tracking-[1.5px]"
name="newAccount.country"
value={props.values.newAccount?.country}
@@ -552,7 +574,7 @@ function NairaWithdraw({
>
{allCountries.loading ? (
<option
className="text-slate-500 text-lg"
className="text-slate-500 text-lg"
value=""
>
Loading...
@@ -585,13 +607,7 @@ function NairaWithdraw({
No Options Found!
</option>
)}
</select>
{/* {props.errors.country &&
props.touched.country && (
<p className="text-sm text-red-500">
{props.errors.country}
</p>
)} */}
</select> */}
</div>
{/* bank name */}
@@ -646,11 +662,6 @@ function NairaWithdraw({
</option>
)}
</select>
{/* {props.errors.bank && props.touched.bank && (
<p className="text-sm text-red-500">
{props.errors.bank}
</p>
)} */}
</div>
</div>
@@ -671,16 +682,12 @@ function NairaWithdraw({
name="newAccount.accountNumber"
placeholder="Account No"
maxLength={10}
value={props.values.newAccount?.accountNumber}
value={
props.values.newAccount?.accountNumber
}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/>
{/* {props.errors.accountNumber &&
props.touched.accountNumber && (
<p className="text-sm text-red-500">
{props.errors.accountNumber}
</p>
)} */}
</div>
{/* Account Type */}
@@ -732,12 +739,6 @@ function NairaWithdraw({
</option>
)}
</select>
{/* {props.errors.accountType &&
props.touched.accountType && (
<p className="text-sm text-red-500">
{props.errors.accountType}
</p>
)} */}
</div>
</div>
@@ -748,7 +749,8 @@ function NairaWithdraw({
htmlFor="newAccount.state"
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4]"
>
State <span className="text-red-500">*</span>
State{" "}
<span className="text-red-500">*</span>
</label>
<InputCom
fieldClass="px-6 tracking-[1.5px]"
@@ -760,11 +762,6 @@ function NairaWithdraw({
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/>
{/* {props.errors.state && props.touched.state && (
<p className="text-sm text-red-500">
{props.errors.state}
</p>
)} */}
</div>
{/* city */}
@@ -785,20 +782,15 @@ function NairaWithdraw({
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/>
{/* {props.errors.city && props.touched.city && (
<p className="text-sm text-red-500">
{props.errors.city}
</p>
)} */}
</div>
</div>
{/* end of inputs for new accounts */}
</div>
</div>
:
) : (
<div className="mt-3 flex w-full h-[188px] justify-center items-center"></div>
)}
))}
</div>
<div className="transfer-fund-btn flex justify-end items-center gap-2 py-4">
+38 -2
View File
@@ -5,7 +5,6 @@ import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner";
const WalletBox = lazy(() => import("./WalletBox"));
const WalletRoutes = () => {
const apiCall = new usersService();
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
@@ -16,6 +15,12 @@ const WalletRoutes = () => {
data: [],
});
const [allCountries, setAllCountries] = useState({
// STATE TO HOLD LIST OF COUNTRIES
loading: true,
data: [],
});
const getPaymentHistory = () => {
apiCall
.getPaymentHx()
@@ -31,14 +36,45 @@ const WalletRoutes = () => {
});
};
// FUNCTION TO GET COUNTRIES
const getCountry = () => {
apiCall
.getSignupCountryData()
.then((res) => {
if (res.data.internal_return < 0) {
setAllCountries((prev) => ({ loading: false, data: [] }));
return;
}
setAllCountries((prev) => ({
loading: false,
data: res.data.signup_country,
}));
})
.catch((error) => {
setAllCountries((prev) => ({ loading: false, data: [] }));
});
};
useEffect(() => {
getCountry();
getPaymentHistory();
}, [walletTable]);
console.log(
"Testing all country: ",
allCountries,
"Testing wallet: ",
walletDetails
);
return (
<Layout>
<Suspense fallback={<LoadingSpinner size="16" color="sky-blue" />}>
<WalletBox wallet={walletDetails} payment={paymentHistory} />
<WalletBox
wallet={walletDetails}
payment={paymentHistory}
countries={allCountries.data}
/>
</Suspense>
</Layout>
);
+2 -2
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react";
import React, { useEffect, useState } from "react";
import usersService from "../../services/UsersService";
import ConfirmNairaWithdraw from "./Popup/ConfirmNairaWithdraw";
import NairaWithdraw from "./Popup/NairaWithdraw";
@@ -8,7 +8,7 @@ function WalletAction({ walletItem, payment, openPopUp }) {
show: false,
state: {},
}); // DETERMINES WHEN NAIRA WITHDRAWAL POPS UP
const [showConfirmNairaWithdraw, setShowConfirmNairaWithdraw] = useState({
show: false,
state: {},
+2 -2
View File
@@ -4,7 +4,7 @@ import WalletItemCard from "./WalletItemCard";
/**
* Renders a list of wallet items or a loading spinner depending on the state of the `wallet` object.
*/
export default function WalletBox({ wallet, payment }) {
export default function WalletBox({ wallet, payment, countries }) {
const { loading, data } = wallet;
return (
@@ -18,7 +18,7 @@ export default function WalletBox({ wallet, payment }) {
) : (
data.length > 0 && data.map((item) => (
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
<WalletItemCard walletItem={item} payment={payment} />
<WalletItemCard walletItem={item} payment={payment} countries={countries} />
</div>
))
)}
+7 -2
View File
@@ -10,7 +10,7 @@ import WalletAction from "./WalletAction";
/**
* Renders a card displaying information about a wallet item.
*/
export default function WalletItemCard({ walletItem, payment }) {
export default function WalletItemCard({ walletItem, payment, countries }) {
const { userDetails } = useSelector((state) => state.userDetails);
const accountType = userDetails?.account_type === "FAMILY";
const dispatch = useDispatch();
@@ -35,10 +35,15 @@ export default function WalletItemCard({ walletItem, payment }) {
dispatch(tableReload({ type: "WALLETTABLE" }));
};
const currentWalletCurrency = countries
.map((country) => country)
.filter((country) => country[0] === walletItem.country);
const image = walletItem.code
? `${walletItem.code.toLowerCase()}.svg`
: "default.png";
return (
<>
<div
@@ -88,7 +93,7 @@ export default function WalletItemCard({ walletItem, payment }) {
{!accountType && (
<WalletAction
walletItem={walletItem}
walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
payment={payment}
openPopUp={openPopUp}
/>
+1
View File
@@ -8,6 +8,7 @@ import {
import DarkModeContext from "../Contexts/DarkModeContext";
import Icons from "../Helpers/Icons";
export default function Sidebar({
sidebar,
action,
@@ -51,6 +51,7 @@ export default function PersonalInfoTab({
coverImgInput,
browseCoverImg,
coverImgChangHandler,
uploadStatus
}) {
let { userDetails } = useSelector((state) => state.userDetails);
@@ -361,7 +362,7 @@ export default function PersonalInfoTab({
{/* inputs ends here */}
</div>
</div>
{process.env.REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE != 0 &&
{/* {process.env.REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE != 0 && */}
<div className="w-[232px] mb-10">
<div className="update-profile w-full mb-9">
<h1 className="text-xl tracking-wide font-bold text-dark-gray dark:text-white flex items-center mb-2">
@@ -417,9 +418,11 @@ export default function PersonalInfoTab({
</div>
</div>
</div>
{uploadStatus.message && !uploadStatus.loading && <p className={`text-center ${uploadStatus.status ? 'text-green-500':'text-red-500'}`}>{uploadStatus.message}</p>}
{uploadStatus.loading && <p className="text-center">{uploadStatus.message}</p>}
</div>
</div>
}
{/* } */}
</div>
<div className="content-footer w-full">
+62 -4
View File
@@ -24,10 +24,12 @@ import {
import RecipientAccountTab from "./Tabs/RecipientAccountTab";
export default function Settings({ faq }) {
const apiCall = new usersService();
const { userDetails } = useSelector((state) => state?.userDetails);
const [profileImg, setProfileImg] = useState(
userDetails?.profile_pic_url ? userDetails.profile_pic_url : profile
);
let [uploadStatus, setUploadStatus] = useState({loading: false, status: false, message:''}) // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
const [coverImg, setCoverImg] = useState(cover);
const [reloadCardList, setReloadCardList] = useState(false); // STATE TO DETERMINE WHEN CARD LIST RELOADS. EG: WHEN USER DELETES A CARD
@@ -36,12 +38,68 @@ export default function Settings({ faq }) {
const browseProfileImg = () => {
profileImgInput.current.click();
};
const profileImgChangHandler = (e) => {
// if (e.target.value !== "") {
// const imgReader = new FileReader();
// imgReader.onload = (event) => {
// setProfileImg(event.target.result);
// };
// imgReader.readAsDataURL(e.target.files[0]);
// }
setUploadStatus({loading: false, status: false, message:''})
let acceptedFormat = ["jpeg", "jpg", "png", "bmp", "gif"] // ARRAY OF SUPPORTED FORMATS
let uploadedFile = e.target.files[0] //UPLOADED FILE
if(!acceptedFormat.includes(uploadedFile?.type?.split("/")[1]?.toLowerCase())){ //CHECKING FOR CORRECT UPLOAD FORMAT
let msg = 'Please select '
for(let i=0; i<=acceptedFormat.length-1; i++){
if(i == acceptedFormat.length-1){
msg+=`or ${acceptedFormat[i]}`
}else{
msg+=`${acceptedFormat[i]}, `
}
}
setUploadStatus({loading: false, status: false, message:msg})
return setTimeout(()=>{
profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
}
if(uploadedFile.size > 5*1048576){ // CHECKING FOR CORRECT FILE SIZE
setUploadStatus({loading: false, status: false, message:'File must not exceed 5MB'})
return setTimeout(()=>{
profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
}
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setProfileImg(event.target.result);
let reqData = { // PAYLOAD FOR API CALL
file_name: uploadedFile?.name,
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: event?.target?.result,
msg_type: 'FILE',
action: 'WRENCHBOARD_PICTURE_PROFILE',
// action: 11307
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
apiCall.sendFiles(reqData).then(res=>{
if(res.status != 200 || res.data.internal_return < 0){
return setUploadStatus({loading: false, status: false, message: 'Something went wrong, try again'})
}
setUploadStatus({loading: false, status: true, message: 'Uploaded successfully'})
setProfileImg(event.target.result);
}).catch(error=>{
setUploadStatus({loading: false, status: false, message: 'Network error, try again'})
}).finally(()=>{
setTimeout(()=>{
setUploadStatus({loading: false, status: false, message: ''})
},5000)
})
};
imgReader.readAsDataURL(e.target.files[0]);
}
@@ -61,7 +119,6 @@ export default function Settings({ faq }) {
}
};
const apiCall = useMemo(() => new usersService(), []);
// Tabs Handling
const tabs = [
{
@@ -113,7 +170,7 @@ export default function Settings({ faq }) {
iconName: "page-right",
},
{
id: 8,
id: 9,
name: "terms",
title: "Terms and Conditions",
iconName: "page-right",
@@ -217,6 +274,7 @@ export default function Settings({ faq }) {
coverImgChangHandler={coverImgChangHandler}
browseCoverImg={browseCoverImg}
coverImgInput={coverImgInput}
uploadStatus={uploadStatus}
/>
</div>
)}
+1 -1
View File
@@ -351,7 +351,7 @@ const EditJobPopOut = ({
className="w-[120px] h-[40px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
// className='w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white'
>
Edit Job
Save
</button>
)}
</div>
@@ -6,6 +6,8 @@ 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 "),
@@ -21,6 +23,8 @@ const validationSchema = Yup.object().shape({
});
function JobListPopout({ details, onClose, situation }) {
const dispatch = useDispatch()
const [familyList, setFamilyList] = useState([]);
let [loader, setLoader] = useState({
member: false,
@@ -159,6 +163,7 @@ function JobListPopout({ details, onClose, situation }) {
const res = await apiCall.assignJobTask(reqData);
let { data } = await res;
setLoader({ jobFields: false });
dispatch(tableReload({ type: "JOBTABLE" }));
onClose();
throw new Response(data);
} catch (error) {
+6
View File
@@ -304,6 +304,12 @@ input[type="text"][dir="rtl"] {
transform: rotate(360deg);
}
}
.my-custom-bg-class{
background: url("./assets/images/wrench-page-notfound.jpg") center/cover;
position: relative;
}
/* TODO: =================================default end================================ */
/* TODO: =================================update password================================ */
.content-wrapper.thankyou-section {
+2 -1
View File
@@ -11,6 +11,7 @@ import { updateNotifications } from "../store/notifications";
import { updateUserJobList } from "../store/userJobList";
import { updateWalletDetails } from "../store/walletDetails";
import { formattedDate } from "../lib";
import { tableReload } from "../store/TableReloads";
const AuthRoute = ({ redirectPath = "/login", children }) => {
const apiCall = useMemo(() => new usersService(), []);
@@ -204,7 +205,7 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}
};
getMarketActiveJobList();
}, [apiCall, dispatch]);
}, [apiCall, dispatch, jobListTable]);
//FUNCTION TO GET COMMON HEAD DATA
useEffect(() => {
+49 -1
View File
@@ -496,6 +496,19 @@ class usersService {
return this.postAuxEnd("/purchasehx", postData);
}
// API FUNCTION TO GET FAMILY REWARD HISTORY
getFamilyRewardHx() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
offset: 1,
limit: 20,
action: 22011,
};
return this.postAuxEnd("/familyrewardhx", postData);
}
// API FUNCTION TO GET PAYMENT HISTORY
getPaymentHx() {
var postData = {
@@ -578,13 +591,14 @@ class usersService {
return this.postAuxEnd("/familyadd", postData);
}
getFamilyUpdate() {
getFamilyUpdate(reqdata) {
var postData = {
uuid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
page: 0,
limit: 100,
...reqdata
};
return this.postAuxEnd("/familyupdate", postData);
}
@@ -1077,6 +1091,40 @@ class usersService {
return this.postAuxEnd("/suggeststatus", postData);
}
// FUNCTION TO GET FAMILY WALLET
getFamilyWallet(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
action: 22012,
...reqData,
};
return this.postAuxEnd("/familywallet", postData);
}
// FUNCTION TO START FAMILY TRANSFER
familyTransferStart(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/familytransferstart", postData);
}
// FUNCTION TO PERFORM FAMILY TRANSFER
familyTransfer(reqData) {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
...reqData,
};
return this.postAuxEnd("/familytransfer", postData);
}
/*
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username)
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password)