Compare commits
188 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f89376aa9 | |||
| 4e91e47978 | |||
| fcaa485b17 | |||
| e4526652d3 | |||
| 64056bb2a4 | |||
| e49c4d66f8 | |||
| 8fdb939b72 | |||
| 79325450f3 | |||
| 7849a027b4 | |||
| 38432a6d50 | |||
| 83a54ff3ef | |||
| 5e0fdffa1e | |||
| 11d2cb3e3a | |||
| 93ac55b44b | |||
| 237ce13a6c | |||
| 4253174494 | |||
| da0ed0364b | |||
| 466175c49d | |||
| ed148ce267 | |||
| 6de795c07b | |||
| 436498bef9 | |||
| 086b1202a4 | |||
| a81ccdc4d7 | |||
| 33abbbcd2b | |||
| 04844af733 | |||
| 46d919090d | |||
| 8e67892f16 | |||
| a67d2b7bb4 | |||
| 99c0c24489 | |||
| 1a1d59a8c7 | |||
| 31dcfcfd0b | |||
| e9aa58f2f5 | |||
| 55fe2bf6d2 | |||
| 738eb1589e | |||
| 139e0c2827 | |||
| 30642bba14 | |||
| f5921612b8 | |||
| 38afece043 | |||
| d44447c6b3 | |||
| d942c6641a | |||
| beed565ba0 | |||
| 329e27b83d | |||
| 3145656d80 | |||
| 5098a45bd5 | |||
| 9e65a6e7d5 | |||
| 83ac1087f3 | |||
| 55b2bccdf0 | |||
| 0c51474dd2 | |||
| 8c7ffb52a5 | |||
| 6c698bc399 | |||
| 540ad6f9ad | |||
| 11342c32c6 | |||
| 356c11d029 | |||
| 934d95e822 | |||
| 0aa49b49a9 | |||
| be52792271 | |||
| c23e61e06b | |||
| 24b9a0e348 | |||
| fcb154ba49 | |||
| c0065ed569 | |||
| 05a2ebec61 | |||
| 63f7deaa2b | |||
| d762ef42e8 | |||
| 3e34c81789 | |||
| a2340af314 | |||
| 2a445fd2d4 | |||
| b5e52fb34e | |||
| 87512bbc23 | |||
| 1e59059394 | |||
| e59c83d216 | |||
| 395569dab5 | |||
| 25a537c5bc | |||
| 5244a2875e | |||
| 54560b3fec | |||
| 078d26317f | |||
| 8dbf638c7f | |||
| a68af7c3a4 | |||
| 905d48ceb7 | |||
| 1e5dac0104 | |||
| 11e52a02f6 | |||
| 4e74198ae5 | |||
| 5d673a630c | |||
| adcb33764b | |||
| 305bff1167 | |||
| 1ebe9fe12b | |||
| 3fbaf6b78a | |||
| 421a24c185 | |||
| 6386fbcda6 | |||
| 2e09d77597 | |||
| 10dae9193c | |||
| 3f487337f4 | |||
| 7eabee8855 | |||
| 360f0500a9 | |||
| 9b6c5b72ad | |||
| afc5e25cfc | |||
| 58fe5eb82c | |||
| 2f3fdc0695 | |||
| 0a465fceb0 | |||
| 5e968db2f5 | |||
| 1916bc1a65 | |||
| 1103127cae | |||
| 751369071c | |||
| 4cc8f27c14 | |||
| aab455c2c3 | |||
| 21843c4bc7 | |||
| 8702728ffa | |||
| 79dcd0f2b5 | |||
| 47b25f3dfe | |||
| 89925a6af9 | |||
| 3c0f951b6e | |||
| ffbfb1da35 | |||
| a8416a8433 | |||
| 70c9d1778c | |||
| 930559c96b | |||
| c4af2dfcc8 | |||
| b186549b8d | |||
| ab191b6a72 | |||
| d130687cf9 | |||
| 5e9a442eac | |||
| 1093c25207 | |||
| 0623227807 | |||
| 3a05790125 | |||
| 85b0456011 | |||
| 6ddd16ee24 | |||
| d034f9be45 | |||
| 2f3940f99c | |||
| 5e998e5e42 | |||
| e113f40c5c | |||
| 42a3df2d65 | |||
| 3fb996887b | |||
| 6d2794dd2f | |||
| 8e683f12a2 | |||
| 1910ea2bb6 | |||
| 5f6471a16e | |||
| 98a4baddab | |||
| 67f8de325f | |||
| 594d2a4224 | |||
| edd48e72ec | |||
| 47c9e1bb6e | |||
| 2fe80ecbe3 | |||
| 1640f25d9d | |||
| 28f3bbcad1 | |||
| c4eca264b1 | |||
| 89a9e77380 | |||
| 349b524151 | |||
| 084370b641 | |||
| c2a6cff3eb | |||
| d45e533d91 | |||
| c89de2559a | |||
| a5a267927a | |||
| 557e0acba4 | |||
| 3e4dfadb41 | |||
| b480d49096 | |||
| ece7bf41d3 | |||
| 250dd0b171 | |||
| f2475ddd88 | |||
| f302ca80d7 | |||
| 11b96e56da | |||
| daad9d18ec | |||
| 3c842f6606 | |||
| 23ef007bb1 | |||
| a9b9a17381 | |||
| d5e66618aa | |||
| 2e89f07ee2 | |||
| 1a51bcf0b5 | |||
| f1ee5150a9 | |||
| 9db7f5c985 | |||
| d56363276b | |||
| 5a9b49559b | |||
| fbc8228977 | |||
| a1140f7006 | |||
| f3561ff0fb | |||
| 42b792ab9d | |||
| 1e3a166172 | |||
| e1c6cb357e | |||
| 1aa64fba1f | |||
| 4f0a6f67c3 | |||
| 4f863f7b1d | |||
| b66f9d7ced | |||
| 493f209162 | |||
| 0aa109e280 | |||
| b0a287c6a8 | |||
| 8c00b157ad | |||
| 85bbd25bbb | |||
| 4d7e42fba8 | |||
| f91e8e9910 | |||
| 9e9b0b5557 | |||
| bfcfcdbf16 |
@@ -63,12 +63,36 @@ REACT_APP_APPLE_REDIRECT_URL='http://localhost:9082/login/auth/apple'
|
||||
# /* 'client_id' => */ 'com.wrenchboard.users.client',
|
||||
# /* 'client_secret' => */ 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6Ilc1V1RXQzlEVEoifQ.eyJpc3MiOiJKUjM2M0ZFWThSIiwiaWF0IjoxNjU0MDgzODQxLCJleHAiOjE2NTkyNjc4NDEsImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJzdWIiOiJjb20ud3JlbmNoYm9hcmQudXNlcnMuY2xpZW50In0.TIPMwjS2MgSysqEuw3yu1nrOcrH-6omzerDhx0CadjWn2yCO8wZhQiAlhIFs7F-WPektIJ6h-2BT62yGrILiTA',
|
||||
# /* 'redirect_uri' => */ site_url('login/auth/apple')
|
||||
#SOCIALS Links Display
|
||||
REACT_APP_APPLE_SOCIAL_LOGIN=0
|
||||
REACT_APP_LINKEDIN_SOCIAL_LOGIN=0
|
||||
|
||||
#File Handling
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
|
||||
#Auth Text(s)
|
||||
REACT_APP_LOGOUT_TEXT="Sign Out"
|
||||
|
||||
|
||||
#apigate.lotus.g1.wrenchboard.com:76.209.103.227
|
||||
#apigate.orion.g1.wrenchboard.com:76.209.103.227
|
||||
|
||||
#Cards Handling
|
||||
REACT_APP_MAX_CREDIT_CARDS=4
|
||||
REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
|
||||
|
||||
#Family
|
||||
REACT_APP_MAX_FAMILY_MEMBERS=8
|
||||
|
||||
REACT_APP_SHOW_OFFER_GROUP_JOB=0
|
||||
|
||||
#UPLOAD PROFILE PICTURE
|
||||
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
|
||||
|
||||
#GOOGLE RECAPTCHA SITEKEY
|
||||
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
|
||||
+22
-1
@@ -42,4 +42,25 @@ REACT_APP_GOOGLE_REDIRECT_URL=http://localhost:9082/login/auth/
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
|
||||
REACT_APP_LOGOUT_TEXT="Sign Out"
|
||||
REACT_APP_LOGOUT_TEXT="Sign Out"
|
||||
|
||||
REACT_APP_APPLE_SOCIAL_LOGIN=0
|
||||
REACT_APP_LINKEDIN_SOCIAL_LOGIN=0
|
||||
|
||||
REACT_APP_MAX_CREDIT_CARDS=4
|
||||
REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
|
||||
|
||||
REACT_APP_MAX_FAMILY_MEMBERS=8
|
||||
|
||||
REACT_APP_SHOW_OFFER_GROUP_JOB=0
|
||||
|
||||
#UPLOAD PROFILE PICTURE
|
||||
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
|
||||
|
||||
#GOOGLE RECAPTCHA SITEKEY
|
||||
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
|
||||
+21
-1
@@ -49,4 +49,24 @@ DISABLE_ESLINT_PLUGIN=true
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
|
||||
REACT_APP_LOGOUT_TEXT="Sign Out"
|
||||
REACT_APP_LOGOUT_TEXT="Sign Out"
|
||||
REACT_APP_APPLE_SOCIAL_LOGIN=0
|
||||
REACT_APP_LINKEDIN_SOCIAL_LOGIN=0
|
||||
|
||||
REACT_APP_MAX_CREDIT_CARDS=4
|
||||
REACT_APP_MAX_CREDIT_BANK_ACCOUNT=4
|
||||
|
||||
REACT_APP_MAX_FAMILY_MEMBERS=8
|
||||
|
||||
REACT_APP_SHOW_OFFER_GROUP_JOB=0
|
||||
|
||||
#UPLOAD PROFILE PICTURE
|
||||
REACT_APP_SHOW_UPLOAD_PROFILE_PICTURE=0
|
||||
|
||||
#GOOGLE RECAPTCHA SITEKEY
|
||||
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
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
#package-lock.json
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
Generated
+74
@@ -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",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"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",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -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 |
@@ -32,7 +32,7 @@ const validationSchema = Yup.object().shape({
|
||||
.required("Description is required"),
|
||||
job_detail: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(1440, "Maximum 1440 characters")
|
||||
.max(499, "Maximum 499 characters")
|
||||
.required("Details is required"),
|
||||
timeline_days: Yup.number()
|
||||
.typeError("you must specify a number")
|
||||
@@ -134,7 +134,7 @@ function AddJob({ popUpHandler, categories }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="add-job p-5 w-full bg-white rounded-md flex flex-col justify-between">
|
||||
<div className="add-job p-5 w-full bg-white dark:bg-dark-white dark:text-white rounded-md flex flex-col justify-between">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
@@ -163,7 +163,7 @@ function AddJob({ popUpHandler, categories }) {
|
||||
id="country"
|
||||
name="country"
|
||||
value={props.values.country}
|
||||
className={`input-field p-2 mt-3 rounded-md 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`}
|
||||
className={`input-field p-2 mt-3 rounded-md 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}
|
||||
>
|
||||
@@ -200,7 +200,6 @@ function AddJob({ popUpHandler, categories }) {
|
||||
fieldClass="px-6 text-right"
|
||||
label="Price"
|
||||
labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="number"
|
||||
name="price"
|
||||
placeholder="0"
|
||||
@@ -222,7 +221,6 @@ function AddJob({ popUpHandler, categories }) {
|
||||
fieldClass="px-6"
|
||||
label="Title"
|
||||
labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="title"
|
||||
value={props.values.title}
|
||||
@@ -242,7 +240,6 @@ function AddJob({ popUpHandler, categories }) {
|
||||
fieldClass="px-6"
|
||||
label="Description"
|
||||
labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="description"
|
||||
value={props.values.description}
|
||||
@@ -274,7 +271,7 @@ function AddJob({ popUpHandler, categories }) {
|
||||
<textarea
|
||||
id="Job Delivery Details"
|
||||
rows="5"
|
||||
className={`input-field px-3 py-2 placeholder:text-base text-dark-gray dark:text-white w-full h-[100px] bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px]`}
|
||||
className={`input-field px-3 py-2 placeholder:text-base text-dark-gray dark:text-white w-full h-[100px] bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] border`}
|
||||
style={{ resize: "none" }}
|
||||
name="job_detail"
|
||||
value={props.values.job_detail}
|
||||
@@ -343,7 +340,7 @@ function AddJob({ popUpHandler, categories }) {
|
||||
<Field
|
||||
component="select"
|
||||
name="timeline_days"
|
||||
className={`input-field p-2 mt-3 rounded-md 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 ${
|
||||
className={`input-field p-2 mt-3 rounded-md 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 ${
|
||||
props.errors.timeline_days &&
|
||||
props.touched.timeline_days
|
||||
? "border-[#ff0a0a63] shadow-red-500 border-[0.5px] animate-shake"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -7,6 +7,8 @@ import AuthLayout from "../AuthLayout";
|
||||
import EmailValidator from "../../../lib/EmailValidator";
|
||||
import ForgetPwdResponse from "../ForgetPwdResponse";
|
||||
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
|
||||
export default function ForgotPassword() {
|
||||
const [checked, setValue] = useState(false);
|
||||
const [resetLoading, setResetLoading] = useState(false);
|
||||
@@ -22,9 +24,18 @@ export default function ForgotPassword() {
|
||||
setMail(e?.target.value);
|
||||
};
|
||||
|
||||
const humanChecker = () => {
|
||||
setValue(!checked);
|
||||
};
|
||||
// const humanChecker = () => {
|
||||
// setValue(!checked);
|
||||
// };
|
||||
|
||||
function humanChecker(value) {
|
||||
// console.log("Captcha value:", value);
|
||||
if(value){
|
||||
setValue(true)
|
||||
}else{
|
||||
setValue(false)
|
||||
}
|
||||
}
|
||||
|
||||
const resetHandler = async () => {
|
||||
if (email == "") {
|
||||
@@ -113,10 +124,16 @@ export default function ForgotPassword() {
|
||||
/>
|
||||
</div>
|
||||
{/* hCaptha clone for the time being */}
|
||||
<div className="mb-10">
|
||||
<div className="mb-10 flex justify-center w-full">
|
||||
<ReCAPTCHA
|
||||
sitekey={process.env.REACT_APP_GOOGLE_RECAPTCHA_SITEKEY}
|
||||
onChange={humanChecker}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="mb-10">
|
||||
<div className="w-[303px] h-[78px] mx-auto overflow-hidden">
|
||||
<div className="w-[300px] h-[74px] bg-white bottom-[1px] rounded border-gray-100 overflow-hidden cursor-pointer">
|
||||
{/* Checkbox */}
|
||||
|
||||
<div className="h-full relative inline-block">
|
||||
<div className="relative table top-0 h-full">
|
||||
<div className="table-cell align-middle">
|
||||
@@ -148,18 +165,25 @@ export default function ForgotPassword() {
|
||||
<div className="h-full relative inline-block w-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
{msgError && (
|
||||
<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]">
|
||||
{msgError}
|
||||
</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>
|
||||
@@ -167,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>
|
||||
|
||||
@@ -14,10 +14,18 @@ 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 queryParams = new URLSearchParams(location?.search);
|
||||
const sessionExpired = queryParams.get("sessionExpired")
|
||||
|
||||
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 +115,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 +136,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 +152,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 +163,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",
|
||||
@@ -219,6 +245,9 @@ export default function Login() {
|
||||
</div>
|
||||
<div className="content-wrapper login shadow-md w-full lg:max-w-[530px] 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="w-full">
|
||||
|
||||
{/* 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">
|
||||
{/* <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
|
||||
Sign In to WrenchBoard
|
||||
@@ -233,6 +262,14 @@ export default function Login() {
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* SHOWS THIS IF USER SESSION HAS EXPIRED */}
|
||||
{sessionExpired == 'true' &&
|
||||
<div className="w-full p-1 mb-7">
|
||||
<p className="text-red-500 text-base text-center">Your session expired and will need to login again</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* switch login component */}
|
||||
<div className="ml-7 flex justify-start items-center gap-3">
|
||||
@@ -296,6 +333,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 +368,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>
|
||||
@@ -329,35 +377,51 @@ export default function Login() {
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div className="sm:flex sm:justify-between sm:items-center sm:space-x-2">
|
||||
<BrandBtn
|
||||
link="#"
|
||||
imgSrc={googleLogo}
|
||||
brand="Google"
|
||||
onClick={googleLogin}
|
||||
/>
|
||||
<BrandBtn
|
||||
// link={`https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&client_id=${process.env.REACT_APP_APPLE_CLIENT_ID}&redirect_uri=https%3A%2F%2Fwork.wrenchboard.com%2Flogin%2Fauth%2Fapple&state=4b2c4456b7&scope=name+email`}
|
||||
link={`https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&client_id=${process.env.REACT_APP_APPLE_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_APPLE_REDIRECT_URL}&state=4b2c4456b7&scope=name+email`}
|
||||
imgSrc={appleLogo}
|
||||
brand="Apple"
|
||||
isAnchor={true}
|
||||
style={{visibility: 'hidden'}}
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:flex sm:justify-between sm:items-center sm:space-x-2">
|
||||
<BrandBtn
|
||||
link={`https://www.facebook.com/v14.0/dialog/oauth?client_id=${process.env.REACT_APP_FACEBOOK_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_FACEBOOK_REDIRECT_URL}&scope=${process.env.REACT_APP_FACEBOOK_CLIENT_SCOPE}`}
|
||||
imgSrc={facebookLogo}
|
||||
brand="Facebook"
|
||||
isAnchor={true}
|
||||
/>
|
||||
<BrandBtn
|
||||
// link="https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&scope=comma-separated-list-of-scopes&state=YOUR_STATE_VALUE"
|
||||
imgSrc={linkedInLogo}
|
||||
brand="LinkedIn"
|
||||
isAnchor={true}
|
||||
/>
|
||||
<div className="sm:grid grid-cols-2 gap-1">
|
||||
<div className="w-full">
|
||||
<BrandBtn
|
||||
link="#"
|
||||
imgSrc={googleLogo}
|
||||
brand="Google"
|
||||
onClick={googleLogin}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`w-full ${
|
||||
process.env.REACT_APP_APPLE_SOCIAL_LOGIN !== 0 &&
|
||||
"hidden"
|
||||
}`}
|
||||
>
|
||||
<BrandBtn
|
||||
// link={`https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&client_id=${process.env.REACT_APP_APPLE_CLIENT_ID}&redirect_uri=https%3A%2F%2Fwork.wrenchboard.com%2Flogin%2Fauth%2Fapple&state=4b2c4456b7&scope=name+email`}
|
||||
link={`https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&client_id=${process.env.REACT_APP_APPLE_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_APPLE_REDIRECT_URL}&state=4b2c4456b7&scope=name+email`}
|
||||
imgSrc={appleLogo}
|
||||
brand="Apple"
|
||||
isAnchor={true}
|
||||
// style={{visibility: 'hidden'}}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<BrandBtn
|
||||
link={`https://www.facebook.com/v14.0/dialog/oauth?client_id=${process.env.REACT_APP_FACEBOOK_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_FACEBOOK_REDIRECT_URL}&scope=${process.env.REACT_APP_FACEBOOK_CLIENT_SCOPE}`}
|
||||
imgSrc={facebookLogo}
|
||||
brand="Facebook"
|
||||
isAnchor={true}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`w-full ${
|
||||
process.env.REACT_APP_LINKEDIN_SOCIAL_LOGIN !== 0 &&
|
||||
"hidden"
|
||||
}`}
|
||||
>
|
||||
<BrandBtn
|
||||
// link="https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&scope=comma-separated-list-of-scopes&state=YOUR_STATE_VALUE"
|
||||
imgSrc={linkedInLogo}
|
||||
brand="LinkedIn"
|
||||
isAnchor={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -417,7 +481,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>
|
||||
@@ -433,12 +497,11 @@ 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 hCaptcha and the our Privacy Policy
|
||||
and Terms of Service apply.
|
||||
</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>
|
||||
</div>
|
||||
@@ -447,7 +510,14 @@ export default function Login() {
|
||||
);
|
||||
}
|
||||
|
||||
const BrandBtn = ({ link, imgSrc, brand, onClick, isAnchor = false, style = {visibility: 'visible' } }) => {
|
||||
const BrandBtn = ({
|
||||
link,
|
||||
imgSrc,
|
||||
brand,
|
||||
onClick,
|
||||
isAnchor = false,
|
||||
style = { visibility: "visible" },
|
||||
}) => {
|
||||
// const doGoogle = async () => {
|
||||
// alert("start google");
|
||||
// };
|
||||
@@ -467,7 +537,7 @@ const BrandBtn = ({ link, imgSrc, brand, onClick, isAnchor = false, style = {vis
|
||||
// alert("start facebook");
|
||||
// };
|
||||
return (
|
||||
<div className="w-full sm:w-1/2 flex justify-center bottomMargin" style={style}>
|
||||
<div className="w-full flex justify-center bottomMargin" style={style}>
|
||||
{isAnchor ? (
|
||||
<a
|
||||
href={link}
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import InputCom from "../../Helpers/Inputs/InputCom";
|
||||
import AuthLayout from "../AuthLayout";
|
||||
|
||||
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 [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([]);
|
||||
const [countries, setCountries] = useState({loading:true, data:[]});
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
country: "",
|
||||
country: country? country : "",
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
email: "",
|
||||
@@ -45,9 +52,18 @@ export default function SignUp() {
|
||||
try {
|
||||
if (res.status === 200) {
|
||||
const { signup_country } = await res.data;
|
||||
setCountries(signup_country);
|
||||
// setCountries(signup_country);
|
||||
if(country){ // IF LINK/PATHNAME HAS CNT QUERY VALUE
|
||||
let cnt = signup_country.filter(item => item[0]==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: signup_country});
|
||||
}
|
||||
return setCountries({loading: false, data: cnt});
|
||||
}
|
||||
setCountries({loading: false, data:signup_country});
|
||||
} else if (res.data.result !== 100) {
|
||||
setCountries("Nothing see here!");
|
||||
setCountries({loading: false, data:[]});
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
@@ -134,7 +150,7 @@ export default function SignUp() {
|
||||
<AuthLayout slogan="Welcome to WrenchBoard">
|
||||
<div className="w-full">
|
||||
<div className="mb-5">
|
||||
<Link to="#">
|
||||
<Link to={currentPath}>
|
||||
<img
|
||||
src={WrenchBoard}
|
||||
alt="wrenchboard"
|
||||
@@ -172,6 +188,7 @@ export default function SignUp() {
|
||||
name="country"
|
||||
value={formData.country}
|
||||
inputHandler={handleInputChange}
|
||||
disable={country && countries?.data?.length <= 1 ? true : false}
|
||||
/>
|
||||
<div className="input-fl-name mb-5 sm:flex w-full sm:space-x-6 ">
|
||||
<div className="input-item sm:w-1/2 w-full mb-5 sm:mb-0">
|
||||
@@ -306,9 +323,10 @@ export default function SignUp() {
|
||||
<div className="signin-area mb-1">
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
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>
|
||||
@@ -333,6 +351,7 @@ const SelectOption = ({
|
||||
inputHandler,
|
||||
value,
|
||||
data, // passing the data from parent
|
||||
disable
|
||||
}) => {
|
||||
return (
|
||||
<div className="input-com mb-7">
|
||||
@@ -346,19 +365,39 @@ const SelectOption = ({
|
||||
</div>
|
||||
<div>
|
||||
<select
|
||||
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}
|
||||
>
|
||||
<option value={""}>Select your Country</option>
|
||||
{data?.length > 0 &&
|
||||
data?.map((item, idx) => (
|
||||
{data?.data?.length > 1 ?
|
||||
<>
|
||||
<option value={""}>Select your Country</option>
|
||||
{data?.data?.map((item, idx) => (
|
||||
<option value={item[0]} key={idx}>
|
||||
{item[1]}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
:
|
||||
data?.data?.length == 1 ?
|
||||
data?.data?.map((item, idx) => (
|
||||
<option value={item[0]} key={idx}>
|
||||
{item[1]}
|
||||
</option>
|
||||
))
|
||||
:
|
||||
data?.data?.length < 1 && data.loading ?
|
||||
<option value=''>
|
||||
Loading...
|
||||
</option>
|
||||
:
|
||||
<option value=''>
|
||||
No Country Found!
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,6 +54,8 @@ 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)
|
||||
|
||||
|
||||
navigate("/", { replace: true });
|
||||
setLinkLoader(false);
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, {
|
||||
Suspense,
|
||||
lazy,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
useTransition,
|
||||
} 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"));
|
||||
@@ -29,113 +28,113 @@ export default function FamilyManageTabs({
|
||||
listReload,
|
||||
loader,
|
||||
}) {
|
||||
// Initial state for family details
|
||||
const initialDetailState = {
|
||||
loading: false,
|
||||
data: null,
|
||||
};
|
||||
|
||||
// State for family details, tasks, waitlist, and pending
|
||||
const [details, setDetails] = useState({
|
||||
familyDetails: { loading: false, data: null },
|
||||
familyTasks: { loading: false, data: null },
|
||||
familyWaitList: { loading: false, data: null },
|
||||
familyPending: { loading: false, data: null },
|
||||
familyDetails: { ...initialDetailState },
|
||||
familyTasks: { ...initialDetailState },
|
||||
familyWaitList: { ...initialDetailState },
|
||||
familyPending: { ...initialDetailState },
|
||||
});
|
||||
|
||||
// Function to reset family details, tasks, waitlist, and pending
|
||||
const resetDetails = () => {
|
||||
setDetails({
|
||||
familyDetails: { ...initialDetailState },
|
||||
familyTasks: { ...initialDetailState },
|
||||
familyWaitList: { ...initialDetailState },
|
||||
familyPending: { ...initialDetailState },
|
||||
});
|
||||
};
|
||||
|
||||
const [updatePage, setUpdatePage] = useState(false) // State to determine when to update the page
|
||||
|
||||
// State for family task data
|
||||
const [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
|
||||
|
||||
// State for active task
|
||||
const [activeTask, setActiveTask] = useState({ id: 0, data: {} });
|
||||
|
||||
// State for error messages
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
|
||||
// State for family task popout
|
||||
const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
|
||||
|
||||
// State for profile image
|
||||
const [profileImg, setProfileImg] = useState(profile);
|
||||
|
||||
// Ref for profile image input
|
||||
const profileImgInput = useRef(null);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
// Create an instance of the usersService class
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
// Function to handle toggling the family task popout
|
||||
const familyPopUpHandler = () => {
|
||||
setFamilyTaskPopout((prev) => !prev);
|
||||
};
|
||||
|
||||
// Function to trigger a click on the hidden profile image input
|
||||
const browseProfileImg = () => {
|
||||
profileImgInput.current.click();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
|
||||
const manageFamily = useCallback(async () => {
|
||||
try {
|
||||
setDetails((prevDetails) => ({
|
||||
...prevDetails,
|
||||
familyDetails: { loading: true },
|
||||
familyTasks: { loading: true },
|
||||
familyWaitList: { loading: true },
|
||||
familyPending: { loading: true },
|
||||
}));
|
||||
|
||||
const { family_uid } = accountDetails;
|
||||
const reqData = { family_uid };
|
||||
|
||||
const [familyRes, tasksRes, familyWaitRes, familyPending] =
|
||||
await Promise.all([
|
||||
apiCall.ManageFamily(reqData),
|
||||
apiCall.ManageTasks(reqData),
|
||||
apiCall.ManageFamilyWaitlist(),
|
||||
apiCall.ManageFamilyPending(),
|
||||
]);
|
||||
|
||||
const familyData = familyRes.data;
|
||||
const tasksData = tasksRes.data;
|
||||
const familyWaitData = familyWaitRes.data;
|
||||
const familyPendingData = familyPending.data;
|
||||
|
||||
if (
|
||||
familyData?.internal_return < 0 ||
|
||||
tasksData?.internal_return < 0 ||
|
||||
familyWaitData?.internal_return < 0 ||
|
||||
familyPendingData?.internal_return < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
startTransition(() => {
|
||||
setDetails({
|
||||
familyDetails: { loading: false, data: familyData },
|
||||
familyTasks: { loading: false, data: tasksData },
|
||||
familyWaitList: { loading: false, data: familyWaitData },
|
||||
familyPending: { loading: false, data: familyPendingData },
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
setDetails((prevDetails) => ({
|
||||
...prevDetails,
|
||||
familyDetails: { loading: false },
|
||||
familyTasks: { loading: false },
|
||||
familyWaitList: { loading: false },
|
||||
familyPending: { loading: false },
|
||||
}));
|
||||
setErrMsg("An error occurred");
|
||||
throw new Error(error);
|
||||
}
|
||||
}, [apiCall, accountDetails]);
|
||||
|
||||
// Ref for the account section
|
||||
const accountRef = useRef();
|
||||
|
||||
// React-to-Print hook for handling printing
|
||||
const useHandlePrint = useReactToPrint({
|
||||
content: () => accountRef.current,
|
||||
});
|
||||
|
||||
// Array of tab names
|
||||
const tabs = [
|
||||
{ id: 1, name: "Tasks" },
|
||||
{ id: 2, name: "Waiting" },
|
||||
{ id: 3, name: "Pending" },
|
||||
];
|
||||
|
||||
// State for the currently selected tab
|
||||
const [tab, setTab] = useState(tabs[0].name);
|
||||
|
||||
// Function to handle tab changes
|
||||
const tabHandler = (value) => {
|
||||
startTransition(() => {
|
||||
setTab(value);
|
||||
});
|
||||
setTab(value);
|
||||
};
|
||||
|
||||
// Object that maps tab names to their corresponding components
|
||||
const tabComponents = {
|
||||
Tasks: (
|
||||
<FamilyTasks
|
||||
@@ -156,7 +155,7 @@ export default function FamilyManageTabs({
|
||||
<FamilyPending
|
||||
familyData={details.familyPending.data}
|
||||
accountDetails={accountDetails}
|
||||
loader={details.familyWaitList.loading}
|
||||
loader={details.familyPending.loading}
|
||||
/>
|
||||
),
|
||||
Account: (
|
||||
@@ -167,9 +166,11 @@ export default function FamilyManageTabs({
|
||||
handlePrint={useHandlePrint}
|
||||
/>
|
||||
),
|
||||
Profile: <FamilyProfile />,
|
||||
Profile: <FamilyProfile familyData={details.familyDetails.data} />,
|
||||
wallet: <FamilyWallet familyData={details.familyDetails.data} />,
|
||||
};
|
||||
|
||||
// Default tab component
|
||||
const defaultTabComponent = (
|
||||
<FamilyTasks
|
||||
className={className}
|
||||
@@ -179,17 +180,101 @@ export default function FamilyManageTabs({
|
||||
/>
|
||||
);
|
||||
|
||||
// Selected tab component based on the current 'tab'
|
||||
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
|
||||
|
||||
// Effect to manage family details and related data
|
||||
useEffect(() => {
|
||||
let __manageFamily = true;
|
||||
if (__manageFamily) {
|
||||
manageFamily();
|
||||
}
|
||||
return () => {
|
||||
__manageFamily = false;
|
||||
const manageFamily = async () => {
|
||||
try {
|
||||
resetDetails();
|
||||
|
||||
setDetails({
|
||||
familyDetails: { loading: true },
|
||||
familyTasks: { loading: true },
|
||||
familyWaitList: { loading: true },
|
||||
familyPending: { loading: true },
|
||||
});
|
||||
|
||||
const { family_uid } = accountDetails;
|
||||
const reqData = { family_uid };
|
||||
|
||||
const [familyRes, tasksRes, familyWaitRes, familyPending] =
|
||||
await Promise.all([
|
||||
apiCall.ManageFamily(reqData),
|
||||
apiCall.ManageTasks(reqData),
|
||||
apiCall.ManageFamilyWaitlist(),
|
||||
apiCall.ManageFamilyPending(),
|
||||
]);
|
||||
|
||||
const familyData = familyRes.data;
|
||||
const tasksData = tasksRes.data;
|
||||
const familyWaitData = familyWaitRes.data;
|
||||
const familyPendingData = familyPending.data;
|
||||
|
||||
// Function to check for errors in data
|
||||
const checkDataError = (data) => data?.internal_return < 0;
|
||||
|
||||
if (
|
||||
checkDataError(familyData) ||
|
||||
checkDataError(tasksData) ||
|
||||
checkDataError(familyWaitData) ||
|
||||
checkDataError(familyPendingData)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDetails({
|
||||
familyDetails: { loading: false, data: familyData },
|
||||
familyTasks: { loading: false, data: tasksData },
|
||||
familyWaitList: { loading: false, data: familyWaitData },
|
||||
familyPending: { loading: false, data: familyPendingData },
|
||||
});
|
||||
} catch (error) {
|
||||
resetDetails();
|
||||
setErrMsg("An error occurred");
|
||||
throw new Error(error);
|
||||
}
|
||||
};
|
||||
}, [tab, manageFamily]);
|
||||
|
||||
// Invoke the manageFamily function when the component mounts
|
||||
manageFamily();
|
||||
}, [updatePage]);
|
||||
|
||||
// Effect to manage family tasks
|
||||
useEffect(() => {
|
||||
let checkFamilyTask = true;
|
||||
const reqData = {
|
||||
limit: 30,
|
||||
offset: 0,
|
||||
job_type: "FAMILY",
|
||||
action: 13005,
|
||||
};
|
||||
|
||||
if (checkFamilyTask) {
|
||||
setFamilyTask({ loading: true });
|
||||
apiCall
|
||||
.getMyJobList(reqData)
|
||||
.then((res) => {
|
||||
setFamilyTask({ loading: false, data: res?.data?.result_list });
|
||||
if (res?.data?.result_list?.length) {
|
||||
setActiveTask((prev) => ({
|
||||
...prev,
|
||||
data: res?.data?.result_list[0],
|
||||
}));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setFamilyTask({ loading: false, data: [] });
|
||||
console.log("Error", err);
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup function to prevent memory leaks
|
||||
return () => {
|
||||
checkFamilyTask = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -214,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")}
|
||||
@@ -232,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>
|
||||
@@ -265,7 +361,7 @@ export default function FamilyManageTabs({
|
||||
Add task
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex-[0.9] h-full">
|
||||
<div className="h-full relative overflow-y-auto">
|
||||
<Suspense
|
||||
@@ -285,7 +381,12 @@ export default function FamilyManageTabs({
|
||||
<AssignTaskPopout
|
||||
action={familyPopUpHandler}
|
||||
situation={familyTaskPopout}
|
||||
familyDetails={details.familyDetails.data}
|
||||
familyTask={familyTask}
|
||||
setFamilyTask={setFamilyTask}
|
||||
setActiveTask={setActiveTask}
|
||||
activeTask={activeTask}
|
||||
familyDetailsData={details.familyDetails.data}
|
||||
setUpdatePage={setUpdatePage}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,441 +1,420 @@
|
||||
import React, { useState, useEffect, useTransition } from "react";
|
||||
import ModalCom from "../../Helpers/ModalCom";
|
||||
import Detail from "../../jobPopout/popoutcomponent/Detail";
|
||||
import React, { useState } from "react";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import ModalCom from "../../Helpers/ModalCom";
|
||||
import { PriceFormatter } from "../../Helpers/PriceFormatter";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import Detail from "../../jobPopout/popoutcomponent/Detail";
|
||||
import { NewTasks } from "./forms";
|
||||
|
||||
const AssignTaskPopout = React.memo(({ action, details, situation, familyDetails }) => {
|
||||
const apiCall = new usersService();
|
||||
const AssignTaskPopout = React.memo(
|
||||
({
|
||||
action,
|
||||
details,
|
||||
situation,
|
||||
familyDetailsData,
|
||||
familyTask,
|
||||
activeTask,
|
||||
setActiveTask,
|
||||
setUpdatePage
|
||||
}) => {
|
||||
const apiCall = new usersService();
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // HOLDS RESPONSE FOR SENDING API REQUEST
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // HOLDS RESPONSE FOR SENDING API REQUEST
|
||||
|
||||
let [familyTask, setFamilyTask] = useState({ loading: false, data: [] });
|
||||
let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK
|
||||
|
||||
let [taskType, setTaskType] = useState(details ? "new" : "select"); // SWITCHES BTW SELECT TASK AND NEW TASK
|
||||
const switchTaskType = ({ target: { value } }) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setTaskType(value);
|
||||
};
|
||||
|
||||
let [activeTask, setActiveTask] = useState({ id: 0, data: {} }); // HOLDS SELECTED TASK
|
||||
const handleActiveTask = (id = 0, data = {}) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setActiveTask({ id, data });
|
||||
};
|
||||
|
||||
const switchTaskType = ({ target: { value } }) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setTaskType(value);
|
||||
};
|
||||
// New Task
|
||||
const [formState, setFormState] = useState({
|
||||
// Initialize form state with desired fields
|
||||
banner: details?.banner || "default.jpg",
|
||||
country: details?.country || "",
|
||||
price: details?.price || "",
|
||||
title: details?.title || "",
|
||||
description: details?.description || "",
|
||||
job_detail: details?.job_detail || "",
|
||||
timeline_days: details?.timeline_days || "",
|
||||
category: details?.category || "",
|
||||
});
|
||||
|
||||
const handleActiveTask = (id = 0, data = {}) => {
|
||||
// FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setActiveTask({ id, data });
|
||||
};
|
||||
|
||||
// New Task
|
||||
const [formState, setFormState] = useState({
|
||||
// Initialize form state with desired fields
|
||||
banner: details?.banner || "default.jpg",
|
||||
country: details?.country || "",
|
||||
price: details?.price || "",
|
||||
title: details?.title || "",
|
||||
description: details?.description || "",
|
||||
job_detail: details?.job_detail || "",
|
||||
timeline_days: details?.timeline_days || "",
|
||||
category: details?.category || "",
|
||||
});
|
||||
|
||||
const assignFamilyTask = () => {
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
let reqData = {};
|
||||
if (taskType == "select") {
|
||||
// RUNS HERE IF TASK TYPE IS SELECT
|
||||
if (!Object.keys(activeTask.data).length) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "No Task is seleted",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
reqData = {
|
||||
// API PAYLOADS
|
||||
job_id: activeTask.data?.job_id,
|
||||
job_uid: activeTask.data?.job_uid,
|
||||
family_uid: familyDetails?.uid || details?.family_uid,
|
||||
job_description: activeTask.data?.description,
|
||||
assign_mode: 110011,
|
||||
};
|
||||
}
|
||||
|
||||
if (taskType === "new") {
|
||||
const {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
} = formState;
|
||||
|
||||
const requiredFields = {
|
||||
banner,
|
||||
// category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
};
|
||||
|
||||
for (let field in requiredFields) {
|
||||
if (requiredFields[field] == "") {
|
||||
// let currencyErrMsg = field == "country" && "currency"
|
||||
const assignFamilyTask = () => {
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
let reqData = {};
|
||||
if (taskType == "select") {
|
||||
// RUNS HERE IF TASK TYPE IS SELECT
|
||||
if (!Object.keys(activeTask.data).length) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: `${field} is empty`,
|
||||
message: "No Task is seleted",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
reqData = {
|
||||
// API PAYLOADS
|
||||
job_id: activeTask.data?.job_id,
|
||||
job_uid: activeTask.data?.job_uid,
|
||||
family_uid: familyDetailsData?.uid || details?.family_uid,
|
||||
job_description: activeTask.data?.description,
|
||||
assign_mode: 110011,
|
||||
};
|
||||
}
|
||||
|
||||
reqData = {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price: price * 100,
|
||||
timeline_days,
|
||||
title,
|
||||
assign_mode: 110055,
|
||||
family_uid: details?.family_uid || familyDetails?.uid,
|
||||
};
|
||||
}
|
||||
if (taskType === "new") {
|
||||
const {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
} = formState;
|
||||
|
||||
apiCall
|
||||
.assignFamilyTask(reqData)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
const requiredFields = {
|
||||
banner,
|
||||
// category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price,
|
||||
timeline_days,
|
||||
title,
|
||||
};
|
||||
|
||||
for (let field in requiredFields) {
|
||||
if (requiredFields[field] == "") {
|
||||
// let currencyErrMsg = field == "country" && "currency"
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: `${field} is empty`,
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
reqData = {
|
||||
banner,
|
||||
category,
|
||||
country,
|
||||
description,
|
||||
job_detail,
|
||||
price: price * 100,
|
||||
timeline_days,
|
||||
title,
|
||||
assign_mode: 110055,
|
||||
family_uid: details?.family_uid || familyDetailsData?.uid,
|
||||
};
|
||||
}
|
||||
|
||||
apiCall
|
||||
.assignFamilyTask(reqData)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "failed to assign task",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: true,
|
||||
message: "action successful",
|
||||
});
|
||||
setUpdatePage(prev => !prev) // Updates family task page by calling the useeffect hook
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
action(); // FUNCTION THAT CLOSES THE MODAL BOX
|
||||
}, 5000);
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "failed to assign task",
|
||||
message: "An Error occured, try again",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: true,
|
||||
message: "action successful",
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
action(); // FUNCTION THAT CLOSES THE MODAL BOX
|
||||
}, 5000);
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "An Error occured, try again",
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let checkFamilyTask = true;
|
||||
const reqData = {
|
||||
limit: 30,
|
||||
offset: 0,
|
||||
job_type: "FAMILY",
|
||||
action: 13005,
|
||||
};
|
||||
|
||||
apiCall
|
||||
.getMyJobList(reqData)
|
||||
.then((res) => {
|
||||
if (checkFamilyTask) {
|
||||
setFamilyTask({ loading: false, data: res?.data?.result_list });
|
||||
if (res?.data?.result_list?.length) {
|
||||
setActiveTask((prev) => ({
|
||||
...prev,
|
||||
data: res?.data?.result_list[0],
|
||||
}));
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setFamilyTask({ loading: false, data: [] });
|
||||
console.log("Error", err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
checkFamilyTask = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalCom
|
||||
action={action}
|
||||
situation={situation}
|
||||
className="assign-task-popup"
|
||||
>
|
||||
<div className="w-full h-full lg:w-[700px] lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
|
||||
<div className="w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Assign task to {familyDetails?.firstname || details?.firstName}
|
||||
</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"
|
||||
return (
|
||||
<>
|
||||
<ModalCom
|
||||
action={action}
|
||||
situation={situation}
|
||||
className="assign-task-popup"
|
||||
>
|
||||
<div className="w-full h-full lg:w-[700px] lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
|
||||
<div className="w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Assign task to{" "}
|
||||
{familyDetailsData?.firstname || details?.firstName}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={action}
|
||||
>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{familyTask.loading ? (
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
<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={`job-action-modal-body w-full md:grid ${
|
||||
taskType !== "new" ? "md:grid-cols-2" : "md:grid-cols-1"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="mb-2 w-full flex items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="select"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "select"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>Select Task</span>
|
||||
{familyTask.loading ? (
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`job-action-modal-body w-full md:grid ${
|
||||
taskType !== "new" ? "md:grid-cols-2" : "md:grid-cols-1"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="mb-2 w-full flex items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="select"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "select"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>Select Task</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="new"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "new"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>New Task</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sky-blue text-base">
|
||||
<input
|
||||
type="radio"
|
||||
name="task-type"
|
||||
value="new"
|
||||
className="w-[20px] h-[20px] cursor-pointer"
|
||||
checked={taskType == "new"}
|
||||
onChange={switchTaskType}
|
||||
/>
|
||||
<span>New Task</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<div className="p-4 w-full h-[400px] overflow-y-auto bg-slate-100 rounded-md dark:bg-[#11131f] dark:text-white">
|
||||
{familyTask?.data?.length ? (
|
||||
familyTask?.data?.map((item, index) => (
|
||||
<div
|
||||
key={item.job_uid}
|
||||
className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer"
|
||||
onClick={() => handleActiveTask(item.job_uid, item)}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="task-list"
|
||||
checked={
|
||||
activeTask.id == item.job_uid ||
|
||||
(activeTask.id == index && true)
|
||||
}
|
||||
onChange={() =>
|
||||
{/* Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<div className="p-4 w-full h-[400px] overflow-y-auto bg-slate-100 rounded-md dark:bg-[#11131f] dark:text-white">
|
||||
{familyTask?.data?.length ? (
|
||||
familyTask?.data?.map((item, index) => (
|
||||
<div
|
||||
key={item.job_uid}
|
||||
className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer"
|
||||
onClick={() =>
|
||||
handleActiveTask(item.job_uid, item)
|
||||
}
|
||||
className="w-[15px] h-[15px] cursor-pointer"
|
||||
/>
|
||||
<p className="w-full text-dark-gray dark:text-white tracking-wide">
|
||||
{item?.title}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="task-list"
|
||||
checked={
|
||||
activeTask.id == item.job_uid ||
|
||||
(activeTask.id == index && true)
|
||||
}
|
||||
onChange={() =>
|
||||
handleActiveTask(item.job_uid, item)
|
||||
}
|
||||
className="w-[15px] h-[15px] cursor-pointer"
|
||||
/>
|
||||
<p className="w-full text-dark-gray dark:text-white tracking-wide">
|
||||
{item?.title}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center cursor-default">
|
||||
No Task found!
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{taskType == "new" && (
|
||||
<div className="p-4 w-full h-[400px]">
|
||||
<NewTasks
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/*Right Hand Side for details && Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<>
|
||||
{familyTask?.data?.length > 0 ? (
|
||||
<div className="p-4">
|
||||
<div className="w-full">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide border-b-2">
|
||||
{activeTask?.data?.title}
|
||||
</p>
|
||||
<div className="my-3">
|
||||
<Detail
|
||||
label="Description"
|
||||
value={activeTask?.data?.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Price
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">
|
||||
{PriceFormatter(
|
||||
activeTask?.data?.price * 0.01,
|
||||
activeTask?.data?.currency,
|
||||
activeTask?.data?.curreny_code
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Timeline
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="my-3 sm:flex items-center">
|
||||
<Detail
|
||||
label="Created"
|
||||
value={`Dummy, no value found for created!`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="my-3">
|
||||
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Delivery Detail
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
value={activeTask?.data?.job_detail}
|
||||
readOnly
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
</div>
|
||||
) : (
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center cursor-default">
|
||||
No Task found!
|
||||
</p>
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{taskType == "new" && (
|
||||
<div className="p-4 w-full h-[400px]">
|
||||
<NewTasks
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/*Right Hand Side for details && Task Type === select */}
|
||||
{taskType == "select" && (
|
||||
<>
|
||||
{familyTask?.data?.length > 0 ? (
|
||||
<div className="p-4">
|
||||
<div className="w-full">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide border-b-2">
|
||||
{activeTask?.data?.title}
|
||||
</p>
|
||||
<div className="my-3">
|
||||
<Detail
|
||||
label="Description"
|
||||
value={activeTask?.data?.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Price
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">
|
||||
{PriceFormatter(
|
||||
activeTask?.data?.price * 0.01,
|
||||
activeTask?.data?.currency,
|
||||
activeTask?.data?.curreny_code
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="my-3 w-full flex items-center gap-1">
|
||||
<label className="text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Timeline
|
||||
</label>
|
||||
<p className="p-1 text-sm text-slate-900 dark:text-white">{`${activeTask?.data?.timeline_days} day(s)`}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="my-3 sm:flex items-center">
|
||||
<Detail
|
||||
label="Created"
|
||||
value={`Dummy, no value found for created!`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="my-3">
|
||||
<label className="w-full text-slate-900 dark:text-white tracking-wide font-semibold">
|
||||
Delivery Detail
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
value={activeTask?.data?.job_detail}
|
||||
readOnly
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* BTN */}
|
||||
<div className="py-2 px-4 border-t-2 flex justify-between items-center">
|
||||
{/* error or success display */}
|
||||
<div className="w-auto h-auto flex items-center">
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`relative p-2 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px] self-start`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
requestStatus.status && (
|
||||
{/* BTN */}
|
||||
<div className="py-2 px-4 border-t-2 flex justify-between items-center">
|
||||
{/* error or success display */}
|
||||
<div className="w-auto h-auto flex items-center">
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`relative p-2 text-green-700 bg-slate-200 border-slate-800 mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
||||
className={`relative p-2 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px] self-start`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
requestStatus.status && (
|
||||
<div
|
||||
className={`relative p-2 text-green-700 bg-slate-200 border-slate-800 mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
||||
>
|
||||
{requestStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* End of error or success display */}
|
||||
<div className="w-auto h-auto flex items-center gap-3">
|
||||
<button
|
||||
disabled={requestStatus.loading}
|
||||
onClick={action}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
<span className="text-gradient">Close</span>
|
||||
</button>
|
||||
<div className="">
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner color="sky-blue" size="8" />
|
||||
) : taskType == "select" ? (
|
||||
<button
|
||||
type="button"
|
||||
disabled={requestStatus.loading}
|
||||
onClick={assignFamilyTask}
|
||||
className="px-1 w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
Assign
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
disabled={requestStatus.loading}
|
||||
onClick={assignFamilyTask}
|
||||
className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
{`Assign to ${
|
||||
familyDetails?.firstname || details?.firstName
|
||||
}`}
|
||||
</button>
|
||||
)}
|
||||
{/* End of error or success display */}
|
||||
<div className="w-auto h-auto flex items-center gap-3">
|
||||
<button
|
||||
disabled={requestStatus.loading}
|
||||
onClick={action}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
<span className="text-gradient">Close</span>
|
||||
</button>
|
||||
<div className="">
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner color="sky-blue" size="8" />
|
||||
) : taskType == "select" ? (
|
||||
<button
|
||||
type="button"
|
||||
disabled={requestStatus.loading}
|
||||
onClick={assignFamilyTask}
|
||||
className="px-1 w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
Assign
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
disabled={requestStatus.loading}
|
||||
onClick={assignFamilyTask}
|
||||
className="px-1 w-40 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
{`Assign to ${
|
||||
familyDetailsData?.firstname || details?.firstName
|
||||
}`}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</ModalCom>
|
||||
</>
|
||||
);
|
||||
})
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</ModalCom>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default AssignTaskPopout;
|
||||
export default AssignTaskPopout;
|
||||
|
||||
@@ -1,29 +1,165 @@
|
||||
import React, { useState } from "react";
|
||||
import dataImage1 from "../../assets/images/data-table-user-1.png";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
|
||||
import familyImage from '../../assets/images/no-family-side.png'
|
||||
import familyImage from "../../assets/images/no-family-side.png";
|
||||
import { formatDateString } from "../../lib";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
|
||||
export default function FamilyTable({ className, familyList, loader, popUpHandler }) {
|
||||
const navigate = useNavigate();
|
||||
/**
|
||||
* Renders a list of family members that can be managed.
|
||||
* It has its current maximum members at 8 and it comes with pagination and loading spinner functionality.
|
||||
|
||||
* @returns {JSX.Element} - The rendered component.
|
||||
*/
|
||||
export default function FamilyTable({
|
||||
className,
|
||||
familyList,
|
||||
loader,
|
||||
popUpHandler,
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const indexOfFirstItem = Number(currentPage);
|
||||
const indexOfLastItem =
|
||||
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const currentFamilyList = familyList?.slice(indexOfFirstItem, indexOfLastItem);
|
||||
const currentFamilyList = familyList?.slice(
|
||||
indexOfFirstItem,
|
||||
indexOfLastItem
|
||||
);
|
||||
|
||||
const handleManageClick = (familyMember) => {
|
||||
navigate("/manage-family", { state: familyMember });
|
||||
};
|
||||
|
||||
const handlePagination = (e) => {
|
||||
handlePagingFunc(e, setCurrentPage);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a table row for a family member.
|
||||
* @returns {JSX.Element} - The table row component.
|
||||
*/
|
||||
const FamilyRow = ({
|
||||
firstname,
|
||||
lastname,
|
||||
age,
|
||||
added,
|
||||
last_login,
|
||||
task_count,
|
||||
family_uid,
|
||||
banner,
|
||||
enable_traking,
|
||||
profile_picture,
|
||||
}) => {
|
||||
// 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={key}
|
||||
>
|
||||
<td className="py-4">
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1]">
|
||||
<img
|
||||
src={profile_picture}
|
||||
// src={profile_picture || localImgLoad(`images/icons/${banner}`)}
|
||||
alt={`Avatar of ${firstname} ${lastname}`}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col flex-[0.9]">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
{`${firstname} ${lastname} (${age})`}
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Added: <span className="text-purple ml-1">{addedDate}</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Last Login:{" "}
|
||||
<span className="text-purple ml-1">{loginDate}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span
|
||||
className={`text-base 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">
|
||||
{task_count}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2 flex items-center justify-center">
|
||||
<button
|
||||
onClick={() =>
|
||||
handleManageClick({
|
||||
firstname,
|
||||
lastname,
|
||||
age,
|
||||
added,
|
||||
last_login,
|
||||
task_count,
|
||||
family_uid,
|
||||
banner,
|
||||
})
|
||||
}
|
||||
type="button"
|
||||
className="w-12 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 11 20"
|
||||
id="Arrow"
|
||||
className="w-[0.7rem]"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M.366 19.708c.405.39 1.06.39 1.464 0l8.563-8.264a1.95 1.95 0 0 0 0-2.827L1.768.292A1.063 1.063 0 0 0 .314.282a.976.976 0 0 0-.011 1.425l7.894 7.617a.975.975 0 0 1 0 1.414L.366 18.295a.974.974 0 0 0 0 1.413"
|
||||
// fill=""
|
||||
className="color000000 svgShape fill-[#fff]"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
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] ${
|
||||
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 ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
@@ -32,125 +168,52 @@ export default function FamilyTable({ className, familyList, loader, popUpHandle
|
||||
<div className="h-full min-h-[500px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
)
|
||||
:
|
||||
familyList?.length > 0 ?
|
||||
(
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 relative">
|
||||
<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">Last Login</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((props, idx) => {
|
||||
let {
|
||||
firstname,
|
||||
lastname,
|
||||
age,
|
||||
added,
|
||||
last_login,
|
||||
task_count,
|
||||
family_uid,
|
||||
banner
|
||||
} = props;
|
||||
let addedDate = added?.split(" ")[0];
|
||||
let LoginDate = last_login?.split(" ")[0];
|
||||
return (
|
||||
<tr
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
key={family_uid}
|
||||
>
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1]">
|
||||
<img
|
||||
// src={dataImage1}
|
||||
src={localImgLoad(`images/icons/${banner}`)}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col flex-[0.9]">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
{`${firstname} ${lastname} (${age})`}
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Added:{" "}
|
||||
<span className="text-purple ml-1">
|
||||
{addedDate}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
{LoginDate}
|
||||
</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">
|
||||
{task_count}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-right py-4 px-2 flex items-center justify-center">
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate("/manage-family", {
|
||||
state: { ...props },
|
||||
});
|
||||
}}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
:
|
||||
(
|
||||
<div className="font-bold text-center text-xl md:text-2xl lg:text-4xl text-dark-gray md:flex items-center justify-between">
|
||||
<div className="p-2 w-full md:w-1/2">
|
||||
<p className="mb-4 p-3 md:p-16">Add your family, assign tasks, and get the whole team engaged.</p>
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
type="button"
|
||||
className="text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full"
|
||||
>
|
||||
Add Family
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-2 w-full md:w-1/2">
|
||||
<img className='w-full' src={familyImage} alt="Add Family" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
) : (
|
||||
<>
|
||||
{familyList?.length > 0 ? (
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 relative">
|
||||
<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, index) => {
|
||||
return <FamilyRow key={index} {...familyMember} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<div className="font-bold text-center text-xl md:text-2xl lg:text-4xl text-dark-gray md:flex items-center justify-between">
|
||||
<div className="p-2 w-full md:w-1/2">
|
||||
<p className="mb-4 p-3 md:p-16">
|
||||
Add your family, assign tasks, and get the whole team
|
||||
engaged.
|
||||
</p>
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
type="button"
|
||||
className="text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full"
|
||||
>
|
||||
Add Family
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-2 w-full md:w-1/2">
|
||||
<img className="w-full" src={familyImage} alt="Add Family" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList
|
||||
onClick={handlePagination}
|
||||
prev={currentPage == 0 ? true : false}
|
||||
next={
|
||||
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
|
||||
familyList?.length
|
||||
? true
|
||||
: false
|
||||
}
|
||||
prev={currentPage == 0}
|
||||
next={currentPage + itemsPerPage >= familyList.length}
|
||||
data={familyList}
|
||||
start={indexOfFirstItem}
|
||||
stop={indexOfLastItem}
|
||||
|
||||
@@ -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" },
|
||||
];
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function FamilyTasks({
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
{value.title}
|
||||
</h1>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
|
||||
<span className="text-sm text-thin-light-gray flex flex-start gap-1">
|
||||
Price:{" "}
|
||||
<span className="text-purple">
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -5,16 +5,18 @@ import React, {
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import usersService from "../../services/UsersService";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import FamilyTable from "./FamilyTable";
|
||||
import SiteService from "../../services/SiteService";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import FamilyTable from "./FamilyTable";
|
||||
|
||||
export default function FamilyAcc() {
|
||||
const [selectTab, setValue] = useState("today");
|
||||
const [selectedAge, setSelectedAge] = useState(undefined);
|
||||
// State to store the selected year and month
|
||||
const [selectedYear, setSelectedYear] = useState("");
|
||||
const [selectedMonth, setSelectedMonth] = useState("");
|
||||
const [familyList, setFamilyList] = useState([]);
|
||||
const [loader, setLoader] = useState(false);
|
||||
const [popUp, setPopUp] = useState(false);
|
||||
@@ -25,7 +27,7 @@ export default function FamilyAcc() {
|
||||
last_name: "",
|
||||
});
|
||||
|
||||
const apiCall = useMemo(() => new SiteService(), []);
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
const popUpHandler = () => {
|
||||
setPopUp((prev) => !prev);
|
||||
@@ -35,17 +37,14 @@ export default function FamilyAcc() {
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
const ageRange = useMemo(() => {
|
||||
const startAge = 5;
|
||||
const endAge = 16;
|
||||
return Array.from(
|
||||
{ length: endAge - startAge + 1 },
|
||||
(_, index) => startAge + index
|
||||
);
|
||||
}, []);
|
||||
// Handle year selection
|
||||
const handleYearChange = (e) => {
|
||||
setSelectedYear(e.target.value);
|
||||
};
|
||||
|
||||
const handleAgeSelect = (event) => {
|
||||
setSelectedAge(parseInt(event.target.value));
|
||||
// Handle month selection
|
||||
const handleMonthChange = (e) => {
|
||||
setSelectedMonth(e.target.value);
|
||||
};
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
@@ -53,6 +52,13 @@ export default function FamilyAcc() {
|
||||
setFormData((prevFormData) => ({ ...prevFormData, [name]: value }));
|
||||
};
|
||||
|
||||
// use the useEffect hook to clear the selected month if the year changes (to ensure consistency)
|
||||
useEffect(() => {
|
||||
if (selectedYear === "" && selectedMonth !== "") {
|
||||
setSelectedMonth("");
|
||||
}
|
||||
}, [selectedYear]);
|
||||
|
||||
const addMember = async () => {
|
||||
const { first_name, last_name } = formData;
|
||||
setLoader(true);
|
||||
@@ -61,7 +67,8 @@ export default function FamilyAcc() {
|
||||
const reqData = {
|
||||
firstname: first_name,
|
||||
lastname: last_name,
|
||||
age: selectedAge,
|
||||
year: +selectedYear,
|
||||
month: +selectedMonth,
|
||||
};
|
||||
|
||||
const res = await apiCall.addFamily(reqData);
|
||||
@@ -91,7 +98,8 @@ export default function FamilyAcc() {
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
});
|
||||
setSelectedAge("");
|
||||
setSelectedMonth("");
|
||||
setSelectedYear("");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -143,13 +151,16 @@ export default function FamilyAcc() {
|
||||
>
|
||||
Family Accounts
|
||||
</span>
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
type="button"
|
||||
className="text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
{familyList.length < process.env.REACT_APP_MAX_FAMILY_MEMBERS &&
|
||||
!loader && (
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
type="button"
|
||||
className="text-white btn-gradient text-lg tracking-wide px-5 py-2 rounded-full"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
@@ -173,9 +184,10 @@ export default function FamilyAcc() {
|
||||
<FamilyForm
|
||||
popUpHandler={popUpHandler}
|
||||
value={formData}
|
||||
ageHandler={handleAgeSelect}
|
||||
ageRange={ageRange}
|
||||
ageValue={selectedAge}
|
||||
selectedYear={selectedYear}
|
||||
selectedMonth={selectedMonth}
|
||||
monthHandler={handleMonthChange}
|
||||
yearHandler={handleYearChange}
|
||||
inputHandler={handleInputChange}
|
||||
msgErr={msgErr}
|
||||
onClick={addMember}
|
||||
@@ -191,8 +203,10 @@ const FamilyForm = ({
|
||||
value: { first_name, last_name },
|
||||
ageValue,
|
||||
inputHandler,
|
||||
ageHandler,
|
||||
ageRange,
|
||||
selectedMonth,
|
||||
selectedYear,
|
||||
monthHandler,
|
||||
yearHandler,
|
||||
msgErr,
|
||||
loader,
|
||||
onClick,
|
||||
@@ -237,33 +251,22 @@ const FamilyForm = ({
|
||||
value={last_name}
|
||||
inputHandler={inputHandler}
|
||||
/>
|
||||
<div className="input-com mb-7 flex gap-1 items-center w-full justify-between">
|
||||
<div className="input-com mb-7 flex flex-col gap-1 w-full">
|
||||
{/* Age dropdown */}
|
||||
<div className="flex items-center justify-between flex-[0.3]">
|
||||
<div className="">
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
|
||||
htmlFor="age-selection"
|
||||
>
|
||||
Select your age:
|
||||
Birthday: (Year/Month)
|
||||
</label>
|
||||
</div>
|
||||
<div className=" flex-[0.7] max-w-[150px]">
|
||||
<select
|
||||
name="age-selection"
|
||||
id="age-selection"
|
||||
className="input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-full rounded-[35px] 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 px-4"
|
||||
onChange={ageHandler}
|
||||
value={ageValue}
|
||||
>
|
||||
<option value={""}>Select age</option>
|
||||
{ageRange?.length > 0 &&
|
||||
ageRange?.map((age) => (
|
||||
<option value={age} key={age}>
|
||||
{age}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<YearMonthDropdowns
|
||||
handleMonthChange={monthHandler}
|
||||
handleYearChange={yearHandler}
|
||||
selectedMonth={selectedMonth}
|
||||
selectedYear={selectedYear}
|
||||
/>
|
||||
</div>
|
||||
{msgErr && (
|
||||
<div className="relative p-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-xs font-light leading-[19.5px]">
|
||||
@@ -312,3 +315,66 @@ const CloseIcon = () => (
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
function YearMonthDropdowns({
|
||||
selectedMonth,
|
||||
selectedYear,
|
||||
handleMonthChange,
|
||||
handleYearChange,
|
||||
}) {
|
||||
// Get the current year
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
// Generate an array of years from the current year to (currentYear - 19)
|
||||
const years = Array.from({ length: 17 }, (_, index) => currentYear - index);
|
||||
|
||||
// Array of month names
|
||||
const months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex max-w-[330px] w-full self-end gap-4">
|
||||
<select
|
||||
id="yearDropdown"
|
||||
value={selectedYear}
|
||||
onChange={handleYearChange}
|
||||
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"
|
||||
// size="5"
|
||||
>
|
||||
<option value="">Select a Year</option>
|
||||
{years.map((year) => (
|
||||
<option key={year} value={year}>
|
||||
{year}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<select
|
||||
id="monthDropdown"
|
||||
value={selectedMonth}
|
||||
onChange={handleMonthChange}
|
||||
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"
|
||||
// size="5"
|
||||
>
|
||||
<option value="">Select a Month</option>
|
||||
{months.map((month, index) => (
|
||||
<option key={month} value={index + 1}>
|
||||
{month}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 min-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='404Image' />
|
||||
<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 can’t 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">→</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,7 @@ export default function InputCom({
|
||||
maxLength = 45,
|
||||
minLength = 0,
|
||||
direction,
|
||||
tabIndex,
|
||||
error,
|
||||
}) {
|
||||
const inputRef = useRef(null);
|
||||
@@ -92,7 +93,7 @@ export default function InputCom({
|
||||
value={value}
|
||||
onChange={inputHandler}
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full ${
|
||||
inputBg ? inputBg : "bg-[#FAFAFA] dark:bg-[#11131F] tracking-wide"
|
||||
inputBg ? inputBg : "bg-[#FAFAFA] dark:bg-[#11131F] dark:text-white tracking-wide"
|
||||
} focus:ring-0 focus:outline-none ${fieldClass}`}
|
||||
type={type}
|
||||
id={name}
|
||||
@@ -100,6 +101,7 @@ export default function InputCom({
|
||||
onInput={onInput}
|
||||
minLength={minLengthValidation()}
|
||||
maxLength={maxLengthValidation()}
|
||||
tabIndex={tabIndex}
|
||||
// pattern={inputPatterns()}
|
||||
ref={inputRef}
|
||||
readOnly={disable}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
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]' />
|
||||
: familyRewardHistory.data.length ?
|
||||
<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>
|
||||
<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>
|
||||
</table>
|
||||
:familyRewardHistory.error ?
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>Opps! an error occurred. Please try again!</span>
|
||||
</div>
|
||||
:
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>No Rewards History Found!</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* 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
|
||||
@@ -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,15 +240,24 @@ 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">
|
||||
{/* PURCHASE SECTION */}
|
||||
{tab == 'purchases' &&
|
||||
<div className="wallet w-full border-t">
|
||||
<h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Purchases</h1>
|
||||
{/* <h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Purchases</h1> */}
|
||||
{purchaseHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
<LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
|
||||
:
|
||||
<PurchasesTable purchase={purchaseHistory} />
|
||||
}
|
||||
@@ -255,16 +268,24 @@ export default function History() {
|
||||
{/* RECENT ACTIVITY SECTION */}
|
||||
{tab == 'recent' &&
|
||||
<div className="wallet w-full border-t">
|
||||
<h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Recent Activity</h1>
|
||||
{/* <h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Recent Activity</h1> */}
|
||||
{/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */}
|
||||
{paymentHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
<LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
|
||||
:
|
||||
<RecentActivityTable payment={paymentHistory} />
|
||||
}
|
||||
</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 />*/}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import React from "react";
|
||||
import datas from "../../data/product_data.json";
|
||||
import TopSellerTopBuyerSliderSection from "./TopSellerTopBuyerSliderSection";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
import FamilyActiveLSlde from "./FamilyActiveLSlde";
|
||||
import ParentWaiting from "../MyPendingJobs/ParentWaiting";
|
||||
import MyOffersFamilyTable from "../MyTasks/MyOffersFamilyTable";
|
||||
import FamilyActiveLSlde from "./FamilyActiveLSlde";
|
||||
|
||||
export default function FamilyDash({familyOffers, MyActiveJobList}) {
|
||||
export default function FamilyDash({ familyOffers, MyActiveJobList }) {
|
||||
console.log("PROPS IN FAMILY DASH->", familyOffers);
|
||||
|
||||
const trending = MyActiveJobList;
|
||||
@@ -14,13 +11,13 @@ export default function FamilyDash({familyOffers, MyActiveJobList}) {
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
{/* <CommonHead commonHeadData={props.commonHeadData} /> */}
|
||||
{familyOffers && familyOffers.length > 0 &&
|
||||
<MyOffersFamilyTable familyOffers={familyOffers} className="mb-10" />
|
||||
}
|
||||
{trending && trending.length > 0 &&
|
||||
<FamilyActiveLSlde trending={trending} className="mb-10" />
|
||||
}
|
||||
|
||||
{familyOffers && familyOffers.length > 0 && (
|
||||
<MyOffersFamilyTable familyOffers={familyOffers} className="mb-10" />
|
||||
)}
|
||||
{trending && trending.length > 0 && (
|
||||
<FamilyActiveLSlde trending={trending} className="mb-10" />
|
||||
)}
|
||||
|
||||
{/*<TopSellerTopBuyerSliderSection className="mb-10" />*/}
|
||||
<ParentWaiting className="mb-10" />
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import React from "react";
|
||||
import datas from "../../data/product_data.json";
|
||||
import Hero from "./Hero";
|
||||
// import HomeTaskDisplay from "./HomeTaskDisplay";
|
||||
import usersService from "../../services/UsersService";
|
||||
import { useSelector } from "react-redux";
|
||||
// import SellHistoryMarketVisitorAnalytic from './SellHistoryMarketVisitorAnalytic';
|
||||
// import TopSellerTopBuyerSliderSection from "./TopSellerTopBuyerSliderSection";
|
||||
//import UpdateTable from "./UpdateTable";
|
||||
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);
|
||||
// console.log("PROPS IN HOME->", props);
|
||||
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<div className="home-page-wrapper">
|
||||
<Hero
|
||||
className="mb-10"
|
||||
@@ -22,7 +19,31 @@ export default function FullAccountDash(props) {
|
||||
bannerList={props.bannerList}
|
||||
nextDueTask={props.nextDueTask}
|
||||
/>
|
||||
<HomeActivities className="mb-10" />
|
||||
{props.offersList?.data?.result_list?.length ? (
|
||||
<MyOffersTable
|
||||
MyActiveOffersList={props.offersList?.data}
|
||||
className="mb-10"
|
||||
/>
|
||||
) : props.MyActiveJobList?.data?.length ? (
|
||||
<>
|
||||
<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>My Tasks</span>
|
||||
</h1>
|
||||
</div>
|
||||
<MyJobTable
|
||||
ActiveJobList={props.MyActiveJobList}
|
||||
Account={userDetails}
|
||||
/>
|
||||
</>
|
||||
) : !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" />*/}
|
||||
@@ -33,24 +54,6 @@ export default function FullAccountDash(props) {
|
||||
{/* bannerList={props.bannerList}*/}
|
||||
{/*/>*/}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
// /*
|
||||
// <Layout>
|
||||
// <div className="home-page-wrapper">
|
||||
// <Hero className="mb-10" data={userDetails} />
|
||||
// {/* <CreateNft />
|
||||
// <TrendingSection trending={trending} className="mb-10" />*/}
|
||||
// <HomeTaskDisplay
|
||||
// jobData={jobData}
|
||||
// className="mb-10"
|
||||
// bannerList={props.bannerList}
|
||||
// />
|
||||
{
|
||||
/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
|
||||
<TopSellerTopBuyerSliderSection className="mb-10" />
|
||||
<UpdateTable className="mb-10"/>*/
|
||||
}
|
||||
// </div>
|
||||
// </Layout>
|
||||
|
||||
@@ -58,8 +58,8 @@ export default function HomeActivities({ className }) {
|
||||
}`}
|
||||
>
|
||||
<div className="header w-full sm:flex justify-between items-center mb-5">
|
||||
<div className="flex space-x-2 items-center mb-2 sm:mb-0">
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
<div className="flex space-x-2 items-center mb-4 sm:mb-0">
|
||||
<h1 className="text-center text-2xl font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Recent Activities
|
||||
</h1>
|
||||
</div>
|
||||
@@ -79,28 +79,32 @@ export default function HomeActivities({ className }) {
|
||||
{/*</tr>*/}
|
||||
|
||||
{recentActivitiesData.loading ? (
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
</div>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="h-[100px] w-full flex justify-center items-center">
|
||||
<LoadingSpinner color="sky-blue" size="16" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : recentActivitiesData.data ? (
|
||||
recentActivitiesData.data?.map((item) => {
|
||||
let addedDate = item?.added?.split(" ")[0];
|
||||
return (
|
||||
<tr
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
key={item.uid}
|
||||
>
|
||||
<td className=" py-8">
|
||||
<td className="py-3">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
|
||||
{/* <div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
|
||||
<img
|
||||
src={dataImage1}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="flex flex-col">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
{item.title ? item.title : "Title"}
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
@@ -110,8 +114,8 @@ export default function HomeActivities({ className }) {
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<td className="text-right py-3">
|
||||
<div className="flex space-x-1 items-center justify-end">
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium">
|
||||
{item.added ? addedDate : ""}
|
||||
</span>
|
||||
|
||||
@@ -12,23 +12,25 @@ export default function Home(props) {
|
||||
const { commonHeadBanner } = useSelector((state) => state.commonHeadBanner);
|
||||
|
||||
let [nextDueTask, setNextDueTask] = useState({});
|
||||
const [MyOffersList, setMyOffersList] = useState([]);
|
||||
const [MyOffersList, setMyOffersList] = useState({loading: true, data: []});
|
||||
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
const [MyActiveJobList, setMyActiveJobList] = useState([]); // STATE TO HOLD ACTIVE/CURRENT TASKS
|
||||
const [MyActiveJobList, setMyActiveJobList] = useState({loading:true, data:[]}); // STATE TO HOLD ACTIVE/CURRENT TASKS
|
||||
// const [MyActiveJobList, setMyActiveJobList] = useState([]); // STATE TO HOLD ACTIVE/CURRENT TASKS
|
||||
|
||||
const getMyActiveJobList = async () => { // FUNCTION TO POPULATE ACTIVE/CURRENT TASK LIST
|
||||
try {
|
||||
const res = await userApi.getMyActiveTaskList();
|
||||
setMyActiveJobList(res?.data?.result_list);
|
||||
setMyActiveJobList({loading:false, data:res?.data?.result_list});
|
||||
// setMyActiveJobList(res?.data?.result_list);
|
||||
} catch (error) {
|
||||
setMyActiveJobList([]);
|
||||
setMyActiveJobList({loading:false, data:[]});
|
||||
// setMyActiveJobList([]);
|
||||
console.log("Error getting tasks");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// FUNCTION TO GET DASH DATA TO DETERMINE CURRENT TASK DUE TIME
|
||||
const getHomeDate = () => {
|
||||
userApi
|
||||
@@ -47,8 +49,9 @@ export default function Home(props) {
|
||||
const getMyOffersList = async () => {
|
||||
try {
|
||||
const res = await userApi.getOffersList();
|
||||
setMyOffersList(res.data?.result_list);
|
||||
setMyOffersList({loading:false, data:res.data});
|
||||
} catch (error) {
|
||||
setMyOffersList({loading:false, data:[]});
|
||||
console.log("Error getting offers", error);
|
||||
}
|
||||
};
|
||||
@@ -72,13 +75,15 @@ export default function Home(props) {
|
||||
<FamilyDash
|
||||
account={userDetails}
|
||||
commonHeadData={props.bannerList}
|
||||
familyOffers={MyOffersList}
|
||||
MyActiveJobList={MyActiveJobList}
|
||||
familyOffers={MyOffersList?.data?.result_list}
|
||||
MyActiveJobList={MyActiveJobList?.data}
|
||||
/>
|
||||
) : userDetails && userDetails?.account_type == "FULL" ? (
|
||||
<FullAccountDash
|
||||
nextDueTask={nextDueTask}
|
||||
bannerList={props.bannerList}
|
||||
offersList={MyOffersList}
|
||||
MyActiveJobList={MyActiveJobList}
|
||||
/>
|
||||
) : (
|
||||
<div>
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -10,24 +10,25 @@ import ActiveJobMessage from "./ActiveJobMessage";
|
||||
import IndexJobActions from "./JobActions/IndexJobActions";
|
||||
|
||||
import usersService from "../../services/UsersService";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
|
||||
function ActiveJobs(props) {
|
||||
const ApiCall = new usersService();
|
||||
let navigate = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
|
||||
let { userDetails } = useSelector((state) => state.userDetails);
|
||||
const { userDetails } = useSelector((state) => state.userDetails);
|
||||
|
||||
let [passDue, setPassDue] = useState(
|
||||
const [passDue, setPassDue] = useState(
|
||||
new Date() > new Date(props.details?.delivery_date)
|
||||
); // STATE TO KNOW IF TASK IS PASSED DUE TIME
|
||||
|
||||
let [messageToSend, setMessageToSend] = useState(""); // State to hold the value of message to be sent
|
||||
const [messageToSend, setMessageToSend] = useState(""); // State to hold the value of message to be sent
|
||||
|
||||
let [filesToSend, setFilesToSend] = useState([]); // State to hold the value of files to be sent
|
||||
const [filesToSend, setFilesToSend] = useState([]); // State to hold the value of files to be sent
|
||||
|
||||
let [tab, setTab] = useState("message");
|
||||
const [tab, setTab] = useState("message");
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
const [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
@@ -248,7 +249,11 @@ function ActiveJobs(props) {
|
||||
}
|
||||
}, [passDue]);
|
||||
|
||||
console.log("AC JOBS >>", props);
|
||||
let thePrice = PriceFormatter(
|
||||
props.details?.price * 0.01,
|
||||
props.details?.currency_code,
|
||||
props.details?.currency
|
||||
);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
@@ -311,10 +316,11 @@ function ActiveJobs(props) {
|
||||
<span className="font-semibold">Due: </span>
|
||||
{props?.details && props.details.delivery_date.split(" ")[0]}
|
||||
</p>
|
||||
<p className="py-2 text-base text-slate-700">
|
||||
{props?.delivery_date &&
|
||||
props.details.delivery_date.split(" ")[1]}
|
||||
</p>
|
||||
{props?.delivery_date && (
|
||||
<p className="py-2 text-base text-slate-700">
|
||||
{props.details.delivery_date.split(" ")[1]}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="my-1 flex items-start gap-3">
|
||||
@@ -334,6 +340,13 @@ function ActiveJobs(props) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="my-1 text-base text-slate-700 tracking-wide flex items-center gap-3">
|
||||
<span className="font-semibold text-black dark:text-white">
|
||||
Price:{" "}
|
||||
</span>
|
||||
<span className="">{thePrice}</span>
|
||||
</div>
|
||||
|
||||
<div className="my-1 text-base text-slate-700 tracking-wide flex items-center gap-3">
|
||||
<span className="font-semibold text-black dark:text-white">
|
||||
Duration:{" "}
|
||||
@@ -405,6 +418,7 @@ function ActiveJobs(props) {
|
||||
name="message"
|
||||
onChange={handleMessageChange}
|
||||
value={messageToSend}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<div className="p-4 w-full h-[300px] text-base text-slate-600 border border-slate-300">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import dataImage2 from "../../assets/images/data-table-user-2.png";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
|
||||
export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
const navigate = useNavigate();
|
||||
@@ -25,7 +24,7 @@ export default function MyActiveJobTable({ MyJobList, 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={`update-table w-full p-3 sm:p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
@@ -33,11 +32,6 @@ export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
{/*<tr className="text-base text-thin-light-gray border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom ">*/}
|
||||
{/* <td className="py-4">All Product</td>*/}
|
||||
{/* <td className="py-4 text-right">.</td>*/}
|
||||
{/*</tr>*/}
|
||||
|
||||
{
|
||||
<>
|
||||
{MyJobList &&
|
||||
@@ -59,7 +53,9 @@ export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
|
||||
<img
|
||||
src={localImgLoad(`images/taskbanners/${value.banner}`)}
|
||||
src={localImgLoad(
|
||||
`images/taskbanners/${value.banner}`
|
||||
)}
|
||||
alt="data"
|
||||
className="w-full h-full rounded-full"
|
||||
/>
|
||||
@@ -75,7 +71,7 @@ export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
{thePrice}
|
||||
</span>
|
||||
</span>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Duration:{" "}
|
||||
<span className="text-purple">
|
||||
@@ -113,9 +109,11 @@ export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
state: { ...value, pathname },
|
||||
});
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
View
|
||||
{value.owner_status == "OWNER"
|
||||
? "Manage"
|
||||
: "Send Updates"}
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -1,42 +1,39 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
import MyActiveJobTable from "./MyActiveJobTable";
|
||||
|
||||
export default function MyReviewDueJobs(props) {
|
||||
const [selectTab, setValue] = useState("today");
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
return (
|
||||
<Layout>
|
||||
<CommonHead
|
||||
commonHeadData={props.commonHeadData}
|
||||
/>
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
const [selectTab, setValue] = useState("today");
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
return (
|
||||
<Layout>
|
||||
<CommonHead commonHeadData={props.commonHeadData} />
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Review Due Job(s)
|
||||
Review Due Job(s)
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<MyActiveJobTable MyJobList={props.MyJobList} />
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<MyActiveJobTable MyJobList={props.myJobList} />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import React, { useState } from "react";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import usersService from "../../services/UsersService";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
|
||||
function DeleteTaskModal({ details, onClose, situation, setReloadList }) {
|
||||
let dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const ApiCall = new usersService();
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
laoding: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER
|
||||
|
||||
// FUNCTION TO DELETE TASK
|
||||
const deleteTask = () => {
|
||||
setRequestStatus({loading:true, status:false, message: ''})
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalCom action={onClose} 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">
|
||||
Delete Task
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={onClose}
|
||||
>
|
||||
<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="what-icon mb-6 cursor-pointer">
|
||||
<svg
|
||||
width="136"
|
||||
height="136"
|
||||
viewBox="0 0 136 136"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="68" cy="68" r="68" fill="#4687ba" />
|
||||
<path
|
||||
d="M69.8844 35.7891C71.1588 36.0357 72.4569 36.1967 73.7044 36.5423C81.5447 38.7098 87.2705 45.5378 87.9574 53.6156C88.5113 60.1147 86.3075 65.6006 81.5043 70.0195C79.8359 71.5545 78.0497 72.9604 76.3408 74.4534C76.127 74.6397 75.9654 75.0037 75.9604 75.2872C75.9284 77.2752 75.9435 79.2649 75.9435 81.2965C70.8895 81.2965 65.8758 81.2965 60.7915 81.2965C60.7915 81.0616 60.7915 80.8385 60.7915 80.6137C60.7915 76.5454 60.7999 72.4772 60.7797 68.4106C60.778 67.9392 60.9312 67.649 61.2831 67.3537C64.5643 64.5957 67.8271 61.8175 71.1033 59.0545C72.2616 58.0781 72.9215 56.8702 72.9081 55.3419C72.8878 52.916 70.8608 50.9146 68.423 50.8911C65.9701 50.8693 63.9145 52.8053 63.832 55.2328C63.8084 55.8988 63.8286 56.5665 63.8286 57.2695C58.7745 57.2695 53.7744 57.2695 48.6917 57.2695C48.6917 56.3149 48.6462 55.3385 48.6984 54.3655C49.222 44.699 56.7442 36.8745 66.4331 35.8914C66.5762 35.8763 66.7142 35.8243 66.854 35.7891C67.8641 35.7891 68.8742 35.7891 69.8844 35.7891Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M67.485 100.21C66.1617 99.9268 64.9041 99.5091 63.803 98.6787C61.3804 96.8484 60.2877 93.7699 61.0386 90.7888C61.7726 87.8747 64.2138 85.6703 67.2089 85.2157C71.273 84.6 75.2024 87.3681 75.8135 91.277C76.4937 95.6153 73.8202 99.3782 69.544 100.103C69.4429 100.12 69.3487 100.172 69.2527 100.209C68.6635 100.21 68.0742 100.21 67.485 100.21Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<p className="text-xl tracking-wide text-dark-gray dark:text-white">
|
||||
{details.title}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex space-x-2.5">
|
||||
<button
|
||||
onClick={onClose}
|
||||
type="button"
|
||||
className=" border-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
<span className="text-gradient">Cancel</span>
|
||||
</button>
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
onClick={() => deleteTask(details)}
|
||||
type="button"
|
||||
className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
Confirm Delete
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`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>
|
||||
);
|
||||
}
|
||||
|
||||
export default DeleteTaskModal;
|
||||
@@ -18,7 +18,7 @@ export default function MyPendingJobTable({ MyJobList, className }) {
|
||||
indexOfFirstItem,
|
||||
indexOfLastItem
|
||||
);
|
||||
|
||||
|
||||
const handlePagination = (e) => {
|
||||
handlePagingFunc(e, setCurrentPage);
|
||||
};
|
||||
@@ -103,9 +103,9 @@ export default function MyPendingJobTable({ MyJobList, className }) {
|
||||
onClick={() => {
|
||||
setJobPopout({ show: true, data: value });
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
View
|
||||
{value.owner_status == 'OWNER' ? 'Manage' : 'Send Updates'}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -7,7 +7,9 @@ import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
import DeleteIcon from '../../assets/images/icon-delete.svg'
|
||||
import DeleteTaskModal from "./DeleteTaskModal";
|
||||
import SendReminderModal from "./SendReminderModal";
|
||||
|
||||
export default function ParentWaitingTable() {
|
||||
// const transationFilterData = [
|
||||
@@ -34,6 +36,11 @@ export default function ParentWaitingTable() {
|
||||
|
||||
const apiCall = new usersService()
|
||||
|
||||
let [reloadList, setReloadList] = useState(false) // STATE TO DETERMINE WHEN TO RELOAD THE FAMILY SUGGEST LIST
|
||||
|
||||
let [deleteTaskPopout, setDeleteTaskPopout] = useState({show:false, data:{}}) // HOLDS THE INFO OF DELETE TASK POPOUT
|
||||
let [sendReminderPopout, setSendReminderPopout] = useState({show:false, data:{}}) // HOLDS THE INFO OF SEND REMINDER POPOUT
|
||||
|
||||
let [familySuggestList, setFamilySuggestList] = useState({loading: true, data:[]})
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
@@ -53,7 +60,7 @@ export default function ParentWaitingTable() {
|
||||
setFamilySuggestList({loading: false, data:[]})
|
||||
console.log('ERROR==>Familysuggestlist', err)
|
||||
})
|
||||
},[])
|
||||
},[reloadList])
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl bg-white dark:bg-dark-white flex flex-col justify-between">
|
||||
@@ -97,7 +104,7 @@ export default function ParentWaitingTable() {
|
||||
<div className="icon w-14 h-14 flex justify-center items-center">
|
||||
<img src={Image} alt="" className="w-full h-full" />
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="w-full">
|
||||
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
|
||||
{item.title}
|
||||
</p>
|
||||
@@ -107,12 +114,35 @@ export default function ParentWaitingTable() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-2 self-end">
|
||||
<p className="text-sm font-bold text-dark-gray dark:text-white">
|
||||
{new Date(item.added).toLocaleString().split(',')[0]}
|
||||
|
||||
</p>
|
||||
<p className="text-xs py-1.5 w-[50px] tracking-wide rounded-full bg-gold text-white flex justify-center items-center">{item.status_text}</p>
|
||||
<div className="min-w-[120px] flex justify-start items-end px-2 gap-1">
|
||||
<button
|
||||
type="button"
|
||||
className="p-1 border-2 border-red-400 rounded-md"
|
||||
onClick={() => {
|
||||
setDeleteTaskPopout({
|
||||
show: true,
|
||||
data: { ...item },
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img className="min-w-[21px] h-[21px]" src={DeleteIcon} alt='delete-icon' />
|
||||
</button>
|
||||
|
||||
<div className="">
|
||||
<p className="text-sm font-bold text-dark-gray dark:text-white">
|
||||
{new Date(item.added).toLocaleString().split(',')[0]}
|
||||
|
||||
</p>
|
||||
<p
|
||||
className="text-xs py-1.5 w-[50px] tracking-wide rounded-full bg-gold text-white flex justify-center items-center cursor-pointer"
|
||||
onClick={() => {
|
||||
setSendReminderPopout({
|
||||
show: true,
|
||||
data: { ...item },
|
||||
});
|
||||
}}
|
||||
>{item.status_text}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@@ -122,6 +152,32 @@ export default function ParentWaitingTable() {
|
||||
:
|
||||
<p className="w-full flex items-center justify-center text-xl text-dark-gray dark:text-white">No List Found!</p>
|
||||
}
|
||||
|
||||
{/* Delete Task Popout */}
|
||||
{deleteTaskPopout.show && (
|
||||
<DeleteTaskModal
|
||||
details={deleteTaskPopout.data}
|
||||
onClose={() => {
|
||||
setDeleteTaskPopout({ show: false, data: {} });
|
||||
}}
|
||||
situation={deleteTaskPopout.show}
|
||||
setReloadList={setReloadList}
|
||||
/>
|
||||
)}
|
||||
{/* END of Delete Task Popout */}
|
||||
|
||||
{/* Send Reminder Popout */}
|
||||
{sendReminderPopout.show && (
|
||||
<SendReminderModal
|
||||
details={sendReminderPopout.data}
|
||||
onClose={() => {
|
||||
setSendReminderPopout({ show: false, data: {} });
|
||||
}}
|
||||
situation={sendReminderPopout.show}
|
||||
setReloadList={setReloadList}
|
||||
/>
|
||||
)}
|
||||
{/* END of Send Reminder Popout */}
|
||||
</div>
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { useState } from "react";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import usersService from "../../services/UsersService";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
|
||||
function SendReminderModal({ details, onClose, situation, setReloadList }) {
|
||||
let dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const ApiCall = new usersService();
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
laoding: false,
|
||||
status: false,
|
||||
message: "",
|
||||
}); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER
|
||||
|
||||
// FUNCTION TO SEND REMINDER
|
||||
const sendReminder = () => {
|
||||
setRequestStatus({loading:true, status:false, message: ''})
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalCom action={onClose} 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">
|
||||
Send Reminder
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={onClose}
|
||||
>
|
||||
<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 p-8">
|
||||
|
||||
<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" />
|
||||
</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-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]}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full flex justify-end">
|
||||
{/* <button
|
||||
onClick={onClose}
|
||||
type="button"
|
||||
className=" border-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
<span className="text-gradient">Cancel</span>
|
||||
</button> */}
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
) : (
|
||||
<button
|
||||
onClick={() => sendReminder(details)}
|
||||
type="button"
|
||||
className="text-white bg-sky-blue text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
Send Reminder
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`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>
|
||||
);
|
||||
}
|
||||
|
||||
export default SendReminderModal;
|
||||
@@ -55,15 +55,14 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
|
||||
{!ActiveJobList?.data.length && accountType && (
|
||||
<div className="absolute inset-0 bg-black opacity-30"></div>
|
||||
)}
|
||||
{ActiveJobList?.data.length > 0 && ActiveJobList.loading && (
|
||||
{ActiveJobList.loading ?
|
||||
<div className="w-full h-[520px] flex items-center justify-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
:
|
||||
<div className="relative w-full sm:rounded-lg">
|
||||
<div className="h-auto w-full">
|
||||
{ActiveJobList?.data?.length > 0 &&
|
||||
{ActiveJobList?.data?.length > 0 ?
|
||||
currentTask?.map((task, idx) => {
|
||||
// find due date
|
||||
const dueDate = task?.delivery_date.split(" ")[0];
|
||||
@@ -97,7 +96,7 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
|
||||
Price:
|
||||
<span className="text-purple ml-1">{thePrice}</span>
|
||||
</span>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Duration:
|
||||
<span className="text-purple ml-1">
|
||||
@@ -129,16 +128,15 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
|
||||
state: { ...task, pathname },
|
||||
});
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
className="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
{task.owner_status == 'OWNER' ? 'Manage' : 'Send Updates'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{ActiveJobList?.data?.length <= 0 && (
|
||||
})
|
||||
:
|
||||
<div
|
||||
className={`flex flex-col ${
|
||||
accountType ? "items-center" : "items-end"
|
||||
@@ -175,12 +173,12 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ActiveJobList?.internal_return < 0 && (
|
||||
}
|
||||
{/* {ActiveJobList?.internal_return < 0 && (
|
||||
<div className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
<p className="p-2">Error Occurred! Unable to display Tasks!</p>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
@@ -199,6 +197,7 @@ export default function MyJobTable({ className, ActiveJobList, Account }) {
|
||||
/>
|
||||
{/* END OF PAGINATION BUTTON */}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@ export default function MyOffersFamilyTable({ className, familyOffers }) {
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
console.log("YES WE SEE OFFERS", familyOffers);
|
||||
// console.log("YES WE SEE OFFERS", familyOffers);
|
||||
|
||||
const trendingSlider = useRef(null);
|
||||
const prevHandler = () => {
|
||||
|
||||
@@ -64,6 +64,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
|
||||
|
||||
const apiCall = new usersService();
|
||||
let countryWallet = props.walletItem.country;
|
||||
const [tab, setTab] = useState("previous");
|
||||
@@ -240,7 +242,7 @@ function AddFundDollars(props) {
|
||||
<label
|
||||
onClick={() => setTab("new")}
|
||||
htmlFor="new"
|
||||
className="cursor-pointer flex items-center gap-1"
|
||||
className={`cursor-pointer flex items-center gap-1 ${payListCards.data.length >= MaxNoOfCards ? 'pointer-events-none':''}`}
|
||||
>
|
||||
<input
|
||||
id="new"
|
||||
@@ -251,7 +253,7 @@ function AddFundDollars(props) {
|
||||
tab == "new" ? "" : ""
|
||||
} tracking-wide transition duration-200`}
|
||||
/>
|
||||
Add New Card
|
||||
Add New Card {payListCards.data.length >= MaxNoOfCards && <span className="text-[14px] text-red-500">Max Reached</span>}
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
@@ -314,245 +316,253 @@ function AddFundDollars(props) {
|
||||
|
||||
{tab === "new" && (
|
||||
<div className="new-details w-full max-h-[22rem]">
|
||||
<div className="w-full flex flex-col justify-between">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className="md:pl-8">
|
||||
<div className="flex flex-col-reverse sm:flex-row">
|
||||
<div className="flex-1 sm:mr-10">
|
||||
<div className="fields w-full">
|
||||
{/* Inputs */}
|
||||
{/* Name */}
|
||||
<div className="flex items-center field w-full my-2 flex-[0.4] gap-3">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1">
|
||||
Name:
|
||||
</label>
|
||||
<p className="input-label text-[#181c32] dark:text-white text-[16px] leading-[20.9625px] font-semibold flex items-center gap-1">{`${firstname} ${lastname}`}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center flex-1 gap-3 my-2">
|
||||
{/* Card Number */}
|
||||
<div className="field w-full flex-[0.6]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
iconName={cardIcons}
|
||||
label="Card Number"
|
||||
type="text"
|
||||
name="cardNum"
|
||||
onInput={handleCards}
|
||||
placeholder="Enter Card Number"
|
||||
value={handleCardNumberChange(
|
||||
props.values.cardNum
|
||||
)}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.cardNum}
|
||||
/>
|
||||
{payListCards.loading ?
|
||||
<div className="pt-10 flex w-full h-full justify-center items-center">
|
||||
<LoadingSpinner size='10' color='sky-blue' />
|
||||
</div>
|
||||
:payListCards.data.length < MaxNoOfCards ?
|
||||
<div className="w-full flex flex-col justify-between">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className="md:pl-8">
|
||||
<div className="flex flex-col-reverse sm:flex-row">
|
||||
<div className="flex-1 sm:mr-10">
|
||||
<div className="fields w-full">
|
||||
{/* Inputs */}
|
||||
{/* Name */}
|
||||
<div className="flex items-center field w-full my-2 flex-[0.4] gap-3">
|
||||
<label className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1">
|
||||
Name:
|
||||
</label>
|
||||
<p className="input-label text-[#181c32] dark:text-white text-[16px] leading-[20.9625px] font-semibold flex items-center gap-1">{`${firstname} ${lastname}`}</p>
|
||||
</div>
|
||||
|
||||
{/* Expire Year, Year */}
|
||||
<div className="sm:grid gap-5 grid-cols-2 flex-[0.4]">
|
||||
<div className="field w-full mb-6 xl:mb-0 col-span-1">
|
||||
<div className="select-option">
|
||||
<div
|
||||
className={`flex items-center justify-between mb-2.5`}
|
||||
>
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold line-clamp-3 flex items-center"
|
||||
htmlFor="expiration"
|
||||
>
|
||||
Exp Month{" "}
|
||||
<span className="text-red-700 text-sm italic">
|
||||
*
|
||||
</span>
|
||||
<span className="text-[12px] text-red-500 ml-1">
|
||||
{props.errors.expirationMonth && "**"}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
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`}
|
||||
>
|
||||
<select
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full tracking-wide dark:bg-[#11131F] bg-[#fafafa] focus:ring-0 focus:outline-none`}
|
||||
value={props.values.expirationMonth}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
name="expirationMonth"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
className="text-dark-gray"
|
||||
>
|
||||
Month
|
||||
</option>
|
||||
{expireMonth?.length &&
|
||||
expireMonth.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
value={
|
||||
Number(item.value) < 10
|
||||
? "0" + item.value
|
||||
: item.value
|
||||
}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center flex-1 gap-3 my-2">
|
||||
{/* Card Number */}
|
||||
<div className="field w-full flex-[0.6]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
iconName={cardIcons}
|
||||
label="Card Number"
|
||||
type="text"
|
||||
name="cardNum"
|
||||
onInput={handleCards}
|
||||
placeholder="Enter Card Number"
|
||||
value={handleCardNumberChange(
|
||||
props.values.cardNum
|
||||
)}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.cardNum}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6 xl:mb-0 col-span-1">
|
||||
<div className="select-option">
|
||||
<div
|
||||
className={`flex items-center justify-between mb-2.5`}
|
||||
>
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center line-clamp-3"
|
||||
htmlFor="expiration"
|
||||
{/* Expire Year, Year */}
|
||||
<div className="sm:grid gap-5 grid-cols-2 flex-[0.4]">
|
||||
<div className="field w-full mb-6 xl:mb-0 col-span-1">
|
||||
<div className="select-option">
|
||||
<div
|
||||
className={`flex items-center justify-between mb-2.5`}
|
||||
>
|
||||
Exp Year{" "}
|
||||
<span className="text-red-700 text-sm tracking-wide">
|
||||
*
|
||||
</span>
|
||||
<span className="text-[12px] text-red-500 italic">
|
||||
{props.errors.expirationYear && "**"}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
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`}
|
||||
>
|
||||
<select
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full tracking-wide dark:bg-[#11131F] bg-[#fafafa] focus:ring-0 focus:outline-none`}
|
||||
value={props.values.expirationYear}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
name="expirationYear"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
className="text-dark-gray"
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold line-clamp-3 flex items-center"
|
||||
htmlFor="expiration"
|
||||
>
|
||||
Year
|
||||
</option>
|
||||
{expireYear?.length &&
|
||||
expireYear.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
Exp Month{" "}
|
||||
<span className="text-red-700 text-sm italic">
|
||||
*
|
||||
</span>
|
||||
<span className="text-[12px] text-red-500 ml-1">
|
||||
{props.errors.expirationMonth && "**"}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
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`}
|
||||
>
|
||||
<select
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full tracking-wide dark:bg-[#11131F] bg-[#fafafa] focus:ring-0 focus:outline-none`}
|
||||
value={props.values.expirationMonth}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
name="expirationMonth"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
className="text-dark-gray"
|
||||
>
|
||||
Month
|
||||
</option>
|
||||
{expireMonth?.length &&
|
||||
expireMonth.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
value={
|
||||
Number(item.value) < 10
|
||||
? "0" + item.value
|
||||
: item.value
|
||||
}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6 xl:mb-0 col-span-1">
|
||||
<div className="select-option">
|
||||
<div
|
||||
className={`flex items-center justify-between mb-2.5`}
|
||||
>
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center line-clamp-3"
|
||||
htmlFor="expiration"
|
||||
>
|
||||
Exp Year{" "}
|
||||
<span className="text-red-700 text-sm tracking-wide">
|
||||
*
|
||||
</span>
|
||||
<span className="text-[12px] text-red-500 italic">
|
||||
{props.errors.expirationYear && "**"}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
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`}
|
||||
>
|
||||
<select
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full tracking-wide dark:bg-[#11131F] bg-[#fafafa] focus:ring-0 focus:outline-none`}
|
||||
value={props.values.expirationYear}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
name="expirationYear"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
className="text-dark-gray"
|
||||
>
|
||||
Year
|
||||
</option>
|
||||
{expireYear?.length &&
|
||||
expireYear.map((item, index) => (
|
||||
<option key={index} value={item}>
|
||||
{item}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Address and CVV */}
|
||||
<div className="flex items-center flex-1 gap-3 my-2">
|
||||
<div className="field w-full col-span-1 flex-[0.4]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
iconName={cardIcons}
|
||||
label="CVV"
|
||||
type="text"
|
||||
name="cvv"
|
||||
placeholder="CVV"
|
||||
maxLength={3}
|
||||
value={props.values.cvv}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.cvv}
|
||||
/>
|
||||
{/* Address and CVV */}
|
||||
<div className="flex items-center flex-1 gap-3 my-2">
|
||||
<div className="field w-full col-span-1 flex-[0.4]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
iconName={cardIcons}
|
||||
label="CVV"
|
||||
type="text"
|
||||
name="cvv"
|
||||
placeholder="CVV"
|
||||
maxLength={3}
|
||||
value={props.values.cvv}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.cvv}
|
||||
/>
|
||||
</div>
|
||||
<div className="field w-full flex-[0.6]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="Billing Address"
|
||||
type="text"
|
||||
name="address"
|
||||
placeholder="Billing Address"
|
||||
value={props.values.Address}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.address}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field w-full flex-[0.6]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="Billing Address"
|
||||
type="text"
|
||||
name="address"
|
||||
placeholder="Billing Address"
|
||||
value={props.values.Address}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.address}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Postal Code and State */}
|
||||
<div className="sm:grid gap-5 grid-cols-3 my-2">
|
||||
<div className="field w-full xl:mb-0 col-span-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="Postal Code"
|
||||
type="number"
|
||||
name="code"
|
||||
placeholder="Postal Code"
|
||||
value={props.values.code}
|
||||
maxLength={6}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.code}
|
||||
/>
|
||||
</div>
|
||||
<div className="field w-full col-span-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="State"
|
||||
type="text"
|
||||
name="state"
|
||||
placeholder="State"
|
||||
value={props.values.state.toUpperCase()}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.state}
|
||||
/>
|
||||
{/* Postal Code and State */}
|
||||
<div className="sm:grid gap-5 grid-cols-3 my-2">
|
||||
<div className="field w-full xl:mb-0 col-span-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="Postal Code"
|
||||
type="number"
|
||||
name="code"
|
||||
placeholder="Postal Code"
|
||||
value={props.values.code}
|
||||
maxLength={6}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.code}
|
||||
/>
|
||||
</div>
|
||||
<div className="field w-full col-span-1">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
spanTag="*"
|
||||
label="State"
|
||||
type="text"
|
||||
name="state"
|
||||
placeholder="State"
|
||||
value={props.values.state.toUpperCase()}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.state}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="add-fund-btn flex justify-end items-center gap-2 mt-4">
|
||||
<button
|
||||
className="px-4 py-1 h-11 max-w-[100px] w-full flex justify-center bg-[#f5a430] text-black items-center text-base rounded-full"
|
||||
onClick={handleClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
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 ? (
|
||||
<LoadingSpinner size="6" color="sky-blue" />
|
||||
) : (
|
||||
<>
|
||||
<span className="text-white">Continue</span>{" "}
|
||||
<Icons name="chevron-right" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
<div className="add-fund-btn flex justify-end items-center gap-2 mt-4">
|
||||
<button
|
||||
className="px-4 py-1 h-11 max-w-[100px] w-full flex justify-center bg-[#f5a430] text-black items-center text-base rounded-full"
|
||||
onClick={handleClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
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 ? (
|
||||
<LoadingSpinner size="6" color="sky-blue" />
|
||||
) : (
|
||||
<>
|
||||
<span className="text-white">Continue</span>{" "}
|
||||
<Icons name="chevron-right" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -26,46 +26,59 @@ function AddFundPop({
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setInputError("");
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: true } },
|
||||
}));
|
||||
|
||||
if (!input || input === "0") {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
}));
|
||||
setInputError("Please Enter Amount");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number(input) * 100 > Number(walletItem?.transfer_limit)) {
|
||||
setInputError("Credit limit has been exceeded");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(input)) {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
}));
|
||||
setInputError("Amount must be a Number");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
let stateData = {
|
||||
amount: Number(input) * 100,
|
||||
currency: walletItem?.code,
|
||||
};
|
||||
|
||||
try {
|
||||
// Clear any previous input error and set the loading spinner to be shown
|
||||
setInputError("");
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: true } },
|
||||
}));
|
||||
|
||||
// Perform validation checks on the input amount
|
||||
if (!input || input === "0") {
|
||||
// Handle input validation error
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
}));
|
||||
setInputError("Please Enter Amount");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number(input) * 100 > Number(walletItem?.transfer_limit)) {
|
||||
// Handle credit limit exceeded error
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
}));
|
||||
setInputError("Credit limit has been exceeded");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(input)) {
|
||||
// Handle invalid input error
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
}));
|
||||
setInputError("Amount must be a Number");
|
||||
setTimeout(() => setInputError(""), 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare state data for API call
|
||||
let stateData = {
|
||||
amount: Number(input) * 100,
|
||||
currency: walletItem?.code,
|
||||
};
|
||||
|
||||
// Make API call to start credit process
|
||||
const res = await apiCall.getStartCredit(stateData);
|
||||
|
||||
if (res.data.internal_return < 0) {
|
||||
// Handle API error
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
@@ -75,6 +88,7 @@ function AddFundPop({
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state with response data
|
||||
const _response = res.data;
|
||||
stateData.amount = Number(input);
|
||||
stateData.currency = currency;
|
||||
@@ -91,6 +105,7 @@ function AddFundPop({
|
||||
}));
|
||||
}, 1500);
|
||||
} catch (error) {
|
||||
// Handle API call error
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: { awaitConfirm: { loader: false } },
|
||||
@@ -116,6 +131,7 @@ function AddFundPop({
|
||||
placeholder="0"
|
||||
value={input}
|
||||
inputHandler={handleChange}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<p className="text-base text-red-500 italic h-5">
|
||||
{inputError && inputError}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* Renders a modal with information about a credit transaction.
|
||||
* @returns {JSX.Element} - The rendered modal component.
|
||||
*/
|
||||
function CompleteConfirmCredit({ onClose, confirmCredit }) {
|
||||
const { data } = confirmCredit;
|
||||
const isSuccess =
|
||||
data?.result === "Charge success" || data?.status === "successful";
|
||||
|
||||
return (
|
||||
<div className="logout-modal-body w-full flex flex-col items-center">
|
||||
<div className="content-wrapper w-full h-[32rem]">
|
||||
@@ -11,91 +16,82 @@ function CompleteConfirmCredit({ onClose, confirmCredit }) {
|
||||
<div className="field w-full mb-3 min-h-[45px]">
|
||||
<div
|
||||
className={`flex flex-col gap-4 ${
|
||||
data?.result !== "Charge success" &&
|
||||
"h-[328px] items-center justify-center"
|
||||
!isSuccess && "h-[328px] items-center justify-center"
|
||||
}`}
|
||||
>
|
||||
{/* Success Icon for now */}
|
||||
<div className="flex items-center w-full justify-center">
|
||||
{data?.result == "Charge success" ||
|
||||
data?.status == "successful" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="green"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className="feather feather-check-circle"
|
||||
>
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
width="100"
|
||||
height="100"
|
||||
stroke="red"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className="feather feather-x-circle"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="15" y1="9" x2="9" y2="15"></line>
|
||||
<line x1="9" y1="9" x2="15" y2="15"></line>
|
||||
</svg>
|
||||
)}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke={isSuccess ? "green" : "red"}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={`feather ${
|
||||
isSuccess ? "feather-check-circle" : "feather-x-circle"
|
||||
}`}
|
||||
>
|
||||
{isSuccess ? (
|
||||
<>
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="15" y1="9" x2="9" y2="15"></line>
|
||||
<line x1="9" y1="9" x2="15" y2="15"></line>
|
||||
</>
|
||||
)}
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className={`flex items-center`}>
|
||||
<div className="flex items-center">
|
||||
<h1 className="text-xl font-semibold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{data?.result == "Charge success" ||
|
||||
data?.status == "successful"
|
||||
{isSuccess
|
||||
? "Credit was Successful!"
|
||||
: "Credit was Unsuccessful"}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{data?.internal_return >= 0 &&
|
||||
data?.result !== "Charge failed" ? (
|
||||
<>
|
||||
<div className="flex items-center gap-8">
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Amount({data?.currency || ""})
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{`${data?.symbol || ""} ${
|
||||
Number(data?.amount * 0.01).toLocaleString() || ""
|
||||
}`}
|
||||
</span>
|
||||
</div>
|
||||
data?.result !== "Charge failed" && (
|
||||
<>
|
||||
<div className="flex items-center gap-8">
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Amount({data?.currency || ""})
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{`${data?.symbol || ""} ${
|
||||
Number(data?.amount * 0.01).toLocaleString() || ""
|
||||
}`}
|
||||
</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">
|
||||
Wallet Balance
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{data?.curr_balance}
|
||||
</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">
|
||||
Wallet Balance
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{data?.curr_balance * 0.01}
|
||||
</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>
|
||||
</>
|
||||
) : null}
|
||||
{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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,84 +1,102 @@
|
||||
import { FlutterWaveButton, closePaymentModal } from "flutterwave-react-v3";
|
||||
import React, { useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useSelector } from "react-redux";
|
||||
import { toast } from "react-toastify";
|
||||
import debounce from "../../../hooks/debounce";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import { tableReload } from "../../../store/TableReloads";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
|
||||
/**
|
||||
* Renders a React component that displays the description and last four digits of a payment card.
|
||||
*/
|
||||
function ThePaymentText({ value, type }) {
|
||||
const cardDetails = value;
|
||||
value.description =
|
||||
type === "new"
|
||||
? cardDetails.cardNum[0] === "4"
|
||||
? "Visa"
|
||||
: cardDetails.cardNum[0] == "5"
|
||||
? "Master"
|
||||
: "ATM"
|
||||
: value.description;
|
||||
value.digits = type === "new" ? cardDetails.cardNum.slice(-4) : value.digits;
|
||||
const { cardNum } = value;
|
||||
let description = value.description;
|
||||
let digits = value.digits;
|
||||
|
||||
if (type === "new") {
|
||||
const firstDigit = cardNum[0];
|
||||
if (firstDigit === "4") {
|
||||
description = "Visa";
|
||||
} else if (firstDigit === "5") {
|
||||
description = "Master";
|
||||
} else {
|
||||
description = "ATM";
|
||||
}
|
||||
digits = cardNum.slice(-4);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="my-2 flex items-center gap-5">
|
||||
<div className="card-details flex items-center gap-3">
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1 space-x-1">
|
||||
{value.description} Card
|
||||
<h1 className="text-xl font-normal text-dark-gray dark:text-white tracking-tighter my-1 space-x-1">
|
||||
{description} Card
|
||||
</h1>
|
||||
<p className="text-base font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Bank **************{value.digits}
|
||||
<p className="text-xl font-normal text-dark-gray dark:text-white tracking-wide">
|
||||
Bank **************{digits}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the amount of a transaction in a specific currency.
|
||||
* @returns {JSX.Element} - The rendered component.
|
||||
*/
|
||||
function AmountSection({ currency, amount, country }) {
|
||||
const formattedAmount = Number(amount).toFixed(2);
|
||||
const formattedAmount = amount?.toFixed(2);
|
||||
const gapClassName = country === "US" ? "gap-14" : "gap-4";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center ${country == "US" ? "gap-14" : "gap-4"}`}
|
||||
>
|
||||
<div className={`flex items-center ${gapClassName}`}>
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Amount({currency})
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
<span className="text-xl font-normal text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{formattedAmount}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the transaction fee for a payment.
|
||||
* @returns {JSX.Element} - Rendered JSX displaying the transaction fee with the label "Transaction Fee".
|
||||
*/
|
||||
function TransactionFeeSection({ currency, fee, country }) {
|
||||
const formattedFee = Number(fee).toFixed(2);
|
||||
const formattedFee = (+fee).toFixed(2);
|
||||
const gapClass = country === "US" ? "gap-[2.7rem]" : "gap-4";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center border-b border-gray-600 ${
|
||||
country == "US" ? "gap-[2.7rem]" : "gap-4"
|
||||
}`}
|
||||
>
|
||||
<div className={`flex items-center border-b border-gray-600 ${gapClass}`}>
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Transaction Fee
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
<span className="text-xl font-normal text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{formattedFee}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the total amount by adding the `amount` and `fee` values together.
|
||||
* Formats the total amount to two decimal places and displays it.
|
||||
* @returns {JSX.Element} - The TotalSection component.
|
||||
*/
|
||||
function TotalSection({ currency, amount, fee, country }) {
|
||||
const total = Number(amount) + Number(fee);
|
||||
const formattedTotal = total.toFixed(2);
|
||||
const formattedTotal = total?.toFixed(2);
|
||||
|
||||
const gap = country === "US" ? "gap-[8rem]" : "gap-[6.3rem]";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center ${
|
||||
country == "US" ? "gap-[8rem]" : "gap-[6.3rem]"
|
||||
}`}
|
||||
>
|
||||
<div className={`flex items-center ${gap}`}>
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Total
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
<span className="text-xl font-normal text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{formattedTotal}
|
||||
</span>
|
||||
</div>
|
||||
@@ -102,8 +120,6 @@ function ConfirmAddFund({
|
||||
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [requestStatus, setRequestStatus] = useState({
|
||||
message: "",
|
||||
loading: false,
|
||||
@@ -127,7 +143,7 @@ function ConfirmAddFund({
|
||||
logo: "https://www.wrenchboard.com/assets/images/wrench-500-500-icon.png",
|
||||
},
|
||||
};
|
||||
//debugger;
|
||||
|
||||
const fwConfig = {
|
||||
...config,
|
||||
text: "Proceed",
|
||||
@@ -162,8 +178,6 @@ function ConfirmAddFund({
|
||||
status: false,
|
||||
});
|
||||
}
|
||||
|
||||
return dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
@@ -188,27 +202,40 @@ function ConfirmAddFund({
|
||||
|
||||
const debouncedSuccessPayment = debounce(onSuccessPayment, 5000);
|
||||
|
||||
/**
|
||||
* Handles the process of making a payment using a previously saved card.
|
||||
* Updates the state to show a loader while the payment is being processed,
|
||||
* sends a request to the server to make the payment, and updates the state with the response.
|
||||
* If the payment is successful, it also dispatches an action to reload the wallet table.
|
||||
*/
|
||||
const handlePrevCard = async () => {
|
||||
const { amount, credit_reference, currency } = __confirmData;
|
||||
const { card_uid } = __confirmCardDetails;
|
||||
|
||||
const reqData = {
|
||||
amount: amount * 100,
|
||||
card_uid,
|
||||
credit_reference,
|
||||
currency,
|
||||
};
|
||||
|
||||
try {
|
||||
// Show loader while the payment is being processed
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
acceptConfirm: { loader: true },
|
||||
},
|
||||
}));
|
||||
|
||||
// Extract necessary data from confirmCredit and confirmCardDetails objects
|
||||
const { amount, credit_reference, currency } = __confirmData;
|
||||
const { card_uid } = __confirmCardDetails;
|
||||
|
||||
// Create request data object with required parameters for making the payment
|
||||
const reqData = {
|
||||
amount: amount * 100,
|
||||
card_uid,
|
||||
credit_reference,
|
||||
currency,
|
||||
};
|
||||
|
||||
// Send request to server to make the payment using getPaidPrevCard method of usersService
|
||||
const res = await apiURL.getPaidPrevCard(reqData);
|
||||
const _response = res.data;
|
||||
if (res.data.internal_return < 0) {
|
||||
|
||||
// If internal_return value in the response is less than 0, hide the loader and return
|
||||
if (_response.internal_return < 0) {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
@@ -218,6 +245,7 @@ function ConfirmAddFund({
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state to show the acceptConfirm state and the response data
|
||||
setTimeout(() => {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
@@ -227,9 +255,9 @@ function ConfirmAddFund({
|
||||
},
|
||||
data: _response,
|
||||
}));
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
}, 1500);
|
||||
} catch (error) {
|
||||
// Handle error and hide the loader
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
@@ -240,45 +268,45 @@ function ConfirmAddFund({
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the payment process when a new card is used.
|
||||
* @async
|
||||
*/
|
||||
const handleNewCard = async () => {
|
||||
const { amount, credit_reference, uid } = __confirmData;
|
||||
const { address, cardNum, cvv, expirationMonth, expirationYear } =
|
||||
__confirmCardDetails;
|
||||
|
||||
const reqData = {
|
||||
amount: amount * 100,
|
||||
cardnumber: cardNum.replace(/\s/g, ""),
|
||||
credit_reference,
|
||||
cvc: cvv,
|
||||
description: address,
|
||||
exp_month: expirationMonth,
|
||||
exp_year: expirationYear,
|
||||
paymenttype: 100,
|
||||
uid,
|
||||
};
|
||||
|
||||
try {
|
||||
// Extract necessary data from __confirmData and __confirmCardDetails
|
||||
const { amount, credit_reference, uid } = __confirmData;
|
||||
const { address, cardNum, cvv, expirationMonth, expirationYear } =
|
||||
__confirmCardDetails;
|
||||
|
||||
// Set loading state to indicate payment is being processed
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
acceptConfirm: { loader: true },
|
||||
},
|
||||
}));
|
||||
|
||||
// Prepare request data
|
||||
const reqData = {
|
||||
amount: amount * 100,
|
||||
cardnumber: cardNum.replace(/\s/g, ""),
|
||||
credit_reference,
|
||||
cvc: cvv,
|
||||
description: address,
|
||||
exp_month: expirationMonth,
|
||||
exp_year: expirationYear,
|
||||
paymenttype: 100,
|
||||
uid,
|
||||
};
|
||||
|
||||
// Send request to server to process payment
|
||||
const res = await apiURL.getPaidNewCard(reqData);
|
||||
const _response = res.data;
|
||||
if (res.data.internal_return < 0) {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
awaitConfirm: { loader: false, state: false },
|
||||
acceptConfirm: { loader: false, state: true },
|
||||
},
|
||||
data: _response,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
// Handle response from server
|
||||
if (res.data.internal_return < 0) {
|
||||
// Payment could not be completed
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
@@ -287,9 +315,21 @@ function ConfirmAddFund({
|
||||
},
|
||||
data: _response,
|
||||
}));
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
}, 1500);
|
||||
} else {
|
||||
// Payment was successful
|
||||
setTimeout(() => {
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
awaitConfirm: { loader: false, state: false },
|
||||
acceptConfirm: { loader: false, state: true },
|
||||
},
|
||||
data: _response,
|
||||
}));
|
||||
}, 1500);
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle error during payment process
|
||||
setConfirmCredit((prev) => ({
|
||||
...prev,
|
||||
show: {
|
||||
@@ -362,7 +402,7 @@ function ConfirmAddFund({
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
Reference No
|
||||
</h1>
|
||||
<span className="text-xl font-bold text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
<span className="text-xl font-normal text-dark-gray dark:text-white tracking-tighter my-1">
|
||||
{__confirmData?.credit_reference}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import CompleteConfirmCredit from "./CompleteConfirmCredit";
|
||||
import ConfirmAddFund from "./ConfirmAddFund";
|
||||
|
||||
const CreditPopup = ({ details, onClose, situation, walletItem }) => {
|
||||
let [input, setInput] = useState("");
|
||||
const [input, setInput] = useState("");
|
||||
const [confirmCredit, setConfirmCredit] = useState({
|
||||
show: {
|
||||
awaitConfirm: { loader: false, state: false },
|
||||
@@ -15,6 +15,20 @@ const CreditPopup = ({ details, onClose, situation, walletItem }) => {
|
||||
data: {},
|
||||
});
|
||||
|
||||
const getTitle = () => {
|
||||
if (confirmCredit?.show?.acceptConfirm?.state) {
|
||||
if (confirmCredit?.data?.internal_return <= 0) {
|
||||
return "Credit Unsuccessful";
|
||||
} else {
|
||||
return "Credit Add Completed";
|
||||
}
|
||||
} else if (confirmCredit?.show?.awaitConfirm?.state) {
|
||||
return "Confirm Credit Add";
|
||||
} else {
|
||||
return "Add Credit";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalCom
|
||||
action={onClose}
|
||||
@@ -24,23 +38,9 @@ const CreditPopup = ({ details, onClose, situation, walletItem }) => {
|
||||
<div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
|
||||
<div className="logout-modal-header w-full flex items-center justify-between lg:p-6 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{confirmCredit?.show?.acceptConfirm?.state &&
|
||||
(confirmCredit?.data?.internal_return < 0
|
||||
// ||
|
||||
// confirmCredit?.data?.status !== "successful"
|
||||
) ? (
|
||||
"Credit Unsuccessful"
|
||||
) : (
|
||||
<>
|
||||
{confirmCredit?.show?.acceptConfirm?.loader
|
||||
? "Confirming Credit..."
|
||||
: confirmCredit?.show?.awaitConfirm?.state
|
||||
? "Confirm Credit Add"
|
||||
: confirmCredit?.show?.acceptConfirm?.state
|
||||
? "Credit Add Completed"
|
||||
: "Add Credit"}
|
||||
</>
|
||||
)}
|
||||
{confirmCredit?.show?.acceptConfirm?.loader
|
||||
? "Confirming Credit..."
|
||||
: getTitle()}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -12,6 +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
|
||||
const apiCall = new usersService();
|
||||
const [tab, setTab] = useState("previous");
|
||||
let [requestStatus, setRequestStatus] = useState(false);
|
||||
@@ -23,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 || "",
|
||||
@@ -65,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: [] }));
|
||||
@@ -138,6 +145,7 @@ function NairaWithdraw({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleBankOptions()
|
||||
getCountry(); // TO LOAD LIST COUNTRY
|
||||
getAccountTypes(); // TO LOAD LIST ACCOUNT TYPES
|
||||
}, []);
|
||||
@@ -224,7 +232,7 @@ function NairaWithdraw({
|
||||
setShowConfirmNairaWithdraw({ show: true, state: stateData });
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
if (tab === "new") {
|
||||
const { accountNumber, accountType, bank, city, country, state } =
|
||||
values?.newAccount;
|
||||
@@ -279,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">
|
||||
@@ -422,7 +432,11 @@ function NairaWithdraw({
|
||||
<label
|
||||
onClick={() => setTab("new")}
|
||||
htmlFor="new"
|
||||
className="cursor-pointer flex items-center gap-1"
|
||||
className={`cursor-pointer flex items-center gap-1 ${
|
||||
recipients.data.length >= MaxNoOfBanks
|
||||
? "pointer-events-none"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
id="new"
|
||||
@@ -435,6 +449,11 @@ function NairaWithdraw({
|
||||
} tracking-wide transition duration-200`}
|
||||
/>
|
||||
New Account{" "}
|
||||
{recipients.data.length >= MaxNoOfBanks && (
|
||||
<span className="text-[14px] text-red-500">
|
||||
Max Reached
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -521,275 +540,257 @@ function NairaWithdraw({
|
||||
</>
|
||||
)}
|
||||
|
||||
{tab == "new" && (
|
||||
<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]">
|
||||
{/* country */}
|
||||
<div className="add-recipient w-full flex items-center flex-1 xl:mb-0">
|
||||
<label
|
||||
htmlFor="newAccount.country"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.3]"
|
||||
>
|
||||
Country{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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}
|
||||
onChange={(e) => {
|
||||
props.handleChange(e);
|
||||
handleBankOptions(e);
|
||||
}}
|
||||
>
|
||||
{allCountries.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : allCountries.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
{errorMsgs.newAccount?.country
|
||||
? errorMsgs.newAccount.country
|
||||
: "Select..."}
|
||||
</option>
|
||||
{allCountries.data.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item[0]}
|
||||
>
|
||||
{item[1]}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
No Options Found!
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{/* {props.errors.country &&
|
||||
props.touched.country && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.country}
|
||||
</p>
|
||||
)} */}
|
||||
</div>
|
||||
|
||||
{/* bank name */}
|
||||
<div className="add-recipient w-full flex items-center flex-1">
|
||||
<label
|
||||
htmlFor="newAccount.bank"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4] tracking-[1.5px]"
|
||||
>
|
||||
Bank Name{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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 "
|
||||
name="newAccount.bank"
|
||||
value={props.values.newAccount?.bank}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{bankName.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : bankName.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{bankName.data?.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.bank_uid}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
{allCountries.data?.length
|
||||
? "Select..."
|
||||
: "No Options Found!"}
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{/* {props.errors.bank && props.touched.bank && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.bank}
|
||||
</p>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-[2] gap-4">
|
||||
{/* ACCOUNT NUMBER */}
|
||||
<div className="field w-full flex-[1.4] flex items-center gap-2">
|
||||
<label
|
||||
htmlFor="newAccount.accountNumber"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex items-center flex-1"
|
||||
>
|
||||
Account Number{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
inputClass="flex items-center max-w-[15rem]"
|
||||
type="text"
|
||||
name="newAccount.accountNumber"
|
||||
placeholder="Account No"
|
||||
maxLength={10}
|
||||
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 */}
|
||||
<div className="add-recipient w-full flex flex-1 items-center">
|
||||
<label
|
||||
htmlFor="newAccount.accountType"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.3]"
|
||||
>
|
||||
Type <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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 flex-grow tracking-[1.5px]"
|
||||
name="newAccount.accountType"
|
||||
value={props.values.newAccount?.accountType}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{accType.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : accType.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{accType.data?.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.value}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
No Options Found!
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{/* {props.errors.accountType &&
|
||||
props.touched.accountType && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.accountType}
|
||||
</p>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center flex-1">
|
||||
{/* state */}
|
||||
<div className="field w-full flex items-center gap-4 flex-[0.4]">
|
||||
<label
|
||||
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>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
inputClass="max-w-[10rem]"
|
||||
type="text"
|
||||
name="newAccount.state"
|
||||
placeholder="State/Province"
|
||||
value={props.values.newAccount?.state}
|
||||
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 */}
|
||||
<div className="field w-full flex items-center flex-[0.4]">
|
||||
<label
|
||||
htmlFor="newAccount.city"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4]"
|
||||
>
|
||||
City <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
type="text"
|
||||
inputClass="max-w-[10rem]"
|
||||
name="newAccount.city"
|
||||
placeholder="City"
|
||||
value={props.values.newAccount?.city}
|
||||
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 */}
|
||||
{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" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
) : 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]">
|
||||
{/* country */}
|
||||
<div className="add-recipient w-full flex items-center flex-1 xl:mb-0">
|
||||
<label
|
||||
htmlFor="newAccount.country"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.3]"
|
||||
>
|
||||
Country{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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}
|
||||
onChange={(e) => {
|
||||
props.handleChange(e);
|
||||
handleBankOptions(e);
|
||||
}}
|
||||
>
|
||||
{allCountries.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : allCountries.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
{errorMsgs.newAccount?.country
|
||||
? errorMsgs.newAccount.country
|
||||
: "Select..."}
|
||||
</option>
|
||||
{allCountries.data.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item[0]}
|
||||
>
|
||||
{item[1]}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
No Options Found!
|
||||
</option>
|
||||
)}
|
||||
</select> */}
|
||||
</div>
|
||||
|
||||
{/* bank name */}
|
||||
<div className="add-recipient w-full flex items-center flex-1">
|
||||
<label
|
||||
htmlFor="newAccount.bank"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4] tracking-[1.5px]"
|
||||
>
|
||||
Bank Name{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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 "
|
||||
name="newAccount.bank"
|
||||
value={props.values.newAccount?.bank}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{bankName.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : bankName.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{bankName.data?.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.bank_uid}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
{allCountries.data?.length
|
||||
? "Select..."
|
||||
: "No Options Found!"}
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-[2] gap-4">
|
||||
{/* ACCOUNT NUMBER */}
|
||||
<div className="field w-full flex-[1.4] flex items-center gap-2">
|
||||
<label
|
||||
htmlFor="newAccount.accountNumber"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex items-center flex-1"
|
||||
>
|
||||
Account Number{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
inputClass="flex items-center max-w-[15rem]"
|
||||
type="text"
|
||||
name="newAccount.accountNumber"
|
||||
placeholder="Account No"
|
||||
maxLength={10}
|
||||
value={
|
||||
props.values.newAccount?.accountNumber
|
||||
}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Account Type */}
|
||||
<div className="add-recipient w-full flex flex-1 items-center">
|
||||
<label
|
||||
htmlFor="newAccount.accountType"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.3]"
|
||||
>
|
||||
Type <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<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 flex-grow tracking-[1.5px]"
|
||||
name="newAccount.accountType"
|
||||
value={props.values.newAccount?.accountType}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{accType.loading ? (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Loading...
|
||||
</option>
|
||||
) : accType.data?.length ? (
|
||||
<>
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{accType.data?.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item.value}
|
||||
>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option
|
||||
className="text-slate-500 text-lg"
|
||||
value=""
|
||||
>
|
||||
No Options Found!
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center flex-1">
|
||||
{/* state */}
|
||||
<div className="field w-full flex items-center gap-4 flex-[0.4]">
|
||||
<label
|
||||
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>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
inputClass="max-w-[10rem]"
|
||||
type="text"
|
||||
name="newAccount.state"
|
||||
placeholder="State/Province"
|
||||
value={props.values.newAccount?.state}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* city */}
|
||||
<div className="field w-full flex items-center flex-[0.4]">
|
||||
<label
|
||||
htmlFor="newAccount.city"
|
||||
className="input-label text-[#181c32] dark:text-white text-base font-semibold inline-flex flex-[0.4]"
|
||||
>
|
||||
City <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<InputCom
|
||||
fieldClass="px-6 tracking-[1.5px]"
|
||||
type="text"
|
||||
inputClass="max-w-[10rem]"
|
||||
name="newAccount.city"
|
||||
placeholder="City"
|
||||
value={props.values.newAccount?.city}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
/>
|
||||
</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">
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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: {},
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import WalletItemCard from "./WalletItemCard";
|
||||
|
||||
export default function WalletBox({ wallet, payment }) {
|
||||
/**
|
||||
* Renders a list of wallet items or a loading spinner depending on the state of the `wallet` object.
|
||||
*/
|
||||
export default function WalletBox({ wallet, payment, countries }) {
|
||||
const { loading, data } = wallet;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="my-wallet-wrapper w-full mb-10">
|
||||
<div className="main-wrapper w-full">
|
||||
<div className="balance-inquery w-full lg:grid grid-cols-[repeat(auto-fill,_minmax(325px,_1fr))] gap-5 mb-11 h-[22rem]">
|
||||
{wallet.loading ? (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
<div className="my-wallet-wrapper w-full mb-10">
|
||||
<div className="main-wrapper w-full">
|
||||
<div className="balance-inquery w-auto grid sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-[repeat(auto-fill,_minmax(354px,_1fr))] min-[1440px]:grid-cols-[repeat(auto-fill,_minmax(415px,_1fr))] gap-5 mb-11 h-auto">
|
||||
{loading ? (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
data.length > 0 && data.map((item) => (
|
||||
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
|
||||
<WalletItemCard walletItem={item} payment={payment} countries={countries} />
|
||||
</div>
|
||||
) : wallet.data.length ? (
|
||||
wallet.data.map((item, index) => (
|
||||
<div key={item.wallet_uid} className="lg:w-full h-full mb-10 lg:mb-0">
|
||||
<WalletItemCard walletItem={item} payment={payment} />
|
||||
</div>
|
||||
))
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,45 +16,36 @@ function PurchasesTable({purchase}) {
|
||||
|
||||
return (
|
||||
<div className='flex flex-col justify-between min-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">Trx.</th>
|
||||
<th className="p-2">Amount</th>
|
||||
<th className="p-2">Fee</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{purchase.data.length ?
|
||||
(
|
||||
<tbody>
|
||||
{currentPurchase.map((item, index) => (
|
||||
<tr key={index} className='text-slate-500'>
|
||||
<td className="p-2">{item.added_date}<br />
|
||||
<b>{item.confirmation} </b>
|
||||
</td>
|
||||
<td className="p-2">{item.amount}</td>
|
||||
<td className="p-2">{item.fee}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
)
|
||||
<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">Trx.</th>
|
||||
<th className="p-2">Amount</th>
|
||||
<th className="p-2">Fee</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{currentPurchase.map((item, index) => (
|
||||
<tr key={index} className='text-slate-500'>
|
||||
<td className="p-2">{item.added_date}<br />
|
||||
<b>{item.confirmation} </b>
|
||||
</td>
|
||||
<td className="p-2">{item.amount}</td>
|
||||
<td className="p-2">{item.fee}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
:purchase.error ?
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>Opps! an error occurred. Please try again!</span>
|
||||
</div>
|
||||
:
|
||||
purchase.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 Purchase History Found!</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>No Purchase History Found!</span>
|
||||
</div>
|
||||
}
|
||||
</table>
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList onClick={handlePagination} prev={currentPage == 0 ? true : false} next={currentPage+Number(process.env.REACT_APP_ITEM_PER_PAGE) >= purchase?.data?.length ? true : false} data={purchase?.data} start={indexOfFirstItem} stop={indexOfLastItem} />
|
||||
|
||||
@@ -19,16 +19,16 @@ function RecentActivityTable({ payment }) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-between min-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">Date</th>
|
||||
<th className="p-4">Trx.</th>
|
||||
<th className="p-2">Amnt./Fee</th>
|
||||
<th className="p-2">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{payment?.data?.length > 0 ? (
|
||||
{payment?.data?.length > 0 ?
|
||||
<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">Date</th>
|
||||
<th className="p-4">Trx.</th>
|
||||
<th className="p-2">Amnt./Fee</th>
|
||||
<th className="p-2">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{currentActivity.map((item, index) => (
|
||||
<tr key={index} className="text-slate-500">
|
||||
@@ -46,24 +46,16 @@ function RecentActivityTable({ payment }) {
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
) : payment?.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 Payment History Found!
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
)}
|
||||
</table>
|
||||
</table>
|
||||
:payment.error ?
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>Opps! an error occurred. Please try again!</span>
|
||||
</div>
|
||||
:
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>No Payment History Found!</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList
|
||||
|
||||
@@ -13,6 +13,12 @@ export default function WalletHeader(props) {
|
||||
//props.myWalletList.result_list
|
||||
let { pathname } = useLocation();
|
||||
let navigate = useNavigate();
|
||||
|
||||
const onWalletClick = () => {
|
||||
if (pathname == "/my-wallet")
|
||||
props.setBalanceDropdown.toggle();
|
||||
else navigate("/my-wallet", { replace: true });
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="lg:flex hidden user-balance cursor-pointer lg:w-[152px] w-[150px] h-[48px] items-center rounded-full relative bg-sky-blue pr-1.5 pl-4">
|
||||
@@ -49,6 +55,7 @@ export default function WalletHeader(props) {
|
||||
<li
|
||||
key={index}
|
||||
className="content-item py-4 border-b dark:border-[#5356fb29] border-light-purple hover:border-purple dark:hover:border-purple"
|
||||
onClick={onWalletClick}
|
||||
>
|
||||
<div className="sm:flex justify-between items-center">
|
||||
<div className="account-name flex space-x-4 items-center mb-2 sm:mb-0">
|
||||
@@ -56,7 +63,7 @@ export default function WalletHeader(props) {
|
||||
<img src={localImgLoad(`images/currency/${image}`)} className="w-14 h-14" alt="" />
|
||||
</div>
|
||||
<div className="name">
|
||||
<p className="text-base text-dark-gray dark:text-white font-medium">
|
||||
<p className="text-2xl font-bold text-dark-gray dark:text-white">
|
||||
{value.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -178,11 +185,7 @@ export default function WalletHeader(props) {
|
||||
</button> */}
|
||||
<Link
|
||||
to="/my-wallet"
|
||||
onClick={() => {
|
||||
if (pathname == "/my-wallet")
|
||||
props.setBalanceDropdown.toggle();
|
||||
else navigate("/my-wallet", { replace: true });
|
||||
}}
|
||||
onClick={onWalletClick}
|
||||
className="w-[122px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Manage
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import React, { useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import background from "../../assets/images/bg-sky-blue.jpg"; //shape/balance-bg.svg";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
import { tableReload } from "../../store/TableReloads";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import CreditPopup from "./Popup/CreditPopup";
|
||||
import WalletAction from "./WalletAction";
|
||||
|
||||
export default function WalletItemCard({ walletItem, payment }) {
|
||||
// const [eth] = useState(90);
|
||||
// const [btc] = useState(85);
|
||||
// const [ltc] = useState(20);
|
||||
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
let accountType = userDetails?.account_type == "FAMILY";
|
||||
|
||||
// Credit popup
|
||||
/**
|
||||
* Renders a card displaying information about a wallet item.
|
||||
*/
|
||||
export default function WalletItemCard({ walletItem, payment, countries }) {
|
||||
const { userDetails } = useSelector((state) => state.userDetails);
|
||||
const accountType = userDetails?.account_type === "FAMILY";
|
||||
const dispatch = useDispatch();
|
||||
const [creditPopup, setCreditPopup] = useState({ show: false, data: {} });
|
||||
|
||||
/**
|
||||
* Opens the credit popup.
|
||||
* @param {Object} value - The value object.
|
||||
*/
|
||||
const openPopUp = (value) => {
|
||||
setCreditPopup({
|
||||
show: true,
|
||||
@@ -23,37 +27,45 @@ export default function WalletItemCard({ walletItem, payment }) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the credit popup and dispatches a table reload action.
|
||||
*/
|
||||
const closePopUp = () => {
|
||||
setCreditPopup({ show: false, data: {} });
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
};
|
||||
|
||||
let image = walletItem.code
|
||||
? `${walletItem.code.toLocaleLowerCase()}.svg`
|
||||
: "default.png"; // HOLDS THE VALUE NAME PROPERTY FOR IMAGE ICON
|
||||
const currentWalletCurrency = countries
|
||||
.map((country) => country)
|
||||
.filter((country) => country[0] === walletItem.country);
|
||||
|
||||
const image = walletItem.code
|
||||
? `${walletItem.code.toLowerCase()}.svg`
|
||||
: "default.png";
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`current-balance-widget w-full h-full rounded-2xl overflow-hidden flex flex-col items-center gap-2 px-8 pt-9 pb-20`}
|
||||
className="current-balance-widget w-full h-full rounded-2xl overflow-hidden flex flex-col items-center gap-2 p-8 justify-between"
|
||||
style={{
|
||||
background: `url(${background}) 0% 0% / cover no-repeat`,
|
||||
}}
|
||||
>
|
||||
{/* <div className="w-[350px]"> */}
|
||||
<div className="wallet w-full flex justify-between items-start gap-3">
|
||||
<div className="min-w-[100px] min-h-[100px] max-w-[100px] max-h-[100px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
|
||||
<div className="min-w-[100px] min-h-[100px] max-w-min md:max-w-[150px] max-h-min md:max-h-[150px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
|
||||
<img
|
||||
src={localImgLoad(`images/currency/${image}`)}
|
||||
className="w-full h-full"
|
||||
alt="curreny-icon"
|
||||
alt="currency-icon"
|
||||
/>
|
||||
</div>
|
||||
<div className="balance w-full mt-2 flex justify-center">
|
||||
<div className="">
|
||||
<p className="text-lg text-white opacity-[70%] tracking-wide mb-6">
|
||||
<p className="text-base sm:text-lg text-white opacity-[70%] tracking-wide mb-2 sm:mb-6">
|
||||
Current Balance
|
||||
</p>
|
||||
<p className="text-[44px] font-bold text-white tracking-wide leading-10 mb-2">
|
||||
<p className="text-[44px] lg:text-[62px] font-bold text-white tracking-wide leading-10 xxs:scale-100 lg:scale-100 xl:scale-125">
|
||||
{PriceFormatter(
|
||||
walletItem.amount * 0.01,
|
||||
walletItem.code,
|
||||
@@ -65,9 +77,9 @@ export default function WalletItemCard({ walletItem, payment }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="my-5 text-lg text-white tracking-wide flex justify-center items-center gap-2">
|
||||
<p className="text-lg text-white tracking-wide flex justify-center items-center gap-8">
|
||||
HOLDINGS :{" "}
|
||||
<span className="mt-1">
|
||||
<span className="xxs:scale-100 lg:scale-100 xl:scale-125">
|
||||
{PriceFormatter(
|
||||
walletItem.escrow * 0.01,
|
||||
walletItem.code,
|
||||
@@ -76,18 +88,18 @@ export default function WalletItemCard({ walletItem, payment }) {
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
{/* for white underline */}
|
||||
|
||||
<div className="my-2 w-full h-[1px] bg-white"></div>
|
||||
|
||||
{!accountType ? (
|
||||
{!accountType && (
|
||||
<WalletAction
|
||||
walletItem={walletItem}
|
||||
walletItem={{ ...walletItem, walletCountry: currentWalletCurrency }}
|
||||
payment={payment}
|
||||
openPopUp={openPopUp}
|
||||
/>
|
||||
) : null}
|
||||
{/* </div> */}
|
||||
)}
|
||||
</div>
|
||||
|
||||
{creditPopup.show && (
|
||||
<CreditPopup
|
||||
details={creditPopup.data}
|
||||
|
||||
@@ -55,59 +55,29 @@ export default function Layout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<div className="nft-main-wrapper-layout">
|
||||
<div className="nft-wrapper-layout-container 2xl:pr-20 md:pr-10 pr-2 pl-2 md:pl-0 w-full min-h-screen flex">
|
||||
<div className={`nft-wrapper-layout-container 2xl:pr-20 md:pr-10 pr-2 pl-2 md:pl-0 w-full min-h-screen flex`}>
|
||||
{/* sidebar */}
|
||||
<div
|
||||
className={`nft-sidebar xl:block hidden section-shadow ${
|
||||
drawer
|
||||
? "2xl:w-[335px] w-[280px] 2xl:pl-20 pl-10 pr-6 "
|
||||
: "w-[70px]"
|
||||
} bg-white dark:bg-dark-white h-full overflow-y-scroll overflow-style-none fixed left-0 top-0 pt-[30px]`}
|
||||
>
|
||||
<Sidebar
|
||||
logoutModalHandler={logoutModalHandler}
|
||||
sidebar={drawer}
|
||||
action={() => dispatch(drawerToggle())}
|
||||
myJobList={userJobList}
|
||||
/>
|
||||
<div className={`nft-sidebar xl:block hidden section-shadow ${drawer ? "2xl:w-[335px] w-[280px] 2xl:pl-20 pl-10 pr-6 " : "w-[70px]"} bg-white dark:bg-dark-white h-full overflow-y-scroll overflow-style-none fixed left-0 top-0 pt-[30px]`}>
|
||||
<Sidebar logoutModalHandler={logoutModalHandler} sidebar={drawer} action={() => dispatch(drawerToggle())} myJobList={userJobList} />
|
||||
</div>
|
||||
{MobileSideBar && (
|
||||
<div
|
||||
onClick={() => setMobileSidebar.toggle()}
|
||||
className="bg-black bg-opacity-20 fixed left-0 top-0 w-full h-full z-[50] block xl:hidden"
|
||||
></div>
|
||||
<div onClick={() => setMobileSidebar.toggle()} className="bg-black bg-opacity-20 fixed left-0 top-0 w-full h-full z-[50] block xl:hidden"></div>
|
||||
)}
|
||||
<div
|
||||
className={`nft-sidebar block xl:hidden section-shadow w-[280px] pl-3 bg-white dark:bg-dark-white h-full overflow-y-scroll overflow-style-none fixed z-[60] top-0 pt-8 ${
|
||||
MobileSideBar ? "left-0" : "-left-[290px]"
|
||||
}`}
|
||||
>
|
||||
<MobileSidebar
|
||||
logoutModalHandler={logoutModalHandler}
|
||||
sidebar={MobileSideBar}
|
||||
action={() => setMobileSidebar.toggle()}
|
||||
myJobList={userJobList}
|
||||
/>
|
||||
<div className={`nft-sidebar block xl:hidden section-shadow w-[280px] pl-3 bg-white dark:bg-dark-white h-full overflow-y-scroll overflow-style-none fixed z-[60] top-0 pt-8 ${MobileSideBar ? "left-0" : "-left-[290px]"}`}>
|
||||
<MobileSidebar logoutModalHandler={logoutModalHandler} sidebar={MobileSideBar} action={() => setMobileSidebar.toggle()} myJobList={userJobList} />
|
||||
</div>
|
||||
{/* end sidebar */}
|
||||
<div
|
||||
className={`nft-header-container-wrapper flex-1 md:ml-10 ${
|
||||
drawer ? "2xl:ml-[375px] xl:ml-[310px]" : "xl:ml-[110px]"
|
||||
} h-full`}
|
||||
>
|
||||
<div className={`nft-header-container-wrapper flex-1 md:ml-10 ${drawer ? "2xl:ml-[375px] xl:ml-[310px]" : "xl:ml-[110px]"} h-full`}>
|
||||
{/* header */}
|
||||
<div className="nft-header w-full lg:h-[100px] h-[70px] default-border-bottom dark:border-[#292967] z-40 xl:sticky fixed top-0 left-0 ">
|
||||
<Header
|
||||
sidebarHandler={() => setMobileSidebar.toggle()}
|
||||
logoutModalHandler={logoutModalHandler}
|
||||
/>
|
||||
<div className="nft-header w-full lg:h-[100px] h-[70px] default-border-bottom dark:border-[#292967] z-40 xl:sticky fixed top-0 left-0 ">
|
||||
<Header sidebarHandler={() => setMobileSidebar.toggle()} logoutModalHandler={logoutModalHandler} />
|
||||
</div>
|
||||
{/* container */}
|
||||
<div className="nft-container 2xl:flex 2xl:space-x-8 h-full mb-12 lg:mt-[140px] mt-24 xl:mt-10">
|
||||
<div className="nft-main-container flex-1">
|
||||
<div className="nft-container 2xl:flex 2xl:space-x-8 h-full mb-12 lg:mt-[140px] mt-24 xl:mt-10 flex flex-col xl:flex-row items-start justify-center gap-4">
|
||||
<div className="nft-main-container flex-[80%] w-full">
|
||||
{children && children}
|
||||
</div>
|
||||
<div className="nft-right-side-content 2xl:w-[270px] w-full h-full 2xl:flex justify-center relative">
|
||||
<div className="nft-right-side-content 2xl:w-[270px] w-full h-full 2xl:flex justify-center relative flex-[20%]">
|
||||
<RightSideBar />
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,50 +91,19 @@ export default function Layout({ children }) {
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Confirm
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={logoutModalHandler}
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<button type="button" className="text-[#374557] dark:text-red-500" onClick={logoutModalHandler}>
|
||||
<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="what-icon mb-6 cursor-pointer">
|
||||
<svg
|
||||
width="136"
|
||||
height="136"
|
||||
viewBox="0 0 136 136"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="68" cy="68" r="68" fill="#5356FB" />
|
||||
<path
|
||||
d="M69.8844 35.7891C71.1588 36.0357 72.4569 36.1967 73.7044 36.5423C81.5447 38.7098 87.2705 45.5378 87.9574 53.6156C88.5113 60.1147 86.3075 65.6006 81.5043 70.0195C79.8359 71.5545 78.0497 72.9604 76.3408 74.4534C76.127 74.6397 75.9654 75.0037 75.9604 75.2872C75.9284 77.2752 75.9435 79.2649 75.9435 81.2965C70.8895 81.2965 65.8758 81.2965 60.7915 81.2965C60.7915 81.0616 60.7915 80.8385 60.7915 80.6137C60.7915 76.5454 60.7999 72.4772 60.7797 68.4106C60.778 67.9392 60.9312 67.649 61.2831 67.3537C64.5643 64.5957 67.8271 61.8175 71.1033 59.0545C72.2616 58.0781 72.9215 56.8702 72.9081 55.3419C72.8878 52.916 70.8608 50.9146 68.423 50.8911C65.9701 50.8693 63.9145 52.8053 63.832 55.2328C63.8084 55.8988 63.8286 56.5665 63.8286 57.2695C58.7745 57.2695 53.7744 57.2695 48.6917 57.2695C48.6917 56.3149 48.6462 55.3385 48.6984 54.3655C49.222 44.699 56.7442 36.8745 66.4331 35.8914C66.5762 35.8763 66.7142 35.8243 66.854 35.7891C67.8641 35.7891 68.8742 35.7891 69.8844 35.7891Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M67.485 100.21C66.1617 99.9268 64.9041 99.5091 63.803 98.6787C61.3804 96.8484 60.2877 93.7699 61.0386 90.7888C61.7726 87.8747 64.2138 85.6703 67.2089 85.2157C71.273 84.6 75.2024 87.3681 75.8135 91.277C76.4937 95.6153 73.8202 99.3782 69.544 100.103C69.4429 100.12 69.3487 100.172 69.2527 100.209C68.6635 100.21 68.0742 100.21 67.485 100.21Z"
|
||||
fill="white"
|
||||
/>
|
||||
<svg width="136" height="136" viewBox="0 0 136 136" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="68" cy="68" r="68" fill="#4687ba" />
|
||||
<path d="M69.8844 35.7891C71.1588 36.0357 72.4569 36.1967 73.7044 36.5423C81.5447 38.7098 87.2705 45.5378 87.9574 53.6156C88.5113 60.1147 86.3075 65.6006 81.5043 70.0195C79.8359 71.5545 78.0497 72.9604 76.3408 74.4534C76.127 74.6397 75.9654 75.0037 75.9604 75.2872C75.9284 77.2752 75.9435 79.2649 75.9435 81.2965C70.8895 81.2965 65.8758 81.2965 60.7915 81.2965C60.7915 81.0616 60.7915 80.8385 60.7915 80.6137C60.7915 76.5454 60.7999 72.4772 60.7797 68.4106C60.778 67.9392 60.9312 67.649 61.2831 67.3537C64.5643 64.5957 67.8271 61.8175 71.1033 59.0545C72.2616 58.0781 72.9215 56.8702 72.9081 55.3419C72.8878 52.916 70.8608 50.9146 68.423 50.8911C65.9701 50.8693 63.9145 52.8053 63.832 55.2328C63.8084 55.8988 63.8286 56.5665 63.8286 57.2695C58.7745 57.2695 53.7744 57.2695 48.6917 57.2695C48.6917 56.3149 48.6462 55.3385 48.6984 54.3655C49.222 44.699 56.7442 36.8745 66.4331 35.8914C66.5762 35.8763 66.7142 35.8243 66.854 35.7891C67.8641 35.7891 68.8742 35.7891 69.8844 35.7891Z" fill="white" />
|
||||
<path d="M67.485 100.21C66.1617 99.9268 64.9041 99.5091 63.803 98.6787C61.3804 96.8484 60.2877 93.7699 61.0386 90.7888C61.7726 87.8747 64.2138 85.6703 67.2089 85.2157C71.273 84.6 75.2024 87.3681 75.8135 91.277C76.4937 95.6153 73.8202 99.3782 69.544 100.103C69.4429 100.12 69.3487 100.172 69.2527 100.209C68.6635 100.21 68.0742 100.21 67.485 100.21Z" fill="white" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
@@ -173,18 +112,10 @@ export default function Layout({ children }) {
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex space-x-2.5">
|
||||
<button
|
||||
onClick={logOut}
|
||||
type="button"
|
||||
className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
<button onClick={logOut} type="button" className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full">
|
||||
{`Yes ${process.env.REACT_APP_LOGOUT_TEXT}`}
|
||||
</button>
|
||||
<button
|
||||
onClick={logoutModalHandler}
|
||||
type="button"
|
||||
className=" border-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
<button onClick={logoutModalHandler} type="button" className=" border-gradient text-18 tracking-wide px-4 py-3 rounded-full">
|
||||
<span className="text-gradient">Not Now</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { useSelector } from "react-redux";
|
||||
import { NavLink } from "react-router-dom";
|
||||
//import SideStatistics from "./SideStatistics";
|
||||
|
||||
export default function RightSideBar() {
|
||||
@@ -35,8 +35,8 @@ export default function RightSideBar() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="right-sidebar-wrapper overflow-y-scroll overflow-style-none 2xl:fixed 2xl:grid-cols-none 2xl:block grid lg:grid-cols-2 grid-cols-1 xl:gap-7 gap-4 h-full 2xl:pb-96">
|
||||
<div className="top-platform bg-white dark:bg-dark-white rounded-2xl p-8 2xl:w-[268px] w-full 2xl:mb-10 2xl:border-none border ">
|
||||
<div className="right-sidebar-wrapper overflow-y-scroll overflow-style-none 2xl:fixed h-full 2xl:pb-96">
|
||||
<div className="top-platform bg-white dark:bg-dark-white rounded-2xl p-8 2xl:w-[268px] w-full 2xl:mb-10 2xl:border-none border ">
|
||||
{/* heading */}
|
||||
<div className="heading flex justify-between items-center mb-3.5">
|
||||
<h3 className="text-xl font-bold text-dark-gray dark:text-white">
|
||||
@@ -47,31 +47,62 @@ export default function RightSideBar() {
|
||||
|
||||
<div className="platform-list">
|
||||
{userDetails && userDetails?.account_type !== "FAMILY" && (
|
||||
<>
|
||||
<div className="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="/history">History</NavLink>
|
||||
</p>
|
||||
</div>
|
||||
{/* action */}
|
||||
</div>
|
||||
<>
|
||||
<div className="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="/history">History</NavLink>
|
||||
</p>
|
||||
</div>
|
||||
{/* action */}
|
||||
</div>
|
||||
|
||||
<div className="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
|
||||
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>
|
||||
{/* name */}
|
||||
@@ -81,16 +112,38 @@ export default function RightSideBar() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="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>
|
||||
<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>
|
||||
{/* name */}
|
||||
<div>
|
||||
@@ -99,7 +152,6 @@ export default function RightSideBar() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/*<SideStatistics />*/}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import DarkModeContext from "../Contexts/DarkModeContext";
|
||||
import Icons from "../Helpers/Icons";
|
||||
|
||||
|
||||
export default function Sidebar({
|
||||
sidebar,
|
||||
action,
|
||||
|
||||
@@ -69,7 +69,7 @@ function DeleteCardPopout({action, situation, data, setReloadCardList}) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="68" cy="68" r="68" fill="#5356FB" />
|
||||
<circle cx="68" cy="68" r="68" fill="#4687ba" />
|
||||
<path
|
||||
d="M69.8844 35.7891C71.1588 36.0357 72.4569 36.1967 73.7044 36.5423C81.5447 38.7098 87.2705 45.5378 87.9574 53.6156C88.5113 60.1147 86.3075 65.6006 81.5043 70.0195C79.8359 71.5545 78.0497 72.9604 76.3408 74.4534C76.127 74.6397 75.9654 75.0037 75.9604 75.2872C75.9284 77.2752 75.9435 79.2649 75.9435 81.2965C70.8895 81.2965 65.8758 81.2965 60.7915 81.2965C60.7915 81.0616 60.7915 80.8385 60.7915 80.6137C60.7915 76.5454 60.7999 72.4772 60.7797 68.4106C60.778 67.9392 60.9312 67.649 61.2831 67.3537C64.5643 64.5957 67.8271 61.8175 71.1033 59.0545C72.2616 58.0781 72.9215 56.8702 72.9081 55.3419C72.8878 52.916 70.8608 50.9146 68.423 50.8911C65.9701 50.8693 63.9145 52.8053 63.832 55.2328C63.8084 55.8988 63.8286 56.5665 63.8286 57.2695C58.7745 57.2695 53.7744 57.2695 48.6917 57.2695C48.6917 56.3149 48.6462 55.3385 48.6984 54.3655C49.222 44.699 56.7442 36.8745 66.4331 35.8914C66.5762 35.8763 66.7142 35.8243 66.854 35.7891C67.8641 35.7891 68.8742 35.7891 69.8844 35.7891Z"
|
||||
fill="white"
|
||||
|
||||
@@ -51,6 +51,7 @@ export default function PersonalInfoTab({
|
||||
coverImgInput,
|
||||
browseCoverImg,
|
||||
coverImgChangHandler,
|
||||
uploadStatus
|
||||
}) {
|
||||
let { userDetails } = useSelector((state) => state.userDetails);
|
||||
|
||||
@@ -68,7 +69,7 @@ export default function PersonalInfoTab({
|
||||
pref_email: 0,
|
||||
pref_phone: 0,
|
||||
accept_promo: false,
|
||||
online_name: "",
|
||||
online_name: userDetails?.online_name,
|
||||
};
|
||||
|
||||
let [profile, setProfile] = useState({
|
||||
@@ -158,7 +159,7 @@ export default function PersonalInfoTab({
|
||||
fieldClass="px-6"
|
||||
label="User Name"
|
||||
type="text"
|
||||
name="online_name"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
value={userDetails?.username}
|
||||
disable={true}
|
||||
@@ -361,63 +362,67 @@ export default function PersonalInfoTab({
|
||||
{/* inputs ends here */}
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
Update Profile
|
||||
<span className="ml-1">
|
||||
<Icons name="block-question" />
|
||||
</span>
|
||||
</h1>
|
||||
<p className="text-base text-thin-light-gray mb-5">
|
||||
Profile of at least Size
|
||||
<span className="ml-1 text-dark-gray dark:text-white">
|
||||
300x300
|
||||
</span>
|
||||
. Gifs work too.
|
||||
<span className="ml-1 text-dark-gray dark:text-white">
|
||||
Max 5mb
|
||||
</span>
|
||||
.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full relative">
|
||||
<img
|
||||
src={profileImg}
|
||||
alt="profile"
|
||||
className="sm:w-[198px] sm:h-[198px] w-[120px] h-[120px] rounded-full overflow-hidden object-contain object-center"
|
||||
/>
|
||||
<input
|
||||
ref={profileImgInput}
|
||||
onChange={(e) => profileImgChangHandler(e)}
|
||||
type="file"
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
onClick={browseProfileImg}
|
||||
className="w-[32px] h-[32px] absolute bottom-7 sm:right-10 right-[105px] hover:bg-pink bg-dark-gray rounded-full cursor-pointer"
|
||||
>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{/* {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">
|
||||
Update Profile
|
||||
<span className="ml-1">
|
||||
<Icons name="block-question" />
|
||||
</span>
|
||||
</h1>
|
||||
<p className="text-base text-thin-light-gray mb-5">
|
||||
Profile of at least Size
|
||||
<span className="ml-1 text-dark-gray dark:text-white">
|
||||
300x300
|
||||
</span>
|
||||
. Gifs work too.
|
||||
<span className="ml-1 text-dark-gray dark:text-white">
|
||||
Max 5mb
|
||||
</span>
|
||||
.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full relative">
|
||||
<img
|
||||
src={profileImg}
|
||||
alt="profile"
|
||||
className="sm:w-[198px] sm:h-[198px] w-[120px] h-[120px] rounded-full overflow-hidden object-contain object-center"
|
||||
/>
|
||||
<input
|
||||
ref={profileImgInput}
|
||||
onChange={(e) => profileImgChangHandler(e)}
|
||||
type="file"
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
onClick={browseProfileImg}
|
||||
className="w-[32px] h-[32px] absolute bottom-7 sm:right-10 right-[105px] hover:bg-pink bg-dark-gray rounded-full cursor-pointer"
|
||||
>
|
||||
<path
|
||||
d="M16.5147 11.5C17.7284 12.7137 18.9234 13.9087 20.1296 15.115C19.9798 15.2611 19.8187 15.4109 19.6651 15.5683C17.4699 17.7635 15.271 19.9587 13.0758 22.1539C12.9334 22.2962 12.7948 22.4386 12.6524 22.5735C12.6187 22.6034 12.5663 22.6296 12.5213 22.6296C11.3788 22.6334 10.2362 22.6297 9.09365 22.6334C9.01498 22.6334 9 22.6034 9 22.536C9 21.4009 9 20.2621 9.00375 19.1271C9.00375 19.0746 9.02997 19.0109 9.06368 18.9772C10.4123 17.6249 11.7609 16.2763 13.1095 14.9277C14.2295 13.8076 15.3459 12.6913 16.466 11.5712C16.4884 11.5487 16.4997 11.5187 16.5147 11.5Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M20.9499 14.2904C19.7436 13.0842 18.5449 11.8854 17.3499 10.6904C17.5634 10.4694 17.7844 10.2446 18.0054 10.0199C18.2639 9.76139 18.5261 9.50291 18.7884 9.24443C19.118 8.91852 19.5713 8.91852 19.8972 9.24443C20.7251 10.0611 21.5492 10.8815 22.3771 11.6981C22.6993 12.0165 22.7105 12.4698 22.3996 12.792C21.9238 13.2865 21.4443 13.7772 20.9686 14.2717C20.9648 14.2792 20.9536 14.2867 20.9499 14.2904Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16.5147 11.5C17.7284 12.7137 18.9234 13.9087 20.1296 15.115C19.9798 15.2611 19.8187 15.4109 19.6651 15.5683C17.4699 17.7635 15.271 19.9587 13.0758 22.1539C12.9334 22.2962 12.7948 22.4386 12.6524 22.5735C12.6187 22.6034 12.5663 22.6296 12.5213 22.6296C11.3788 22.6334 10.2362 22.6297 9.09365 22.6334C9.01498 22.6334 9 22.6034 9 22.536C9 21.4009 9 20.2621 9.00375 19.1271C9.00375 19.0746 9.02997 19.0109 9.06368 18.9772C10.4123 17.6249 11.7609 16.2763 13.1095 14.9277C14.2295 13.8076 15.3459 12.6913 16.466 11.5712C16.4884 11.5487 16.4997 11.5187 16.5147 11.5Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M20.9499 14.2904C19.7436 13.0842 18.5449 11.8854 17.3499 10.6904C17.5634 10.4694 17.7844 10.2446 18.0054 10.0199C18.2639 9.76139 18.5261 9.50291 18.7884 9.24443C19.118 8.91852 19.5713 8.91852 19.8972 9.24443C20.7251 10.0611 21.5492 10.8815 22.3771 11.6981C22.6993 12.0165 22.7105 12.4698 22.3996 12.792C21.9238 13.2865 21.4443 13.7772 20.9686 14.2717C20.9648 14.2792 20.9536 14.2867 20.9499 14.2904Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</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>
|
||||
|
||||
<div className="content-footer w-full">
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -103,7 +103,7 @@ function DeleteJobPopout({ details, onClose, situation }) {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="68" cy="68" r="68" fill="#5356FB" />
|
||||
<circle cx="68" cy="68" r="68" fill="#4687ba" />
|
||||
<path
|
||||
d="M69.8844 35.7891C71.1588 36.0357 72.4569 36.1967 73.7044 36.5423C81.5447 38.7098 87.2705 45.5378 87.9574 53.6156C88.5113 60.1147 86.3075 65.6006 81.5043 70.0195C79.8359 71.5545 78.0497 72.9604 76.3408 74.4534C76.127 74.6397 75.9654 75.0037 75.9604 75.2872C75.9284 77.2752 75.9435 79.2649 75.9435 81.2965C70.8895 81.2965 65.8758 81.2965 60.7915 81.2965C60.7915 81.0616 60.7915 80.8385 60.7915 80.6137C60.7915 76.5454 60.7999 72.4772 60.7797 68.4106C60.778 67.9392 60.9312 67.649 61.2831 67.3537C64.5643 64.5957 67.8271 61.8175 71.1033 59.0545C72.2616 58.0781 72.9215 56.8702 72.9081 55.3419C72.8878 52.916 70.8608 50.9146 68.423 50.8911C65.9701 50.8693 63.9145 52.8053 63.832 55.2328C63.8084 55.8988 63.8286 56.5665 63.8286 57.2695C58.7745 57.2695 53.7744 57.2695 48.6917 57.2695C48.6917 56.3149 48.6462 55.3385 48.6984 54.3655C49.222 44.699 56.7442 36.8745 66.4331 35.8914C66.5762 35.8763 66.7142 35.8243 66.854 35.7891C67.8641 35.7891 68.8742 35.7891 69.8844 35.7891Z"
|
||||
fill="white"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Field, Form, Formik } from "formik";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import SiteService from "../../services/SiteService";
|
||||
import usersService from "../../services/UsersService";
|
||||
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,
|
||||
@@ -32,7 +36,7 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
},
|
||||
});
|
||||
|
||||
const apiCall = useMemo(() => new SiteService(), []);
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
// member listing
|
||||
const memberList = useCallback(async () => {
|
||||
@@ -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) {
|
||||
@@ -168,7 +173,6 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
};
|
||||
|
||||
// console.log("Job List P >> ", details)
|
||||
|
||||
return (
|
||||
<ModalCom action={onClose} situation={situation} className="job-popup">
|
||||
<div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
|
||||
@@ -225,8 +229,8 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
<div className="my-3 md:flex">
|
||||
<Detail
|
||||
label="Created"
|
||||
value={`Dummy, no value found for created!`}
|
||||
/>
|
||||
value={new Date(details?.created).toDateString()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="my-3">
|
||||
@@ -234,8 +238,8 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
Delivery Detail
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 dark:text-white bg-transparent outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
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}
|
||||
@@ -338,7 +342,8 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
|
||||
|
||||
{ process.env.REACT_APP_SHOW_OFFER_GROUP_JOB != 0 &&
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema.fields.group}
|
||||
@@ -368,6 +373,7 @@ function JobListPopout({ details, onClose, situation }) {
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
}
|
||||
</div>
|
||||
{/* END OF ACTION SECTION */}
|
||||
</div>
|
||||
@@ -468,10 +474,14 @@ const JobFieldInput = ({
|
||||
type="submit"
|
||||
name={inputName}
|
||||
onClick={errorHandler}
|
||||
className={`px-2 py-1 text-sm text-white btn-gradient tracking-wide rounded-md ${
|
||||
!value && "disabled:grayscale-[65%] transition duration-300"
|
||||
}`}
|
||||
disabled={!value}
|
||||
// className={`px-2 py-1 text-sm text-white btn-gradient tracking-wide rounded-md ${
|
||||
// !value && "disabled:grayscale-[65%] transition duration-300"
|
||||
// }`}
|
||||
className={`px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white ${
|
||||
!value && ""
|
||||
}
|
||||
`}
|
||||
// disabled={!value}
|
||||
>
|
||||
{loader ? <LoadingSpinner size={5} /> : btnText}
|
||||
</button>
|
||||
|
||||
+174
-76
@@ -3,7 +3,7 @@
|
||||
font-family: "Product Sans";
|
||||
src: url("./assets/fonts/Product Sans Regular.ttf");
|
||||
}
|
||||
.nft-main-container{
|
||||
.nft-main-container {
|
||||
max-width: 1200px;
|
||||
}
|
||||
/* Bold Weight */
|
||||
@@ -11,57 +11,59 @@
|
||||
font-family: "Product Sans";
|
||||
src: url("./assets/fonts/Product Sans Bold.ttf");
|
||||
}
|
||||
.SENDER{
|
||||
.SENDER {
|
||||
margin-left: 60px !important;
|
||||
background-color: azure;
|
||||
}
|
||||
.RECIPIENT{
|
||||
.RECIPIENT {
|
||||
margin-right: 60px !important;
|
||||
background-color: #add8e6 !important;
|
||||
}
|
||||
.wallet-box{
|
||||
.wallet-box {
|
||||
background-color: aliceblue;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.bal-col1{
|
||||
.bal-col1 {
|
||||
width: 110px;
|
||||
}
|
||||
.bg-green{
|
||||
.bg-green {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
.referral{
|
||||
margin-bottom: 20px
|
||||
.referral {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.task_action_panel{
|
||||
font-family: sans; color: white;
|
||||
.task_action_panel {
|
||||
font-family: sans;
|
||||
color: white;
|
||||
font-weight: bolder;
|
||||
font-size: 14px;
|
||||
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
|
||||
padding: 0px 10px 5px 10px
|
||||
padding: 0px 10px 5px 10px;
|
||||
}
|
||||
.heroSilderTitle{
|
||||
.heroSilderTitle {
|
||||
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
|
||||
font-family: sans; color: white;
|
||||
font-family: sans;
|
||||
color: white;
|
||||
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
|
||||
}
|
||||
.back-dark1{
|
||||
background-color: #193F5F;
|
||||
.back-dark1 {
|
||||
background-color: #193f5f;
|
||||
min-width: 280px !important;
|
||||
}
|
||||
.job-action{
|
||||
.job-action {
|
||||
background-color: #4687ba;
|
||||
height: 100px;
|
||||
border-radius: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.msg_box{
|
||||
.msg_box {
|
||||
background-color: aliceblue;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.msg_header{
|
||||
.msg_header {
|
||||
background-color: white;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
@@ -69,7 +71,7 @@
|
||||
font-size: 14px;
|
||||
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
|
||||
}
|
||||
.siderCardDescription{
|
||||
.siderCardDescription {
|
||||
background-color: aliceblue;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
@@ -78,7 +80,7 @@
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.56;
|
||||
}
|
||||
.siderCardButton{
|
||||
.siderCardButton {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@@ -91,33 +93,39 @@
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.short_style{
|
||||
.short_style {
|
||||
background-color: transparent;
|
||||
border-color: #a2d7f1;
|
||||
border-width: 3px;
|
||||
}
|
||||
.lr{
|
||||
.lr {
|
||||
background-color: #e1cace;
|
||||
}
|
||||
.lg{
|
||||
.lg {
|
||||
background-color: #a7dca7;
|
||||
}
|
||||
.lb{
|
||||
.lb {
|
||||
background-color: #b3ccd7;
|
||||
}
|
||||
.ly{
|
||||
.ly {
|
||||
background-color: #eeee67;
|
||||
}
|
||||
.offer-slide-item{
|
||||
background: rgb(2,0,36);
|
||||
background: radial-gradient(circle, rgba(2,0,36,1) 0%, rgba(3,51,2,0.782125350140056) 0%, rgba(0,212,255,0.07904411764705888) 0%, rgba(153,182,201,1) 99%);
|
||||
.offer-slide-item {
|
||||
background: rgb(2, 0, 36);
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
rgba(2, 0, 36, 1) 0%,
|
||||
rgba(3, 51, 2, 0.782125350140056) 0%,
|
||||
rgba(0, 212, 255, 0.07904411764705888) 0%,
|
||||
rgba(153, 182, 201, 1) 99%
|
||||
);
|
||||
margin: 5px;
|
||||
border-radius: 15px;
|
||||
padding: 15px;
|
||||
height: 250px;
|
||||
border-color: beige;
|
||||
}
|
||||
.banner-630-340{
|
||||
.banner-630-340 {
|
||||
width: 630px;
|
||||
height: 340px;
|
||||
background-color: aliceblue;
|
||||
@@ -133,6 +141,7 @@
|
||||
font-family: "Product Sans";
|
||||
src: url("./assets/fonts/Product Sans Regular.ttf");
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -144,9 +153,8 @@
|
||||
--toastify-color-success: #f539f8;
|
||||
}
|
||||
|
||||
|
||||
/* ===================== EXTRA ===================== */
|
||||
.bottomMargin{
|
||||
.bottomMargin {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
/* TODO: =================================default================================ */
|
||||
@@ -159,8 +167,13 @@ html {
|
||||
font-family: "Product Sans";
|
||||
}
|
||||
.primary-gradient {
|
||||
background: linear-gradient(134.38deg, #f539f8 0%, #284f64 43.55%, #1a3544 104.51%);
|
||||
/* background-image: url("./assets/images/left-myft.jpg");
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#f539f8 0%,
|
||||
#284f64 43.55%,
|
||||
#1a3544 104.51%
|
||||
);
|
||||
/* background-image: url("./assets/images/left-myft.jpg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover; */
|
||||
}
|
||||
@@ -199,7 +212,12 @@ html {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#5356fb 0%,
|
||||
#c342f9 43.55%,
|
||||
#f539f8 104.51%
|
||||
);
|
||||
opacity: 30%;
|
||||
}
|
||||
/* Chrome, Safari, Edge, Opera */
|
||||
@@ -229,10 +247,20 @@ input[type="text"][dir="rtl"] {
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
.btn-gradient {
|
||||
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#f539f8 0%,
|
||||
#c342f9 43.55%,
|
||||
#5356fb 104.51%
|
||||
);
|
||||
}
|
||||
.btn-gradient:hover {
|
||||
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#5356fb 0%,
|
||||
#c342f9 43.55%,
|
||||
#f539f8 104.51%
|
||||
);
|
||||
}
|
||||
.text-26 {
|
||||
font-size: 26px;
|
||||
@@ -246,7 +274,12 @@ input[type="text"][dir="rtl"] {
|
||||
}
|
||||
|
||||
.text-gradient {
|
||||
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#f539f8 0%,
|
||||
#c342f9 43.55%,
|
||||
#5356fb 104.51%
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
@@ -271,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 {
|
||||
@@ -305,6 +344,16 @@ input[type="text"][dir="rtl"] {
|
||||
transform: scale(1);
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 25rem) {
|
||||
.sidebar-logo.enter {
|
||||
width: 65%;
|
||||
}
|
||||
.sidebar-logo.enter + span{
|
||||
position: revert;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-logo {
|
||||
transform: scale(0);
|
||||
width: 0;
|
||||
@@ -437,7 +486,12 @@ input[type="text"][dir="rtl"] {
|
||||
.home-page-wrapper .hero-slider .slick-slider .slick-dots li {
|
||||
margin: 0;
|
||||
}
|
||||
.home-page-wrapper .hero-slider .slick-slider .slick-dots li.slick-active button {
|
||||
.home-page-wrapper
|
||||
.hero-slider
|
||||
.slick-slider
|
||||
.slick-dots
|
||||
li.slick-active
|
||||
button {
|
||||
background: white;
|
||||
}
|
||||
.home-page-wrapper .hero-slider .slick-slider .slick-dots li button {
|
||||
@@ -460,7 +514,12 @@ input[type="text"][dir="rtl"] {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(134.38deg, #5356fb 0%, #c342f9 43.55%, #f539f8 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#5356fb 0%,
|
||||
#c342f9 43.55%,
|
||||
#f539f8 104.51%
|
||||
);
|
||||
z-index: -1;
|
||||
opacity: 30%;
|
||||
}
|
||||
@@ -476,8 +535,10 @@ input[type="text"][dir="rtl"] {
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
.transfer-field, .transfer-field:focus, .transfer-field:focus-within{
|
||||
background: #FFF !important;
|
||||
.transfer-field,
|
||||
.transfer-field:focus,
|
||||
.transfer-field:focus-within {
|
||||
background: #fff !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
@@ -583,12 +644,12 @@ input[type="text"][dir="rtl"] {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.content{
|
||||
.content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.job-items{
|
||||
.job-sub-menu{
|
||||
.job-items {
|
||||
.job-sub-menu {
|
||||
background-color: yellow;
|
||||
}
|
||||
}
|
||||
@@ -597,7 +658,7 @@ input[type="text"][dir="rtl"] {
|
||||
top: 0;
|
||||
right: -100%;
|
||||
opacity: 0;
|
||||
transition: all .5s;
|
||||
transition: all 0.5s;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -612,7 +673,12 @@ input[type="text"][dir="rtl"] {
|
||||
.notification-page .content-item .notifications {
|
||||
@apply flex space-x-4 items-center;
|
||||
}
|
||||
.notification-page .content-item .notifications .notification-page .content-item .notifications {
|
||||
.notification-page
|
||||
.content-item
|
||||
.notifications
|
||||
.notification-page
|
||||
.content-item
|
||||
.notifications {
|
||||
@apply mb-0;
|
||||
}
|
||||
.notification-setting-tab .notification-settings-items li:last-child {
|
||||
@@ -621,7 +687,11 @@ input[type="text"][dir="rtl"] {
|
||||
.faq-tab .accordion-items .accordion-item:first-child .accordion-title-bar {
|
||||
padding-top: 0;
|
||||
}
|
||||
.faq-tab .accordion-items .accordion-item:last-child .accordion-body .accordion-body-content {
|
||||
.faq-tab
|
||||
.accordion-items
|
||||
.accordion-item:last-child
|
||||
.accordion-body
|
||||
.accordion-body-content {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.faq-tab .accordion-title-bar {
|
||||
@@ -665,14 +735,15 @@ input[type="text"][dir="rtl"] {
|
||||
}
|
||||
|
||||
@media print {
|
||||
body .modal-com{
|
||||
body .modal-com {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.job-action-modal-body button, .message-modal-header button {
|
||||
.job-action-modal-body button,
|
||||
.message-modal-header button {
|
||||
display: none;
|
||||
}
|
||||
.message-modal-wrapper .message-table{
|
||||
.message-modal-wrapper .message-table {
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
@@ -839,30 +910,40 @@ TODO: Responsive ===========================
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LoginPage */
|
||||
.main-wrapper.login-wrapper{
|
||||
background-image: url('./assets/images/login-dots.jpg');
|
||||
.main-wrapper.login-wrapper {
|
||||
background-image: url("./assets/images/login-dots.jpg");
|
||||
background-attachment: fixed;
|
||||
background-size: contain;
|
||||
background-position-y: bottom;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
}
|
||||
|
||||
.layout-wrapper.login{
|
||||
background: rgb(236,237,241);
|
||||
background: linear-gradient(90deg, rgba(236,237,241,1) 0%, rgba(252,252,252,1) 31%, rgba(255,255,255,0.9416141456582633) 41%, rgba(255,255,255,0.9752275910364145) 61%, rgba(252,252,252,1) 71%, rgba(236,237,241,1) 100%);
|
||||
.layout-wrapper.login {
|
||||
background: rgb(236, 237, 241);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(236, 237, 241, 1) 0%,
|
||||
rgba(252, 252, 252, 1) 31%,
|
||||
rgba(255, 255, 255, 0.9416141456582633) 41%,
|
||||
rgba(255, 255, 255, 0.9752275910364145) 61%,
|
||||
rgba(252, 252, 252, 1) 71%,
|
||||
rgba(236, 237, 241, 1) 100%
|
||||
);
|
||||
font-family: Circular, Helvetica Neue, Helvetica, Roboto, Arial, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.56;
|
||||
}
|
||||
|
||||
.content-wrapper.login{
|
||||
--bg-color: 255,255,255;
|
||||
background: linear-gradient(90deg, rgba(236,237,240,1) 0%, rgba(255,255,255,1) 50%, rgba(236,237,240,1) 100%);
|
||||
|
||||
.content-wrapper.login {
|
||||
--bg-color: 255, 255, 255;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(236, 237, 240, 1) 0%,
|
||||
rgba(255, 255, 255, 1) 50%,
|
||||
rgba(236, 237, 240, 1) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.content-wrapper select {
|
||||
@@ -880,51 +961,68 @@ TODO: Responsive ===========================
|
||||
}
|
||||
|
||||
/* Update table scrollbar */
|
||||
.update-table::-webkit-scrollbar-track, .update-table > *::-webkit-scrollbar-track,
|
||||
.update-table::-webkit-scrollbar-track,
|
||||
.update-table > *::-webkit-scrollbar-track,
|
||||
.market-pop::-webkit-scrollbar-track,
|
||||
.wallet.coupon::-webkit-scrollbar-track{
|
||||
.wallet.coupon::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.update-table::-webkit-scrollbar, .update-table > *::-webkit-scrollbar,
|
||||
.update-table::-webkit-scrollbar,
|
||||
.update-table > *::-webkit-scrollbar,
|
||||
.market-pop::-webkit-scrollbar,
|
||||
.wallet.coupon::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.update-table::-webkit-scrollbar-thumb, .update-table > *::-webkit-scrollbar-thumb, .wallet.coupon::-webkit-scrollbar-thumb {
|
||||
.update-table::-webkit-scrollbar-thumb,
|
||||
.update-table > *::-webkit-scrollbar-thumb,
|
||||
.wallet.coupon::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
border-top-right-radius: 50px;
|
||||
border-bottom-right-radius: 50px;
|
||||
background-color: #fff;
|
||||
background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%);
|
||||
background: linear-gradient(
|
||||
134.38deg,
|
||||
#f539f8 0%,
|
||||
#c342f9 43.55%,
|
||||
#5356fb 104.51%
|
||||
);
|
||||
}
|
||||
|
||||
.market-pop::-webkit-scrollbar-thumb {
|
||||
border-radius: 100px;
|
||||
|
||||
|
||||
/* background-color: #fafafa; */
|
||||
/* background: linear-gradient(134.38deg, #f539f8 0%, #c342f9 43.55%, #5356fb 104.51%); */
|
||||
background: rgb(236,237,241);
|
||||
background: linear-gradient(90deg, rgba(236,237,241,1) 0%, rgba(252,252,252,1) 31%, rgba(255,255,255,0.9416141456582633) 41%, rgba(255,255,255,0.9752275910364145) 61%, rgba(252,252,252,1) 71%, rgba(236,237,241,1) 100%);
|
||||
background: rgb(236, 237, 241);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(236, 237, 241, 1) 0%,
|
||||
rgba(252, 252, 252, 1) 31%,
|
||||
rgba(255, 255, 255, 0.9416141456582633) 41%,
|
||||
rgba(255, 255, 255, 0.9752275910364145) 61%,
|
||||
rgba(252, 252, 252, 1) 71%,
|
||||
rgba(236, 237, 241, 1) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.input-curve.lg{
|
||||
.input-curve.lg {
|
||||
border-radius: 35px !important;
|
||||
}
|
||||
|
||||
.edit-popup{
|
||||
.edit-popup {
|
||||
top: 75px;
|
||||
}
|
||||
|
||||
.job-popup{
|
||||
.job-popup {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
.addJob-popup{
|
||||
.addJob-popup {
|
||||
top: 30px;
|
||||
height: 55rem !important;
|
||||
}
|
||||
@@ -952,10 +1050,10 @@ TODO: Responsive ===========================
|
||||
}
|
||||
|
||||
/* TO REMOVE SLIDER COMPONENT FROM CENTRALIZED */
|
||||
.slider-left .slick-slider .slick-track{
|
||||
.slider-left .slick-slider .slick-track {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.assign-task-popup{
|
||||
.assign-task-popup {
|
||||
top: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-1
@@ -1,4 +1,4 @@
|
||||
export default function formattedDate(dateString) {
|
||||
export function formattedDate(dateString) {
|
||||
const parts = dateString.split(" ");
|
||||
const datePart = parts[0];
|
||||
const timePart = parts[1];
|
||||
@@ -15,3 +15,26 @@ export default function formattedDate(dateString) {
|
||||
|
||||
return new Date(year, month - 1, day, hour, minute);
|
||||
}
|
||||
|
||||
export function formatDateString(inputDateString) {
|
||||
// Parse the input date string
|
||||
const parsedDate = new Date(inputDateString);
|
||||
|
||||
// Get day, month, year, and time components
|
||||
const day = parsedDate.toLocaleDateString(undefined, { weekday: "long" });
|
||||
const month = parsedDate.toLocaleDateString(undefined, { month: "short" });
|
||||
const date = parsedDate.toLocaleDateString(undefined, { day: "numeric" });
|
||||
const year = parsedDate.toLocaleDateString(undefined, { year: "numeric" });
|
||||
|
||||
// Get the time in 12-hour format with 'AM' or 'PM'
|
||||
const hours = parsedDate.getHours();
|
||||
const minutes = parsedDate.getMinutes();
|
||||
const time = `${hours % 12 || 12}:${minutes.toString().padStart(2, "0")} ${
|
||||
hours < 12 ? "AM" : "PM"
|
||||
}`;
|
||||
|
||||
// Combine the components into the desired format
|
||||
const formattedDate = `${day}, ${month} ${date} ${year} - ${time}`;
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
+2
-1
@@ -1,12 +1,13 @@
|
||||
import ClearCookies from "./ClearCookies";
|
||||
import checkAndSetError from "./checkAndSetError";
|
||||
import formattedDate from "./fomattedDate";
|
||||
import { formatDateString, formattedDate } from "./fomattedDate";
|
||||
import getTimeAgo from "./getTimeAgo";
|
||||
import localImgLoad from "./localImgLoad";
|
||||
|
||||
export {
|
||||
ClearCookies,
|
||||
checkAndSetError,
|
||||
formatDateString,
|
||||
formattedDate,
|
||||
getTimeAgo,
|
||||
localImgLoad,
|
||||
|
||||
@@ -2,7 +2,6 @@ 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/fomattedDate";
|
||||
import usersService from "../services/UsersService";
|
||||
import { commonHeadBanner } from "../store/CommonHeadBanner";
|
||||
import { recentActivitiesData } from "../store/RecentActivitiesData";
|
||||
@@ -11,6 +10,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";
|
||||
|
||||
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(() => {
|
||||
|
||||
+98
-92
@@ -1,107 +1,113 @@
|
||||
import React from "react";
|
||||
import Axios from "axios";
|
||||
|
||||
class SiteService {
|
||||
constructor() {
|
||||
console.log("Er are here anyway");
|
||||
}
|
||||
// Blog Data {Get}
|
||||
blogData() {
|
||||
return this.getAuxEnd("/blogdata", null);
|
||||
}
|
||||
constructor() {
|
||||
console.log("Er are here anyway");
|
||||
}
|
||||
// Blog Data {Get}
|
||||
blogData() {
|
||||
return this.getAuxEnd("/blogdata", null);
|
||||
}
|
||||
|
||||
// Country Data {GET}
|
||||
countryData() {
|
||||
return this.getAuxEnd("/country", null);
|
||||
}
|
||||
// Country Data {GET}
|
||||
countryData() {
|
||||
return this.getAuxEnd("/country", null);
|
||||
}
|
||||
|
||||
// Contact Data{POST}
|
||||
contactData() {
|
||||
return this.postAuxEnd("/contact", null)
|
||||
}
|
||||
// Contact Data{POST}
|
||||
contactData() {
|
||||
return this.postAuxEnd("/contact", null);
|
||||
}
|
||||
|
||||
faqData() {
|
||||
return this.getAuxEnd("/faq", null);
|
||||
}
|
||||
faqData() {
|
||||
return this.getAuxEnd("/faq", null);
|
||||
}
|
||||
|
||||
priceData() {
|
||||
return this.getAuxEnd("/pricing", null);
|
||||
}
|
||||
priceData() {
|
||||
return this.getAuxEnd("/pricing", null);
|
||||
}
|
||||
|
||||
addFamily(reqData) {
|
||||
return this.postAuxEnd('/familyadd', reqData)
|
||||
}
|
||||
addFamily(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
action: 22015,
|
||||
...reqData,
|
||||
};
|
||||
return this.postAuxEnd("/familyadd", postData);
|
||||
}
|
||||
|
||||
familyListings(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
...reqData
|
||||
};
|
||||
return this.postAuxEnd('/familylist', postData)
|
||||
}
|
||||
familyListings(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
...reqData,
|
||||
};
|
||||
return this.postAuxEnd("/familylist", postData);
|
||||
}
|
||||
|
||||
assignJobTask(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
...reqData
|
||||
};
|
||||
return this.postAuxEnd('/assigntask', postData)
|
||||
}
|
||||
assignJobTask(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
...reqData,
|
||||
};
|
||||
return this.postAuxEnd("/assigntask", postData);
|
||||
}
|
||||
|
||||
//---------------------------------------- -----
|
||||
//---------------------------------------- -----
|
||||
// Unified call below
|
||||
//---------------------------------------- -----
|
||||
//---------------------------------------- -----
|
||||
getAuxEnd(uri, reqData) {
|
||||
const endPoint = process.env.REACT_APP_AUX_ENDPOINT + uri;
|
||||
return Axios.get(endPoint)
|
||||
.then((response) => {
|
||||
// console.log(response);
|
||||
// res = response;
|
||||
// console.log("~~~~~~~ Toks2 GET ~~~~~~~~");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
//response status is an error code
|
||||
console.log(error.response.status);
|
||||
} else if (error.request) {
|
||||
//response not received though the request was sent
|
||||
console.log(error.request);
|
||||
} else {
|
||||
//an error occurred when setting up the request
|
||||
console.log(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
//---------------------------------------- -----
|
||||
//---------------------------------------- -----
|
||||
// Unified call below
|
||||
//---------------------------------------- -----
|
||||
//---------------------------------------- -----
|
||||
getAuxEnd(uri, reqData) {
|
||||
const endPoint = process.env.REACT_APP_AUX_ENDPOINT + uri;
|
||||
return Axios.get(endPoint)
|
||||
.then((response) => {
|
||||
// console.log(response);
|
||||
// res = response;
|
||||
// console.log("~~~~~~~ Toks2 GET ~~~~~~~~");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
//response status is an error code
|
||||
console.log(error.response.status);
|
||||
} else if (error.request) {
|
||||
//response not received though the request was sent
|
||||
console.log(error.request);
|
||||
} else {
|
||||
//an error occurred when setting up the request
|
||||
console.log(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
postAuxEnd(uri, reqData) {
|
||||
const endPoint = process.env.REACT_APP_AUX_ENDPOINT + uri;
|
||||
return Axios.post(endPoint, reqData)
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
// res = response;
|
||||
console.log("~~~~~~~ Toks2 POST ~~~~~~~~");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
//response status is an error code
|
||||
console.log(error.response.status);
|
||||
} else if (error.request) {
|
||||
//response not received though the request was sent
|
||||
console.log(error.request);
|
||||
} else {
|
||||
//an error occurred when setting up the request
|
||||
console.log(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
postAuxEnd(uri, reqData) {
|
||||
const endPoint = process.env.REACT_APP_AUX_ENDPOINT + uri;
|
||||
return Axios.post(endPoint, reqData)
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
// res = response;
|
||||
console.log("~~~~~~~ Toks2 POST ~~~~~~~~");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
//response status is an error code
|
||||
console.log(error.response.status);
|
||||
} else if (error.request) {
|
||||
//response not received though the request was sent
|
||||
console.log(error.request);
|
||||
} else {
|
||||
//an error occurred when setting up the request
|
||||
console.log(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default SiteService;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1064,6 +1078,53 @@ class usersService {
|
||||
return this.postAuxEnd("/blogdata", postData);
|
||||
}
|
||||
|
||||
|
||||
// FUNCTION TO CANCEL TASK OR SEND REMINDER BY FAMILY MEMBER
|
||||
suggestStatus(reqData) {
|
||||
var postData = {
|
||||
uid: localStorage.getItem("uid"),
|
||||
member_id: localStorage.getItem("member_id"),
|
||||
sessionid: localStorage.getItem("session_token"),
|
||||
action: 22026,
|
||||
...reqData,
|
||||
};
|
||||
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)
|
||||
@@ -1176,6 +1237,10 @@ class usersService {
|
||||
console.log(response);
|
||||
// res = response;
|
||||
console.log("~~~~~~~ Toks2 POST ~~~~~~~~");
|
||||
if(response.data.internal_return == '-9999'){
|
||||
localStorage.clear()
|
||||
window.location.href=`/login?sessionExpired=true`
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
+15
-10
@@ -5,27 +5,32 @@ import ModalCom from "../components/Helpers/ModalCom";
|
||||
function AddJobPage({ action, situation, categories }) {
|
||||
return (
|
||||
<ModalCom action={action} situation={situation} className="edit-popup">
|
||||
<div className="lg:w-[600px] w-full lg:overflow-hidden lg:rounded-2xl bg-white dark:bg-dark-white ">
|
||||
<div className="heading flex justify-between items-center py-6 md:px-[30px] px-[23px] border-b dark:border-[#5356fb29] border-light-purple dark:border-[#5356fb29] ">
|
||||
<div className="lg:w-[600px] w-full lg:overflow-hidden lg:rounded-2xl bg-white dark:bg-dark-white dark:text-white">
|
||||
<div className="heading flex justify-between items-center py-6 md:px-[30px] px-[23px] border-b border-light-purple dark:border-[#5356fb29] ">
|
||||
<p className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Create New Job
|
||||
</p>
|
||||
<button type="button" onClick={action}>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={action}
|
||||
>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M32 14.3645C32 15.5022 32 16.6399 32 17.7779C31.8143 17.8408 31.8787 18.0048 31.8565 18.1334C30.6952 24.8402 26.8853 29.2664 20.4091 31.362C19.4672 31.6668 18.4669 31.7917 17.4935 31.9997C16.3558 31.9997 15.2181 31.9997 14.0801 31.9997C13.8574 31.741 13.5279 31.7984 13.2475 31.7416C6.90872 30.4552 2.74424 26.7311 0.684152 20.6107C0.386668 19.7268 0.396442 18.7733 0 17.9199C0 16.6399 0 15.3598 0 14.0798C0.259 13.884 0.190585 13.5694 0.240675 13.3162C1.52285 6.84244 5.35655 2.66392 11.5936 0.623067C12.4549 0.34116 13.3785 0.343909 14.2221 0C15.3125 0 16.4029 0 17.4932 0C17.525 0.110258 17.6111 0.120948 17.7089 0.130417C24.2666 0.77242 29.8064 5.52819 31.449 11.9351C31.6552 12.739 31.8174 13.5542 32 14.3645ZM29.3431 16.0699C29.3718 8.68538 23.4154 2.66942 16.0684 2.66178C8.69759 2.65445 2.66972 8.58489 2.65353 15.8601C2.63704 23.2563 8.52319 29.2979 15.7868 29.3404C23.2862 29.3846 29.3144 23.4832 29.3431 16.0699Z"
|
||||
fill="#374557"
|
||||
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="M14.1604 16.0221C12.3843 14.2567 10.6724 12.5534 8.95837 10.8525C8.53353 10.431 8.23421 9.97162 8.46175 9.34031C8.83956 8.29209 9.95101 8.07371 10.794 8.906C12.3611 10.4536 13.9344 11.9963 15.4529 13.5909C15.9202 14.0817 16.1447 14.0005 16.5662 13.5643C18.0961 11.9804 19.6617 10.4307 21.2282 8.88248C22.0596 8.06058 23.208 8.30064 23.5522 9.35008C23.7584 9.97865 23.459 10.4383 23.0336 10.8619C21.489 12.3991 19.9531 13.9443 18.4088 15.4815C18.2421 15.6476 18.0408 15.779 17.8188 15.9558C19.629 17.7563 21.366 19.4676 23.0831 21.1987C23.934 22.0567 23.6875 23.2106 22.6072 23.556C21.9658 23.761 21.5223 23.4186 21.1067 23.0023C19.5502 21.444 17.9757 19.9031 16.448 18.3171C16.0616 17.9157 15.8854 17.9811 15.5375 18.3378C13.9835 19.9318 12.399 21.4956 10.8242 23.0692C10.4015 23.4916 9.94887 23.7768 9.30961 23.516C8.27819 23.0948 8.06073 22.0814 8.87591 21.2418C10.0307 20.0528 11.2118 18.8891 12.3895 17.7221C12.9588 17.1577 13.5462 16.6106 14.1604 16.0221Z"
|
||||
fill="#374557"
|
||||
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>
|
||||
|
||||
@@ -1,31 +1,37 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import ActiveJobs from "../components/MyActiveJobs/ActiveJobs";
|
||||
import usersService from "../services/UsersService";
|
||||
|
||||
/**
|
||||
* This code defines a React functional component called `ManageActiveJobs`.
|
||||
* It fetches a list of active job messages and renders the `ActiveJobs` component with the necessary props.
|
||||
*/
|
||||
function ManageActiveJobs() {
|
||||
const ApiCall = new usersService();
|
||||
|
||||
let navigate = useNavigate();
|
||||
let { state } = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { state } = useLocation();
|
||||
|
||||
let [details, setDetails] = useState({}); // to hold state values
|
||||
const [details, setDetails] = useState({});
|
||||
|
||||
let [activeJobMesList, setActiveJobMesList] = useState({
|
||||
const [activeJobMesList, setActiveJobMesList] = useState({
|
||||
loading: true,
|
||||
error: false,
|
||||
data: [],
|
||||
});
|
||||
|
||||
let [activeJobMesListReload, setActiveJobMesListReload] = useState(false); // state to determine when ACTIVE JOB MESSAGE LIST RELOADS/RE-RENDERS
|
||||
const [activeJobMesListReload, setActiveJobMesListReload] = useState(false);
|
||||
|
||||
/**
|
||||
* Fetches the active job message list.
|
||||
*/
|
||||
const getActiveJobMesList = () => {
|
||||
// FUNCTION TO GET ACTIVE JOB MESSAGE LIST
|
||||
setActiveJobMesList({ loading: true, error: false, data: [] });
|
||||
let contract = { contract: state.contract };
|
||||
const contract = { contract: state.contract };
|
||||
ApiCall.activeJobMesList(contract)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
if (res.status !== 200 || res.data.internal_return < 0) {
|
||||
setActiveJobMesList({ loading: false, error: false, data: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
import React, { useContext,useState, useEffect } from "react";
|
||||
import usersService from "../services/UsersService";
|
||||
import MyReviewDueJobs from "../components/MyActiveJobs/MyReviewDueJobs";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import MyReviewDueJobs from "../components/MyActiveJobs/MyReviewDueJobs";
|
||||
import usersService from "../services/UsersService";
|
||||
|
||||
/**
|
||||
* React component that fetches a list of review due jobs and renders the `MyReviewDueJobs` component with the fetched data.
|
||||
*/
|
||||
export default function MyReviewDueJobsPage() {
|
||||
let {commonHeadBanner} = useSelector(state => state.commonHeadBanner)
|
||||
const [MyJobList, setMyJobList] = useState([]);
|
||||
const api = new usersService();
|
||||
const getMyJobList = async () => {
|
||||
try {
|
||||
const res = await api.getMyReviewDueJobList();
|
||||
setMyJobList(res.data);
|
||||
} catch (error) {
|
||||
console.log("Error getting mode");
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
getMyJobList();
|
||||
}, []);
|
||||
const { commonHeadBanner } = useSelector((state) => state.commonHeadBanner);
|
||||
const [myJobList, setMyJobList] = useState([]);
|
||||
|
||||
// debugger;
|
||||
return (
|
||||
<>
|
||||
<MyReviewDueJobs
|
||||
MyJobList={MyJobList}
|
||||
commonHeadData={commonHeadBanner.result_list}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
useEffect(() => {
|
||||
const api = new usersService();
|
||||
|
||||
const getMyJobList = async () => {
|
||||
try {
|
||||
const res = await api.getMyReviewDueJobList();
|
||||
setMyJobList(res.data);
|
||||
} catch (error) {
|
||||
console.log("Error getting mode");
|
||||
}
|
||||
};
|
||||
|
||||
getMyJobList();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MyReviewDueJobs
|
||||
myJobList={myJobList}
|
||||
commonHeadData={commonHeadBanner.result_list}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user