Compare commits
428 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2beaa7c2b | |||
| c18373f9db | |||
| 24ac0daf29 | |||
| 4dd58b16d8 | |||
| cc66ebbbde | |||
| 3d61b3259d | |||
| 40b614356f | |||
| dbba6c4014 | |||
| ae93de5f25 | |||
| 4904f1d398 | |||
| 880b084547 | |||
| c807a2657b | |||
| 37a0ffed27 | |||
| 067d9ca5d1 | |||
| 6e3061b9db | |||
| 4f9ca918c9 | |||
| 12f805f0a7 | |||
| 175ac7e2b6 | |||
| bb0796d1e6 | |||
| c0d01e05fe | |||
| 38a888a8a1 | |||
| 8b0aedcbf2 | |||
| dfdccc0287 | |||
| 12512cef97 | |||
| d5d0e64070 | |||
| d55f7ce175 | |||
| f81b687f9f | |||
| 3de1ef71c9 | |||
| fe7d23837c | |||
| bdc000fb8e | |||
| 01f8c7b49b | |||
| 05384fe001 | |||
| 66a43ac636 | |||
| 0ff4e5cf1e | |||
| 6c0a107919 | |||
| 5c8d1e72dd | |||
| 4b11d7ec77 | |||
| baf2ca155f | |||
| fffc51d77a | |||
| c622d73058 | |||
| d0237872ad | |||
| 4403c8650e | |||
| 2afffb1dc9 | |||
| 3a72ebc7a0 | |||
| ecfef0d6e1 | |||
| 7abf4fb7f7 | |||
| 6c601a605a | |||
| 4480e2ebd6 | |||
| 9f11e8b415 | |||
| a1d74b773d | |||
| 7969199584 | |||
| 9dd8f49ff8 | |||
| fa5e9b8107 | |||
| 3e7ab11e62 | |||
| 6f259ad8ad | |||
| a31a20652f | |||
| e3a5952675 | |||
| f48297c5c0 | |||
| 23e5a9aaa4 | |||
| 02d90ebb14 | |||
| 38b979a2e9 | |||
| 93d9afa417 | |||
| 1e2219fb00 | |||
| 560897f6f9 | |||
| 630a029c6e | |||
| 6e2fdc46d1 | |||
| d3b2cddd6c | |||
| f6bd70fdca | |||
| de3bfa2541 | |||
| cd60831f76 | |||
| 71152f7a05 | |||
| 8cbdb1b8a6 | |||
| abbf60ad48 | |||
| c956befed9 | |||
| a5dbeaecbf | |||
| 0b0b563dda | |||
| f8a3e42fe6 | |||
| ced88fa497 | |||
| 89e2527ba6 | |||
| 9e6b59624f | |||
| 1b6b4f17b0 | |||
| 8a9ec35994 | |||
| fa2102eb61 | |||
| bf73461c64 | |||
| 5ffa6eb691 | |||
| 5a0d8aebdb | |||
| e8ed10ddbf | |||
| cca423a41c | |||
| 6a6900a62b | |||
| c6b4fcc43d | |||
| 29510c3b85 | |||
| 1d8e54c57d | |||
| 426599dd1f | |||
| c8d6d3d7d4 | |||
| 593ea74388 | |||
| d81b9970b3 | |||
| 777ff54220 | |||
| 382a266b9a | |||
| 2d80dd9450 | |||
| 0eaa72a5ec | |||
| a2e2df867d | |||
| 10d4e169d3 | |||
| 79ed578483 | |||
| 25440a3c06 | |||
| 5f4c40a318 | |||
| ff7e8ea1ab | |||
| cba14f4265 | |||
| 9c342f87f7 | |||
| 498966dd23 | |||
| b282295924 | |||
| 7222a4d750 | |||
| 271f5635a0 | |||
| 86c4283507 | |||
| 5e5d953769 | |||
| aa7065c5b4 | |||
| 29fee11ec3 | |||
| 264d7b8501 | |||
| 8f90bcdf10 | |||
| 4b897cb3a9 | |||
| 0977650bf4 | |||
| 1f76dd0db8 | |||
| f772cf0a68 | |||
| c4c5c7967e | |||
| 45ecec24ac | |||
| 16fd35df83 | |||
| 3f6a391d30 | |||
| 5eb64f49c0 | |||
| 1761150bd3 | |||
| a4b15dd06e | |||
| 1a15410e4c | |||
| da1133ed43 | |||
| 23605bc358 | |||
| 2092682be6 | |||
| 0e270d8efa | |||
| 3bb4fe6a02 | |||
| fa728d3879 | |||
| a9ce76123b | |||
| 3ac1be9b89 | |||
| e4be117c90 | |||
| 58834cd7ca | |||
| 59945c28e4 | |||
| 0feaf42f49 | |||
| 5a623dd147 | |||
| 9265fde343 | |||
| 452bb73bef | |||
| cfec230ce3 | |||
| 87430f530d | |||
| 52cb0cb2da | |||
| a19df45997 | |||
| 7868e7d689 | |||
| 08f1ae1a9f | |||
| c4cc27490b | |||
| 90b609d457 | |||
| a6c6c36fbc | |||
| 03b79f0e0c | |||
| 0af52df1d2 | |||
| 9e1a68f81a | |||
| 12e4b7824a | |||
| 5769332e74 | |||
| bab0296f4f | |||
| d457550d58 | |||
| f106e17ce6 | |||
| 8f1d2b6584 | |||
| 3a3503447a | |||
| e46d2bea8d | |||
| b05c519571 | |||
| 48ab2d80ad | |||
| 47876875cf | |||
| d78ad0b648 | |||
| d63690a43c | |||
| 3ce97a4b76 | |||
| 6e9af99d46 | |||
| 4ce8f813c4 | |||
| 9163c42d77 | |||
| 3b4ce9c99e | |||
| cfa6117a07 | |||
| 6f26e2e88f | |||
| b7927a9d6a | |||
| 2d366cd103 | |||
| 6eed7bf1f3 | |||
| 3c87a67581 | |||
| e31ee86299 | |||
| 4d3fe6a799 | |||
| 3e8c8e88ea | |||
| feca65eb80 | |||
| 9ea846bc56 | |||
| 8c31eb3145 | |||
| d049d1b2b0 | |||
| d34895c64c | |||
| 9a3fa2a4a4 | |||
| a9d982386c | |||
| 2341d2a17d | |||
| 076df9438d | |||
| bbf03b2b10 | |||
| afead464b0 | |||
| dcdf03e9c5 | |||
| 44e2402cb3 | |||
| 5c223ba641 | |||
| cc0e2c2c6b | |||
| 3df97c0760 | |||
| 6d742e92b5 | |||
| 44090c94a1 | |||
| 63f4658449 | |||
| 552224c489 | |||
| 134be6a1f0 | |||
| fcca050ff6 | |||
| 197dc2e0bc | |||
| e0f8e8df12 | |||
| b5625ab799 | |||
| 9dc8acc584 | |||
| 6d51fdfc19 | |||
| 800c62d76f | |||
| ae23195e0e | |||
| 4ef9b2f20e | |||
| 709b8ea8f2 | |||
| 549af89a43 | |||
| 123ed2056a | |||
| f04f4c713e | |||
| 6d16e7f63f | |||
| 153bc7ab7d | |||
| 054688af8b | |||
| 9994ccc26a | |||
| f5c24ffb0c | |||
| d5ce5d758a | |||
| 0b14c7675b | |||
| 6a3662d69e | |||
| 8a6c8badbe | |||
| 99be0961a9 | |||
| 22bfcbf0c6 | |||
| 7975bd3d11 | |||
| 5475719e7e | |||
| 36420a4b47 | |||
| 6df489a0c2 | |||
| 15adddb0ed | |||
| 83e6cef40a | |||
| 4e275da916 | |||
| 610768f4a5 | |||
| 39e1b05461 | |||
| b89cf9a6bc | |||
| 549d61d81b | |||
| 0ba8bbd2e7 | |||
| 9bdde5376c | |||
| 8e35839ddf | |||
| 4abd8a911b | |||
| a2a9fb2842 | |||
| 9a2fd54bd5 | |||
| d7dbacc69e | |||
| 464969530d | |||
| 7074347289 | |||
| 6a79d6369f | |||
| 984cdeaa24 | |||
| 7946ab12a1 | |||
| 392e0394ed | |||
| a5d534f364 | |||
| 01416ff42c | |||
| 976b4afbbf | |||
| 3818e05d2f | |||
| 5f0364df10 | |||
| 5810345ca7 | |||
| 9adc7eaf1a | |||
| 61d8c938e9 | |||
| b96bb061d0 | |||
| e0a728c5cf | |||
| f63e52422d | |||
| 12a56bdb05 | |||
| 7666d78c0b | |||
| 0a0cca7326 | |||
| 3749fc89db | |||
| fcab0acdad | |||
| 497407112c | |||
| bbbfe799a3 | |||
| 97bfcd68b5 | |||
| 7125ce936e | |||
| a235448897 | |||
| 36479d1246 | |||
| 134f2fbe9f | |||
| c1805376ae | |||
| e60a2aaea2 | |||
| 72118cefc4 | |||
| 30131e53c2 | |||
| 79361f35f2 | |||
| 8749bf9f55 | |||
| 4204b94231 | |||
| 7b1f27a641 | |||
| e4569ca81f | |||
| 58d0fc3dee | |||
| 2f2777cc05 | |||
| e534c81606 | |||
| e76b589e4d | |||
| 1cc0c314a2 | |||
| c01cfa104c | |||
| f5c3922a02 | |||
| 8255eedb00 | |||
| b4ff0b5eca | |||
| 120f2c1866 | |||
| 7389cf164c | |||
| 3700fe066f | |||
| 5e85697c82 | |||
| 5f87c5f36c | |||
| 66b7d20e43 | |||
| c389e06ae6 | |||
| 0b83682da7 | |||
| 78b14ec797 | |||
| 8b0954c28c | |||
| 15ef592252 | |||
| 4d74946f0d | |||
| 78ee32efcc | |||
| a2ef201cfd | |||
| 746cd00ec4 | |||
| 3461b828dd | |||
| d0e1a7acd0 | |||
| c5d84655a9 | |||
| 796f220c1d | |||
| 99ea92ae99 | |||
| d279e707dc | |||
| ba8213d120 | |||
| 0933dc8925 | |||
| fe48c962b2 | |||
| d2738f28d5 | |||
| 0f17783ab5 | |||
| 83f2339a17 | |||
| 13c0571b92 | |||
| a3e53afd99 | |||
| 83f9d5a1f4 | |||
| a16d958fa2 | |||
| 2ffabb63f3 | |||
| 1d673487af | |||
| 313c47f430 | |||
| 67aaf62f7b | |||
| 0526fdb572 | |||
| 7352c30969 | |||
| 7079ae963e | |||
| 9bfe3ce642 | |||
| ff862e72be | |||
| a1dc63e958 | |||
| 465e0745ec | |||
| e8789e7be6 | |||
| e84d583958 | |||
| 06549bf9bb | |||
| 2cd7ce9392 | |||
| 835b583056 | |||
| b72d9ccc35 | |||
| 225166a8be | |||
| b54a6fbee2 | |||
| db03242886 | |||
| 07c20fd927 | |||
| c706b5c143 | |||
| 294f6af6e4 | |||
| 76603294a3 | |||
| 5ff9876681 | |||
| aba23e82a1 | |||
| 7175c217b2 | |||
| 8a81e6da54 | |||
| 36ee1e8987 | |||
| b73a6afeac | |||
| 721c5a588f | |||
| a2431ff825 | |||
| 692fe461c3 | |||
| 3f84eef132 | |||
| 119f48642d | |||
| 1a0f97030f | |||
| 71d1b61bbd | |||
| 17ffe957e8 | |||
| e23aa95685 | |||
| 1c1293989b | |||
| 63448429b2 | |||
| 8d1eac9ff6 | |||
| 25e5c3f47a | |||
| 9f9c36ec85 | |||
| 05eb1a020d | |||
| 30d344833c | |||
| acdf167a69 | |||
| fd00113aab | |||
| 8765329256 | |||
| 3b9c0987b8 | |||
| 0304eaa328 | |||
| 85ac8d183c | |||
| 1aa0fc6016 | |||
| 18b85e0ec9 | |||
| 024c8bbed1 | |||
| 865c61f393 | |||
| bb79342762 | |||
| 413e8e0361 | |||
| ce5438ff85 | |||
| cf644d6349 | |||
| 0f6a49246c | |||
| 6c690fe897 | |||
| 1895b47b76 | |||
| 442fb36578 | |||
| cf157df31e | |||
| 99359d7568 | |||
| 0e09b84be2 | |||
| bbedfbd801 | |||
| 3d940a8629 | |||
| 6c38c6b44c | |||
| aeb22d7f28 | |||
| 1d50790cc1 | |||
| 172c4b7e6f | |||
| 3ea0737341 | |||
| bb0c8c9f34 | |||
| 9139f637cf | |||
| 16401cc3a2 | |||
| 93f26fcfba | |||
| ced9c523ad | |||
| 759269cd74 | |||
| fb27a0d156 | |||
| 03da0e211b | |||
| c00d702a6b | |||
| 206f292dd9 | |||
| abb2329795 | |||
| a92a9f961d | |||
| f90a6e6687 | |||
| b44c039bbf | |||
| 09e0661e48 | |||
| af2c2d66a3 | |||
| b2bfa6cd54 | |||
| 577212eb19 | |||
| f5bf5997d6 | |||
| 42c3676bcf | |||
| 9c00badcf6 | |||
| 85899a72d2 | |||
| 9cd3ef273b | |||
| 918575d802 | |||
| f2070ae31d | |||
| 4d9f0adf0c | |||
| e9271e649f | |||
| f4e5ba1586 | |||
| 3ee01736db |
@@ -9,15 +9,16 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
|
||||
|
||||
# REACT_APP_AUX_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
# REACT_APP_USERS_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
#REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
#REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
|
||||
#REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
#REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
|
||||
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=300000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
|
||||
REACT_APP_SESSION_EXPIRE_CHECKER=60000
|
||||
|
||||
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
|
||||
@@ -45,6 +46,9 @@ REACT_APP_FACEBOOK_CLIENT_ID=390204307987009
|
||||
REACT_APP_FACEBOOK_CLIENT_SECRET=19f778e312f2ab96d147bacb612910c2
|
||||
REACT_APP_FACEBOOK_CLIENT_SCOPE="email, public_profile"
|
||||
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
|
||||
|
||||
#apigate.lotus.g1.wrenchboard.com:76.209.103.227
|
||||
#apigate.orion.g1.wrenchboard.com:76.209.103.227
|
||||
|
||||
@@ -9,15 +9,16 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
|
||||
|
||||
# REACT_APP_AUX_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
# REACT_APP_USERS_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
# REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
# REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
|
||||
|
||||
#REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
#REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
|
||||
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=300000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
|
||||
REACT_APP_SESSION_EXPIRE_CHECKER=60000
|
||||
|
||||
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
|
||||
@@ -37,4 +38,7 @@ REACT_APP_ITEM_PER_PAGE=5
|
||||
REACT_APP_GOOGLE_CLIENT_ID=817021856543-ad9nsjgdpsu2s2jrl63j3ihrv7lbf6ma.apps.googleusercontent.com
|
||||
REACT_APP_GOOGLE_CLIENT_SECRET=aozK_2G8UjaCmLgPPkv9abIm
|
||||
REACT_APP_GOOGLE_CLIENT_SCOPE="https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
|
||||
REACT_APP_GOOGLE_REDIRECT_URL=http://localhost:9082/login/auth/
|
||||
REACT_APP_GOOGLE_REDIRECT_URL=http://localhost:9082/login/auth/
|
||||
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
@@ -9,15 +9,16 @@ REACT_APP_APPSITE="https://myfitapp.mermsemr.com"
|
||||
|
||||
# REACT_APP_AUX_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
# REACT_APP_USERS_ENDPOINT="http://10.20.30.32:9083/svs/user"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/svs/user"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/svs/user"
|
||||
#REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/svs/user"
|
||||
#REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/svs/user"
|
||||
|
||||
#REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
#REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_AUX_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
REACT_APP_USERS_ENDPOINT="https://apigate.orion.g1.wrenchboard.com/en/wrench/api/v1"
|
||||
|
||||
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
|
||||
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=300000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES=600000
|
||||
REACT_APP_SESSION_EXPIRE_MINUTES_FAMILY=600000
|
||||
REACT_APP_SESSION_EXPIRE_CHECKER=60000
|
||||
|
||||
REACT_APP_LOGIN_ERROR_TIMEOUT=7000
|
||||
@@ -37,4 +38,9 @@ REACT_APP_ITEM_PER_PAGE=5
|
||||
REACT_APP_GOOGLE_CLIENT_ID=817021856543-ad9nsjgdpsu2s2jrl63j3ihrv7lbf6ma.apps.googleusercontent.com
|
||||
REACT_APP_GOOGLE_CLIENT_SECRET=aozK_2G8UjaCmLgPPkv9abIm
|
||||
REACT_APP_GOOGLE_CLIENT_SCOPE="https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
|
||||
REACT_APP_GOOGLE_REDIRECT_URL=https://users.wrenchboard.com/login/auth/
|
||||
REACT_APP_GOOGLE_REDIRECT_URL=https://users.wrenchboard.com/login/auth/
|
||||
|
||||
DISABLE_ESLINT_PLUGIN=true
|
||||
|
||||
REACT_APP_MAX_FILE_SIZE=1000000
|
||||
REACT_APP_TOTAL_NUM_FILE=4
|
||||
@@ -14,17 +14,19 @@
|
||||
"chartjs": "^0.3.24",
|
||||
"cors": "^2.8.5",
|
||||
"faker": "^6.6.6",
|
||||
"flutterwave-react-v3": "^1.3.0",
|
||||
"formik": "^2.2.9",
|
||||
"react": "^18.2.0",
|
||||
"react-chartjs-2": "^4.1.0",
|
||||
"react-countup": "^6.2.0",
|
||||
"react-router-dom": "^6.0.2",
|
||||
"react-slick": "^0.29.0",
|
||||
"react-toastify": "^9.0.1",
|
||||
"flutterwave-react-v3": "^1.3.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.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",
|
||||
"web-vitals": "^1.0.1",
|
||||
@@ -54,4 +56,4 @@
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,13 @@ import ManageActiveJobs from "./views/ManageActiveJobs";
|
||||
import FamilyManagePage from "./views/FamilyManagePage";
|
||||
import MyCouponPage from "./views/MyCouponPage";
|
||||
import AuthRedirect from "./views/AuthRedirect";
|
||||
import MyPastDueJobsPage from "./views/MyPastDueJobsPage";
|
||||
import BlogPage from "./views/BlogPage";
|
||||
import MyReviewDueJobsPage from "./views/MyReviewDueJobsPage";
|
||||
import OffersInterestPage from "./views/OffersInterestPage";
|
||||
import ManageInterestOfferPage from './views/ManageInterestOfferPage'
|
||||
import MyWaitingJobsPage from "./views/MyWaitingJobsPage";
|
||||
import FamilyMarketPage from "./views/FamilyMarketPage";
|
||||
|
||||
export default function Routers() {
|
||||
return (
|
||||
@@ -81,16 +88,25 @@ export default function Routers() {
|
||||
<Route exact path="/notification" element={<Notification />} />
|
||||
<Route exact path="/market-place" element={<MarketPlacePage />} />
|
||||
<Route exact path="/market" element={<MarketPlacePage />} />
|
||||
<Route exact path="/familymarket" element={<FamilyMarketPage />} />
|
||||
<Route exact path="/notification" element={<Notification />} />
|
||||
<Route exact path="/mytask" element={<MyTaskPage />} />
|
||||
<Route exact path="/myjobs" element={<MyJobsPage />} />
|
||||
<Route exact path="/add-job" element={<AddJobPage />} />
|
||||
{/* <Route exact path="/add-job" element={<AddJobPage />} /> */}
|
||||
<Route exact path="/my-active-jobs" element={<MyActiveJobsPage />} />
|
||||
<Route exact path="/my-pastdue-jobs" element={<MyPastDueJobsPage />} />
|
||||
<Route exact path="/my-pending-jobs" element={<MyPendingJobsPage />} />
|
||||
<Route exact path="/pend-interest" element={<MyWaitingJobsPage />} />
|
||||
<Route exact path="/my-review-jobs" element={<MyReviewDueJobsPage />} />
|
||||
<Route exact path="/acc-family" element={<FamilyAccPage />} />
|
||||
<Route exact path="/manage-family" element={<FamilyManagePage />} />
|
||||
<Route exact path="/start-job" element={<StartJob />} />
|
||||
<Route exact path="/manage-active-job" element={<ManageActiveJobs />} />
|
||||
<Route exact path="/blog-page" element={<BlogPage />} />
|
||||
<Route exact path="/offer-interest" element={<OffersInterestPage />} />
|
||||
<Route exact path="/manage-offer" element={<ManageInterestOfferPage />} />
|
||||
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/my-collection/collection-item"
|
||||
|
||||
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="905" height="575" viewBox="0 0 905 575" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="905" height="575" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_201_3" transform="matrix(0.00849979 0 0 0.0131639 -0.0662984 -0.354783)"/>
|
||||
</pattern>
|
||||
<image id="image0_201_3" width="130" height="130" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAACCCAMAAAC93eDPAAAApVBMVEX///82OzgAAAAuMi81OjdVXVfqpQCzs7NCSUSwsbAaIBslKyjk5OQuNDAhJiLZ2tpJT0opNTkvNzloVy31rAC1hRtPV1HNzc34+PgaLztBQUHLkg9UVFTw8PDGxsaioqKampp/f39sbGyIiIgaGho9Qj5MTExeXl5fUi+9vb03Nzd2dnYjIyORkZFjZWMNFQ9CQTWYcyLAjBSsfx12XytSSjEQEBBeBsYmAAAEiklEQVR4nO3a7XaqOBQG4BjoQXRraKc1GUoSPgQaETszZ473f2kTqm0VsKLLYs80b3+UhQgPOwlBESETExMTExMTExMTExMTk/9HQDk9xHUdcgiwmk7HPWQ0Gj0HrQiaWvagh9iWztSiTQH3rD4AW4I19nmDUI77EWwJ1ihpENJeWuGdYE0afXHSN2EMdUI/fXGHMK0Piv6rcJhg39VyadpRwt3g6Y+9PNl3/RLsvx7va3kcXLYOxwh/Ptz/qOX+79t+CY91wY8fD4ZgCIbwvQn/NAT3P/sl3P3bENz/uuwkcXSaun162M/PX5ctQofJ+u62lgtPlL/HLYshGIIhfDGC3chZ65ur7c6EYSN2+/r0wPYvn4/ttH19B4Lt3TRSGexZc316YP3LgZrrZ9sqTK5PsK7fEMcJn90d7eOEz84XIEyuT7CuTrCvT5hcn2BdnWBfnbAj+CaEtyvizrXROpfQOu0fAwyGnucN9X89XeiltPrebnIuwU5nO+n2dbmdbqfH1B6+Le02w4mEvYnX60J4PW61/fukb51PGO4SulWheRehMecTTu8LbTc+NzMvPZ9wctrupW505+yR0NYOelR41yVUgq5VaLnjOvmy0GyIStC5L6RH0okwbBN4g06ExpubFe00JPbKMNsIOl4XWofT6YTB4HU/3mDWLjjpc8RevE4APSF4VSFmQ31VTl8AqdWZcInuuEFUHWczLdgDuw7o637BnjSP/AHh8o9KPwR8fhXslsrXCfUHxpd8bH7k9LdpPDZHyajL+y6XUdQggD/uUzAeNNoBIWpN+xNMJy0/JNF1mD2Pespz0FKDDcJxe4k6BDAxMTExMTH5kunjZ8cfB+Gr53sTluE7YQ0gBSGrBEgEROIcCA0oVnEEkFfbCp44ZUYDAhLjiGAKCiugmASlXAGMa/teEBCLHCCSYZmEofBlqUIcACQ44r4PoJbVZnOk3ghzFPlMujyEbIViH8es4C6LSAKuAP16gaqlAlwomY9DVrCElSjhCVfSAYe6NYLPSq6oCFmohFIhl64kLqYkZEuFogzlqMSZEPo2nr4TijVLQk1YBihYa0IGigMNeZRF+vUcFTiGkiqxTpa45BIWUjIfQs4dh8KiXmGfBZQSqc9EACExsBcCuDHyKXd8hLmu9GY8wvKVADHnKJZIBIis8AoByTnoc4k2Z6hPeYlUKIRUfkXgcxxpQskBqTlhywYh3xB8DkRvByysCE6McghptiGwjYG+EgLMSigkwQHS5xTzAGdQIk2QVUP4q5BlnOVC5PqVqgq+cF+qkCCV64odICCMqEBLvadwW4UYCcj3quC/E1BElS5wjlaLqiFwwHUPAf2ho1jhGCUso2jh8IgFVV9ACSpRxBO2Ig4oShuEgju6ZJrgKraEgEmilrovaHKk/wKUbPsCmb+OCJphEReioDTRG+JAl9tXa7mKiZLSxWtJEpyo+ZwKx8eFwEoPG71XLLKo9Cmtd4aFomrp616gB1Xhrp0sSiQlmSBx4uLqKHK+GRHibUR8mCQ4tsW5mUrcjfD5+QKE/wC0yMO17JCUyAAAAABJRU5ErkJggg=="/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" ?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 52 52" data-name="Layer 1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"><path d="M14,16H2a2,2,0,0,1-2-2V2A2,2,0,0,1,2,0H14a2,2,0,0,1,2,2V14A2,2,0,0,1,14,16ZM4,12h8V4H4Z"/><path d="M14,34H2a2,2,0,0,1-2-2V20a2,2,0,0,1,2-2H14a2,2,0,0,1,2,2V32A2,2,0,0,1,14,34ZM4,30h8V22H4Z"/><path d="M14,52H2a2,2,0,0,1-2-2V38a2,2,0,0,1,2-2H14a2,2,0,0,1,2,2V50A2,2,0,0,1,14,52ZM4,48h8V40H4Z"/><path d="M32,16H20a2,2,0,0,1-2-2V2a2,2,0,0,1,2-2H32a2,2,0,0,1,2,2V14A2,2,0,0,1,32,16ZM22,12h8V4H22Z"/><path d="M32,34H20a2,2,0,0,1-2-2V20a2,2,0,0,1,2-2H32a2,2,0,0,1,2,2V32A2,2,0,0,1,32,34ZM22,30h8V22H22Z"/><path d="M32,52H20a2,2,0,0,1-2-2V38a2,2,0,0,1,2-2H32a2,2,0,0,1,2,2V50A2,2,0,0,1,32,52ZM22,48h8V40H22Z"/><path d="M50,16H38a2,2,0,0,1-2-2V2a2,2,0,0,1,2-2H50a2,2,0,0,1,2,2V14A2,2,0,0,1,50,16ZM40,12h8V4H40Z"/><path d="M50,34H38a2,2,0,0,1-2-2V20a2,2,0,0,1,2-2H50a2,2,0,0,1,2,2V32A2,2,0,0,1,50,34ZM40,30h8V22H40Z"/><path d="M50,52H38a2,2,0,0,1-2-2V38a2,2,0,0,1,2-2H50a2,2,0,0,1,2,2V50A2,2,0,0,1,50,52ZM40,48h8V40H40Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" id="delete"><g color="#000"><path fill="#ee4c45" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;block-progression:tb;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" d="M12 1028.362c-6.626 0-12 5.374-12 12s5.374 12 12 12 12-5.374 12-12-5.374-12-12-12z" font-family="sans-serif" font-weight="400" overflow="visible" transform="translate(0 -1028.362)"></path><path fill="#fff" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" d="M10.5 1034.362v1h-3v1h9v-1h-3v-1h-3zm-2 3v9h7v-9h-7zm1 1h1v7h-1v-7zm2 0h1v7h-1v-7zm2 0h1v7h-1v-7z" overflow="visible" transform="translate(0 -1028.362)"></path></g></svg>
|
||||
|
After Width: | Height: | Size: 841 B |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 60 60" viewBox="0 0 60 60" id="edit"><path fill="#3B4652" d="M52.9687347,19.3099976l-2.7999878-2.7999878c-0.9099731-0.9100342-2.3899536-0.9100342-3.2999878,0
|
||||
l-1.4129639,1.4129639c0.0185547,0.017395,0.0423584,0.0234985,0.0601196,0.0422974l5.7765503,6.1199341
|
||||
c0.0361328,0.038269,0.0506592,0.0881348,0.0813599,0.1296997l1.5949097-1.5949097
|
||||
C53.8787689,21.7099609,53.8787689,20.2199707,52.9687347,19.3099976z"></path><path fill="#2B79C2" d="M10.8887787,25.5499878H34.998764l7.5900269-7.5900269l1.7599487-1.75V9c0-1.6500244-1.3499756-3-3-3h-32
|
||||
c-1.6599731,0-3,1.3499756-3,3v42c0,1.6499634,1.3400269,3,3,3h32c1.6500244,0,3-1.3500366,3-3V34.0700073l-5.8899536,5.8800049
|
||||
c-0.3099976,0.3199463-0.7000122,0.5599976-1.1199951,0.7099609l-7.2200317,2.5200195
|
||||
c-0.3099976,0.1099854-0.6500244,0.1699829-0.9899902,0.1699829c-0.7800293,0-1.5200195-0.2999878-2.0900269-0.8399658
|
||||
c-0.3399658-0.3400269-0.5799561-0.7400513-0.7299805-1.1600342H10.8887787c-0.5599976,0-1-0.4500122-1-1s0.4400024-1,1-1
|
||||
h15.4199829v-0.0100098l1.7000122-4.8899536H10.8887787c-0.5599976,0-1-0.4500122-1-1c0-0.5500488,0.4400024-1,1-1H28.708786
|
||||
l0.0999756-0.3000488c0.1699829-0.4699707,0.4400024-0.8800049,0.789978-1.1900024l3.4000244-3.4099731H10.8887787
|
||||
c-0.5599976,0-1-0.4500122-1-1S10.3287811,25.5499878,10.8887787,25.5499878z M10.8887787,46.25h24.9099731
|
||||
c0.5599976,0,1,0.4500122,1,1s-0.4400024,1-1,1H10.8887787c-0.5599976,0-1-0.4500122-1-1S10.3287811,46.25,10.8887787,46.25z
|
||||
M10.8887787,11.75h24.9099731c0.5599976,0,1,0.4500122,1,1s-0.4400024,1-1,1H10.8887787c-0.5599976,0-1-0.4500122-1-1
|
||||
S10.3287811,11.75,10.8887787,11.75z M10.8887787,18.6499634h24.9099731c0.5599976,0,1,0.4500122,1,1c0,0.5500488-0.4400024,1-1,1
|
||||
H10.8887787c-0.5599976,0-1-0.4499512-1-1C9.8887787,19.0999756,10.3287811,18.6499634,10.8887787,18.6499634z"></path><path fill="#3B4652" d="M30.9387665,32.4400024c-0.1099854,0.0999756-0.1900024,0.2299805-0.2399902,0.3699951
|
||||
l-2.5100098,7.2099609c-0.1300049,0.3600464-0.039978,0.7700195,0.2299805,1.0400391
|
||||
c0.2000122,0.1900024,0.4500122,0.289978,0.710022,0.289978c0.1099854,0,0.2199707-0.0200195,0.3300171-0.0599976
|
||||
l7.2099609-2.5100098c0.1400146-0.0499878,0.2700195-0.1300049,0.3800049-0.2399902l12.5599976-12.5599976l-5.9299927-6.2799683
|
||||
L30.9387665,32.4400024z"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 441 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,73 +1,66 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Field, Form, Formik } from "formik";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import * as Yup from "yup";
|
||||
import usersService from "../../services/UsersService";
|
||||
import { tableReload } from "../../store/TableReloads";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { Field, Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
country: Yup.string()
|
||||
.min(1, "Minimum 3 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Country is required"),
|
||||
price: Yup.number()
|
||||
.typeError("you must specify a number")
|
||||
price: 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("Price is required"),
|
||||
title: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(100, "Maximum 25 characters")
|
||||
.min(5, "Minimum 5 characters")
|
||||
.max(149, "Maximum 149 characters")
|
||||
.required("Title is required"),
|
||||
description: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(250, "Maximum 250 characters")
|
||||
.min(5, "Minimum 5 characters")
|
||||
.max(299, "Maximum 299 characters")
|
||||
.required("Description is required"),
|
||||
job_detail: Yup.string()
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(250, "Maximum 250 characters")
|
||||
.max(1440, "Maximum 1440 characters")
|
||||
.required("Details is required"),
|
||||
timeline_days: Yup.number()
|
||||
.typeError("you must specify a number")
|
||||
.min(1, "Price must be greater than 0")
|
||||
.required("Timeline is required"),
|
||||
category: Yup.array().min(1, "Select at least one checkbox"),
|
||||
});
|
||||
|
||||
// let initialValues = {
|
||||
// // initial values for formik
|
||||
// country: "NG",
|
||||
// price: 0,
|
||||
// title: "",
|
||||
// description: "",
|
||||
// job_detail: "",
|
||||
// timeline_days: "",
|
||||
// };
|
||||
|
||||
function AddJob() {
|
||||
function AddJob({ popUpHandler, categories }) {
|
||||
const ApiCall = new usersService();
|
||||
const navigate = useNavigate();
|
||||
|
||||
let { userDetails } = useSelector((state) => state.userDetails);
|
||||
let dispatch = useDispatch();
|
||||
|
||||
let [pageLoading, setPageLoading] = useState(true); // State used for knowing when the page is mounting
|
||||
|
||||
let [country, setCountry] = useState({
|
||||
let [currency, setCurrency] = useState({
|
||||
loading: true,
|
||||
status: false,
|
||||
data: [],
|
||||
}); // To Hold the array of country getUserCountry returns
|
||||
data: null,
|
||||
}); // To Hold the array of currency getUserCurrency returns
|
||||
|
||||
let initialValues = {
|
||||
// initial values for formik
|
||||
country: userDetails.country,
|
||||
country: "",
|
||||
price: "",
|
||||
title: "",
|
||||
description: "",
|
||||
job_detail: "",
|
||||
timeline_days: "",
|
||||
category: [],
|
||||
};
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
@@ -76,30 +69,42 @@ function AddJob() {
|
||||
message: "",
|
||||
}); // Holds state when submit button is pressed
|
||||
|
||||
// FUNCTION TO GET COUNTRY
|
||||
const getUserCountry = () => {
|
||||
setCountry((prev) => ({ ...prev, loading: true }));
|
||||
ApiCall.getSignupCountryData()
|
||||
// FUNCTION TO GET Currency
|
||||
const getUserCurrency = () => {
|
||||
setCurrency((prev) => ({ ...prev, loading: true }));
|
||||
ApiCall.getUserWallets()
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 1) {
|
||||
setCountry({ loading: false, status: true, data: [] });
|
||||
if (res.data.internal_return < 0) {
|
||||
setCurrency({ loading: false, status: true, data: [] });
|
||||
return;
|
||||
}
|
||||
setCountry({
|
||||
console.log("Res for currency >> ", res);
|
||||
|
||||
setCurrency({
|
||||
loading: false,
|
||||
status: true,
|
||||
data: res.data.signup_country,
|
||||
data: res.data.result_list,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
setCountry({ loading: false, status: false, data: [] });
|
||||
setCurrency({ loading: false, status: false, data: [] });
|
||||
});
|
||||
};
|
||||
|
||||
// FUNCTION TO HANDLE ADD JOB FORM
|
||||
const handleAddJob = (values, helpers) => {
|
||||
let reqData = {
|
||||
country: values?.country,
|
||||
price: Number(values.price) * 100,
|
||||
title: values?.title,
|
||||
description: values?.description,
|
||||
job_detail: values?.job_detail,
|
||||
timeline_days: values?.timeline_days,
|
||||
category: values.category?.join("@"),
|
||||
};
|
||||
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
ApiCall.jobManagerCreateJob(values)
|
||||
ApiCall.jobManagerCreateJob(reqData)
|
||||
.then((res) => {
|
||||
if (res.data.internal_return < 1) {
|
||||
setRequestStatus({
|
||||
@@ -107,6 +112,9 @@ function AddJob() {
|
||||
status: false,
|
||||
message: "Could not complete your request at the moment",
|
||||
});
|
||||
setTimeout(() => {
|
||||
popUpHandler();
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
setRequestStatus({
|
||||
@@ -115,14 +123,15 @@ function AddJob() {
|
||||
message: "Job Added Successfully",
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate("/myjobs", { replace: true });
|
||||
dispatch(tableReload({ type: "JOBTABLE" }));
|
||||
popUpHandler();
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "Opps! soemthing went wrong. Try Again",
|
||||
message: "Opps! something went wrong. Try Again",
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -133,17 +142,10 @@ function AddJob() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getUserCountry();
|
||||
setPageLoading(false);
|
||||
getUserCurrency();
|
||||
}, []);
|
||||
|
||||
return pageLoading.loading ? (
|
||||
<div className="personal-info-tab w-full flex flex-col justify-between">
|
||||
<div className="p-3">
|
||||
<LoadingSpinner size="32" color="sky-blue" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
return (
|
||||
<div className="add-job p-5 w-full bg-white rounded-md flex flex-col justify-between">
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
@@ -153,64 +155,44 @@ function AddJob() {
|
||||
{(props) => {
|
||||
return (
|
||||
<Form>
|
||||
<h1 className="py-2 my-4 text-lg md:text-xl font-bold tracking-wide">
|
||||
Create New Job
|
||||
</h1>
|
||||
<div className="flex flex-col-reverse sm:flex-row">
|
||||
<div className="fields w-full">
|
||||
{/* inputs starts here */}
|
||||
{/* country */}
|
||||
<div className="xl:flex xl:space-x-7 mb-6">
|
||||
<div className="xl:flex xl:space-x-7 mb-[5px]">
|
||||
<div className="field w-full mb-6 xl:mb-0">
|
||||
{/* <InputCom
|
||||
fieldClass="px-6 cursor-not-allowed"
|
||||
label="Country"
|
||||
labelClass='tracking-wide'
|
||||
inputBg = 'bg-slate-100'
|
||||
type="text"
|
||||
name="country"
|
||||
disable={true}
|
||||
value={country.loading ? 'loading' : country.data ? country.data : 'no country found!'}
|
||||
inputHandler={(e)=> setCountry((prev) => ({...prev, data:e.target.value}))}
|
||||
|
||||
/> */}
|
||||
<label
|
||||
htmlFor="country"
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1"
|
||||
>
|
||||
Country
|
||||
Currency
|
||||
{props.errors.country && props.touched.country && <span className="text-[12px] text-red-500">{props.errors.country}</span>}
|
||||
</label>
|
||||
<select
|
||||
id="country"
|
||||
name="country"
|
||||
disabled
|
||||
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`}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
>
|
||||
{country.loading ? (
|
||||
{currency.loading ? (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Loading...
|
||||
</option>
|
||||
) : country.data.length ? (
|
||||
) : currency.data.length ? (
|
||||
<>
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
Select...
|
||||
Select a currency
|
||||
</option>
|
||||
{country.data.map((item, index) => {
|
||||
if (item[0] == userDetails.country) {
|
||||
return (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item[0]}
|
||||
>
|
||||
{item[1]}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
})}
|
||||
{currency.data?.map((item, index) => (
|
||||
<option
|
||||
key={index}
|
||||
className="text-slate-500 text-lg"
|
||||
value={item?.country}
|
||||
>
|
||||
{item?.description}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<option className="text-slate-500 text-lg" value="">
|
||||
@@ -218,11 +200,6 @@ function AddJob() {
|
||||
</option>
|
||||
)}
|
||||
</select>
|
||||
{props.errors.country && props.touched.country && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.country}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Price */}
|
||||
@@ -238,18 +215,14 @@ function AddJob() {
|
||||
value={props.values.price}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.price && props.touched.price && props.errors.price}
|
||||
/>
|
||||
{props.errors.price && props.touched.price && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.price}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
|
||||
<div className="field w-full mb-6">
|
||||
<div className="field w-full mb-[5px]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Title"
|
||||
@@ -257,20 +230,15 @@ function AddJob() {
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="title"
|
||||
// placeholder="Enter Job Title"
|
||||
value={props.values.title}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.title && props.touched.title && props.errors.title}
|
||||
/>
|
||||
{props.errors.title && props.touched.title && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.title}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="field w-full mb-6">
|
||||
<div className="field w-full mb-[5px]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Description"
|
||||
@@ -278,44 +246,71 @@ function AddJob() {
|
||||
inputBg="bg-slate-100"
|
||||
type="text"
|
||||
name="description"
|
||||
// placeholder="Enter a description"
|
||||
value={props.values.description}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={props.errors.description && props.touched.description && props.errors.description}
|
||||
/>
|
||||
{props.errors.description && props.touched.description && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Details */}
|
||||
<div className="field w-full mb-6">
|
||||
<label
|
||||
htmlFor="Job Delivery Details"
|
||||
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"'
|
||||
>
|
||||
Job Delivery Details
|
||||
</label>
|
||||
<textarea
|
||||
id="Job Delivery Details"
|
||||
rows="7"
|
||||
className={`input-field p-6 mt-3 rounded-md placeholder:text-base text-dark-gray dark:text-white w-full h-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none`}
|
||||
style={{ resize: "none" }}
|
||||
name="job_detail"
|
||||
value={props.values.job_detail}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
/>
|
||||
{props.errors.job_detail && props.touched.job_detail && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.job_detail}
|
||||
</p>
|
||||
)}
|
||||
<div className="field flex flex-col sm:flex-row w-full mb-[5px] gap-2">
|
||||
<div className="sm:w-[60%] w-full">
|
||||
<label
|
||||
htmlFor="Job Delivery Details"
|
||||
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1'
|
||||
>
|
||||
Job Delivery Details
|
||||
{props.errors.job_detail && props.touched.job_detail && <span className="text-[12px] text-red-500">{props.errors.job_detail}</span>}
|
||||
</label>
|
||||
<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]`}
|
||||
style={{ resize: "none" }}
|
||||
name="job_detail"
|
||||
value={props.values.job_detail}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="sm:w-[35%] w-full">
|
||||
<div
|
||||
htmlFor="Job Categories"
|
||||
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"'
|
||||
id="checked-group"
|
||||
>
|
||||
Categories
|
||||
</div>
|
||||
<div
|
||||
className="sm:flex-col flex flex-wrap px-3 mt-3"
|
||||
role="group"
|
||||
aria-labelledby="checked-group"
|
||||
>
|
||||
{Object?.entries(categories).map(([key, value]) => (
|
||||
<label
|
||||
key={key}
|
||||
className="flex gap-1 w-full items-center"
|
||||
>
|
||||
<Field
|
||||
type="checkbox"
|
||||
name="category"
|
||||
value={key}
|
||||
/>
|
||||
<span className="text-[13.975px]">{value}</span>
|
||||
</label>
|
||||
))}
|
||||
<span className="h-5 text-sm italic text-[#cf3917]">
|
||||
{props.errors.category &&
|
||||
props.touched.category &&
|
||||
"please select a category"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field w-full mb-6">
|
||||
<div className="field w-full mb-[5px]">
|
||||
<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 block"
|
||||
@@ -331,7 +326,12 @@ function AddJob() {
|
||||
<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 ${
|
||||
props.errors.timeline_days &&
|
||||
props.touched.timeline_days
|
||||
? "border-[#ff0a0a63] shadow-red-500 border-[0.5px] animate-shake"
|
||||
: "border border-[#f5f8fa] dark:border-[#5e6278]"
|
||||
}`}
|
||||
value={props.values.timeline_days}
|
||||
>
|
||||
<option value="">Select Duration</option>
|
||||
@@ -344,12 +344,6 @@ function AddJob() {
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
{props.errors.timeline_days &&
|
||||
props.touched.timeline_days && (
|
||||
<p className="text-sm text-red-500">
|
||||
{props.errors.timeline_days}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{/* inputs ends here */}
|
||||
</div>
|
||||
@@ -376,17 +370,20 @@ function AddJob() {
|
||||
))}
|
||||
{/* End of error or success display */}
|
||||
|
||||
<div className="w-full h-[120px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
||||
<div className="w-full h-[70px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
||||
<div className="flex items-center space-x-4 mr-9">
|
||||
<Link
|
||||
to="/myjobs"
|
||||
<button
|
||||
type="button"
|
||||
className="text-18 text-light-red tracking-wide "
|
||||
>
|
||||
<span className="border-b dark:border-[#5356fb29] border-light-red">
|
||||
<span
|
||||
className="border-b dark:border-[#5356fb29] border-light-red"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
{" "}
|
||||
Cancel
|
||||
</span>
|
||||
</Link>
|
||||
</button>
|
||||
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
@@ -424,3 +421,10 @@ const publicArray = [
|
||||
{ duration: 21, name: "3 weeks" },
|
||||
{ duration: 28, name: "4 weeks" },
|
||||
];
|
||||
|
||||
// .test("no-e", "Invalid number", (value) => {
|
||||
// if (value && /\d+e/.test(value)) {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// })
|
||||
|
||||
@@ -4,12 +4,12 @@ import { Link } from "react-router-dom";
|
||||
export default function LoginLayout({ slogan, children }) {
|
||||
return (
|
||||
<div className={`layout-wrapper login`}>
|
||||
<div className={`main-wrapper login-wrapper w-full h-screen overflow-y-auto p-2 sm:p-20`}>
|
||||
<div className={`main-wrapper login-wrapper w-full h-screen overflow-y-auto p-2 sm:px-20 sm:py-5`}>
|
||||
<div className="w-full h-full">
|
||||
<div className="flex-1 flex justify-center items-center">
|
||||
{children && children}
|
||||
</div>
|
||||
<div className="flex-1 flex justify-center items-center p-10">
|
||||
<div className="flex-1 flex justify-center items-center px-10 pt-10">
|
||||
<div className="flex items-center">
|
||||
<a
|
||||
href="https://www.wrenchboard.com/about-us"
|
||||
@@ -37,7 +37,7 @@ export default function LoginLayout({ slogan, children }) {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 flex justify-center items-center p-10">
|
||||
<div className="flex-1 flex justify-center items-center px-10 py-1">
|
||||
<p className="text-black text-[15px] px-2 font-medium flex items-center">
|
||||
<span className="text-3xl mt-2 mr-1">©</span> 2023 - {" "}
|
||||
<Link to="/" className="text-[#009ef7] ml-1">
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function CollectionTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<CollectionCard key={datas.uniqKey} collectionData={datas} />
|
||||
|
||||
@@ -42,7 +42,9 @@ export default function CreateSaleSlider({
|
||||
{/* heading */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">Create for Sell</h1>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
Create for Sell
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<button onClick={nextHandler} type="button">
|
||||
@@ -89,7 +91,7 @@ export default function CreateSaleSlider({
|
||||
<div className="trending-products relative w-full">
|
||||
<SliderCom selector={trendingSlider} settings={settings}>
|
||||
{products &&
|
||||
products.length > 0 &&
|
||||
products?.length > 0 &&
|
||||
products.map((item) => (
|
||||
<ProductCardStyleTwo
|
||||
key={item.id}
|
||||
|
||||
@@ -49,7 +49,9 @@ export default function CreatedBidsSlider({
|
||||
{/* heading */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">Create for Bits</h1>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
Create for Bits
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<button onClick={nextHandler} type="button">
|
||||
@@ -96,7 +98,7 @@ export default function CreatedBidsSlider({
|
||||
<div className="trending-products relative w-full">
|
||||
<SliderCom selector={trendingSlider} settings={settings}>
|
||||
{products &&
|
||||
products.length > 0 &&
|
||||
products?.length > 0 &&
|
||||
products.map((item) => (
|
||||
<ProductCardStyleOne
|
||||
key={item.id}
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function OnSaleTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<ProductCardStyleTwo key={datas.id} datas={datas} />
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function OwnTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<ProductCardStyleOne key={datas.id} datas={datas} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useLayoutEffect, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import linkedInLogo from "../../../assets/images/Linkedin.png";
|
||||
import appleLogo from "../../../assets/images/apple-black.svg";
|
||||
@@ -17,7 +17,7 @@ import { updateUserDetails } from "../../../store/UserDetails";
|
||||
export default function Login() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
let [loginType, setLoginType] = useState({ full: true, family: false });
|
||||
let [loginType, setLoginType] = useState('');
|
||||
|
||||
const [checked, setValue] = useState(false);
|
||||
const [loginLoading, setLoginLoading] = useState(false);
|
||||
@@ -33,11 +33,12 @@ export default function Login() {
|
||||
|
||||
//FUNCTION TO DETERMINE/CHANGE LOGIN COMPONENT
|
||||
const handleLoginType = ({ target: { name } }) => {
|
||||
if (name == "full") {
|
||||
setLoginType({ [name]: true, family: false });
|
||||
} else if ((name = "family")) {
|
||||
setLoginType({ [name]: false, family: true });
|
||||
}
|
||||
setLoginType(name);
|
||||
let currentDate = new Date();
|
||||
let expirationDate = new Date(currentDate.getTime() + (24 * 60 * 60 * 1000));
|
||||
// Convert the expiration date to the appropriate format
|
||||
let expirationDateString = expirationDate.toUTCString();
|
||||
document.cookie = `loginType=${name}; expires=${expirationDateString}; path=/;`;
|
||||
};
|
||||
|
||||
// email
|
||||
@@ -68,7 +69,7 @@ export default function Login() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "loginfull") {
|
||||
if (name == "full") {
|
||||
// Post Data Info for normal Login
|
||||
postData = {
|
||||
username: email,
|
||||
@@ -77,7 +78,7 @@ export default function Login() {
|
||||
login_mode: 1100,
|
||||
action: 11025,
|
||||
};
|
||||
} else if (name == "loginfamily") {
|
||||
} else if (name == "family") {
|
||||
// Post Data Info for family Login
|
||||
postData = {
|
||||
username: email,
|
||||
@@ -127,25 +128,59 @@ export default function Login() {
|
||||
};
|
||||
|
||||
const googleLogin = useGoogleLogin({
|
||||
flow: 'auth-code',
|
||||
ux_mode:'redirect',
|
||||
flow: "auth-code",
|
||||
ux_mode: "redirect",
|
||||
redirect_uri: process.env.REACT_APP_GOOGLE_REDIRECT_URL,
|
||||
onSuccess: async (codeResponse) => {
|
||||
console.log(codeResponse);
|
||||
console.log("GOOGLE LOGIN GOOD --- ", codeResponse);
|
||||
},
|
||||
onError: (errorResponse) => console.log(errorResponse),
|
||||
});
|
||||
|
||||
// In order to update the selected login type whenever the component renders
|
||||
// useEffect(() => {
|
||||
// Clear the loginType cookie if the user switches to loginfull
|
||||
// document.cookie ="loginType=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
// }, []);
|
||||
|
||||
useLayoutEffect(()=>{ // checks the cookie in order to set the login type before components mounts
|
||||
// if(document.cookie.includes("loginType=family")){
|
||||
// setLoginType('family')
|
||||
// }else if(document.cookie.includes("loginType=full")){
|
||||
// setLoginType('full')
|
||||
// }else{
|
||||
// setLoginType('full')
|
||||
// }
|
||||
function readCookie(cname) { // checks the cookie in order to set the login type before components mounts
|
||||
let name = cname + "=";
|
||||
let decoded_cookie = decodeURIComponent(document.cookie);
|
||||
let carr = decoded_cookie.split(';');
|
||||
for(let i=0; i<carr.length;i++){
|
||||
let c = carr[i];
|
||||
while(c.charAt(0)==' '){
|
||||
c=c.substring(1);
|
||||
}
|
||||
if(c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return 'full'
|
||||
}
|
||||
let loginValue = readCookie('loginType')
|
||||
setLoginType(loginValue)
|
||||
},[loginType])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setMail("");
|
||||
setPassword("");
|
||||
}, [loginType.full, loginType.family]);
|
||||
}, [loginType]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthLayout slogan="Welcome to WrenchBoard">
|
||||
<div className="w-full">
|
||||
<div className="mb-12">
|
||||
<div className="mb-5">
|
||||
<Link to="#">
|
||||
<img
|
||||
src={WrenchBoard}
|
||||
@@ -176,7 +211,7 @@ export default function Login() {
|
||||
<button
|
||||
name="full"
|
||||
className={`px-2 py-1 w-[100px] text-left h-[40px] text-lg font-bold text-[#4687ba] hover:text-[#009ef7] tracking-wide transition outline-none border-2 border-b-0 border-r-0 border-[#4687ba] ${
|
||||
loginType.full && "border-r-2 h-[45px]"
|
||||
loginType=='full' && "border-r-2 h-[45px]"
|
||||
}`}
|
||||
onClick={handleLoginType}
|
||||
>
|
||||
@@ -185,7 +220,7 @@ export default function Login() {
|
||||
<button
|
||||
name="family"
|
||||
className={`px-2 py-1 w-[100px] text-left h-[40px] text-lg font-bold text-[#4687ba] hover:text-[#009ef7] tracking-wide transition outline-none border-2 border-b-0 border-l-0 border-[#4687ba] ${
|
||||
loginType.family && "border-l-2 h-[45px]"
|
||||
loginType=='family' && "border-l-2 h-[45px]"
|
||||
}`}
|
||||
onClick={handleLoginType}
|
||||
>
|
||||
@@ -197,7 +232,7 @@ export default function Login() {
|
||||
|
||||
{/* for login component */}
|
||||
{
|
||||
loginType.full ? (
|
||||
loginType == 'full' ? (
|
||||
//user login component
|
||||
<div className="p-2 input-area border-2 border-[#4687ba]">
|
||||
<div className="input-item mb-5">
|
||||
@@ -206,7 +241,7 @@ export default function Login() {
|
||||
fieldClass="sm:px-6 px-2"
|
||||
value={email}
|
||||
inputHandler={handleEmail}
|
||||
placeholder="support@mermsemr.com"
|
||||
placeholder="Your Email"
|
||||
label="Email"
|
||||
name="email"
|
||||
type="email"
|
||||
@@ -248,7 +283,7 @@ export default function Login() {
|
||||
<div className="signin-area mb-3.5">
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
name="loginfull"
|
||||
name="full"
|
||||
onClick={doLogin}
|
||||
type="button"
|
||||
disabled={loginLoading}
|
||||
@@ -294,7 +329,7 @@ export default function Login() {
|
||||
fieldClass="px-6"
|
||||
value={email}
|
||||
inputHandler={handleEmail}
|
||||
placeholder="support@mermsemr.com"
|
||||
placeholder="Account ID"
|
||||
label="Username"
|
||||
name="email"
|
||||
type="email"
|
||||
@@ -336,7 +371,7 @@ export default function Login() {
|
||||
<div className="signin-area mb-1.5">
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
name="loginfamily"
|
||||
name="family"
|
||||
onClick={doLogin}
|
||||
disabled={loginLoading}
|
||||
type="button"
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function SignUp() {
|
||||
|
||||
if (res.status === 200) {
|
||||
const { data } = res;
|
||||
if (data.status === -1 && data.acc === "DULPICATE") {
|
||||
if (data && data.acc === "DULPICATE") {
|
||||
setMsgError("This account has been already created");
|
||||
setSignUpLoading(false);
|
||||
}
|
||||
@@ -108,12 +108,12 @@ export default function SignUp() {
|
||||
|
||||
useEffect(() => {
|
||||
getCountryList();
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="layout-wrapper login">
|
||||
<div className="main-wrapper w-full xl:h-screen h-full xl:py-10 py-12 overflow-y-auto">
|
||||
<div className="main-wrapper login-wrapper w-full xl:h-screen h-full xl:py-10 py-12 overflow-y-auto">
|
||||
<div className=" h-full">
|
||||
<div className="flex-1 flex justify-center items-center">
|
||||
<div className="w-full">
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function CollectionTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<CollectionCard key={datas.uniqKey} collectionData={datas} />
|
||||
|
||||
@@ -42,7 +42,9 @@ export default function CreateSaleSlider({
|
||||
{/* heading */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">Create for Sell</h1>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
Create for Sell
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<button onClick={nextHandler} type="button">
|
||||
@@ -89,7 +91,7 @@ export default function CreateSaleSlider({
|
||||
<div className="trending-products relative w-full">
|
||||
<SliderCom selector={trendingSlider} settings={settings}>
|
||||
{products &&
|
||||
products.length > 0 &&
|
||||
products?.length > 0 &&
|
||||
products.map((item) => (
|
||||
<ProductCardStyleTwo
|
||||
key={item.id}
|
||||
|
||||
@@ -49,7 +49,9 @@ export default function CreatedBidsSlider({
|
||||
{/* heading */}
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">Create for Bits</h1>
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
|
||||
Create for Bits
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<button onClick={nextHandler} type="button">
|
||||
@@ -96,7 +98,7 @@ export default function CreatedBidsSlider({
|
||||
<div className="trending-products relative w-full">
|
||||
<SliderCom selector={trendingSlider} settings={settings}>
|
||||
{products &&
|
||||
products.length > 0 &&
|
||||
products?.length > 0 &&
|
||||
products.map((item) => (
|
||||
<ProductCardStyleOne
|
||||
key={item.id}
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function OnSaleTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<ProductCardStyleTwo key={datas.id} datas={datas} />
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function OwnTab({ className, products }) {
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products.length}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<ProductCardStyleOne key={datas.id} datas={datas} />
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
|
||||
export default function BlogItem(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">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Title of this Blog Items
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
Blog Items Details
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -1,118 +1,210 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
import Icons from "../Helpers/Icons";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import MarketPopUp from "../MarketPlace/PopUp/MarketPopUp";
|
||||
import usersService from "../../services/UsersService";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
import dataImage2 from "../../assets/images/data-table-user-2.png";
|
||||
|
||||
export default function AvailableJobsCard({
|
||||
className,
|
||||
datas,
|
||||
hidden = false,
|
||||
contentDisplay
|
||||
}) {
|
||||
//debugger;
|
||||
const [addFavorite, setValue] = useState(datas.whishlisted);
|
||||
const [options, setOption] = useState(false);
|
||||
const favoriteHandler = () => {
|
||||
if (!addFavorite) {
|
||||
setValue(true);
|
||||
toast.success("Added to Favorite List");
|
||||
} else {
|
||||
setValue(false);
|
||||
toast.warn("Remove to Favorite List");
|
||||
}
|
||||
};
|
||||
const [marketPopUp, setMarketPopUp] = useState({ show: false, data: {} });
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
|
||||
let thePrice = PriceFormatter(
|
||||
datas?.price * 0.01,
|
||||
datas?.currency_code,
|
||||
datas?.currency
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const imagePath = require(`../../assets/images/${datas.thumbnil}`); // Replace with your directory path for local images
|
||||
setImageUrl(imagePath);
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
className={`card-style-two w-full h-[426px] p-[20px] bg-white dark:bg-dark-white rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-col justify-between w-full h-full">
|
||||
<Link to="/shop-details" className="mb-2.5">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{datas.title}
|
||||
</h1>
|
||||
</Link>
|
||||
<>
|
||||
{contentDisplay == 'grid' ?
|
||||
<div
|
||||
className={`card-style-two w-full h-[426px] p-[20px] bg-white dark:bg-dark-white rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-col justify-between w-full h-full">
|
||||
<Link to="/shop-details" className="mb-2.5">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{datas.title}
|
||||
</h1>
|
||||
</Link>
|
||||
|
||||
<div className="card-two-info flex justify-between items-center">
|
||||
<div className="owned-by flex space-x-2 items-center">
|
||||
<div>
|
||||
<p className="text-thin-light-gray text-sm leading-3">Added</p>
|
||||
<p className="text-base text-dark-gray dark:text-white">
|
||||
{datas.offer_added}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-[1px] bg-light-purple dark:bg-dark-light-purple h-7"></div>
|
||||
<div className="created-by flex space-x-2 items-center flex-row-reverse">
|
||||
<div>
|
||||
<p className="text-thin-light-gray text-sm leading-3 text-right">
|
||||
Expires
|
||||
</p>
|
||||
<p className="text-base text-dark-gray dark:text-white text-right">
|
||||
{datas.expire}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="thumbnail-area w-full">
|
||||
<div
|
||||
className="w-full h-[236px] p-6 rounded-xl overflow-hidden"
|
||||
style={{
|
||||
background: `url(${localImgLoad(
|
||||
`images/${datas.thumbnil}`
|
||||
)}) 0% 0% / cover no-repeat`,
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-center">{datas.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="details-area">
|
||||
<div className="product-two-options flex justify-between mb-5 relative">
|
||||
{/* <div className="status">*/}
|
||||
{/* {datas.isActive && (*/}
|
||||
{/* <span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">*/}
|
||||
{/* Active*/}
|
||||
{/*</span>*/}
|
||||
{/* )}*/}
|
||||
{/* </div>*/}
|
||||
|
||||
{/*<div className=" review flex space-x-2">*/}
|
||||
{/* <button*/}
|
||||
{/* onClick={favoriteHandler}*/}
|
||||
{/* type="button"*/}
|
||||
{/* className={`w-7 h-7 bg-white rounded-full flex justify-center items-center ${*/}
|
||||
{/* addFavorite ? "text-red-500" : "text-thin-light-gray"*/}
|
||||
{/* }`}*/}
|
||||
{/* >*/}
|
||||
{/* <Icons name="star" />*/}
|
||||
{/* </button>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="card-two-info flex justify-between items-center">
|
||||
<div className="owned-by flex space-x-2 items-center">
|
||||
<div>
|
||||
<p className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white">
|
||||
{datas.price * 0.01}
|
||||
{datas.currency} | {datas.timeline_days} day(s)
|
||||
</p>
|
||||
<p className="text-sm text-lighter-gray">
|
||||
( {datas.offer_code})
|
||||
<p className="text-thin-light-gray text-sm leading-3">Added</p>
|
||||
<p className="text-base text-dark-gray dark:text-white">
|
||||
{datas.offer_added}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
<div className="w-[1px] bg-light-purple dark:bg-dark-light-purple h-7"></div>
|
||||
<div className="created-by flex space-x-2 items-center flex-row-reverse">
|
||||
<div>
|
||||
<p className="text-thin-light-gray text-sm leading-3 text-right">
|
||||
Expires
|
||||
</p>
|
||||
<p className="text-base text-dark-gray dark:text-white text-right">
|
||||
{datas.expire}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="thumbnail-area w-full">
|
||||
<div
|
||||
className="w-full h-[236px] p-6 rounded-xl overflow-hidden bg-center bg-cover bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url('${imageUrl}')`,
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-center">{datas.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="details-area">
|
||||
<div className="product-two-options flex justify-between mb-5 relative">
|
||||
{/* <div className="status">*/}
|
||||
{/* {datas.isActive && (*/}
|
||||
{/* <span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">*/}
|
||||
{/* Active*/}
|
||||
{/*</span>*/}
|
||||
{/* )}*/}
|
||||
{/* </div>*/}
|
||||
|
||||
{/*<div className=" review flex space-x-2">*/}
|
||||
{/* <button*/}
|
||||
{/* onClick={favoriteHandler}*/}
|
||||
{/* type="button"*/}
|
||||
{/* className={`w-7 h-7 bg-white rounded-full flex justify-center items-center ${*/}
|
||||
{/* addFavorite ? "text-red-500" : "text-thin-light-gray"*/}
|
||||
{/* }`}*/}
|
||||
{/* >*/}
|
||||
{/* <Icons name="star" />*/}
|
||||
{/* </button>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>
|
||||
<p className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white">
|
||||
{/* {thePrice} | {datas.timeline_days} day(s) */}
|
||||
{thePrice}
|
||||
</p>
|
||||
<p className="text-sm text-lighter-gray">
|
||||
( {datas.offer_code}) |
|
||||
<span className="italic ml-1">
|
||||
{datas.timeline_days} day(s)
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
|
||||
onClick={() => {
|
||||
setMarketPopUp({ show: true, data: datas });
|
||||
}}
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="card-style-two w-full p-8 my-2 flex items-center gap-4 bg-white dark:bg-dark-white rounded-2xl section-shadow">
|
||||
<div className="flex gap-5 items-center w-full">
|
||||
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] min-w-[60px] max-w-[60px]">
|
||||
<img src={dataImage2} alt="data" className="w-full h-full" />
|
||||
</div>
|
||||
<div className="flex flex-col flex-[0.9]">
|
||||
<Link to="/shop-details" className="">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{datas?.title}
|
||||
</h1>
|
||||
</Link>
|
||||
|
||||
<div className="my-2">
|
||||
<p className="text-dark-gray dark:text-white">{datas?.description}</p>
|
||||
</div>
|
||||
|
||||
{/* <div className="card-two-info flex gap-2 items-center">
|
||||
<div className="owned-by flex space-x-2 items-center">
|
||||
<div>
|
||||
<p className="text-thin-light-gray text-sm leading-3">Added</p>
|
||||
<p className="text-base text-dark-gray dark:text-white">
|
||||
{datas.offer_added}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-[1px] bg-light-purple dark:bg-dark-light-purple h-7"></div>
|
||||
<div className="created-by flex space-x-2 items-center flex-row-reverse">
|
||||
<div>
|
||||
<p className="text-thin-light-gray text-sm leading-3 text-right">
|
||||
Expires
|
||||
</p>
|
||||
<p className="text-base text-dark-gray dark:text-white text-right">
|
||||
{datas.expire}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="block sm:flex flex-wrap gap-4">
|
||||
<p className="text-sm text-thin-light-gray flex flext-start gap-1">
|
||||
Price: <span className="text-purple">{thePrice}</span>
|
||||
</p>
|
||||
<p className="text-sm text-thin-light-gray">
|
||||
Duration:{" "}
|
||||
<span className="text-purple italic">
|
||||
{" "}
|
||||
{datas?.timeline_days} day(s)
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-sm text-thin-light-gray">
|
||||
Code:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{datas?.offer_code}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="">
|
||||
<button
|
||||
type="button"
|
||||
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
|
||||
onClick={() => {
|
||||
setMarketPopUp({ show: true, data: datas });
|
||||
}}
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{marketPopUp.show && (
|
||||
<MarketPopUp
|
||||
details={datas}
|
||||
onClose={() => {
|
||||
setMarketPopUp({ show: false, data: {} });
|
||||
}}
|
||||
situation={marketPopUp.show}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { useState } from "react";
|
||||
import SuggestTask from "../FamilyPopup/SuggestTask";
|
||||
|
||||
export default function FamilyMarketCard({ className, datas, hidden = false }) {
|
||||
// debugger;
|
||||
const [popUp, setPopUp] = useState(false);
|
||||
const popUpHandler = () => {
|
||||
setPopUp((prev) => !prev);
|
||||
};
|
||||
// Image
|
||||
let selectedImage = require(`../../assets/images/family/${
|
||||
datas.banner || "default.jpg"
|
||||
}`);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`card-style-two w-full h-[336px] p-[20px] bg-white dark:bg-dark-white rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
key={datas?.uid}
|
||||
>
|
||||
<div className="flex flex-col justify-between w-full h-full">
|
||||
<div className="thumbnail-area w-full">
|
||||
<div
|
||||
className="w-full h-[236px] p-6 rounded-xl overflow-hidden"
|
||||
onClick={popUpHandler}
|
||||
style={{
|
||||
// background: `url(${selectedImage}) 0% 0% / cover no-repeat`,
|
||||
background: `url(${selectedImage}) center / contain no-repeat`,
|
||||
}}
|
||||
>
|
||||
<div className="product-two-options flex justify-between mb-5 relative">
|
||||
<div className="status">
|
||||
{/* <span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">
|
||||
Active
|
||||
</span> */}
|
||||
</div>
|
||||
</div>
|
||||
{hidden && <div className="flex justify-center"></div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="details-area mt-12 flex justify-between items-center gap-2">
|
||||
{/* title */}
|
||||
<button onClick={popUpHandler}>
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{datas?.title}
|
||||
</h1>
|
||||
</button>
|
||||
<div className="flex justify-between">
|
||||
{/* <div className="flex items-center space-x-2">
|
||||
<p className="italic text-gray-400">
|
||||
{getTimeAgo(datas?.added)}
|
||||
</p>
|
||||
</div> */}
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={popUpHandler}
|
||||
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{popUp && (
|
||||
<SuggestTask
|
||||
onClose={popUpHandler}
|
||||
situation={popUp}
|
||||
details={{ ...datas, selectedImage }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +1,44 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
|
||||
export default function HomeBannerOffersCard(props) {
|
||||
console.log("HomeBannerOffersCard->",props.itemData)
|
||||
return (
|
||||
<Link
|
||||
to="/my-collection/collection-item"
|
||||
className="item w-full block group banner-630-340"
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<div className="content flex justify-between items-center mb-5">
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
<>{props.itemData.title}</>
|
||||
</h1>
|
||||
</div>
|
||||
{/*<SelectBox datas={filterDatas} action={dataSetHandler} />*/}
|
||||
</div>
|
||||
<div className="h-[233px]">
|
||||
{props.itemData.description}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const link_result = "/" + props.itemData.link_path;
|
||||
|
||||
useEffect(() => {
|
||||
let { banner, banner_location } = props?.itemData;
|
||||
if (banner_location === "LOCAL") {
|
||||
const imagePath = require(`../../assets/images/${banner}`); // Replace with your directory path for local images
|
||||
setImageUrl(imagePath);
|
||||
} else if (banner_location === "URL") setImageUrl(banner);
|
||||
else return null;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={link_result}
|
||||
className="item w-full block group banner-630-340 bg-cover bg-center"
|
||||
style={{
|
||||
backgroundImage: `url('${imageUrl}')`,
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<div className="content flex justify-between items-center">
|
||||
<div className="siderCardHeader">
|
||||
<h1 className="text-2xl font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
<span className="heroSilderTitle">{props.itemData.title}</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-around items-center flex-1">
|
||||
<div className="siderCardDescription">
|
||||
{props.itemData.description}
|
||||
</div>
|
||||
<button className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
{props.itemData.button_text}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import localImgLoad from "../../lib/localImgLoad";
|
||||
@@ -6,6 +6,7 @@ import CountDown from "../Helpers/CountDown";
|
||||
import Icons from "../Helpers/Icons";
|
||||
|
||||
export default function ProductCardStyleOne({ datas, hidden = false }) {
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const [addFavorite, setValue] = useState(false);
|
||||
const [options, setOption] = useState(false);
|
||||
const favoriteHandler = () => {
|
||||
@@ -17,6 +18,8 @@ export default function ProductCardStyleOne({ datas, hidden = false }) {
|
||||
toast.warn("Remove to Favorite List");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="card-style-one flex flex-col justify-between w-full h-[387px] bg-white dark:bg-dark-white p-3 pb rounded-2xl">
|
||||
<div className="content">
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
export default function ProductCardStyleTwo({
|
||||
className,
|
||||
datas,
|
||||
hidden = false,
|
||||
bg
|
||||
}) {
|
||||
// debugger;
|
||||
const [addFavorite, setValue] = useState(datas.whishlisted);
|
||||
const [options, setOption] = useState(false);
|
||||
const favoriteHandler = () => {
|
||||
if (!addFavorite) {
|
||||
setValue(true);
|
||||
toast.success("Added to Favorite List");
|
||||
} else {
|
||||
setValue(false);
|
||||
toast.warn("Remove to Favorite List");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`card-style-two w-full h-[336px] p-[20px] bg-white dark:bg-dark-white rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-col justify-between w-full h-full">
|
||||
<div className="thumbnail-area w-full">
|
||||
<div
|
||||
className="w-full h-[236px] p-6 rounded-xl overflow-hidden"
|
||||
style={{
|
||||
// background: `url(${`https://blog.wrenchboard.com/wp-content/uploads/${datas.meta_value}`}) 0% 0% / cover no-repeat`,
|
||||
background: `url(${`${bg}${datas.meta_value}`}) 0% 0% / cover no-repeat`,
|
||||
}}
|
||||
>
|
||||
<div className="product-two-options flex justify-between mb-5 relative">
|
||||
<div className="status">
|
||||
{datas?.isActive && (
|
||||
<span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">
|
||||
Active
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{hidden && <div className="flex justify-center"></div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="details-area">
|
||||
{/* title */}
|
||||
<a href={datas.guid} target="_blank" className="mb-2.5" rel="noreferrer">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{datas.post_title || "dummy title..."}
|
||||
</h1>
|
||||
</a>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center space-x-2"></div>
|
||||
<div className="my-1">
|
||||
<a
|
||||
href={datas.guid}
|
||||
target="_blank"
|
||||
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
|
||||
rel="noreferrer"
|
||||
>
|
||||
View
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,44 +1,60 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import Layout from "../Partials/Layout";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import FamilyManageTabs from "./FamilyManageTabs";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
export default function FamilyManage() {
|
||||
const [selectTab, setValue] = useState("today");
|
||||
let [pageLoading, setPageLoading] = useState(true);
|
||||
|
||||
let location = useLocation();
|
||||
let accountDetails = location?.state
|
||||
let navigate = useNavigate();
|
||||
let accountDetails = location?.state;
|
||||
|
||||
// tab handler
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!accountDetails) {
|
||||
navigate("/acc-family", { replace: true });
|
||||
} else {
|
||||
setPageLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
{/*<CommonHead />*/}
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Manage Family
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
{pageLoading ? (
|
||||
<LoadingSpinner size={8} color="sky-blue" />
|
||||
) : (
|
||||
<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 inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Manage Family
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<FamilyManageTabs accountDetails={accountDetails} />
|
||||
</div>
|
||||
<FamilyManageTabs accountDetails={accountDetails} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import React, {
|
||||
Suspense,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { useReactToPrint } from "react-to-print";
|
||||
import profile from "../../assets/images/profile-info-profile.png";
|
||||
import usersService from "../../services/UsersService";
|
||||
import FamilyTasks from "./FamilyTasks";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import AssignTaskPopout from "./FamilyPopout/AssignTaskPopout";
|
||||
import {
|
||||
FamilyWaitlist,
|
||||
FamilyAccount,
|
||||
FamilyProfile,
|
||||
FamilyTasks,
|
||||
ProfileInfo,
|
||||
} from "./Tabs";
|
||||
|
||||
export default function FamilyManageTabs({
|
||||
className,
|
||||
@@ -16,36 +25,26 @@ export default function FamilyManageTabs({
|
||||
listReload,
|
||||
loader,
|
||||
}) {
|
||||
const [familyDetails, setFamilyDetails] = useState(null);
|
||||
const [details, setDetails] = useState({
|
||||
familyDetails: { loading: false, data: null },
|
||||
familyTasks: { loading: false, data: null },
|
||||
familyWaitList: { loading: false, data: null },
|
||||
});
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
// List of tabs
|
||||
const tabs = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Tasks",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Account",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Profile",
|
||||
},
|
||||
];
|
||||
const [tab, setTab] = useState(tabs[0].name);
|
||||
const [manageLoader, setManageLoader] = useState(false);
|
||||
const tabHandler = (value) => {
|
||||
setTab(value);
|
||||
const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
|
||||
|
||||
const familyPopUpHandler = () => {
|
||||
setFamilyTaskPopout((prev) => !prev);
|
||||
};
|
||||
// For profile uploads
|
||||
|
||||
const [profileImg, setProfileImg] = useState(profile);
|
||||
// profile img
|
||||
const profileImgInput = useRef(null);
|
||||
|
||||
const browseProfileImg = () => {
|
||||
profileImgInput.current.click();
|
||||
};
|
||||
const profileImgChangHandler = (e) => {
|
||||
|
||||
const profileImgChangeHandler = (e) => {
|
||||
if (e.target.value !== "") {
|
||||
const imgReader = new FileReader();
|
||||
imgReader.onload = (event) => {
|
||||
@@ -54,178 +53,181 @@ export default function FamilyManageTabs({
|
||||
imgReader.readAsDataURL(e.target.files[0]);
|
||||
}
|
||||
};
|
||||
// Api call
|
||||
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
// function for manage family
|
||||
const familyManageHandler = useCallback(async () => {
|
||||
setManageLoader(true);
|
||||
|
||||
const manageFamily = useCallback(async () => {
|
||||
try {
|
||||
let { family_uid } = accountDetails;
|
||||
let reqData = { family_uid };
|
||||
let res = await apiCall.ManageFamily(reqData);
|
||||
let { data } = await res;
|
||||
if (data?.internal_return < 0) return;
|
||||
setFamilyDetails(data);
|
||||
setManageLoader(false);
|
||||
setDetails({
|
||||
familyDetails: { loading: true },
|
||||
familyTasks: { loading: true },
|
||||
familyWaitList: { loading: true },
|
||||
});
|
||||
|
||||
const { family_uid } = accountDetails;
|
||||
const reqData = { family_uid };
|
||||
|
||||
const [familyRes, tasksRes, familyWaitRes] = await Promise.all([
|
||||
apiCall.ManageFamily(reqData),
|
||||
apiCall.ManageTasks(reqData),
|
||||
apiCall.ManageFamilyWaitlist(),
|
||||
]);
|
||||
|
||||
const familyData = familyRes.data;
|
||||
const tasksData = tasksRes.data;
|
||||
const familyWaitData = familyWaitRes.data;
|
||||
|
||||
if (
|
||||
familyData?.internal_return < 0 ||
|
||||
tasksData?.internal_return < 0 ||
|
||||
familyWaitData?.internal_return < 0
|
||||
)
|
||||
return;
|
||||
|
||||
setDetails({
|
||||
familyDetails: { loading: false, data: familyData },
|
||||
familyTasks: { loading: false, data: tasksData },
|
||||
familyWaitList: { loading: false, data: familyWaitData },
|
||||
});
|
||||
} catch (error) {
|
||||
setDetails({
|
||||
familyDetails: { loading: false },
|
||||
familyTasks: { loading: false },
|
||||
familyWaitList: { loading: false },
|
||||
});
|
||||
setErrMsg("An error occurred");
|
||||
throw new Error(error);
|
||||
}
|
||||
}, [apiCall, accountDetails]);
|
||||
|
||||
const accountRef = useRef();
|
||||
|
||||
const useHandlePrint = useReactToPrint({
|
||||
content: () => accountRef.current,
|
||||
});
|
||||
|
||||
const tabs = [
|
||||
{ id: 1, name: "Tasks" },
|
||||
{ id: 2, name: "Waiting" },
|
||||
{ id: 3, name: "Account" },
|
||||
{ id: 4, name: "Profile" },
|
||||
];
|
||||
|
||||
const [tab, setTab] = useState(tabs[0].name);
|
||||
|
||||
const tabHandler = (value) => {
|
||||
setTab(value);
|
||||
};
|
||||
|
||||
const tabComponents = {
|
||||
Tasks: (
|
||||
<FamilyTasks
|
||||
className={className}
|
||||
loader={details.familyTasks.loading}
|
||||
familyData={details.familyTasks.data}
|
||||
accountDetails={accountDetails}
|
||||
/>
|
||||
),
|
||||
Waiting: (
|
||||
<FamilyWaitlist
|
||||
familyData={details.familyWaitList.data}
|
||||
loader={details.familyWaitList.loading}
|
||||
/>
|
||||
),
|
||||
Account: (
|
||||
<FamilyAccount
|
||||
familyData={details.familyDetails.data}
|
||||
myRef={accountRef}
|
||||
loader={details.familyDetails.loading}
|
||||
handlePrint={useHandlePrint}
|
||||
/>
|
||||
),
|
||||
Profile: <FamilyProfile />,
|
||||
};
|
||||
|
||||
const defaultTabComponent = (
|
||||
<FamilyTasks
|
||||
className={className}
|
||||
loader={details.familyTasks.loading}
|
||||
familyData={details.familyTasks.data}
|
||||
accountDetails={accountDetails}
|
||||
/>
|
||||
);
|
||||
|
||||
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
|
||||
|
||||
useEffect(() => {
|
||||
familyManageHandler();
|
||||
}, [tab]);
|
||||
manageFamily();
|
||||
}, [tab, manageFamily]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] max-h-[600px] ${
|
||||
className={`w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] max-h-[600px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg">
|
||||
{loader ? (
|
||||
<div className="h-full min-h-[500px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="h-full min-h-[500px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="w-full h-full text-sm text-left text-gray-500 dark:text-gray-400 relative grid grid-cols-4 min-h-[520px]">
|
||||
<div className="border-r border-[#E3E4FE] dark:border-[#a7a9b533] p-6 h-full">
|
||||
<ProfileInfo
|
||||
profileImg={profileImg}
|
||||
profileImgInput={profileImgInput}
|
||||
profileImgChangHandler={profileImgChangHandler}
|
||||
profileImgChangeHandler={profileImgChangeHandler}
|
||||
browseProfileImg={browseProfileImg}
|
||||
accountDetails={accountDetails}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-3 p-6 h-full w-full">
|
||||
<div className="col-span-3 justify-self-end h-full w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<ul className="flex-[0.1] flex gap-2 items-center border-b border-b-[#FAFAF] w-full">
|
||||
{tabs.map(({ name, id }) => (
|
||||
<li
|
||||
onClick={() => tabHandler(name)}
|
||||
className={`p-4 flex hover:text-purple transition-all ease-in-out items-center cursor-pointer overflow-hidden text-xl ${
|
||||
tab === name
|
||||
? "text-purple border-r"
|
||||
: " text-thin-light-gray"
|
||||
}`}
|
||||
key={id}
|
||||
>
|
||||
<h1>{name}</h1>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex-[0.9] lg:min-h-[450px] h-full">
|
||||
{/* Your content here */}
|
||||
{tabs.map(({ name, id }) => {
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
tab === name ? "block" : "hidden"
|
||||
} h-full p-4 border border-[#dbd9d9]`}
|
||||
<div className="w-full pr-8 flex items-center gap-1">
|
||||
<ul className="flex gap-2 items-center border-b border-b-[#FAFAF] w-full">
|
||||
{tabs.map(({ name, id }) => (
|
||||
<li
|
||||
onClick={() => tabHandler(name)}
|
||||
className={`p-4 flex hover:text-purple transition-all ease-in-out items-center cursor-pointer overflow-hidden text-xl relative top-1 ${
|
||||
tab === name
|
||||
? "text-purple border-r"
|
||||
: "text-thin-light-gray"
|
||||
}`}
|
||||
key={id}
|
||||
>
|
||||
{manageLoader ? (
|
||||
<LoadingSpinner size="8" color="sky-blue" />
|
||||
) : (
|
||||
<>
|
||||
{name === "Tasks" && <FamilyTasks className={className} loader={loader}/>}
|
||||
{name === "Account" && (
|
||||
<Account familyDetails={familyDetails} />
|
||||
)}
|
||||
{name === "Profile" && <Profile />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<h1>{name}</h1>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
onClick={familyPopUpHandler}
|
||||
className="p-1 my-1 w-[100px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
Add task
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex-[0.9] lg:min-h-[450px] h-full">
|
||||
<div className="h-full p-4 border border-[#dbd9d9] relative overflow-y-auto">
|
||||
{selectedTabComponent}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{familyTaskPopout && (
|
||||
<AssignTaskPopout
|
||||
action={familyPopUpHandler}
|
||||
situation={familyTaskPopout}
|
||||
familyDetails={details.familyDetails.data}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ProfileInfo({
|
||||
profileImg,
|
||||
profileImgInput,
|
||||
profileImgChangHandler,
|
||||
browseProfileImg,
|
||||
accountDetails,
|
||||
}) {
|
||||
let { firstname, lastname, age } = accountDetails;
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full relative">
|
||||
<img
|
||||
src={profileImg}
|
||||
alt=""
|
||||
className="sm:w-[198px] sm:h-[198px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover"
|
||||
/>
|
||||
<input
|
||||
ref={profileImgInput}
|
||||
onChange={(e) => profileImgChangHandler(e)}
|
||||
type="file"
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
onClick={browseProfileImg}
|
||||
className="w-[32px] h-[32px] absolute bottom-7 sm:right-2 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"
|
||||
>
|
||||
<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>
|
||||
<div className="flex flex-col justify-center gap-3 items-center">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{firstname}
|
||||
</h1>
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{lastname}
|
||||
</h1>
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{age}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Account({ familyDetails }) {
|
||||
return (
|
||||
<div className="w-full lg:min-h-[400px] h-full flex items-center justify-center">
|
||||
<div className="flex flex-col">
|
||||
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
Username: <span className="ml-2 normal-case">{familyDetails?.username}</span>
|
||||
</h2>
|
||||
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
Pin: <span className="ml-2 normal-case">{familyDetails?.pin}</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Profile() {
|
||||
return <>Profile</>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import Layout from "../Partials/Layout";
|
||||
import SearchCom from "../Helpers/SearchCom";
|
||||
import FamilyMarketCard from "../Cards/FamilyMarketCard";
|
||||
import usersService from "../../services/UsersService";
|
||||
import SuggestTask from "../FamilyPopup/SuggestTask";
|
||||
|
||||
export default function FamilyMarket() {
|
||||
const [popUp, setPopUp] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [myFamilySampleTasks, setMyFamilySampleTasks] = useState({
|
||||
loading: true,
|
||||
status: false,
|
||||
data: [],
|
||||
});
|
||||
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
const getMyFamilySampleTasks = useCallback(async () => {
|
||||
try {
|
||||
setMyFamilySampleTasks({ loading: true, status: false, data: [] });
|
||||
const res = await apiCall.getFamilySampleTasks();
|
||||
setMyFamilySampleTasks({
|
||||
loading: false,
|
||||
status: true,
|
||||
data: res.data.result_list,
|
||||
});
|
||||
} catch (error) {
|
||||
setMyFamilySampleTasks({ loading: false, status: false, data: [] });
|
||||
console.log("Error getting tasks:", error);
|
||||
}
|
||||
}, [apiCall]);
|
||||
|
||||
useEffect(() => {
|
||||
getMyFamilySampleTasks();
|
||||
}, [getMyFamilySampleTasks]);
|
||||
|
||||
const handleSearch = (event) => {
|
||||
setSearchQuery(event.target.value);
|
||||
};
|
||||
|
||||
const filteredTasks =
|
||||
myFamilySampleTasks.data?.filter((task) =>
|
||||
task.title.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
) || [];
|
||||
|
||||
const popUpHandler = () => {
|
||||
setPopUp((prev) => !prev);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<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 inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span>Suggest Task to the Parents</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
{/* Body */}
|
||||
<div className="filter-section w-full items-center sm:flex justify-between mb-6">
|
||||
{/* filter-search */}
|
||||
<div className="sm:w-1/2 w-full sm:pr-20 pr-0 mb-5 sm:mb-0">
|
||||
<SearchCom
|
||||
placeholder="Search for tasks..."
|
||||
handleSearch={handleSearch}
|
||||
value={searchQuery}
|
||||
/>
|
||||
</div>
|
||||
{/* filer-dropdown */}
|
||||
<div className="flex-1 flex sm:justify-end">
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
className="btn-gradient lg:flex hidden w-[153px] h-[46px] rounded-full text-white justify-center items-center"
|
||||
>
|
||||
Any Other Task
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="content-section w-full-width">
|
||||
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-[30px]">
|
||||
{filteredTasks.map((task) => (
|
||||
<FamilyMarketCard key={task.id} datas={task} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{popUp && <SuggestTask onClose={popUpHandler} situation={popUp} />}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
import React, {useState, useEffect} from 'react'
|
||||
import ModalCom from '../../Helpers/ModalCom'
|
||||
import Detail from '../../jobPopout/popoutcomponent/Detail'
|
||||
import usersService from '../../../services/UsersService'
|
||||
import LoadingSpinner from '../../Spinners/LoadingSpinner'
|
||||
import { PriceFormatter } from '../../Helpers/PriceFormatter'
|
||||
|
||||
function AssignTaskPopout({action, situation, familyDetails}) {
|
||||
const apiCall = new usersService()
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({loading: false, status: false, message: ''}) // HOLDS RESPONSE FOR SENDING API REQUEST
|
||||
|
||||
let [familyTask, setFamilyTask] = useState({loading: true, data: []})
|
||||
|
||||
let [taskType, setTaskType] = useState('select') // SWITCHES BTW SELECT TASK AND NEW TASK
|
||||
|
||||
let [activeTask, setActiveTask] = useState({id: 0, data: {}}) // HOLDS SELECTED TASK
|
||||
|
||||
const switchTaskType = ({target:{value}}) => { // FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setTaskType(value)
|
||||
}
|
||||
|
||||
const handleActiveTask = (id=0, data={}) => { // FUNCTION TO CHANGE SELECTED ACTIVE TASK
|
||||
setActiveTask({id, data})
|
||||
}
|
||||
|
||||
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,
|
||||
job_description: activeTask.data?.description,
|
||||
assign_mode: 110011,
|
||||
}
|
||||
|
||||
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'})
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
if(taskType == 'new'){ // RUNS HERE IF TASK TYPE IS NEW TASK
|
||||
console.log('TESTING')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
const reqData = {
|
||||
limit: 30,
|
||||
offset: 0,
|
||||
job_type: 'FAMILY',
|
||||
action: 13005
|
||||
}
|
||||
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)
|
||||
})
|
||||
},[])
|
||||
return (
|
||||
<>
|
||||
<ModalCom
|
||||
action={action}
|
||||
situation={situation}
|
||||
>
|
||||
<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}
|
||||
</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>
|
||||
{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 md:grid-cols-2">
|
||||
<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='p-4 w-full h-[400px] overflow-y-auto bg-slate-100'>
|
||||
{
|
||||
taskType == 'select' ?
|
||||
familyTask?.data?.length ?
|
||||
familyTask?.data?.map((item, index)=>(
|
||||
<div key={item.job_uid} className="mb-2 flex justify-start items-center gap-2 text-sky-blue text-base cursor-pointer" onClick={()=>handleActiveTask(item.job_uid, item)}>
|
||||
<input
|
||||
type="radio"
|
||||
name='task-list'
|
||||
checked={(activeTask.id == item.job_uid) || (activeTask.id==index)&& true}
|
||||
onChange={()=>handleActiveTask(item.job_uid, item)}
|
||||
className="w-[15px] h-[15px] cursor-pointer"
|
||||
/>
|
||||
<p className="w-full text-dark-gray tracking-wide">{item?.title}</p>
|
||||
</div>
|
||||
))
|
||||
:
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center">No Task found!</p>
|
||||
:
|
||||
<p className="p-8 text-lg text-dark-gray dark:text-white tracking-wide text-center">SPACE FOR NEW TASK</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{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 outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
value={activeTask?.data?.job_detail}
|
||||
readOnly
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
{/* <p>{}</p> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* BTN */}
|
||||
<div className='p-2 border-t-2 flex justify-end items-center gap-3'>
|
||||
{/* error or success display */}
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
<div
|
||||
className={`relative p-2 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-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>
|
||||
)
|
||||
))}
|
||||
{/* End of error or success display */}
|
||||
<button
|
||||
disabled={requestStatus.loading}
|
||||
onClick={action} type="button"
|
||||
className="w-20 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
<span className='text-gradient'>Close</span>
|
||||
</button>
|
||||
<div className=''>
|
||||
{requestStatus.loading ?
|
||||
<LoadingSpinner color='sky-blue' size='8' />
|
||||
:
|
||||
<button
|
||||
type="button"
|
||||
disabled={requestStatus.loading}
|
||||
onClick={assignFamilyTask}
|
||||
className="px-1 w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white cursor-pointer"
|
||||
>
|
||||
Assign
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</ModalCom>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AssignTaskPopout
|
||||
@@ -5,7 +5,9 @@ import { useNavigate, useLocation, Link } from "react-router-dom";
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
|
||||
export default function FamilyTable({ className, familyList, loader }) {
|
||||
import familyImage from '../../assets/images/no-family-side.png'
|
||||
|
||||
export default function FamilyTable({ className, familyList, loader, popUpHandler }) {
|
||||
const filterCategories = ["All Categories", "Explore", "Featured"];
|
||||
const [selectedCategory, setCategory] = useState(filterCategories[0]);
|
||||
const navigate = useNavigate();
|
||||
@@ -23,7 +25,7 @@ export default function FamilyTable({ className, familyList, loader }) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full h-full p-8 bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow ${
|
||||
className={`update-table w-full h-full p-8 bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
@@ -32,9 +34,11 @@ export default function FamilyTable({ className, familyList, loader }) {
|
||||
<div className="h-full min-h-[500px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 relative">
|
||||
<>
|
||||
)
|
||||
:
|
||||
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>
|
||||
@@ -44,9 +48,7 @@ export default function FamilyTable({ className, familyList, loader }) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="h-full">
|
||||
<>
|
||||
{familyList?.length > 0 ? (
|
||||
currentFamilyList?.map((props, idx) => {
|
||||
{currentFamilyList?.map((props, idx) => {
|
||||
let {
|
||||
firstname,
|
||||
lastname,
|
||||
@@ -115,18 +117,29 @@ export default function FamilyTable({ className, familyList, loader }) {
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
<td className="p-2" colSpan="4">
|
||||
No Family Accounts Found!
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
</tbody>
|
||||
</>
|
||||
</table>
|
||||
)}
|
||||
</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
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import dataImage1 from "../../assets/images/data-table-user-1.png";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import { useNavigate, useLocation, Link } from "react-router-dom";
|
||||
|
||||
export default function FamilyTasks({ className, loader }) {
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] max-h-[600px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg">
|
||||
{loader ? (
|
||||
<div className="h-full min-h-[500px] w-full overflow-hidden flex justify-center items-center">
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 relative">
|
||||
|
||||
<tr>
|
||||
<td> Yes This are my tasks </td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { forwardRef } from 'react'
|
||||
import QRCode from 'react-qr-code';
|
||||
|
||||
const FamilyAccount = forwardRef(({ familyData, myRef, handlePrint }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className="w-full lg:min-h-[500px] h-full flex flex-col items-center justify-center"
|
||||
ref={myRef}
|
||||
>
|
||||
<div className="update-table w-full lg:min-h-[450px] h-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow ">
|
||||
<div className="flex items-center justify-around h-[380px]">
|
||||
<div className="flex flex-col">
|
||||
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
Username:{" "}
|
||||
<span className="ml-2 normal-case">
|
||||
{familyData?.username ? familyData?.username : "please wait..."}
|
||||
</span>
|
||||
</h2>
|
||||
<h2 className="font-bold text-lg tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
Pin:{" "}
|
||||
<span className="ml-2 normal-case">
|
||||
{familyData?.pin ? familyData?.pin : "please wait..."}
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<span className="text-5xl text-gray-400 opacity-20 font-bold">
|
||||
or
|
||||
</span>
|
||||
|
||||
<div className="max-w-[200px]">
|
||||
<p className="text-xl tracking-wide mb-[15px] text-center font-bold text-dark-gray dark:text-white">
|
||||
Scan the code from mobile app
|
||||
</p>
|
||||
<QRCode
|
||||
size={256}
|
||||
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
|
||||
value={`https://www.google.com`}
|
||||
viewBox={`0 0 256 256`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-[50px] w-full flex justify-center items-center">
|
||||
<button
|
||||
className="btn-shine w-[116px] h-[46px] text-white rounded-full text-base bg-pink flex justify-center items-center"
|
||||
onClick={handlePrint}
|
||||
>
|
||||
Print
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default FamilyAccount
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function FamilyProfile() {
|
||||
return <>Profile</>;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import React, { useState } from "react";
|
||||
import dataImage2 from "../../../assets/images/data-table-user-2.png";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { handlePagingFunc } from "../../Pagination/HandlePagination";
|
||||
import PaginatedList from "../../Pagination/PaginatedList";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import Icons from "../../Helpers/Icons";
|
||||
import { PriceFormatter } from "../../Helpers/PriceFormatter";
|
||||
import ModalCom from "../../Helpers/ModalCom";
|
||||
import Detail from "../../jobPopout/popoutcomponent/Detail";
|
||||
|
||||
|
||||
export default function FamilyTasks({ familyData, className, loader, accountDetails }) {
|
||||
let navigate = useNavigate();
|
||||
let { pathname } = useLocation();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const indexOfFirstItem = Number(currentPage);
|
||||
const indexOfLastItem =
|
||||
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const currentTask = familyData?.result_list.slice(
|
||||
indexOfFirstItem,
|
||||
indexOfLastItem
|
||||
);
|
||||
|
||||
const handlePagination = (e) => handlePagingFunc(e, setCurrentPage);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full bg-white dark:bg-dark-white h-full lg:min-h-[450px] overflow-hidden rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
{loader ? (
|
||||
<div className="w-full h-full flex justify-center items-center lg:min-h-[470px]">
|
||||
<LoadingSpinner size={16} color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{familyData && familyData?.result_list && (
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
{
|
||||
<>
|
||||
{familyData &&
|
||||
familyData?.result_list &&
|
||||
familyData.result_list.length > 0 &&
|
||||
currentTask.map((value, index) => {
|
||||
// find due date
|
||||
const dueDate = value?.delivery_date.split(" ")[0];
|
||||
// the price
|
||||
let thePrice = PriceFormatter(
|
||||
value?.price * 0.01,
|
||||
value?.currency_code,
|
||||
value?.currency
|
||||
);
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
>
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] max-w-[60px] min-w-[60px]">
|
||||
<img
|
||||
src={dataImage2}
|
||||
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">
|
||||
{value.title}
|
||||
</h1>
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="text-sm text-thin-light-gray flex flex-start gap-1">
|
||||
Price:{" "}
|
||||
<span className="text-purple">
|
||||
{thePrice}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Duration:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.timeline_days} day(s)
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Due Date:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{dueDate}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigate("/manage-active-job", {
|
||||
state: {
|
||||
...value,
|
||||
pathname,
|
||||
accountDetails
|
||||
}
|
||||
});
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
<Icons name="right-arrow" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList
|
||||
onClick={handlePagination}
|
||||
prev={currentPage == 0 ? true : false}
|
||||
next={
|
||||
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
|
||||
familyData?.result_list.length
|
||||
? true
|
||||
: false
|
||||
}
|
||||
data={familyData?.result_list}
|
||||
start={indexOfFirstItem}
|
||||
stop={indexOfLastItem}
|
||||
/>
|
||||
{/* END OF PAGINATION BUTTON */}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { handlePagingFunc, PaginatedList } from "../../Pagination";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
|
||||
const FamilyWaitlist = ({ familyData, className, loader }) => {
|
||||
const navigate = useNavigate();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const itemsPerPage = Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const indexOfFirstItem = currentPage;
|
||||
const indexOfLastItem = currentPage + itemsPerPage;
|
||||
const currentTask = familyData?.result_list?.slice(
|
||||
indexOfFirstItem,
|
||||
indexOfLastItem
|
||||
);
|
||||
|
||||
const handlePagination = (e) => handlePagingFunc(e, setCurrentPage);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full bg-white dark:bg-dark-white h-full lg:min-h-[450px] overflow-hidden rounded-2xl section-shadow ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
{loader ? (
|
||||
<div className="w-full h-full flex justify-center items-center lg:min-h-[470px]">
|
||||
<LoadingSpinner size={16} color="sky-blue" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{familyData && familyData.result_list && (
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
{currentTask.map((value) => {
|
||||
const addedDate = value?.added.split(" ")[0];
|
||||
const taskImg = require(`../../../assets/images/family/${
|
||||
value?.banner || "default.jpg"
|
||||
}`);
|
||||
return (
|
||||
<tr
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
key={value.uid}
|
||||
>
|
||||
<td className="py-4">
|
||||
<div className="w-full flex justify-between items-center">
|
||||
<div className="account-name flex space-x-4 items-center">
|
||||
<div className="icon w-14 h-14 flex justify-center items-center">
|
||||
<img
|
||||
src={taskImg}
|
||||
alt="task_img"
|
||||
className="w-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="">
|
||||
<p className="text-xl font-bold text-dark-gray dark:text-white mb-2 capitalize line-clamp-1">
|
||||
{value.title}
|
||||
</p>
|
||||
<p className="text-sm text-thin-light-gray font-medium">
|
||||
{value.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<p className="text-sm font-bold text-dark-gray dark:text-white">
|
||||
{addedDate}
|
||||
</p>
|
||||
<p className="text-sm text-dark-gray dark:text-white">
|
||||
Status: {value.status}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-right py-4 px-2">
|
||||
<button
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<PaginatedList
|
||||
onClick={handlePagination}
|
||||
prev={currentPage === 0}
|
||||
next={
|
||||
currentPage + itemsPerPage >= familyData?.result_list.length
|
||||
}
|
||||
data={familyData?.result_list}
|
||||
start={indexOfFirstItem}
|
||||
stop={indexOfLastItem}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FamilyWaitlist;
|
||||
@@ -0,0 +1,61 @@
|
||||
import React from "react";
|
||||
|
||||
export default function ProfileInfo({
|
||||
profileImg,
|
||||
profileImgInput,
|
||||
profileImgChangHandler,
|
||||
browseProfileImg,
|
||||
accountDetails,
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full relative">
|
||||
<img
|
||||
src={profileImg}
|
||||
alt=""
|
||||
className="sm:w-[198px] sm:h-[198px] w-[120px] h-[120px] rounded-full overflow-hidden object-cover"
|
||||
/>
|
||||
<input
|
||||
ref={profileImgInput}
|
||||
onChange={(e) => profileImgChangHandler(e)}
|
||||
type="file"
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
onClick={browseProfileImg}
|
||||
className="w-[32px] h-[32px] absolute bottom-7 sm:right-2 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"
|
||||
>
|
||||
<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>
|
||||
<div className="flex flex-col justify-center gap-3 items-center">
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{accountDetails?.firstname}
|
||||
</h1>
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{accountDetails?.lastname}
|
||||
</h1>
|
||||
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
|
||||
{accountDetails?.age}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import FamilyAccount from "./FamilyAccount";
|
||||
import FamilyProfile from "./FamilyProfile";
|
||||
import FamilyTasks from "./FamilyTasks";
|
||||
import FamilyWaitlist from "./FamilyWaitlist";
|
||||
import ProfileInfo from "./ProfileInfo";
|
||||
|
||||
export {
|
||||
FamilyAccount,
|
||||
FamilyProfile,
|
||||
FamilyTasks,
|
||||
FamilyWaitlist,
|
||||
ProfileInfo,
|
||||
};
|
||||
@@ -158,7 +158,7 @@ export default function FamilyAcc() {
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<FamilyTable familyList={familyList} loader={loader} />
|
||||
<FamilyTable familyList={familyList} loader={loader} popUpHandler={popUpHandler} />
|
||||
</div>
|
||||
</div>
|
||||
{popUp && (
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import { Form, Formik } from "formik";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
const DEFAULT_IMAGE = require("../../assets/images/family/default.jpg");
|
||||
const SuggestTask = ({ details, onClose, situation }) => {
|
||||
const [submitTask, setSubmitTask] = useState({
|
||||
loading: false,
|
||||
msg: "",
|
||||
state: "",
|
||||
});
|
||||
// default image
|
||||
const selectedImage = details?.selectedImage || DEFAULT_IMAGE;
|
||||
const initialValues = {
|
||||
title: details?.title || "",
|
||||
description: details?.description || "",
|
||||
};
|
||||
|
||||
const apiCall = new usersService();
|
||||
|
||||
const handleSubmit = async (values) => {
|
||||
if(!values.title && !values.description) return;
|
||||
try {
|
||||
setSubmitTask({ loading: true });
|
||||
const reqData = { ...values };
|
||||
const res = await apiCall.sendFamilySuggestedTasks(reqData);
|
||||
if (res.internal_return < 0) {
|
||||
setSubmitTask({ loading: false, msg: res.status, state: "bad" });
|
||||
return;
|
||||
}
|
||||
setSubmitTask({ loading: false, msg: res.status, state: "success" });
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
setSubmitTask({ loading: false, msg: error, state: "bad" });
|
||||
throw new Error("Error Occurred", error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<ModalCom action={onClose} situation={situation}>
|
||||
<div className="logout-modal-wrapper lw-[90%] md:w-[768px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl overflow-y-auto">
|
||||
<div className="logout-modal-header w-full flex items-center justify-between lg:p-6 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-base md:text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Suggest to Parent
|
||||
</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>
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form>
|
||||
<div className="p-5 w-full bg-white rounded-md flex justify-between">
|
||||
<div className="p-4 w-full md:w-2/4 md:border-r-2">
|
||||
<div
|
||||
className="w-full h-[236px] p-6 bg-gray-400 rounded-xl overflow-hidden"
|
||||
style={{
|
||||
// background: `url(${selectedImage}) 0% 0% / cover no-repeat`,
|
||||
background: `url(${selectedImage}) center / contain no-repeat`,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
{/* ACTION SECTION */}
|
||||
<div className="p-4 w-full md:w-2/4 h-full">
|
||||
{/* Title */}
|
||||
<div className="field w-full mb-[15px]">
|
||||
<InputCom
|
||||
fieldClass="px-6"
|
||||
label="Title"
|
||||
labelClass="tracking-wide"
|
||||
inputBg="bg-slate-100"
|
||||
inputClass="disabled:cursor-default"
|
||||
type="text"
|
||||
name="title"
|
||||
disable={details?.title}
|
||||
value={props.values.title}
|
||||
inputHandler={props.handleChange}
|
||||
blurHandler={props.handleBlur}
|
||||
error={
|
||||
props.errors.title &&
|
||||
props.touched.title &&
|
||||
props.errors.title
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="field w-full mb-[5px]">
|
||||
<label
|
||||
htmlFor="description"
|
||||
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1'
|
||||
>
|
||||
Description
|
||||
{props.errors.description &&
|
||||
props.touched.description && (
|
||||
<span className="text-[12px] text-red-500">
|
||||
{props.errors.description}
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<textarea
|
||||
id="description"
|
||||
rows="5"
|
||||
className={`input-field px-3 pt-2 placeholder:text-base text-dark-gray dark:text-white w-full h-[130px] bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px]`}
|
||||
style={{ resize: "none" }}
|
||||
name="description"
|
||||
value={props.values.description}
|
||||
onChange={props.handleChange}
|
||||
onBlur={props.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-[70px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
||||
<div className="flex items-center space-x-4 mr-9">
|
||||
<button
|
||||
type="button"
|
||||
className=" border-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
onClick={onClose}
|
||||
>
|
||||
<span className="text-gradient"> Cancel</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={props.isSubmitting}
|
||||
className="text-white primary-gradient text-18 tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
{submitTask.loading
|
||||
? "Submitting Task"
|
||||
: submitTask.state == "success"
|
||||
? "Task Submitted"
|
||||
: submitTask.state == "bad"
|
||||
? "An Error Occurred"
|
||||
: "Send to Parents"}
|
||||
</button>
|
||||
{/* )} */}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
</div>
|
||||
</ModalCom>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuggestTask;
|
||||
@@ -10,7 +10,7 @@ export default function Accordion({ datas }) {
|
||||
<>
|
||||
<div className="accordion-item overflow-hidden relative z-[1]">
|
||||
<div
|
||||
className="accordion-title-bar flex items-center space-x-3 py-5 border-b border-light-purple dark:border-[#5356fb29] "
|
||||
className="accordion-title-bar flex items-center space-x-3 py-5 border-b border-light-purple dark:border-[#5356fb29] cursor-pointer"
|
||||
onClick={accordionHandler}
|
||||
>
|
||||
<div className="accordion-title-icon relative">
|
||||
@@ -36,7 +36,7 @@ export default function Accordion({ datas }) {
|
||||
<div className="w-[3px] h-auto bg-purple rounded-[28px]"></div>
|
||||
<div className="flex-1">
|
||||
<p className="text-base text-thin-light-gray tracking-wide">
|
||||
{datas.content}
|
||||
{datas.msg}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,59 +1,64 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function CountDown({ lastDate = "" }) {
|
||||
// const [showDate, setDate] = useState(0);
|
||||
const [showHour, setHour] = useState(0);
|
||||
const [showMinute, setMinute] = useState(0);
|
||||
const [showSecound, setDateSecound] = useState(0);
|
||||
// count Down
|
||||
const provideDate = new Date(lastDate);
|
||||
// format date
|
||||
const year = provideDate.getFullYear();
|
||||
const month = provideDate.getMonth();
|
||||
// console.log(month);
|
||||
const date = provideDate.getDate();
|
||||
// console.log(date);
|
||||
const hours = provideDate.getHours();
|
||||
// console.log(hours);
|
||||
const minutes = provideDate.getMinutes();
|
||||
// console.log(minutes);
|
||||
const seconds = provideDate.getSeconds();
|
||||
// console.log(seconds);
|
||||
|
||||
// date calculation logic
|
||||
const _seconds = 1000;
|
||||
const _minutes = _seconds * 60;
|
||||
const _hours = _minutes * 60;
|
||||
const _date = _hours * 24;
|
||||
|
||||
// interval function
|
||||
const startInterval = () => {
|
||||
const timer = setInterval(() => {
|
||||
const now = new Date();
|
||||
const distance =
|
||||
new Date(year, month, date, hours, minutes, seconds).getTime() -
|
||||
now.getTime();
|
||||
if (distance < 0) {
|
||||
clearInterval(timer);
|
||||
return;
|
||||
}
|
||||
// setDate(Math.floor(distance / _date));
|
||||
setMinute(Math.floor((distance % _hours) / _minutes));
|
||||
setHour(Math.floor((distance % _date) / _hours));
|
||||
setDateSecound(Math.floor((distance % _minutes) / _seconds));
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// effect
|
||||
useEffect(() => {
|
||||
if (lastDate !== "") {
|
||||
startInterval();
|
||||
}
|
||||
// State to store the countdown values
|
||||
const [countdownValues, setCountdownValues] = useState({
|
||||
showHour: 0,
|
||||
showMinute: 0,
|
||||
showSecond: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (lastDate) {
|
||||
// Interval function to update countdown values
|
||||
const intervalId = setInterval(() => {
|
||||
const now = new Date().getTime();
|
||||
const targetDate = new Date(lastDate).getTime();
|
||||
const distance = targetDate - now;
|
||||
|
||||
if (distance < 0) {
|
||||
// If the countdown has reached zero or gone past the target date, clear the interval
|
||||
clearInterval(intervalId);
|
||||
setCountdownValues({
|
||||
showHour: 0,
|
||||
showMinute: 0,
|
||||
showSecond: 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the countdown values (days, hours, minutes, seconds)
|
||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor(
|
||||
(distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
|
||||
);
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
// since we don't have a slot for days...
|
||||
const totalHours = days * 24 + hours;
|
||||
|
||||
// Update the countdown values in the state
|
||||
setCountdownValues({
|
||||
showHour: totalHours,
|
||||
showMinute: minutes,
|
||||
showSecond: seconds,
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// Clean up the interval on component unmount or when the lastDate prop changes
|
||||
return () => clearInterval(intervalId);
|
||||
}
|
||||
}, [lastDate]);
|
||||
|
||||
// Destructure the countdown values from the state
|
||||
const { showHour, showMinute, showSecond } = countdownValues;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{showHour} : {showMinute} : {showSecound}
|
||||
{showHour < 10 ? "0" + showHour : showHour} :{" "}
|
||||
{showMinute < 10 ? "0" + showMinute : showMinute} :{" "}
|
||||
{showSecond < 10 ? "0" + showSecond : showSecond}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import ATMCard from '../../assets/images/card.svg'
|
||||
import VisaCard from '../../assets/images/visa.svg'
|
||||
import MasterCard from '../../assets/images/master.svg'
|
||||
|
||||
export default function Icons({ name }) {
|
||||
return (
|
||||
<>
|
||||
@@ -468,6 +472,27 @@ export default function Icons({ name }) {
|
||||
>
|
||||
<rect y="0.823242" width="20" height="2.35294" rx="1.17647" />
|
||||
</svg>
|
||||
) : name === "right-arrow" ? (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
// enableBackground="new 0 0 24 24"
|
||||
viewBox="0 0 24 24"
|
||||
className="fill-black dark:fill-white"
|
||||
id="right-arrow"
|
||||
>
|
||||
<path
|
||||
d="M15.5,11.3L9.9,5.6c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l4.9,4.9l-4.9,4.9c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.6,0.4,1,1,1
|
||||
c0.3,0,0.5-0.1,0.7-0.3l5.7-5.7c0,0,0,0,0,0C15.9,12.3,15.9,11.7,15.5,11.3z"
|
||||
></path>
|
||||
</svg>
|
||||
) : name === "atm-card" ? (
|
||||
<img className="w-[20px]" src={ATMCard} alt="card" />
|
||||
) : name === "visa-card" ? (
|
||||
<img className="w-[20px]" src={VisaCard} alt="card" />
|
||||
) : name === "master-card" ? (
|
||||
<img className="w-[20px]" src={MasterCard} alt="card" />
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useRef } from "react";
|
||||
import Icons from "../../Icons";
|
||||
import { Link } from "react-router-dom";
|
||||
import Icons from "../../Icons";
|
||||
|
||||
export default function InputCom({
|
||||
label,
|
||||
@@ -21,7 +21,8 @@ export default function InputCom({
|
||||
blurHandler,
|
||||
spanTag,
|
||||
inputBg,
|
||||
direction
|
||||
direction,
|
||||
error,
|
||||
}) {
|
||||
const inputRef = useRef(null);
|
||||
// Entry Validation
|
||||
@@ -40,22 +41,29 @@ export default function InputCom({
|
||||
// for Patterns
|
||||
const inputPatterns = () => {
|
||||
const inputConfig = inputConfigs[inputRef?.current?.name]?.pattern;
|
||||
return inputConfig || ""
|
||||
}
|
||||
return inputConfig || "";
|
||||
};
|
||||
return (
|
||||
<div className={`input-com ${parentClass}`}>
|
||||
<div className={`flex items-center justify-between mb-2.5 ${labelClass}`}>
|
||||
{label && (
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
|
||||
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
|
||||
htmlFor={name}
|
||||
>
|
||||
{label}
|
||||
{spanTag && (
|
||||
{spanTag && spanTag == "*" ? (
|
||||
<span className="text-red-700 text-sm tracking-wide">
|
||||
{" "}
|
||||
{spanTag}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-green-700 text-sm tracking-wide">
|
||||
{spanTag}
|
||||
</span>
|
||||
)}
|
||||
{/* displays error is any */}
|
||||
{error && <span className="text-[12px] text-red-500">{error}</span>}
|
||||
</label>
|
||||
)}
|
||||
{forgotPassword && (
|
||||
@@ -68,13 +76,13 @@ export default function InputCom({
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={`input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-full rounded-[0.475rem] 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 ${inputClass}`}
|
||||
className={`input-wrapper border 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 ${inputClass}`}
|
||||
>
|
||||
<input
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={inputHandler}
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full ${
|
||||
className={`input-field placeholder:text-base text-dark-gray w-full h-full tracking-wide ${
|
||||
inputBg ? inputBg : "bg-[#FAFAFA]"
|
||||
} dark:bg-[#11131F] focus:ring-0 focus:outline-none ${fieldClass}`}
|
||||
type={type}
|
||||
@@ -89,8 +97,10 @@ export default function InputCom({
|
||||
dir={direction}
|
||||
/>
|
||||
{iconName && (
|
||||
<div className="absolute right-6 bottom-[10px] z-10">
|
||||
<Icons name={iconName} />
|
||||
<div className="absolute right-6 bottom-[10px] z-10 flex gap-2">
|
||||
{iconName.split(" ").map((item, index) => (
|
||||
<Icons key={index} name={item} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{passIcon && (
|
||||
@@ -116,6 +126,9 @@ const inputConfigs = {
|
||||
province: { minLength: 3, maxLength: 25, pattern: "[a-zA-Z]+" },
|
||||
city: { minLength: 3, maxLength: 25, pattern: "[a-zA-Z]+" },
|
||||
amount: { minLength: 1, maxLength: 9, pattern: "[0-9]+" },
|
||||
description: { minLength: 5, maxLength: 299 },
|
||||
title: { minLength: 5, maxLength: 149 },
|
||||
job_detail: { minLength: 4, maxLength: 1440 }
|
||||
};
|
||||
|
||||
/* Numbers Only: <input type="text" pattern="[0-9]*" /> strictly numbers
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
|
||||
// export const PriceFormatter = (price, currency, currencyName) => {
|
||||
// const supportedCurrencies = ["USD", "EUR", "GBP"];
|
||||
// const symbolFormatter = supportedCurrencies.includes(currency)
|
||||
// ? currency
|
||||
// : undefined;
|
||||
|
||||
// const formatter = new Intl.NumberFormat("en", {
|
||||
// style: symbolFormatter,
|
||||
// currencyDisplay: "symbol",
|
||||
// minimumFractionDigits: 2,
|
||||
// });
|
||||
|
||||
// const displayCurrencyName = symbolFormatter ? "" : currencyName;
|
||||
|
||||
// return `${formatter.format(price)} ${displayCurrencyName}`;
|
||||
// };
|
||||
|
||||
export const PriceFormatter = (
|
||||
price = "00",
|
||||
currency = "",
|
||||
currencyName = ""
|
||||
) => {
|
||||
// Convert the number to a string
|
||||
let numStr = String(price);
|
||||
|
||||
// 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, ',');
|
||||
let formattedInteger = integerPart;
|
||||
|
||||
// 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 (
|
||||
<span className="text-sm flex items-center">
|
||||
<sup>{currency || currencyName || ""}</sup>
|
||||
<span className="px-1 font-bold text-lg">{formattedInteger || ""}</span>
|
||||
<sup>{formattedDecimal || ""}</sup>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -1,7 +1,13 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import Icons from "./Icons";
|
||||
|
||||
export default function SearchCom({ className, inputClasses }) {
|
||||
export default function SearchCom({
|
||||
className,
|
||||
inputClasses,
|
||||
placeholder,
|
||||
handleSearch,
|
||||
value,
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`w-full h-[48px] pl-8 flex rounded-full overflow-hidden bg-white dark:bg-dark-white ${
|
||||
@@ -17,7 +23,9 @@ export default function SearchCom({ className, inputClasses }) {
|
||||
inputClasses || ""
|
||||
}`}
|
||||
type="text"
|
||||
placeholder="Search items, collections..."
|
||||
onInput={handleSearch}
|
||||
value={value}
|
||||
placeholder={placeholder || "Search items, collections..."}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import useToggle from "../../../hooks/useToggle";
|
||||
|
||||
function SelectBox({ datas = [], className, action, contentBodyClasses }) {
|
||||
function SelectBox({ datas = [], className, action, contentBodyClasses, position }) {
|
||||
const [item, setItem] = useState(datas[0]);
|
||||
// custom hook
|
||||
const [toggle, setToggle] = useToggle(false);
|
||||
@@ -49,7 +49,7 @@ function SelectBox({ datas = [], className, action, contentBodyClasses }) {
|
||||
|
||||
<div
|
||||
style={{ boxShadow: "0px 4px 87px 0px #0000002B" }}
|
||||
className={`drop-down-content w-[120px] bg-white dark:bg-dark-white rounded-[4px] p-3 absolute right-0 top-[100%] z-20 ${
|
||||
className={`drop-down-content w-[120px] bg-white dark:bg-dark-white rounded-[4px] p-3 absolute ${position =='left' ? 'left-0' : 'right-0'} top-[100%] z-20 ${
|
||||
toggle ? "active" : ""
|
||||
} ${contentBodyClasses || ""}`}
|
||||
>
|
||||
|
||||
@@ -51,8 +51,6 @@ export default function HistoryTable({ className }) {
|
||||
<td className="py-4 text-center">Value</td>
|
||||
<td className="py-4 text-center">USD</td>
|
||||
<td className="py-4 text-center">24H%</td>
|
||||
<td className="py-4 text-center">Bits</td>
|
||||
<td className="py-4 text-center">Time</td>
|
||||
<td className="py-4 text-right">Status</td>
|
||||
</tr>
|
||||
|
||||
@@ -165,16 +163,6 @@ export default function HistoryTable({ className }) {
|
||||
-24.75 (11.5%)
|
||||
</span>
|
||||
</td>
|
||||
<td className="text-right py-4 px-2">
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium">
|
||||
343
|
||||
</span>
|
||||
</td>
|
||||
<td className="text-right py-4 px-2">
|
||||
<span className="text-base text-thin-light-gray">
|
||||
2 Hours 1 min 30s
|
||||
</span>
|
||||
</td>
|
||||
<td className="text-right py-4 px-2">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -13,7 +13,9 @@ import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
|
||||
export default function History() {
|
||||
|
||||
const apiCall = new usersService()
|
||||
const apiCall = new usersService()
|
||||
|
||||
let [tab, setTab] = useState("purchases"); //STATE FOR SWITCHING BETWEEN TABS
|
||||
|
||||
let [paymentHistory, setPaymentHistory] = useState({ // FOR PAYMENT HISTORY
|
||||
loading: true,
|
||||
@@ -63,7 +65,7 @@ export default function History() {
|
||||
<>
|
||||
<Layout>
|
||||
<div className="history-wrapper w-full mb-10">
|
||||
<div className="main-wrapper w-full">
|
||||
<div className="w-full">
|
||||
<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">
|
||||
@@ -213,35 +215,59 @@ export default function History() {
|
||||
{/*</div>*/}
|
||||
{/*<MarketHistorySection />*/}
|
||||
{/* <TopHxBox className="mb-11" /> */}
|
||||
<div className='w-full lg:flex xl:space-x-8 lg:space-x-4 bottomMargin'>
|
||||
{/* PURCHASE SECTION */}
|
||||
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
|
||||
<div className="wallet w-full md:p-8 p-4 h-full max-h-[700px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
|
||||
<h2 className='text-slate-900 dark:text-white text-xl lg:text-2xl font-medium'>Purchases</h2>
|
||||
{purchaseHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
:
|
||||
<PurchasesTable purchase={purchaseHistory} />
|
||||
}
|
||||
</div>
|
||||
<div className='w-full p-4 md:p-8 bg-white dark:bg-dark-white rounded-2xl shadow bottomMargin'>
|
||||
{/* switch button */}
|
||||
<div className="my-1 flex items-center border-b border-slate-300">
|
||||
<button
|
||||
name="purchases"
|
||||
onClick={(e) => setTab(e.target.name)}
|
||||
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border ${
|
||||
tab == "purchases" ? "border-sky-blue" : "border-slate-300"
|
||||
} tracking-wide transition duration-200`}
|
||||
>
|
||||
Purchases
|
||||
</button>
|
||||
<button
|
||||
name="recent"
|
||||
onClick={(e) => setTab(e.target.name)}
|
||||
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border ${
|
||||
tab == "recent" ? "border-sky-blue" : "border-slate-300"
|
||||
} tracking-wide transition duration-200`}
|
||||
>
|
||||
Recent Activity
|
||||
</button>
|
||||
</div>
|
||||
{/* END OF PURCHASE SECTION */}
|
||||
|
||||
{/* RECENT ACTIVITY SECTION */}
|
||||
<div className="lg:w-1/2 w-full mb-10 lg:mb-0">
|
||||
<div className="wallet w-full md:p-8 p-4 h-full max-h-[700px] bg-white dark:bg-dark-white overflow-y-auto rounded-2xl shadow">
|
||||
<h2 className='text-slate-900 dark:text-white text-xl lg:text-2xl font-medium'>Recent Activity</h2>
|
||||
{/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */}
|
||||
{paymentHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
:
|
||||
<RecentActivityTable payment={paymentHistory} />
|
||||
{/* 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>
|
||||
{purchaseHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
:
|
||||
<PurchasesTable purchase={purchaseHistory} />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{/* END OF PURCHASE SECTION */}
|
||||
|
||||
{/* 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>
|
||||
{/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */}
|
||||
{paymentHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
:
|
||||
<RecentActivityTable payment={paymentHistory} />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{/* END OF RECENT ACTIVITY SECTION */}
|
||||
</div>
|
||||
{/* END OF RECENT ACTIVITY SECTION */}
|
||||
</div>
|
||||
<HistoryTable />
|
||||
{/*<HistoryTable />*/}
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
@@ -6,8 +6,8 @@ import SliderCom from "../Helpers/SliderCom";
|
||||
export default function FamilyActiveLSlde({ className, trending }) {
|
||||
const settings = {
|
||||
arrows: false,
|
||||
slidesToShow: 4,
|
||||
slidesToScroll: 4,
|
||||
slidesToShow: 3,
|
||||
slidesToScroll: 3,
|
||||
infinite: true,
|
||||
responsive: [
|
||||
{
|
||||
|
||||
@@ -3,23 +3,22 @@ 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";
|
||||
|
||||
export default function FamilyDash({familyOffers}) {
|
||||
console.log("PROPS IN FAMILY DASH->", familyOffers);
|
||||
|
||||
|
||||
export default function FamilyDash(props) {
|
||||
|
||||
console.log("PROPS IN FAMILY DASH->",props);
|
||||
|
||||
const trending = datas.datas;
|
||||
return (
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
<CommonHead
|
||||
commonHeadData={props.commonHeadData}
|
||||
/>
|
||||
<FamilyActiveLSlde trending={trending} className="mb-10" />
|
||||
<TopSellerTopBuyerSliderSection className="mb-10" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const trending = datas.datas;
|
||||
return (
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
{/* <CommonHead commonHeadData={props.commonHeadData} /> */}
|
||||
<MyOffersFamilyTable familyOffers={familyOffers} className="mb-10" />
|
||||
<FamilyActiveLSlde trending={trending} className="mb-10" />
|
||||
{/*<TopSellerTopBuyerSliderSection className="mb-10" />*/}
|
||||
<ParentWaiting className="mb-10" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,39 +1,46 @@
|
||||
import React from "react";
|
||||
import datas from "../../data/product_data.json";
|
||||
import Hero from "./Hero";
|
||||
import HomeTaskDisplay from "./HomeTaskDisplay";
|
||||
// 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 HomeActivities from "./HomeActivities";
|
||||
|
||||
export default function FullAccountDash(props) {
|
||||
console.log("PROPS IN HOME->", props);
|
||||
|
||||
console.log("PROPS IN HOME->",props);
|
||||
const trending = datas.datas;
|
||||
const jobData = datas.datas; // api calls or cache
|
||||
|
||||
const trending = datas.datas;
|
||||
const jobData = datas.datas; // api calls or cache
|
||||
//getHomeDate
|
||||
const userApi = new usersService();
|
||||
const homeData = userApi.getHomeDate();
|
||||
const userApi = new usersService();
|
||||
|
||||
const {userDetails} = useSelector((state) => state?.userDetails)
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
<Hero className="mb-10"
|
||||
data={userDetails}
|
||||
bannerList={props.bannerList}
|
||||
/>
|
||||
<HomeTaskDisplay
|
||||
jobData={jobData}
|
||||
className="mb-10"
|
||||
bannerList={props.bannerList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<div className="home-page-wrapper">
|
||||
<Hero
|
||||
className="mb-10"
|
||||
data={userDetails}
|
||||
bannerList={props.bannerList}
|
||||
nextDueTask={props.nextDueTask}
|
||||
/>
|
||||
<HomeActivities className="mb-10" />
|
||||
{/*<UpdateTable className="mb-10"/>*/}
|
||||
{/*<SellHistoryMarketVisitorAnalytic className="mb-10"/>*/}
|
||||
{/*<TopSellerTopBuyerSliderSection className="mb-10" />*/}
|
||||
|
||||
{/*<HomeTaskDisplay*/}
|
||||
{/* jobData={jobData}*/}
|
||||
{/* className="mb-10"*/}
|
||||
{/* bannerList={props.bannerList}*/}
|
||||
{/*/>*/}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// /*
|
||||
// <Layout>
|
||||
@@ -46,10 +53,10 @@ export default function FullAccountDash(props) {
|
||||
// className="mb-10"
|
||||
// bannerList={props.bannerList}
|
||||
// />
|
||||
{/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
|
||||
{
|
||||
/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
|
||||
<TopSellerTopBuyerSliderSection className="mb-10" />
|
||||
<UpdateTable className="mb-10"/>*/}
|
||||
<UpdateTable className="mb-10"/>*/
|
||||
}
|
||||
// </div>
|
||||
// </Layout>
|
||||
|
||||
|
||||
|
||||
@@ -3,15 +3,11 @@ import { Link } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import heroBg from "../../assets/images/hero-bg.svg";
|
||||
import heroUser from "../../assets/images/hero-user.png";
|
||||
import slider1 from "../../assets/images/slider-1.jpg";
|
||||
import slider2 from "../../assets/images/slider-2.jpg";
|
||||
import slider3 from "../../assets/images/slider-3.jpg";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
import SliderCom from "../Helpers/SliderCom";
|
||||
import HomeSliders from "./HomeSliders";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export default function Hero({ className,bannerList }) {
|
||||
export default function Hero({ className, bannerList, nextDueTask }) {
|
||||
const settings = {
|
||||
autoplay: true,
|
||||
dots: true,
|
||||
@@ -19,23 +15,12 @@ export default function Hero({ className,bannerList }) {
|
||||
infinite: true,
|
||||
swipe: true,
|
||||
};
|
||||
const sildeData =null;
|
||||
const [addFavorite, setValue] = useState(false);
|
||||
const sildeData = null;
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
const {userDetails} = useSelector((state) => state?.userDetails)
|
||||
const favoriteHandler = () => {
|
||||
if (!addFavorite) {
|
||||
setValue(true);
|
||||
toast.success("Added to Favorite List");
|
||||
} else {
|
||||
setValue(false);
|
||||
toast.warn("Remove to Favorite List");
|
||||
}
|
||||
};
|
||||
|
||||
let loginDate = userDetails?.last_login.split(' ')[0]
|
||||
let {firstname, lastname, email, profile_pic} = userDetails
|
||||
let userEmail = email.split('@')[0]
|
||||
let loginDate = userDetails?.last_login.split(" ")[0];
|
||||
let { firstname, lastname, email, profile_pic } = userDetails;
|
||||
let userEmail = email.split("@")[0];
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -55,13 +40,13 @@ export default function Hero({ className,bannerList }) {
|
||||
Welcome
|
||||
</h1>
|
||||
<span className="text-[18px] font-thin tracking-wide text-white">
|
||||
Last Login : {loginDate}
|
||||
Last Login : {loginDate}
|
||||
</span>
|
||||
</div>
|
||||
{/* user */}
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-14 h-14 flex justify-center items-center rounded-full overflow-hidden">
|
||||
<img src={profile_pic != '' ? profile_pic : heroUser} alt="" />
|
||||
<img src={profile_pic != "" ? profile_pic : heroUser} alt="" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xl tracking-wide font-bold antise text-white">
|
||||
@@ -71,33 +56,35 @@ export default function Hero({ className,bannerList }) {
|
||||
</div>
|
||||
</div>
|
||||
{/* countdown */}
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Current Task</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
ABCDEFGH01
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">773.69 USD</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Next due in</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
<CountDown lastDate="2023-04-26 4:00:00" />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
{nextDueTask?.next_due && Object.keys(nextDueTask.next_due)?.length != 0 && (
|
||||
<div className="w-full h-32 flex justify-evenly items-center sm:p-6 p-1 rounded-2xl border border-white-opacity">
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Current Task</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{(nextDueTask.next_due.item_code).substr(0,4)+'...'}
|
||||
</p>
|
||||
<p className="text-base text-white tracking-wide">
|
||||
{nextDueTask.next_due.price * 0.01} Naira
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1px] h-full bg-white-opacity"></div>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-white tracking-wide">Next due in</p>
|
||||
<p className="lg:text-2xl text-lg font-bold tracking-wide text-white">
|
||||
{/* <CountDown lastDate="2023-04-26 4:00:00" /> */}
|
||||
<CountDown lastDate={nextDueTask.next_due.due_date} />
|
||||
</p>
|
||||
<div className="text-base text-white tracking-wide flex gap-[23px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* action */}
|
||||
<div className="flex lg:space-x-3 space-x-1 items-center">
|
||||
<Link
|
||||
to="/mytask"
|
||||
className="text-white text-base sm:block hidden"
|
||||
>
|
||||
<Link to="/mytask" className="text-white text-base sm:block hidden">
|
||||
<span className=" border-b dark:border-[#5356fb29] border-white">
|
||||
{" "}
|
||||
View All Task(s)
|
||||
@@ -106,9 +93,9 @@ export default function Hero({ className,bannerList }) {
|
||||
</div>
|
||||
</div>
|
||||
<HomeSliders
|
||||
settings={settings}
|
||||
sideData={sildeData}
|
||||
bannerList={bannerList}
|
||||
settings={settings}
|
||||
sideData={sildeData}
|
||||
bannerList={bannerList}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
import React, { useState } from "react";
|
||||
import dataImage1 from "../../assets/images/data-table-user-1.png";
|
||||
import dataImage2 from "../../assets/images/data-table-user-2.png";
|
||||
import dataImage3 from "../../assets/images/data-table-user-3.png";
|
||||
import dataImage4 from "../../assets/images/data-table-user-4.png";
|
||||
import SelectBox from "../Helpers/SelectBox";
|
||||
|
||||
export default function HomeActivities({ className }) {
|
||||
const filterCategories = ["All Categories", "Explore", "Featured"];
|
||||
const [selectedCategory, setCategory] = useState(filterCategories[0]);
|
||||
return (
|
||||
<div
|
||||
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow relative min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
<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">
|
||||
Recent Activities
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative w-full overflow-x-auto sm:rounded-lg">
|
||||
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<tbody>
|
||||
{/* table heading */}
|
||||
{/*<tr className="text-base text-thin-light-gray whitespace-nowrap px-2 border-b dark:border-[#5356fb29] default-border-b dark:border-[#5356fb29] ottom ">*/}
|
||||
{/* <td className="py-4 w-[300px] block whitespace-nowrap">*/}
|
||||
{/* All Product*/}
|
||||
{/* </td>*/}
|
||||
{/* <td className="py-4 whitespace-nowrap text-center">.</td>*/}
|
||||
{/* <td className="py-4 whitespace-nowrap text-center"></td>*/}
|
||||
|
||||
{/* <td className="py-4 whitespace-nowrap text-right"></td>*/}
|
||||
{/*</tr>*/}
|
||||
<tr className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<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 className="flex flex-col">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
Mullican Computer Joy
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Owned by <span className="text-purple">Xoeyam</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18Z"
|
||||
fill="#627EEA"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 2.25V7.23937L13.4983 9.12375L9.28125 2.25Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
<path
|
||||
d="M9.28012 2.25L5.0625 9.12375L9.28012 7.23937V2.25Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 12.3582V15.7483L13.5011 9.91016L9.28125 12.3582Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
<path
|
||||
d="M9.28012 15.7483V12.3576L5.0625 9.91016L9.28012 15.7483Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 11.572L13.4983 9.12348L9.28125 7.24023V11.572Z"
|
||||
fill="white"
|
||||
fillOpacity="0.2"
|
||||
/>
|
||||
<path
|
||||
d="M5.0625 9.12348L9.28012 11.572V7.24023L5.0625 9.12348Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
7473 ETH
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.55225 0C7.8457 0 8.13914 0 8.43205 0C8.44829 0.026534 8.47537 0.0151623 8.49756 0.0162453C9.28966 0.0649812 10.0606 0.220936 10.8013 0.505229C12.7699 1.26172 14.2323 2.58354 15.183 4.46638C15.5999 5.29218 15.8506 6.16997 15.9561 7.08891C15.9691 7.201 15.9621 7.3158 16 7.42465C16 7.80858 16 8.19251 16 8.57698C15.9778 8.5916 15.9854 8.61543 15.9838 8.63546C15.9475 9.10387 15.8744 9.56686 15.7515 10.0206C15.1787 12.1342 13.9524 13.7603 12.0818 14.8942C11.1516 15.4579 10.1397 15.8002 9.06064 15.941C8.89497 15.9626 8.72875 15.98 8.56308 15.9995C8.17217 15.9995 7.78127 15.9995 7.39036 16C7.3752 15.9789 7.35138 15.9865 7.33135 15.9848C6.96752 15.9545 6.60639 15.9009 6.25068 15.8197C4.77639 15.4829 3.48998 14.793 2.4131 13.7311C0.998917 12.3372 0.204656 10.6461 0.0270709 8.66687C0.0205739 8.59431 0.033568 8.51904 0 8.44972C0 8.15081 0 7.85244 0 7.55352C0.0265295 7.53403 0.0151597 7.50479 0.016784 7.47988C0.0730915 6.64162 0.251218 5.83044 0.564158 5.05066C1.10179 3.71043 1.93774 2.59058 3.07634 1.70142C4.33839 0.715876 5.77098 0.159745 7.36762 0.0270755C7.4288 0.0216604 7.49432 0.0341151 7.55225 0ZM7.24635 9.86252C7.24635 10.2383 7.24526 10.6147 7.24743 10.9905C7.24797 11.0457 7.23389 11.0679 7.17596 11.0593C7.09691 11.0479 7.01678 11.0446 6.93774 11.0338C6.26746 10.9461 5.63563 10.7371 5.03952 10.4192C5.00379 10.4002 4.97834 10.3802 4.9621 10.4425C4.81375 11.0176 4.66324 11.5926 4.51164 12.1666C4.50027 12.2094 4.51272 12.2278 4.54954 12.2473C4.66486 12.3096 4.78235 12.3665 4.90309 12.4152C5.5961 12.6968 6.31998 12.8408 7.06497 12.8842C7.14131 12.8885 7.16134 12.9112 7.1608 12.9865C7.15701 13.4159 7.16026 13.8453 7.15809 14.2747C7.15755 14.3397 7.17488 14.3619 7.2431 14.3614C7.69085 14.3581 8.13914 14.3576 8.5869 14.3614C8.66432 14.3619 8.67731 14.3359 8.67731 14.2666C8.67461 13.8026 8.67677 13.3385 8.67461 12.8744C8.67407 12.8089 8.68544 12.7786 8.76015 12.765C9.09962 12.7049 9.4288 12.6058 9.74228 12.4607C10.3498 12.1802 10.8408 11.7703 11.1603 11.1724C11.4288 10.6699 11.51 10.1327 11.4618 9.56957C11.4158 9.03239 11.2366 8.55207 10.8787 8.14431C10.5506 7.77121 10.1402 7.51129 9.69843 7.29522C9.39145 7.14523 9.07363 7.02284 8.75041 6.91129C8.7098 6.89721 8.67407 6.88693 8.67407 6.82736C8.67623 6.14993 8.67569 5.4725 8.67461 4.79507C8.67461 4.75121 8.68489 4.73117 8.73308 4.73767C8.87547 4.75717 9.01895 4.77016 9.16134 4.79236C9.634 4.86493 10.0796 5.02467 10.5116 5.22395C10.5717 5.25157 10.5945 5.24886 10.6123 5.17684C10.7434 4.6467 10.8771 4.1171 11.0162 3.58913C11.0379 3.5079 11.0244 3.47541 10.948 3.44076C10.2799 3.13751 9.57282 3.01025 8.8457 2.97614C8.78018 2.97289 8.76123 2.95556 8.76178 2.88896C8.76503 2.50232 8.76232 2.11568 8.76448 1.72904C8.76503 1.66785 8.75041 1.64727 8.68489 1.64727C8.23173 1.64998 7.77802 1.64998 7.32485 1.64727C7.26151 1.64673 7.24418 1.66406 7.24418 1.72742C7.24689 2.1433 7.24256 2.55972 7.24797 2.9756C7.24905 3.06116 7.2209 3.08661 7.14239 3.10285C6.73579 3.18679 6.34651 3.32271 5.98646 3.53281C5.20628 3.98822 4.72117 4.64724 4.61938 5.5586C4.51597 6.48837 4.83812 7.2427 5.57661 7.81778C6.05739 8.19251 6.60639 8.43781 7.1738 8.64683C7.2274 8.66633 7.24743 8.68907 7.24689 8.7481C7.24472 9.12066 7.24635 9.49159 7.24635 9.86252Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
<path
|
||||
d="M7.2452 9.86252C7.2452 9.49158 7.24358 9.12119 7.24683 8.75026C7.24737 8.69123 7.22734 8.66903 7.17374 8.64899C6.60687 8.43997 6.05787 8.19467 5.57655 7.81994C4.8386 7.24486 4.51591 6.49053 4.61933 5.56076C4.72057 4.6494 5.20568 3.99092 5.98641 3.53497C6.34645 3.32486 6.73519 3.18894 7.14233 3.10501C7.22084 3.08876 7.24899 3.06277 7.24791 2.97775C7.2425 2.56187 7.24683 2.14545 7.24412 1.72957C7.24358 1.66621 7.2609 1.64888 7.32479 1.64943C7.77796 1.65213 8.23167 1.65213 8.68483 1.64943C8.7498 1.64888 8.76442 1.66946 8.76442 1.73119C8.76171 2.11783 8.76496 2.50447 8.76171 2.89111C8.76117 2.95717 8.78012 2.97504 8.84563 2.97829C9.57276 3.01295 10.2793 3.13966 10.948 3.44291C11.0243 3.47757 11.0373 3.51006 11.0162 3.59128C10.877 4.11926 10.7433 4.64885 10.6123 5.17899C10.5944 5.25156 10.5717 5.25372 10.5116 5.2261C10.079 5.02683 9.63394 4.86708 9.16128 4.79452C9.01889 4.77286 8.87595 4.75932 8.73302 4.73983C8.68483 4.73333 8.67455 4.75337 8.67455 4.79723C8.67563 5.47466 8.67617 6.15209 8.674 6.82952C8.674 6.88908 8.70974 6.89937 8.75034 6.91345C9.07303 7.02446 9.39138 7.14684 9.69837 7.29738C10.1396 7.51344 10.5506 7.77283 10.8787 8.14647C11.2365 8.55369 11.4157 9.03455 11.4618 9.57173C11.51 10.1349 11.4287 10.6726 11.1602 11.1746C10.8408 11.7724 10.3497 12.1818 9.74222 12.4629C9.42874 12.608 9.09956 12.7071 8.76009 12.7672C8.68483 12.7802 8.674 12.811 8.67455 12.8766C8.67671 13.3406 8.67455 13.8047 8.67725 14.2688C8.67779 14.3381 8.66426 14.3646 8.58684 14.3636C8.13908 14.3598 7.69079 14.3608 7.24304 14.3636C7.17536 14.3641 7.15803 14.3424 7.15803 14.2769C7.1602 13.8475 7.15695 13.4181 7.16074 12.9887C7.16128 12.9128 7.14179 12.8906 7.06491 12.8863C6.31992 12.843 5.59658 12.699 4.90303 12.4174C4.78229 12.3681 4.66426 12.3112 4.54948 12.2495C4.51321 12.23 4.50075 12.2116 4.51158 12.1688C4.66318 11.5943 4.81369 11.0197 4.96204 10.4446C4.97829 10.3824 5.00373 10.4024 5.03947 10.4214C5.63557 10.7387 6.2674 10.9477 6.93768 11.036C7.01672 11.0463 7.09685 11.0501 7.1759 11.0614C7.23383 11.0695 7.24737 11.0479 7.24737 10.9927C7.24412 10.6147 7.2452 10.2383 7.2452 9.86252ZM8.68537 9.36325C8.67942 9.37245 8.67455 9.37678 8.67455 9.38112C8.674 9.83978 8.67401 10.2984 8.67292 10.7571C8.67292 10.8177 8.70216 10.7928 8.72598 10.7755C8.82452 10.7046 8.90736 10.619 8.96691 10.5123C9.17698 10.1333 9.05679 9.63725 8.68537 9.36325ZM7.23871 6.11147C7.23871 5.75354 7.23871 5.40589 7.23871 5.05174C6.92522 5.33982 6.92522 5.77249 7.23871 6.11147Z"
|
||||
fill="#FEFEFE"
|
||||
/>
|
||||
<path
|
||||
d="M8.68433 9.36328C9.05574 9.63729 9.17539 10.1333 8.96586 10.5118C8.90631 10.619 8.82347 10.7046 8.72493 10.775C8.70111 10.7918 8.67188 10.8172 8.67188 10.7566C8.67242 10.2979 8.67296 9.83927 8.6735 9.38061C8.67404 9.37682 8.67891 9.37249 8.68433 9.36328Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
<path
|
||||
d="M7.23882 6.11149C6.92533 5.77305 6.92587 5.33984 7.23882 5.05176C7.23882 5.40591 7.23882 5.75355 7.23882 6.11149Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium">
|
||||
6392.99$
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4">
|
||||
<button
|
||||
type="button"
|
||||
className="text-sm text-white bg-purple px-2.5 py-1.5 rounded-full"
|
||||
>
|
||||
Active
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50">
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
|
||||
<img
|
||||
src={dataImage2}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
Mullican Computer Joy
|
||||
</h1>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Owned by <span className="text-purple">Xoeyam</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18Z"
|
||||
fill="#627EEA"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 2.25V7.23937L13.4983 9.12375L9.28125 2.25Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
<path
|
||||
d="M9.28012 2.25L5.0625 9.12375L9.28012 7.23937V2.25Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 12.3582V15.7483L13.5011 9.91016L9.28125 12.3582Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
<path
|
||||
d="M9.28012 15.7483V12.3576L5.0625 9.91016L9.28012 15.7483Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.28125 11.572L13.4983 9.12348L9.28125 7.24023V11.572Z"
|
||||
fill="white"
|
||||
fillOpacity="0.2"
|
||||
/>
|
||||
<path
|
||||
d="M5.0625 9.12348L9.28012 11.572V7.24023L5.0625 9.12348Z"
|
||||
fill="white"
|
||||
fillOpacity="0.602"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
|
||||
7473 ETH
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-center py-4 px-2">
|
||||
<div className="flex space-x-1 items-center justify-center">
|
||||
<span>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.55225 0C7.8457 0 8.13914 0 8.43205 0C8.44829 0.026534 8.47537 0.0151623 8.49756 0.0162453C9.28966 0.0649812 10.0606 0.220936 10.8013 0.505229C12.7699 1.26172 14.2323 2.58354 15.183 4.46638C15.5999 5.29218 15.8506 6.16997 15.9561 7.08891C15.9691 7.201 15.9621 7.3158 16 7.42465C16 7.80858 16 8.19251 16 8.57698C15.9778 8.5916 15.9854 8.61543 15.9838 8.63546C15.9475 9.10387 15.8744 9.56686 15.7515 10.0206C15.1787 12.1342 13.9524 13.7603 12.0818 14.8942C11.1516 15.4579 10.1397 15.8002 9.06064 15.941C8.89497 15.9626 8.72875 15.98 8.56308 15.9995C8.17217 15.9995 7.78127 15.9995 7.39036 16C7.3752 15.9789 7.35138 15.9865 7.33135 15.9848C6.96752 15.9545 6.60639 15.9009 6.25068 15.8197C4.77639 15.4829 3.48998 14.793 2.4131 13.7311C0.998917 12.3372 0.204656 10.6461 0.0270709 8.66687C0.0205739 8.59431 0.033568 8.51904 0 8.44972C0 8.15081 0 7.85244 0 7.55352C0.0265295 7.53403 0.0151597 7.50479 0.016784 7.47988C0.0730915 6.64162 0.251218 5.83044 0.564158 5.05066C1.10179 3.71043 1.93774 2.59058 3.07634 1.70142C4.33839 0.715876 5.77098 0.159745 7.36762 0.0270755C7.4288 0.0216604 7.49432 0.0341151 7.55225 0ZM7.24635 9.86252C7.24635 10.2383 7.24526 10.6147 7.24743 10.9905C7.24797 11.0457 7.23389 11.0679 7.17596 11.0593C7.09691 11.0479 7.01678 11.0446 6.93774 11.0338C6.26746 10.9461 5.63563 10.7371 5.03952 10.4192C5.00379 10.4002 4.97834 10.3802 4.9621 10.4425C4.81375 11.0176 4.66324 11.5926 4.51164 12.1666C4.50027 12.2094 4.51272 12.2278 4.54954 12.2473C4.66486 12.3096 4.78235 12.3665 4.90309 12.4152C5.5961 12.6968 6.31998 12.8408 7.06497 12.8842C7.14131 12.8885 7.16134 12.9112 7.1608 12.9865C7.15701 13.4159 7.16026 13.8453 7.15809 14.2747C7.15755 14.3397 7.17488 14.3619 7.2431 14.3614C7.69085 14.3581 8.13914 14.3576 8.5869 14.3614C8.66432 14.3619 8.67731 14.3359 8.67731 14.2666C8.67461 13.8026 8.67677 13.3385 8.67461 12.8744C8.67407 12.8089 8.68544 12.7786 8.76015 12.765C9.09962 12.7049 9.4288 12.6058 9.74228 12.4607C10.3498 12.1802 10.8408 11.7703 11.1603 11.1724C11.4288 10.6699 11.51 10.1327 11.4618 9.56957C11.4158 9.03239 11.2366 8.55207 10.8787 8.14431C10.5506 7.77121 10.1402 7.51129 9.69843 7.29522C9.39145 7.14523 9.07363 7.02284 8.75041 6.91129C8.7098 6.89721 8.67407 6.88693 8.67407 6.82736C8.67623 6.14993 8.67569 5.4725 8.67461 4.79507C8.67461 4.75121 8.68489 4.73117 8.73308 4.73767C8.87547 4.75717 9.01895 4.77016 9.16134 4.79236C9.634 4.86493 10.0796 5.02467 10.5116 5.22395C10.5717 5.25157 10.5945 5.24886 10.6123 5.17684C10.7434 4.6467 10.8771 4.1171 11.0162 3.58913C11.0379 3.5079 11.0244 3.47541 10.948 3.44076C10.2799 3.13751 9.57282 3.01025 8.8457 2.97614C8.78018 2.97289 8.76123 2.95556 8.76178 2.88896C8.76503 2.50232 8.76232 2.11568 8.76448 1.72904C8.76503 1.66785 8.75041 1.64727 8.68489 1.64727C8.23173 1.64998 7.77802 1.64998 7.32485 1.64727C7.26151 1.64673 7.24418 1.66406 7.24418 1.72742C7.24689 2.1433 7.24256 2.55972 7.24797 2.9756C7.24905 3.06116 7.2209 3.08661 7.14239 3.10285C6.73579 3.18679 6.34651 3.32271 5.98646 3.53281C5.20628 3.98822 4.72117 4.64724 4.61938 5.5586C4.51597 6.48837 4.83812 7.2427 5.57661 7.81778C6.05739 8.19251 6.60639 8.43781 7.1738 8.64683C7.2274 8.66633 7.24743 8.68907 7.24689 8.7481C7.24472 9.12066 7.24635 9.49159 7.24635 9.86252Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
<path
|
||||
d="M7.2452 9.86252C7.2452 9.49158 7.24358 9.12119 7.24683 8.75026C7.24737 8.69123 7.22734 8.66903 7.17374 8.64899C6.60687 8.43997 6.05787 8.19467 5.57655 7.81994C4.8386 7.24486 4.51591 6.49053 4.61933 5.56076C4.72057 4.6494 5.20568 3.99092 5.98641 3.53497C6.34645 3.32486 6.73519 3.18894 7.14233 3.10501C7.22084 3.08876 7.24899 3.06277 7.24791 2.97775C7.2425 2.56187 7.24683 2.14545 7.24412 1.72957C7.24358 1.66621 7.2609 1.64888 7.32479 1.64943C7.77796 1.65213 8.23167 1.65213 8.68483 1.64943C8.7498 1.64888 8.76442 1.66946 8.76442 1.73119C8.76171 2.11783 8.76496 2.50447 8.76171 2.89111C8.76117 2.95717 8.78012 2.97504 8.84563 2.97829C9.57276 3.01295 10.2793 3.13966 10.948 3.44291C11.0243 3.47757 11.0373 3.51006 11.0162 3.59128C10.877 4.11926 10.7433 4.64885 10.6123 5.17899C10.5944 5.25156 10.5717 5.25372 10.5116 5.2261C10.079 5.02683 9.63394 4.86708 9.16128 4.79452C9.01889 4.77286 8.87595 4.75932 8.73302 4.73983C8.68483 4.73333 8.67455 4.75337 8.67455 4.79723C8.67563 5.47466 8.67617 6.15209 8.674 6.82952C8.674 6.88908 8.70974 6.89937 8.75034 6.91345C9.07303 7.02446 9.39138 7.14684 9.69837 7.29738C10.1396 7.51344 10.5506 7.77283 10.8787 8.14647C11.2365 8.55369 11.4157 9.03455 11.4618 9.57173C11.51 10.1349 11.4287 10.6726 11.1602 11.1746C10.8408 11.7724 10.3497 12.1818 9.74222 12.4629C9.42874 12.608 9.09956 12.7071 8.76009 12.7672C8.68483 12.7802 8.674 12.811 8.67455 12.8766C8.67671 13.3406 8.67455 13.8047 8.67725 14.2688C8.67779 14.3381 8.66426 14.3646 8.58684 14.3636C8.13908 14.3598 7.69079 14.3608 7.24304 14.3636C7.17536 14.3641 7.15803 14.3424 7.15803 14.2769C7.1602 13.8475 7.15695 13.4181 7.16074 12.9887C7.16128 12.9128 7.14179 12.8906 7.06491 12.8863C6.31992 12.843 5.59658 12.699 4.90303 12.4174C4.78229 12.3681 4.66426 12.3112 4.54948 12.2495C4.51321 12.23 4.50075 12.2116 4.51158 12.1688C4.66318 11.5943 4.81369 11.0197 4.96204 10.4446C4.97829 10.3824 5.00373 10.4024 5.03947 10.4214C5.63557 10.7387 6.2674 10.9477 6.93768 11.036C7.01672 11.0463 7.09685 11.0501 7.1759 11.0614C7.23383 11.0695 7.24737 11.0479 7.24737 10.9927C7.24412 10.6147 7.2452 10.2383 7.2452 9.86252ZM8.68537 9.36325C8.67942 9.37245 8.67455 9.37678 8.67455 9.38112C8.674 9.83978 8.67401 10.2984 8.67292 10.7571C8.67292 10.8177 8.70216 10.7928 8.72598 10.7755C8.82452 10.7046 8.90736 10.619 8.96691 10.5123C9.17698 10.1333 9.05679 9.63725 8.68537 9.36325ZM7.23871 6.11147C7.23871 5.75354 7.23871 5.40589 7.23871 5.05174C6.92522 5.33982 6.92522 5.77249 7.23871 6.11147Z"
|
||||
fill="#FEFEFE"
|
||||
/>
|
||||
<path
|
||||
d="M8.68433 9.36328C9.05574 9.63729 9.17539 10.1333 8.96586 10.5118C8.90631 10.619 8.82347 10.7046 8.72493 10.775C8.70111 10.7918 8.67188 10.8172 8.67188 10.7566C8.67242 10.2979 8.67296 9.83927 8.6735 9.38061C8.67404 9.37682 8.67891 9.37249 8.68433 9.36328Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
<path
|
||||
d="M7.23882 6.11149C6.92533 5.77305 6.92587 5.33984 7.23882 5.05176C7.23882 5.40591 7.23882 5.75355 7.23882 6.11149Z"
|
||||
fill="#59BE59"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="text-base text-dark-gray dark:text-white font-medium">
|
||||
6392.99$
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4">
|
||||
<button
|
||||
type="button"
|
||||
className="text-sm text-white bg-light-green px-2.5 py-1.5 rounded-full"
|
||||
>
|
||||
Complated
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,37 +1,31 @@
|
||||
import SliderCom from "../Helpers/SliderCom";
|
||||
import slider1 from "../../assets/images/slider-1.jpg";
|
||||
import slider2 from "../../assets/images/slider-2.jpg";
|
||||
import slider3 from "../../assets/images/slider-3.jpg";
|
||||
import HomeBannerOffersCard from "../Cards/HomeBannerOffersCard";
|
||||
|
||||
|
||||
export default function HomeSliders(props) {
|
||||
console.log("BANNER LIST IN HomeSliders->",props.bannerList);
|
||||
// debugger;
|
||||
return (
|
||||
<>
|
||||
<div className="hero-slider relative 2xl:w-[600px] xl:w-[500px] lg:w-[420px] w-full mb-2 lg:mb-0 ">
|
||||
<div className="w-full">
|
||||
<SliderCom settings={props.settings}>
|
||||
{/*<div className="item w-full h-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">*/}
|
||||
{/* <img src={slider1} alt="slider" className="w-full h-full" />*/}
|
||||
{/*</div>*/}
|
||||
<div className="item w-full h-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">
|
||||
<img src={slider2} alt="slider" className="w-full h-full" />
|
||||
</div>
|
||||
<div className="item w-full h-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">
|
||||
<img src={slider3} alt="slider" className="w-full h-full" />
|
||||
</div>
|
||||
{props.bannerList.map((item, index) => (
|
||||
<div className="item w-full h-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden">
|
||||
<HomeBannerOffersCard
|
||||
itemData={item}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</SliderCom>
|
||||
// debugger;
|
||||
return (
|
||||
<>
|
||||
<div className="hero-slider relative 2xl:w-[600px] xl:w-[400px] lg:w-[420px] w-full mb-2 lg:mb-0 ">
|
||||
<div className="w-full">
|
||||
<SliderCom settings={props.settings}>
|
||||
{props.bannerList?.length <= 0 && (
|
||||
<div className="item w-full h-full bg-white dark:bg-dark-white max-h-80 rounded-2xl overflow-hidden">
|
||||
<img src={slider2} alt="slider" className="w-full h-full" />
|
||||
</div>
|
||||
)}
|
||||
{props.bannerList?.length > 0 &&
|
||||
props.bannerList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="item w-full h-full bg-white dark:bg-dark-white rounded-2xl overflow-hidden"
|
||||
>
|
||||
<HomeBannerOffersCard itemData={item} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
))}
|
||||
</SliderCom>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import datas from "../../data/product_data.json";
|
||||
import Layout from "../Partials/Layout";
|
||||
import usersService from "../../services/UsersService";
|
||||
@@ -6,35 +6,72 @@ import { useSelector } from "react-redux";
|
||||
import FamilyDash from "./FamilyDash";
|
||||
import FullAccountDash from "./FullAccountDash";
|
||||
|
||||
|
||||
export default function Home(props) {
|
||||
console.log("PROPS IN HOME->", props);
|
||||
|
||||
console.log("PROPS IN HOME->",props);
|
||||
let [nextDueTask, setNextDueTask] = useState({});
|
||||
const [MyOffersList, setMyOffersList] = useState([]);
|
||||
|
||||
// const trending = datas.datas;
|
||||
// const jobData = datas.datas; // api calls or cache
|
||||
const userApi = new usersService();
|
||||
// const homeData = userApi.getHomeDate();
|
||||
const {userDetails} = useSelector((state) => state?.userDetails)
|
||||
const userApi = new usersService();
|
||||
|
||||
const commonHeadData =()=>{
|
||||
console.log("COMMON HEAD DATA INDEX ----------------=====---------------------");
|
||||
return 0;
|
||||
const { userDetails } = useSelector((state) => state?.userDetails);
|
||||
|
||||
const { commonHeadBanner } = useSelector((state) => state.commonHeadBanner);
|
||||
|
||||
// FUNCTION TO GET DASH DATA TO DETERMINE CURRENT TASK DUE TIME
|
||||
const getHomeDate = () => {
|
||||
userApi
|
||||
.getHomeDate()
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.internal_return < 0) {
|
||||
return;
|
||||
}
|
||||
setNextDueTask(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const getMyOffersList = async () => {
|
||||
try {
|
||||
const res = await userApi.getOffersList();
|
||||
setMyOffersList(res.data?.result_list);
|
||||
} catch (error) {
|
||||
console.log("Error getting offers", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="home-page-wrapper">
|
||||
{userDetails && userDetails?.account_type == "FAMILY" && (
|
||||
<FamilyDash commonHeadData={commonHeadData} />
|
||||
)}
|
||||
{userDetails && userDetails?.account_type == "FULL" && (
|
||||
<FullAccountDash bannerList={props.bannerList} />
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await Promise.all([getHomeDate(), getMyOffersList()]);
|
||||
};
|
||||
|
||||
)}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="home-page-wrapper">
|
||||
{userDetails && userDetails?.account_type == "FAMILY" ? (
|
||||
<FamilyDash
|
||||
account={userDetails}
|
||||
commonHeadData={props.bannerList}
|
||||
familyOffers={MyOffersList}
|
||||
/>
|
||||
) : userDetails && userDetails?.account_type == "FULL" ? (
|
||||
<FullAccountDash
|
||||
nextDueTask={nextDueTask}
|
||||
bannerList={props.bannerList}
|
||||
/>
|
||||
) : (
|
||||
<div>
|
||||
You are not logged in or your account type is not supported.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
// /*
|
||||
// <Layout>
|
||||
@@ -47,10 +84,10 @@ export default function Home(props) {
|
||||
// className="mb-10"
|
||||
// bannerList={props.bannerList}
|
||||
// />
|
||||
{/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
|
||||
{
|
||||
/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
|
||||
<TopSellerTopBuyerSliderSection className="mb-10" />
|
||||
<UpdateTable className="mb-10"/>*/}
|
||||
<UpdateTable className="mb-10"/>*/
|
||||
}
|
||||
// </div>
|
||||
// </Layout>
|
||||
|
||||
|
||||
|
||||
@@ -1,102 +1,105 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import DataIteration from "../Helpers/DataIteration";
|
||||
import AvailableJobsCard from "../Cards/AvailableJobsCard";
|
||||
import ListView from '../../assets/images/list-view.png'
|
||||
import GridView from '../../assets/images/grid-view.svg'
|
||||
import SelectBox from "../Helpers/SelectBox";
|
||||
|
||||
export default function MainSection({ className, marketPlaceProduct }) {
|
||||
const [tab, setTab] = useState("explore");
|
||||
const [products, setProducts] = useState(marketPlaceProduct);
|
||||
export default function MainSection({
|
||||
className,
|
||||
marketPlaceProduct,
|
||||
categories,
|
||||
}) {
|
||||
// Creating All cart..
|
||||
let marketCategories = useMemo(
|
||||
() => ({ All: "All Categories", ...categories }),
|
||||
[categories]
|
||||
);
|
||||
const [tab, setTab] = useState(Object.keys(marketCategories)[0]);
|
||||
|
||||
let [contentDisplay, setContentDisplay] = useState('grid') // STATE TO HOLD LIST VIEW STYLE
|
||||
|
||||
// Convert to array in order to map
|
||||
const mappedArray = Object.entries(marketCategories).map(([key, value]) => {
|
||||
return { key, value };
|
||||
});
|
||||
|
||||
const [products, setProducts] = useState([]);
|
||||
const tabHandler = (value) => {
|
||||
setTab(value);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (tab === "artist") {
|
||||
setProducts(marketPlaceProduct?.slice(0, 3));
|
||||
} else if (tab === "market") {
|
||||
setProducts(marketPlaceProduct?.slice(0, 6));
|
||||
} else if (tab === "shop") {
|
||||
setProducts(marketPlaceProduct?.slice(6, 9));
|
||||
} else if (tab === "assets") {
|
||||
setProducts(marketPlaceProduct?.slice(3, 6));
|
||||
} else {
|
||||
setProducts(marketPlaceProduct);
|
||||
|
||||
// Handles the category selection on mobile view
|
||||
const handleSetCategory = (value) => {
|
||||
for (let i in marketCategories) {
|
||||
if (marketCategories[i] == value) {
|
||||
setTab(i);
|
||||
}
|
||||
}
|
||||
}, [tab, marketPlaceProduct]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (tab === "All") {
|
||||
setProducts(marketPlaceProduct);
|
||||
} else {
|
||||
const filteredProducts = marketPlaceProduct.filter((product) =>
|
||||
product.category.includes(tab)
|
||||
);
|
||||
setProducts(filteredProducts);
|
||||
}
|
||||
}, [tab, marketPlaceProduct, categories, marketCategories]);
|
||||
|
||||
return (
|
||||
<div className={`market-place-section w-full ${className || ""}`}>
|
||||
<div className="market-place-wrapper w-full">
|
||||
<div className="filter-navigate-area lg:flex justify-between mb-8 items-center">
|
||||
<div className="tab-item lg:mb-0 mb-5">
|
||||
<div className="md:flex md:space-x-8 space-x-2">
|
||||
<span
|
||||
onClick={() => tabHandler("explore")}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === "explore"
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
Explore
|
||||
</span>
|
||||
<span
|
||||
onClick={() => tabHandler("artist")}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === "artist"
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
Featured Artist
|
||||
</span>
|
||||
<span
|
||||
onClick={() => tabHandler("market")}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === "market"
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
Open Market
|
||||
</span>
|
||||
<span
|
||||
onClick={() => tabHandler("shop")}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === "shop"
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
Partner Shops
|
||||
</span>
|
||||
<span
|
||||
onClick={() => tabHandler("assets")}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === "assets"
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
Game Assets
|
||||
</span>
|
||||
<div className="filter-navigate-area flex justify-between items-center mb-8">
|
||||
<div className="tab-item w-full flex items-center">
|
||||
<div className="hidden lg:flex md:space-x-8 space-x-2">
|
||||
{mappedArray.map(({ key, value }) => (
|
||||
<span
|
||||
key={key}
|
||||
onClick={() => tabHandler(key)}
|
||||
className={`md:text-[18px] text-md text-dark-gray dark:text-white hover:text-pink border-b hover:border-pink font-medium cursor-pointer ${
|
||||
tab === key
|
||||
? "text-pink border-pink"
|
||||
: " border-transparent"
|
||||
}`}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
{/* market categories on screen smaller than large screen */}
|
||||
<div className="w-[80%] lg:hidden">
|
||||
<SelectBox
|
||||
action={handleSetCategory}
|
||||
datas={Object.values(marketCategories)}
|
||||
className="Update-table-dropdown"
|
||||
contentBodyClasses="w-auto min-w-max"
|
||||
position='left'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/*<div className="search-item flex lg:flex-none justify-end">*/}
|
||||
{/* <SearchCom*/}
|
||||
{/* className="lg:bg-transparent"*/}
|
||||
{/* inputClasses="lg:bg-transparent"*/}
|
||||
{/* />*/}
|
||||
{/*</div>*/}
|
||||
{/* contentDisplay toggler */}
|
||||
<div className="p-2 w-[35px] h-[35px] bg-white dark:bg-slate-200 rounded-lg">
|
||||
<img
|
||||
title={contentDisplay=='grid'? 'list view' : 'grid view'}
|
||||
onClick={()=>setContentDisplay((prev)=>prev=='grid'? 'list' : 'grid')}
|
||||
src={contentDisplay=='grid'? ListView : GridView}
|
||||
className="w-full h-full cursor-pointer" alt="view"
|
||||
/>
|
||||
</div>
|
||||
{/* end of contentDisplay toggler */}
|
||||
</div>
|
||||
<div className="filter-navigate-content w-full min-h-screen">
|
||||
<div className="grid lg:grid-cols-3 sm:grid-cols-2 gap-[30px]">
|
||||
<div className={contentDisplay == 'grid' ? 'grid lg:grid-cols-3 sm:grid-cols-2 gap-[30px]' : 'w-full'}>
|
||||
<DataIteration
|
||||
datas={products}
|
||||
startLength={process.env.REACT_APP_ZERO_STATE}
|
||||
endLength={products?.length}
|
||||
>
|
||||
{({ datas }) => (
|
||||
<AvailableJobsCard key={datas.id} datas={datas} />
|
||||
<AvailableJobsCard contentDisplay={contentDisplay} key={datas.id} datas={datas} />
|
||||
)}
|
||||
</DataIteration>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
function Detail({label, value, bg,}) {
|
||||
return (
|
||||
<>
|
||||
<label className='w-full md:w-1/4 text-slate-900 tracking-wide font-semibold'>{label}</label>
|
||||
<p className={`p-1 w-full md:w-3/4 text-sm text-slate-900 ${bg ? bg : null}`}>{value}</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Detail
|
||||
@@ -0,0 +1,321 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import ModalCom from "../../Helpers/ModalCom";
|
||||
import { toast } from "react-toastify";
|
||||
import usersService from "../../../services/UsersService";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import { PriceFormatter } from "../../Helpers/PriceFormatter";
|
||||
|
||||
const MarketPopUp = ({ details, onClose, situation, marketInt }) => {
|
||||
const MarketCalls = (details) => {
|
||||
const [marketMsg, setMarketMsg] = useState({
|
||||
loading: false,
|
||||
data: {},
|
||||
state: undefined,
|
||||
});
|
||||
const [manageInt, setManageInt] = useState({
|
||||
loading: false,
|
||||
data: {},
|
||||
state: undefined,
|
||||
msg: "",
|
||||
});
|
||||
|
||||
const { offer_code } = details;
|
||||
const reqData = { offer_code };
|
||||
|
||||
const MarketDetail = async () => {
|
||||
try {
|
||||
setMarketMsg({ loading: true });
|
||||
if (!textValue) return;
|
||||
|
||||
reqData.yourmessage = textValue;
|
||||
|
||||
const marketMessage = await apiCall.MarketMessage(reqData);
|
||||
const marketMessageRes = marketMessage?.data;
|
||||
|
||||
if (marketMessageRes?.internal_return < 0) {
|
||||
toast.warn("Something wrong happened", {
|
||||
autoClose: 2000,
|
||||
hideProgressBar: true,
|
||||
});
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success("Message sent", {
|
||||
autoClose: 2500,
|
||||
hideProgressBar: true,
|
||||
});
|
||||
|
||||
setMarketMsg({ data: marketMessageRes, state: true });
|
||||
setTimeout(() => onClose(), 2000);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setTextValue("");
|
||||
setMarketMsg({ loading: false });
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
const ManageInterest = async () => {
|
||||
try {
|
||||
setManageInt({ loading: true });
|
||||
|
||||
const manageInt = await apiCall.MarketInterest(reqData);
|
||||
const manageIntRes = manageInt?.data;
|
||||
|
||||
if (manageIntRes?.internal_return < 0) {
|
||||
setManageInt({
|
||||
loading: false,
|
||||
msg: manageIntRes?.status,
|
||||
data: manageIntRes,
|
||||
state: false,
|
||||
});
|
||||
} else {
|
||||
setManageInt({
|
||||
loading: false,
|
||||
msg: manageIntRes?.status,
|
||||
data: manageIntRes,
|
||||
state: true,
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => setManageInt({ msg: "" }), 3000);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// ManageInterest();
|
||||
// }, []);
|
||||
|
||||
return { MarketDetail, ManageInterest, manageInt, marketMsg };
|
||||
};
|
||||
|
||||
const [textValue, setTextValue] = useState("");
|
||||
|
||||
const handleInputChange = ({ target: { value } }) => {
|
||||
setTextValue(value);
|
||||
};
|
||||
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
|
||||
let { manageInt, ManageInterest, MarketDetail, marketMsg } = MarketCalls(details);
|
||||
|
||||
let thePrice = PriceFormatter(
|
||||
details?.price * 0.01,
|
||||
details?.currency_code,
|
||||
details?.currency
|
||||
);
|
||||
|
||||
// let addedIntDate = marketInt?.added?.split(" ")[0];
|
||||
// let expireIntDate = marketInt?.expire?.split(" ")[0];
|
||||
|
||||
let cleanedText = details?.job_description
|
||||
?.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/&/g, "&");
|
||||
|
||||
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-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}
|
||||
</h1>
|
||||
<CloseIcon onClose={onClose} />
|
||||
</div>
|
||||
|
||||
<div className="md:flex bg-white rounded-lg">
|
||||
<div className="p-4 w-full md:w-[75%] md:border-r-1">
|
||||
<div className="min-h-[263px]">
|
||||
<h2 className="font-semibold text-slate-900 dark:text-black tracking-wide">
|
||||
{details?.title}
|
||||
</h2>
|
||||
|
||||
{/* INPUT SECTION */}
|
||||
{[
|
||||
{
|
||||
name: "Description",
|
||||
content: details.description,
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
content: {
|
||||
text: `Timeline: ${details.timeline_days} day(s) -- `,
|
||||
bold: `Budget: ${thePrice}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Delivery Detail",
|
||||
content: cleanedText,
|
||||
danger: true,
|
||||
},
|
||||
].map(({ name, content, danger }, idx) => (
|
||||
<div className={`my-3 md:flex items-center`} key={idx}>
|
||||
<label className="w-full md:w-[19%] text-slate-900 tracking-wide font-semibold whitespace-pre-wrap">
|
||||
{name}
|
||||
</label>
|
||||
<div
|
||||
className={`w-full md:w-3/4 text-slate-900 market-pop ${
|
||||
name !== "Delivery Detail"
|
||||
? " h-full max-h-28 flex items-center"
|
||||
: " overflow-y-auto max-h-[100px]"
|
||||
}`}
|
||||
>
|
||||
{danger ? (
|
||||
<p
|
||||
className={``}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: danger && content,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<p className={`w-full text-slate-900`}>
|
||||
{name !== "Delivery Detail" ? (
|
||||
<>
|
||||
{typeof content !== "object" ? content : null}
|
||||
{typeof content === "object" && (
|
||||
<>
|
||||
<hr className="mb-1" />
|
||||
<span className="flex items-center gap-2">
|
||||
{content?.text}
|
||||
<strong>{thePrice}</strong>
|
||||
</span>
|
||||
<hr className="mt-1" />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
<div className="my-3 w-full flex flex-col gap-3">
|
||||
<div className="w-full">
|
||||
<label className="w-full text-slate-900 tracking-wide">
|
||||
If you have any questions about this task:
|
||||
</label>
|
||||
<textarea
|
||||
className={`p-1 w-full text-sm text-slate-900 outline-none border border-slate-300 rounded-md`}
|
||||
rows="5"
|
||||
style={{ resize: "none" }}
|
||||
placeholder="Enter message here ..."
|
||||
value={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>
|
||||
</div>
|
||||
|
||||
<div className="w-full md:w-[23%] h-full ">
|
||||
<div className="mx-auto bg-[#f1f8ff] 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">
|
||||
Interested in the task?
|
||||
</p>
|
||||
<hr />
|
||||
<button
|
||||
className="bg-[#57cd89] text-center text-lg font-semibold text-white py-2 px-4 rounded-md inline-flex sm:flex-col flex-row sm:gap-0 gap-1 items-center justify-center"
|
||||
name="market-interest"
|
||||
onClick={ManageInterest}
|
||||
>
|
||||
{" "}
|
||||
<span>Send</span>
|
||||
<span>Interest</span>
|
||||
<span>Request</span>
|
||||
</button>
|
||||
<>
|
||||
{manageInt.loading ? (
|
||||
<p className="text-sm italic">please wait...</p>
|
||||
) : (
|
||||
<>
|
||||
{manageInt?.msg !== "" && (
|
||||
<p
|
||||
className={`text-sm italic ${
|
||||
manageInt?.state ? "text-green-500" : "text-red-500"
|
||||
}`}
|
||||
>
|
||||
{manageInt?.msg}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<p className="flex items-center tracking-wide">
|
||||
Interest: <b className="ml-1">{details.interest_count}</b>
|
||||
</p>
|
||||
<hr />
|
||||
<p className="my-1">
|
||||
Expire: {details.expire}
|
||||
</p>
|
||||
</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"
|
||||
name="cancel"
|
||||
onClick={onClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
{/* END OF ACTION SECTION */}
|
||||
</div>
|
||||
</div>
|
||||
</ModalCom>
|
||||
);
|
||||
};
|
||||
|
||||
export default MarketPopUp;
|
||||
|
||||
const CloseIcon = ({ onClose }) => (
|
||||
<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>
|
||||
);
|
||||
@@ -1,22 +1,23 @@
|
||||
import React from "react";
|
||||
// import products from "../../data/marketplace_data.json";
|
||||
//import CreateNft from "../Home/CreateNft";
|
||||
import Layout from "../Partials/Layout";
|
||||
import MainSection from "./MainSection";
|
||||
import CommonHead from "../UserHeader/CommonHead";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export default function MarketPlace({commonHeadData}) {
|
||||
export default function MarketPlace({ commonHeadData }) {
|
||||
let { jobLists } = useSelector((state) => state.jobLists);
|
||||
const marketData = jobLists?.result_list;
|
||||
const categories = jobLists?.categories;
|
||||
|
||||
// const marketProduct = products.data;
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<CommonHead commonHeadData={commonHeadData} />
|
||||
<MainSection marketPlaceProduct={marketData} className="mb-10" />
|
||||
<CommonHead commonHeadData={commonHeadData} />
|
||||
<MainSection
|
||||
marketPlaceProduct={marketData}
|
||||
categories={categories}
|
||||
className="mb-10"
|
||||
/>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,13 @@ export default function ActiveJobMessage({ activeJobMesList }) {
|
||||
<tbody>
|
||||
{currentActiveJobMesList.map((item, index) => (
|
||||
<tr key={index} className='text-slate-500'>
|
||||
<td className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></td>
|
||||
<td>
|
||||
<div className="msg_box">
|
||||
<div className="msg_header">{item.msg_date} {item.msg_firstname}</div>
|
||||
<span className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></span>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -48,7 +54,7 @@ export default function ActiveJobMessage({ activeJobMesList }) {
|
||||
:
|
||||
<tbody>
|
||||
<tr className='text-slate-500'>
|
||||
<td className="p-2" colSpan={4}>No Purchase History Found!</td>
|
||||
<td className="p-2" colSpan={4}>No Message Found!</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
}
|
||||
|
||||
@@ -1,218 +1,692 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import Layout from "../Partials/Layout";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ActiveJobMessage from "./ActiveJobMessage";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import CountDown from "../Helpers/CountDown";
|
||||
import IndexJobActions from "./JobActions/IndexJobActions";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import { useReactToPrint } from "react-to-print";
|
||||
|
||||
import usersService from "../../services/UsersService";
|
||||
|
||||
function ActiveJobs(props) {
|
||||
const ApiCall = new usersService()
|
||||
const ApiCall = new usersService();
|
||||
let navigate = useNavigate();
|
||||
|
||||
let { userDetails } = useSelector((state) => state.userDetails);
|
||||
let navigate = useNavigate()
|
||||
|
||||
let [messageToSend, setMessageToSend] = useState('') // State to hold the value of message to be sent
|
||||
let [passDue, setPassDue] = useState(
|
||||
new Date() > new Date(props.details?.delivery_date)
|
||||
); // STATE TO KNOW IF TASK IS PASSED DUE TIME
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({loading: false, status: false, message: ''})
|
||||
let [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
|
||||
|
||||
let [tab, setTab] = useState("message");
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
let [popUp, setPopUp] = useState(false); // STATE FOR POPOUT MODAL
|
||||
|
||||
const printRef = useRef();
|
||||
// to handle printing
|
||||
const handlePrint = useReactToPrint({
|
||||
content: () => printRef.current,
|
||||
});
|
||||
|
||||
const popUpHandler = () => {
|
||||
// FUNCTION TO HANDLE POPOUT
|
||||
setPopUp((prev) => !prev);
|
||||
};
|
||||
|
||||
// FUNCTION TO HANDLE MESSAGE CHANGE
|
||||
const handleMessageChange = ({target:{value}}) => {
|
||||
setMessageToSend(value)
|
||||
}
|
||||
const handleMessageChange = ({ target: { value } }) => {
|
||||
setMessageToSend(value);
|
||||
};
|
||||
|
||||
// FUNCTION TO HANDLE FILE UPlOAD CHANGE
|
||||
const handleFileChange = ({ target: { files } }) => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" }); // State to determine error state
|
||||
|
||||
if (!files[0]) {
|
||||
// IF NO FILE SELECTED RETURN
|
||||
return;
|
||||
}
|
||||
if (files[0].size > Number(process.env.REACT_APP_MAX_FILE_SIZE)) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "File must be <= 1mb",
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
return;
|
||||
}
|
||||
if (filesToSend.length >= Number(process.env.REACT_APP_TOTAL_NUM_FILE)) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: `Total number of attachment is ${Number(
|
||||
process.env.REACT_APP_TOTAL_NUM_FILE
|
||||
)}`,
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
return;
|
||||
}
|
||||
// INCLUDE FILE IF NO ERROR
|
||||
setFilesToSend((prev) => [...prev, files[0]]);
|
||||
};
|
||||
|
||||
// FUNCTION TO CLEAR ALL TYPED MESSAGE OR FILES
|
||||
const handleClearAll = ({ target: { name } }) => {
|
||||
if (tab == "message") {
|
||||
setMessageToSend("");
|
||||
} else if (tab == "files") {
|
||||
setFilesToSend([]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// FUNCTION TO REMOVE AND IMAGE
|
||||
const handleRemoveImage = (imageToDelete) => {
|
||||
setFilesToSend((prev) =>
|
||||
prev.filter((item) => item.name != imageToDelete.name)
|
||||
);
|
||||
};
|
||||
|
||||
// FUNCTION TO SEND TASK MESSAGE
|
||||
const sendTaskMessage = () => {
|
||||
let reqData={message: messageToSend, msg_type: 'TEXT', contract:props.details.contract}
|
||||
if(!reqData.message){
|
||||
setRequestStatus({loading: false, status: false, message: 'Message is empty'})
|
||||
return setTimeout(()=>{
|
||||
setRequestStatus({loading: false, status: false, message: ''})
|
||||
}, 5000)
|
||||
let reqData = {
|
||||
message: messageToSend,
|
||||
msg_type: "TEXT",
|
||||
contract: props.details.contract,
|
||||
};
|
||||
if (!reqData.message) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "Message is empty",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
setRequestStatus({loading: true, status: false, message: ''})
|
||||
ApiCall.sendTaskMessage(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setRequestStatus({loading: false, status: false, message: 'Message could not be sent, try again later'})
|
||||
return
|
||||
}
|
||||
setRequestStatus({loading: false, status: true, message: 'Message Sent Successfully'})
|
||||
props.reloadActiveJobList(prev => !prev) // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
|
||||
setMessageToSend('') // SENDS MESSAGE TO SEND BACK TO EMPTY STRINGS
|
||||
}).catch(error => {
|
||||
setRequestStatus({loading: false, status: false, message: 'Opps! something went wrong'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setRequestStatus({loading: false, status: false, message: ''})
|
||||
}, 5000)
|
||||
})
|
||||
}
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
ApiCall.sendTaskMessage(reqData)
|
||||
.then((res) => {
|
||||
if (res.status != 200 || res.data.internal_return < 0) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "Message could not be sent, try again later",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: true,
|
||||
message: "Message Sent Successfully",
|
||||
});
|
||||
props.reloadActiveJobList((prev) => !prev); // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
|
||||
setMessageToSend(""); // SENDS MESSAGE TO SEND BACK TO EMPTY STRINGS
|
||||
})
|
||||
.catch((error) => {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "Opps! something went wrong",
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
});
|
||||
};
|
||||
|
||||
// FUNCTION TO SEND FILES
|
||||
const sendFile = async () => {
|
||||
setRequestStatus({ loading: true, status: false, message: "" });
|
||||
|
||||
if (!filesToSend.length) {
|
||||
// checks if file to send is empty
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: "No File(s) selected",
|
||||
});
|
||||
return setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
for (let i = 0; i <= filesToSend.length - 1; i++) {
|
||||
// Loops through files to send array and trigger upload API call
|
||||
|
||||
const fileToBase64 = async () => {
|
||||
// Converts file data to base64 string
|
||||
try {
|
||||
const base64String = await convertFileToBase64(filesToSend[i]);
|
||||
return base64String;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// if(await !fileToBase64()){
|
||||
// return
|
||||
// }
|
||||
|
||||
let reqData = {
|
||||
file_name: filesToSend[i].name,
|
||||
file_size: filesToSend[i].size,
|
||||
file_type: "image/png",
|
||||
file_data: await fileToBase64(),
|
||||
msg_type: "FILE",
|
||||
contract: props.details.contract,
|
||||
};
|
||||
|
||||
ApiCall.sendFiles(reqData)
|
||||
.then((res) => {
|
||||
// if(res.status != 200 || res.data.internal_return < 0){
|
||||
// setRequestStatus({loading: false, status: false, message: 'Files(s) could not be sent, try again later'})
|
||||
// return
|
||||
// }
|
||||
// setRequestStatus({loading: false, status: true, message: 'File(s) Uploaded Successfully'})
|
||||
// props.reloadActiveJobList(prev => !prev) // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
|
||||
// setFilesToSend([]) // SETS FILES TO SEND TO SEND BACK TO EMPTY ARRAY
|
||||
})
|
||||
.catch((error) => {
|
||||
// setRequestStatus({loading: false, status: false, message: 'Opps! something went wrong'})
|
||||
})
|
||||
.finally(() => {
|
||||
if (i == filesToSend.length - 1) {
|
||||
setRequestStatus({
|
||||
loading: false,
|
||||
status: true,
|
||||
message: "File(s) Uploaded Successfully",
|
||||
});
|
||||
setFilesToSend([]); // SETS FILES TO SEND TO SEND BACK TO EMPTY ARRAY
|
||||
props.reloadActiveJobList((prev) => !prev); // MAKES ACTIVE JOB MESSAGE LIST TO RELOAD
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// FUNCTION TO CHECK IF TASK PASS DUE IS REACHED
|
||||
let isPassedDue = () => {
|
||||
// console.log('TESTING',new Date() > new Date(props.details?.delivery_date) )
|
||||
if (new Date() > new Date(props.details?.delivery_date)) {
|
||||
setPassDue(true);
|
||||
} else {
|
||||
setPassDue(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!passDue) {
|
||||
let passDueInterval = setInterval(() => {
|
||||
isPassedDue();
|
||||
}, 1000);
|
||||
return () => {
|
||||
clearInterval(passDueInterval);
|
||||
};
|
||||
}
|
||||
}, [passDue]);
|
||||
|
||||
console.log("AC JOBS >>", props);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="py-[20px] bg-white dark:bg-black dark:text-white px-4 rounded-2xl shadow-md md:flex justify-between items-start gap-16">
|
||||
{/* job title */}
|
||||
<div className="w-full md:w-8/12">
|
||||
<div className="w-full flex justify-start space-x-3 items-start">
|
||||
<button
|
||||
type="button"
|
||||
className="min-w-[45px] h-auto text-[#374557] border border-sky-blue p-1 rounded-full"
|
||||
onClick={() =>{
|
||||
if(props.details.pathname == '/manage-family'){
|
||||
navigate(props.details.pathname, {state: { ...props.details.accountDetails }}, { replace: true })
|
||||
}else{
|
||||
navigate(props.details.pathname, { replace: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="35"
|
||||
height="35"
|
||||
viewBox="0 0 24 24"
|
||||
fill="skyblue"
|
||||
>
|
||||
<path d="M19 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H19v-2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 className="text-xl lg:text-2xl font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{props.details?.title && props.details.title}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="p-4 lg:flex justify-between items-start space-y-4 lg:space-x-4 lg:space-y-0 rounded-lg shadow-lg bg-slate-100">
|
||||
<div className="w-full lg:w-1/2">
|
||||
<div className="py-[20px] bg-white px-4 rounded-md shadow-md">
|
||||
{/* back btn and title */}
|
||||
<div className="w-full flex justify-start space-x-3 items-center">
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] border border-sky-blue p-1 rounded-full"
|
||||
onClick={() => navigate(props.details.pathname, {replace: true})}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="35"
|
||||
height="35"
|
||||
viewBox="0 0 24 24"
|
||||
fill="skyblue"
|
||||
>
|
||||
<path d="M19 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H19v-2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{props.details?.title && props.details.title}
|
||||
</h1>
|
||||
</div>
|
||||
{/* END of back btn and title */}
|
||||
<div className="w-full my-2">
|
||||
<p className="w-full text-base text-right text-sky-blue">
|
||||
{props?.details && props.details.job_to}
|
||||
</p>
|
||||
<div className="text-base text-slate-700 dark:text-white tracking-wide">
|
||||
<p className="font-semibold text-black dark:text-white">
|
||||
Description:{" "}
|
||||
</p>
|
||||
<p className="p-2 border border-sky-blue">
|
||||
{props?.details && props.details.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* end of job title */}
|
||||
|
||||
<div className="mt-2 w-full flex flex-col-reverse lg:flex-row lg:justify-between lg:items-start lg:space-x-2">
|
||||
<div className="w-full lg:w-2/3 my-2 lg:my-0">
|
||||
<p className="text-base text-slate-700 dark:text-black">
|
||||
{props.details?.contract && props.details.contract}
|
||||
</p>
|
||||
<p className="text-base text-slate-700 dark:text-black">
|
||||
<span className="font-semibold">Description: </span>
|
||||
{props.details?.description && props.details.description}
|
||||
</p>
|
||||
<p className="text-base text-sky-blue">Delivery Detail</p>
|
||||
<div className="">
|
||||
<p className="text-base text-slate-700 dark:text-black">
|
||||
<span className="font-semibold">Due: </span>
|
||||
{props.details?.delivery_date &&
|
||||
props.details.delivery_date.split(" ")[0]}
|
||||
</p>
|
||||
<p className="text-base text-slate-700 dark:text-black">
|
||||
{props.details?.delivery_date &&
|
||||
props.details.delivery_date.split(" ")[1]}
|
||||
</p>
|
||||
<p className="text-base text-slate-700 dark:text-black">
|
||||
{props.details?.timeline_days && props.details.timeline_days} day(s)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/3 lg:text-center">
|
||||
<p className="text-base text-sky-blue">
|
||||
{userDetails.firstname && userDetails.firstname}
|
||||
</p>
|
||||
{/* job details */}
|
||||
<div className="w-full md:w-4/12">
|
||||
<p className="text-base text-sky-blue">Delivery Detail</p>
|
||||
{passDue ? (
|
||||
<div className="my-1">
|
||||
<p className="text-base text-slate-700">
|
||||
<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>
|
||||
</div>
|
||||
) : (
|
||||
<div className="my-1 flex items-start gap-3">
|
||||
<p className="font-semibold">Due: </p>
|
||||
<div className="flex flex-col justify-between">
|
||||
<p className="text-base text-slate-700 tracking-wide">
|
||||
<CountDown
|
||||
lastDate={props?.details && props.details.delivery_date}
|
||||
/>
|
||||
</p>
|
||||
<div className="text-base text-slate-700 tracking-wide flex gap-[5px]">
|
||||
<span>Hrs</span>
|
||||
<span>Min</span>
|
||||
<span>Sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-5 bg-white p-4 rounded-md shadow-md">
|
||||
<div className="">
|
||||
<p className="relative py-2 my-2 text-lg font-bold text-slate-600 dark:text-black border-b-2 border-slate-300 tracking-wide after:absolute after:-bottom-0.5 after:content-[''] after:w-[100px] after:h-[2px] after:bg-sky-blue after:left-0">Message(s)</p>
|
||||
<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:{" "}
|
||||
</span>
|
||||
<span className="">
|
||||
{props.details?.timeline_days && props.details.timeline_days}{" "}
|
||||
day(s)
|
||||
</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">
|
||||
No:{" "}
|
||||
</span>
|
||||
<span className="">
|
||||
{props.details?.contract && props.details.contract}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* end of job details */}
|
||||
</div>
|
||||
|
||||
<div className="my-4 py-[20px] bg-white dark:bg-black px-4 rounded-2xl shadow-md lg:flex justify-between items-start space-y-4 lg:space-x-4 lg:space-y-0">
|
||||
<div className="w-full lg:w-1/2">
|
||||
<div className="">
|
||||
<h1 className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Actions
|
||||
</h1>
|
||||
{/* <p className="my-3 py-1 text-base">
|
||||
Waiting for the completion message from the client before you can approve.
|
||||
</p> */}
|
||||
<IndexJobActions details={props.details} />
|
||||
</div>
|
||||
|
||||
{/* TEXTAREA SECTION */}
|
||||
<div className="mt-5">
|
||||
<div className="">
|
||||
{/* <p className="relative py-2 my-2 text-lg font-bold text-slate-600 dark:text-black border-b-2 border-slate-300 tracking-wide after:absolute after:-bottom-0.5 after:content-[''] after:w-[100px] after:h-[2px] after:bg-sky-blue after:left-0">Message(s)</p> */}
|
||||
<div className="my-2 flex items-center border-b border-slate-300">
|
||||
<button
|
||||
name="message"
|
||||
onClick={(e) => setTab(e.target.name)}
|
||||
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border ${
|
||||
tab == "message" ? "border-sky-blue" : "border-slate-300"
|
||||
} tracking-wide transition duration-200`}
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
<button
|
||||
name="files"
|
||||
onClick={(e) => setTab(e.target.name)}
|
||||
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border ${
|
||||
tab == "files" ? "border-sky-blue" : "border-slate-300"
|
||||
} tracking-wide transition duration-200`}
|
||||
>
|
||||
Send Files
|
||||
</button>
|
||||
</div>
|
||||
{tab == "message" ? (
|
||||
<textarea
|
||||
className="p-4 w-full text-base text-slate-600 border-y border-slate-300 outline-none"
|
||||
rows="10"
|
||||
className="p-4 w-full h-[300px] text-base text-slate-600 dark:text-white bg-white dark:bg-black border border-slate-300 outline-none"
|
||||
// rows="10"
|
||||
style={{ resize: "none" }}
|
||||
name='message'
|
||||
name="message"
|
||||
onChange={handleMessageChange}
|
||||
value={messageToSend}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-4 w-full h-[300px] text-base text-slate-600 border border-slate-300">
|
||||
<div className="files">
|
||||
<label
|
||||
htmlFor="file"
|
||||
className="h-20 btn-gradient text-base tracking-wide px-4 py-2 rounded-full text-white cursor-pointer"
|
||||
>
|
||||
Select Files to Upload
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
accept="image/*"
|
||||
style={{ display: "none" }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected_file my-2">
|
||||
{filesToSend.length > 0 &&
|
||||
filesToSend.map((item, index) => (
|
||||
<p key={index} className="flex items-center space-x-2">
|
||||
<span>{item.name}</span>
|
||||
<button
|
||||
name="remove"
|
||||
onClick={() => handleRemoveImage(item)}
|
||||
className="px-2 flex justify-center items-center rounded-full border border-red-500 text-red-500"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
|
||||
<div className="w-full">
|
||||
{/* error or success display */}
|
||||
{requestStatus.message != "" &&
|
||||
(!requestStatus.status ? (
|
||||
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
|
||||
<div className="w-full">
|
||||
{/* error or success display */}
|
||||
{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-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
||||
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>
|
||||
) : (
|
||||
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>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
{/* End of error or success display */}
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
{/* End of error or success display */}
|
||||
|
||||
{/* Buttons Sections */}
|
||||
<div className="py-2 mb-8 sm:flex sm:justify-center sm:items-center">
|
||||
<div className="w-full sm:w-2/4 mb-5 sm:mb-0">
|
||||
{/* Buttons Sections */}
|
||||
<div className="py-2 sm:flex sm:justify-end sm:items-center">
|
||||
<div className="w-full sm:w-2/4 flex justify-between items-center space-x-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClearAll}
|
||||
className="border-gradient text-base tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
<span className="text-gradient">Clear</span>
|
||||
</button>
|
||||
{tab == "files" ? (
|
||||
<button
|
||||
onClick={()=>{console.log('working')}}
|
||||
onClick={sendFile}
|
||||
type="button"
|
||||
className="btn-gradient text-base tracking-wide px-4 py-2 rounded-md flex justify-center items-center"
|
||||
className="btn-gradient text-base tracking-wide px-4 py-3 rounded-full flex justify-center items-center"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill='white'>
|
||||
<path d="M12 2L2 12h3v8h14v-8h3L12 2zm0 16v-6h-2v6H7l5-5 5 5h-3z"/>
|
||||
</svg>
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="6" color="sky-blue" />
|
||||
) : (
|
||||
<>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="white"
|
||||
>
|
||||
<path d="M12 2L2 12h3v8h14v-8h3L12 2zm0 16v-6h-2v6H7l5-5 5 5h-3z" />
|
||||
</svg>
|
||||
|
||||
<span className="text-white">Upload Files</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="w-full sm:w-2/4 flex justify-between items-center space-x-2">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-red-600 text-base text-white tracking-wide px-4 py-2 rounded-md hover:opacity-90"
|
||||
>
|
||||
<span className="text-white">Clear</span>
|
||||
<span className="text-white">Upload Files</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={sendTaskMessage}
|
||||
type="button"
|
||||
className="btn-gradient text-base text-white tracking-wide px-4 py-2 rounded-md"
|
||||
type="button"
|
||||
className="btn-gradient text-base text-white tracking-wide px-4 py-3 rounded-full"
|
||||
>
|
||||
{requestStatus.loading ?
|
||||
<LoadingSpinner size='6' color='sky-blue' />
|
||||
:
|
||||
{requestStatus.loading ? (
|
||||
<LoadingSpinner size="6" color="sky-blue" />
|
||||
) : (
|
||||
<span className="text-white">Send</span>
|
||||
}
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/* end of Buttons Sections */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ACTION SECTION */}
|
||||
<div className="w-full lg:w-1/2 h-full">
|
||||
<div className="py-[20px] bg-white px-4 rounded-md shadow-md">
|
||||
<h1 className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">Actions</h1>
|
||||
|
||||
<p className="my-3 py-1 text-base">
|
||||
Waiting for the completion message from the client before you can approve.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 bg-white p-4 rounded-md shadow-md">
|
||||
<div className="">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-black tracking-wide">Message</p>
|
||||
{props.activeJobMesList.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' />
|
||||
:
|
||||
<ActiveJobMessage activeJobMesList={props.activeJobMesList} />
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* end of Buttons Sections */}
|
||||
</div>
|
||||
{/* END OF TEXTAREA */}
|
||||
</div>
|
||||
|
||||
{/* MESSAGE SECTION */}
|
||||
<div className="w-full lg:w-1/2">
|
||||
<div className="flex justify-between items-center gap-5">
|
||||
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Message
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={popUpHandler}
|
||||
className="px-2 py-1 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
view all
|
||||
</button>
|
||||
</div>
|
||||
{props.activeJobMesList.loading ? (
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
) : (
|
||||
<ActiveJobMessage activeJobMesList={props.activeJobMesList} />
|
||||
)}
|
||||
</div>
|
||||
{/* END OF MESSAGE */}
|
||||
</div>
|
||||
|
||||
{/* POPOUT SECTION */}
|
||||
{popUp && (
|
||||
<PopModal
|
||||
popUpHandler={popUpHandler}
|
||||
popUp={popUp}
|
||||
details={props.details}
|
||||
activeJobMesList={props.activeJobMesList}
|
||||
handlePrint={handlePrint}
|
||||
myRef={printRef}
|
||||
/>
|
||||
)}
|
||||
{/* END OF POPOUT SECTION */}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default ActiveJobs;
|
||||
|
||||
function convertFileToBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = () => {
|
||||
const base64String = reader.result.split(",")[1];
|
||||
resolve(base64String);
|
||||
};
|
||||
|
||||
reader.onerror = (error) => {
|
||||
reject(error);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
//POPOUT COMPONENT FUNCTION
|
||||
const PopModal = ({
|
||||
popUpHandler,
|
||||
popUp,
|
||||
details,
|
||||
activeJobMesList,
|
||||
handlePrint,
|
||||
myRef,
|
||||
}) => {
|
||||
return (
|
||||
<ModalCom action={popUpHandler} situation={popUp} className="edit-popup">
|
||||
<div
|
||||
ref={myRef}
|
||||
className="message-modal-wrapper min-w-[500px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl"
|
||||
>
|
||||
<div className="message-modal-header w-full flex items-center justify-between lg:px-10 lg:py-8 px-[30px] py-[23px] border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
{details?.contract}
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
<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 px-10 py-8 gap-4">
|
||||
<div className="w-full flex flex-col items-center">
|
||||
{activeJobMesList.loading ? (
|
||||
<LoadingSpinner size="16" color="sky-blue" />
|
||||
) : (
|
||||
<div className="message-table h-[500px] overflow-y-auto">
|
||||
<table className="wallet-activity w-full table-auto border-collapse text-left">
|
||||
<thead className="border-b-2">
|
||||
<tr className="text-slate-600">
|
||||
<th className="p-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{activeJobMesList?.data?.length ? (
|
||||
<tbody>
|
||||
{activeJobMesList?.data?.map((item, index) => (
|
||||
<tr key={index} className="text-slate-500">
|
||||
<td>
|
||||
<div className="msg_box">
|
||||
<div className="msg_header">
|
||||
{item.msg_date} {item.msg_firstname}
|
||||
</div>
|
||||
<span
|
||||
className="p-2"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.message,
|
||||
}}
|
||||
></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
) : activeJobMesList.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 Message Found!
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
)}
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* btn */}
|
||||
<div className="flex justify-end items-center">
|
||||
<div className="py-3 w-full lg:w-1/2 flex justify-between items-center">
|
||||
<button
|
||||
onClick={handlePrint}
|
||||
type="button"
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
<span className="text-white">Print</span>
|
||||
</button>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCom>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from 'react'
|
||||
|
||||
function CurrentJobAction() {
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
<p className="my-3 py-1 text-base active-owner">
|
||||
<table className="w-full text-sm text-left text-gray-500">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
|
||||
<h1 className="text-xl text-dark-gray dark:text-white">
|
||||
Waiting for the completion message from the client before you can approve.
|
||||
</h1>
|
||||
{/*<div className="flex flex-col flex-[0.9]"> </div>*/}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2">
|
||||
<div className="flex justify-center items-center">
|
||||
.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CurrentJobAction
|
||||
@@ -0,0 +1,182 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import ModalCom from '../../Helpers/ModalCom'
|
||||
import LoadingSpinner from '../../Spinners/LoadingSpinner'
|
||||
|
||||
import usersService from '../../../services/UsersService'
|
||||
|
||||
function CurrentTaskAction({jobDetails}) {
|
||||
|
||||
const apiCall = new usersService()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [checked, setChecked] = useState(false)
|
||||
|
||||
const [reqStatus, setReqStatus] = useState({loading:false, status: false, message: ''})
|
||||
|
||||
let [popUp, setPopUp] = useState(false)
|
||||
|
||||
const popUpHandler = () => {
|
||||
if(popUp){
|
||||
setChecked(false)
|
||||
}
|
||||
setPopUp(prev => !prev)
|
||||
}
|
||||
|
||||
// FUNCTION TO HANDLE WHEN USER CLICKS ON SEND FOR REVIEW AND ACCEPTANCE
|
||||
const taskCompletedSubmit = () => {
|
||||
setReqStatus({loading:true, status: false, message: ''}) // Sets loading spinner active
|
||||
let reqData = {
|
||||
contract: jobDetails.contract,
|
||||
contract_uid: jobDetails.contract_uid,
|
||||
job_action: 'NOTIFY_COMPLETE',
|
||||
}
|
||||
if(!checked){ // checks that checkbox is selected
|
||||
setReqStatus({loading:false, status: false, message: 'Please check the box above'})
|
||||
return setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
// API CALL TO MARK TASK AS COMPLETED BY WORKER
|
||||
apiCall.workerJobAction(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setReqStatus({loading:false, status: false, message: 'unable to complete request. Try again'})
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'Task marked completed successfully'})
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /mytask after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/mytask', {replace: true})
|
||||
}, 3000)
|
||||
}).catch(err => {
|
||||
setReqStatus({loading:false, status: false, message: 'Opps! Network error. Try again'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
|
||||
<table className="w-full text-sm text-left text-gray-500 active-worker">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<h1 className="text-xl text-dark-gray dark:text-white">
|
||||
I completed this task and ready for review and acceptance.
|
||||
</h1>
|
||||
{/*<div className="flex flex-col flex-[0.9]">*/}
|
||||
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex justify-center items-center">
|
||||
<button onClick={popUpHandler} type="button" className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Send of Review
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{popUp && (
|
||||
<ModalCom action={popUpHandler} situation={popUp}>
|
||||
<div className="logout-modal-wrapper lg:w-[460px] 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 dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Confirm Completion
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
<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 px-10 py-8 gap-4">
|
||||
<div className="w-full flex flex-col items-center">
|
||||
<div className="mb-10 flex justify-center items-center gap-2">
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={checked}
|
||||
onChange={()=>{setChecked(prev => !prev)}}
|
||||
className='w-6 h-6 text-sky-blue bg-gray-100 focus:ring-sky-blue'
|
||||
/>
|
||||
<p className='font-bold text-base tracking-wide text-dark-gray dark:text-white'>If you have completed this task</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-10 flex justify-center items-center">
|
||||
{reqStatus.loading ?
|
||||
<LoadingSpinner color='sky-blue' size='10' />
|
||||
:
|
||||
<button type="button" onClick={taskCompletedSubmit} className="px-2 py-1 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Send for Review & Acceptance
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
<div className="w-full">
|
||||
{reqStatus.message != "" &&
|
||||
(!reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
{/* END OF FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
</div>
|
||||
|
||||
{/* 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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCom>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CurrentTaskAction
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
|
||||
import CurrentJobAction from './CurrentJobAction'
|
||||
import CurrentTaskAction from './CurrentTaskAction'
|
||||
|
||||
import PastDueJobAction from './PastDueJobAction'
|
||||
import PastDueTaskAction from './PastDueTaskAction'
|
||||
|
||||
import ReviewJobAction from './ReviewJobAction'
|
||||
import ReviewTaskAction from './ReviewTaskAction'
|
||||
|
||||
function IndexJobActions({details}) { // FUNCTION TO RENDER SPECIFIC JOB ACTION DEPENDING ON OWNER STATUS & STATUS DESCRIPTION
|
||||
let owner = details?.owner_status
|
||||
let description = details?.status_description
|
||||
switch(owner) {
|
||||
case 'OWNER':
|
||||
return (()=>{
|
||||
if(description == 'ACTIVE'){
|
||||
return <CurrentJobAction jobDetails={details} />
|
||||
}else if(description == 'PASTDUE'){
|
||||
return <PastDueJobAction jobDetails={details} />
|
||||
}else if(description == 'REVIEW'){
|
||||
return <ReviewJobAction jobDetails={details} />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})()
|
||||
case 'WORKER':
|
||||
return (()=>{
|
||||
if(description == 'ACTIVE'){
|
||||
return <CurrentTaskAction jobDetails={details} />
|
||||
}else if(description == 'PASTDUE'){
|
||||
return <PastDueTaskAction jobDetails={details} />
|
||||
}else if(description == 'REVIEW'){
|
||||
return <ReviewTaskAction jobDetails={details} />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})()
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default IndexJobActions
|
||||
@@ -0,0 +1,246 @@
|
||||
import React,{useState} from 'react'
|
||||
import ModalCom from '../../Helpers/ModalCom'
|
||||
import LoadingSpinner from '../../Spinners/LoadingSpinner'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import usersService from '../../../services/UsersService'
|
||||
|
||||
function PastDueJobAction({jobDetails}) {
|
||||
|
||||
const apiCall = new usersService()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [checked, setChecked] = useState(false)
|
||||
|
||||
const [extendedTime, setExtendedTime] = useState('') // VALUE OF NEW EXTENDED TIME
|
||||
|
||||
const [action, setAction] = useState('') // VALUE OF NEW EXTENDED TIME
|
||||
|
||||
const [reqStatus, setReqStatus] = useState({loading:false, status: false, message: ''})
|
||||
|
||||
let [popUp, setPopUp] = useState(false)
|
||||
|
||||
const popUpHandler = () => {
|
||||
if(popUp){
|
||||
setChecked(false)
|
||||
}
|
||||
setPopUp(prev => !prev)
|
||||
}
|
||||
|
||||
// FUNCTION TO HANDLE WHEN OWNER CANCELS JOB
|
||||
const cancelTask = () => {
|
||||
setAction('cancel')
|
||||
setReqStatus({loading:true, status: false, message: ''})
|
||||
|
||||
let reqData = { // API PAYLOADS
|
||||
contract: jobDetails.contract,
|
||||
contract_uid: jobDetails.contract_uid,
|
||||
job_action: 'REQUEST_CANCEL',
|
||||
}
|
||||
|
||||
if(!checked){ // CHECKS IF CHECKBOX IS SELECTED
|
||||
setReqStatus({loading:false, status: false, message: 'Please check the box above'})
|
||||
return setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
}
|
||||
// API CALL TO ACCEPT COMPLETION BY OWNER
|
||||
apiCall.ownerJobAction(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setReqStatus({loading:false, status: false, message: 'unable to complete request. Try again'})
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'job cancelled successfully'})
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /my-pastdue-jobs after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/my-pastdue-jobs', {replace: true})
|
||||
}, 3000)
|
||||
}).catch(err => {
|
||||
setReqStatus({loading:false, status: false, message: 'Opps! Network error. Try again'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
// FUNCTION TO HANDLE WHEN USER/OWNER CLICKS ON EXTEND TIMELINE FOR A JOB
|
||||
const extendTime = () => {
|
||||
setAction('extend')
|
||||
setReqStatus({loading:true, status: false, message: ''}) // Sets loading spinner active
|
||||
let reqData = {
|
||||
contract: jobDetails.contract,
|
||||
contract_uid: jobDetails.contract_uid,
|
||||
job_action: 'EXTEND_TIMELINE',
|
||||
extension: Number(extendedTime)
|
||||
}
|
||||
if(!extendedTime){ // checks that timeline duration is selected
|
||||
setReqStatus({loading:false, status: false, message: 'Please select timeline duration'})
|
||||
return setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
// API CALL EXTEND TIMELINE BY OWNER
|
||||
apiCall.ownerJobAction(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setReqStatus({loading:false, status: false, message: 'unable to complete request. Try again'})
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'Timeline extended successfully'})
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /my-pastdue-jobs after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/my-pastdue-jobs', {replace: true})
|
||||
}, 3000)
|
||||
}).catch(err => {
|
||||
setReqStatus({loading:false, status: false, message: 'Opps! Network error. Try again'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
|
||||
<table className="w-full text-sm text-left text-gray-500 owner-pastdue">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
|
||||
<h1 className="text-xl text-dark-gray dark:text-white">
|
||||
Time allocated has passed
|
||||
</h1>
|
||||
{/*<div className="flex flex-col flex-[0.9]"> </div>*/}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex justify-center items-center">
|
||||
<button type="button" onClick={popUpHandler} className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Cancel or Extend Timeline
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{popUp && (
|
||||
<ModalCom action={popUpHandler} situation={popUp}>
|
||||
<div className="logout-modal-wrapper lg:w-[460px] 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 dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Past Due Task
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
<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 px-10 py-8 gap-4">
|
||||
<div className="w-full flex flex-col items-center">
|
||||
<div className="mb-5 flex justify-center items-center gap-2">
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={checked}
|
||||
onChange={()=>{setChecked(prev => !prev)}}
|
||||
className='w-6 h-6 text-sky-blue bg-gray-100 focus:ring-sky-blue'
|
||||
/>
|
||||
<p className='font-bold text-base tracking-wide text-dark-gray dark:text-white'>I am ready to cancel this task</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-5 flex justify-center items-center">
|
||||
{reqStatus.loading && action=='cancel'?
|
||||
<LoadingSpinner color='sky-blue' size='10' />
|
||||
:
|
||||
<button disabled={reqStatus.loading} onClick={cancelTask} type="button" className="px-2 py-1 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white">
|
||||
<span className='text-gradient'>Cancel this task</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* EXTEND TIMELINE SECTION */}
|
||||
<div className='w-full my-3 py-3 border-y flex flex-col items-center'>
|
||||
<div className='mb-5 flex items-center gap-2'>
|
||||
<p className='font-bold text-base tracking-wide text-dark-gray dark:text-white'>Extend the timeline by:</p>
|
||||
<select
|
||||
onChange={({target})=>{setExtendedTime(target.value)}}
|
||||
className='text-base p-2 text-dark-gray dark:text-white rounded-md border border-slate-300 outline-0'
|
||||
>
|
||||
<option className='text-slate-500 text-lg' value=''>select</option>
|
||||
<option className='text-slate-500 text-lg' value='2'>1 days</option>
|
||||
<option className='text-slate-500 text-lg' value='3'>3 days</option>
|
||||
<option className='text-slate-500 text-lg' value='5'>5 days</option>
|
||||
<option className='text-slate-500 text-lg' value='7'>1 week</option>
|
||||
</select>
|
||||
</div>
|
||||
{reqStatus.loading && action=='extend' ?
|
||||
<LoadingSpinner color='sky-blue' size='10' />
|
||||
:
|
||||
<button disabled={reqStatus.loading} type="button" onClick={extendTime} className="px-2 py-1 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Extend Timeline
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
<div className="w-full">
|
||||
{reqStatus.message != "" &&
|
||||
(!reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
{/* END OF FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
</div>
|
||||
|
||||
{/* 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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCom>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PastDueJobAction
|
||||
@@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
|
||||
function PastDueTaskAction() {
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
|
||||
<table className="w-full text-sm text-left text-gray-500 worker-pastdue">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
|
||||
<h1 className="text-xl text-dark-gray dark:text-white">
|
||||
You have missed the allocated time
|
||||
</h1>
|
||||
{/*<div className="flex flex-col flex-[0.9]"> </div>*/}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex justify-center items-center">
|
||||
<button type="button" className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Request Extension
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PastDueTaskAction
|
||||
@@ -0,0 +1,226 @@
|
||||
import React,{useState} from 'react'
|
||||
import ModalCom from '../../Helpers/ModalCom'
|
||||
import LoadingSpinner from '../../Spinners/LoadingSpinner'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import usersService from '../../../services/UsersService'
|
||||
|
||||
function ReviewJobAction({jobDetails}) {
|
||||
|
||||
const apiCall = new usersService()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [checked, setChecked] = useState(false)
|
||||
|
||||
const [action, setAction] = useState('') // VALUE OF NEW EXTENDED TIME
|
||||
|
||||
const [reqStatus, setReqStatus] = useState({loading:false, status: false, message: ''})
|
||||
|
||||
let [popUp, setPopUp] = useState(false)
|
||||
|
||||
const popUpHandler = () => {
|
||||
if(popUp){
|
||||
setChecked(false)
|
||||
}
|
||||
setPopUp(prev => !prev)
|
||||
}
|
||||
|
||||
// FUNCTION TO HANDLE WHEN OWNER ACCEPTS COMPLETION OF JOB
|
||||
const acceptCompletion = () => {
|
||||
setAction('accept')
|
||||
setReqStatus({loading:true, status: false, message: ''})
|
||||
|
||||
let reqData = { // API PAYLOADS
|
||||
contract: jobDetails.contract,
|
||||
contract_uid: jobDetails.contract_uid,
|
||||
job_action: 'ACCEPT_COMPLETE',
|
||||
}
|
||||
|
||||
if(!checked){ // CHECKS IF CHECKBOX IS SELECTED
|
||||
setReqStatus({loading:false, status: false, message: 'Please check the box above'})
|
||||
return setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
}
|
||||
// API CALL TO ACCEPT COMPLETION BY OWNER
|
||||
apiCall.ownerJobAction(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setReqStatus({loading:false, status: false, message: 'unable to complete request. Try again'})
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'job completion accepted successfully'})
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /my-review-jobs after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/my-review-jobs', {replace: true})
|
||||
}, 3000)
|
||||
}).catch(err => {
|
||||
setReqStatus({loading:false, status: false, message: 'Opps! Network error. Try again'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
// FUNCTION TO HANDLE WHEN USER/OWNER CLICKS ON REJECT COMPLETION OF JOB
|
||||
const rejectCompletion = () => {
|
||||
setAction('reject')
|
||||
setReqStatus({loading:true, status: false, message: ''}) // Sets loading spinner active
|
||||
let reqData = { // API PAYLOADS
|
||||
contract: jobDetails.contract,
|
||||
contract_uid: jobDetails.contract_uid,
|
||||
job_action: 'REJECT_COMPLETE',
|
||||
}
|
||||
// API CALL TO REJECT COMPLETION BY OWNER
|
||||
apiCall.ownerJobAction(reqData).then((res)=>{
|
||||
if(res.status != 200 || res.data.internal_return < 0){
|
||||
setReqStatus({loading:false, status: false, message: 'unable to complete request. Try again'})
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'job completion rejected successfully'})
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /my-review-jobs after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/my-review-jobs', {replace: true})
|
||||
}, 3000)
|
||||
}).catch(err => {
|
||||
setReqStatus({loading:false, status: false, message: 'Opps! Network error. Try again'})
|
||||
}).finally(()=>{
|
||||
setTimeout(()=>{
|
||||
setReqStatus({loading:false, status: false, message: ''})
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
<div className="my-3 py-1 text-base">
|
||||
<table className="w-full text-sm text-left text-gray-500 review-owner">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
|
||||
<h1 className="text-xl text-dark-gray dark:text-white">
|
||||
This Job is Ready for your review
|
||||
</h1>
|
||||
{/*<div className="flex flex-col flex-[0.9]"> </div>*/}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="flex justify-center items-center">
|
||||
<button type="button" onClick={popUpHandler} className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Reject or Accept
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{popUp && (
|
||||
<ModalCom action={popUpHandler} situation={popUp}>
|
||||
<div className="logout-modal-wrapper lg:w-[460px] 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 dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Completion
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
<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 px-10 py-8 gap-4">
|
||||
<div className="w-full flex flex-col items-center">
|
||||
<div className="mb-5 flex justify-center items-center gap-2">
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={checked}
|
||||
onChange={()=>{setChecked(prev => !prev)}}
|
||||
className='w-6 h-6 text-sky-blue bg-gray-100 focus:ring-sky-blue'
|
||||
/>
|
||||
<p className='font-bold text-base tracking-wide text-dark-gray dark:text-white'>I am ready to accept completion</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-5 flex justify-center items-center">
|
||||
{reqStatus.loading && action=='accept'?
|
||||
<LoadingSpinner color='sky-blue' size='10' />
|
||||
:
|
||||
<button disabled={reqStatus.loading} onClick={acceptCompletion} type="button" className="px-2 py-1 h-11 flex justify-center items-center border-gradient text-base rounded-full text-white">
|
||||
<span className='text-gradient'>Accept Completion</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* EXTEND TIMELINE SECTION */}
|
||||
<div className='w-full my-3 py-3 border-y flex flex-col items-center'>
|
||||
<div className='mb-5 flex items-center gap-2'>
|
||||
<p className='font-bold text-base tracking-wide text-dark-gray dark:text-white'>I am not ready to accept completion of task</p>
|
||||
</div>
|
||||
{reqStatus.loading && action=='reject' ?
|
||||
<LoadingSpinner color='sky-blue' size='10' />
|
||||
:
|
||||
<button disabled={reqStatus.loading} type="button" onClick={rejectCompletion} className="px-2 py-1 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
|
||||
Reject Completion
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
<div className="w-full">
|
||||
{reqStatus.message != "" &&
|
||||
(!reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
) : (
|
||||
reqStatus.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]`}
|
||||
>
|
||||
{reqStatus.message}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
{/* END OF FOR SUCCESS/ERROR DISPLAY SECTION*/}
|
||||
</div>
|
||||
|
||||
{/* 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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalCom>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReviewJobAction
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
function ReviewTaskAction() {
|
||||
return (
|
||||
<div className='job-action bg-white dark:bg-black'>
|
||||
<p className="my-3 py-1 text-base text-dark-gray dark:text-white">
|
||||
Waiting for the completion message from the client before you can approve. Worker True & Review Job
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReviewTaskAction
|
||||
@@ -1,17 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import dataImage2 from "../../assets/images/data-table-user-2.png";
|
||||
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
|
||||
export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
const navigate = useNavigate();
|
||||
let {pathname} = useLocation()
|
||||
|
||||
const filterCategories = ["All Categories", "Explore", "Featured"];
|
||||
const [selectedCategory, setCategory] = useState(filterCategories[0]);
|
||||
let { pathname } = useLocation();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const indexOfFirstItem = Number(currentPage);
|
||||
@@ -28,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 ${
|
||||
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
|
||||
className || ""
|
||||
}`}
|
||||
>
|
||||
@@ -44,75 +40,92 @@ export default function MyActiveJobTable({ MyJobList, className }) {
|
||||
{
|
||||
<>
|
||||
{MyJobList &&
|
||||
MyJobList?.result_list &&
|
||||
MyJobList.result_list.length > 0 &&
|
||||
currentActiveJobList.map((value, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
>
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] max-w-[60px]">
|
||||
<img
|
||||
src={dataImage2}
|
||||
alt="data"
|
||||
className="w-full h-full"
|
||||
/>
|
||||
MyJobList?.result_list &&
|
||||
MyJobList.result_list.length > 0 ? (
|
||||
currentActiveJobList.map((value, index) => {
|
||||
let deliveryDate = value?.delivery_date?.split(" ")[0];
|
||||
let thePrice = PriceFormatter(
|
||||
value?.price * 0.01,
|
||||
value?.currency_code,
|
||||
value?.currency
|
||||
);
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
|
||||
>
|
||||
<td className=" py-4">
|
||||
<div className="flex space-x-2 items-center w-full">
|
||||
<div className="w-full h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1] max-w-[60px]">
|
||||
<img
|
||||
src={dataImage2}
|
||||
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">
|
||||
{value.title}
|
||||
</h1>
|
||||
<div>{value.description}</div>
|
||||
<span className="text-sm text-thin-light-gray flex flext-start gap-1">
|
||||
Price:{" "}
|
||||
<span className="text-purple">
|
||||
{thePrice}
|
||||
</span>
|
||||
</span>
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Duration:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.timeline_days} day(s)
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Due:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{deliveryDate}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Sent to:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.job_to === null
|
||||
? "public"
|
||||
: value.job_to}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col flex-[0.9]">
|
||||
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
|
||||
{value.title}
|
||||
</h1>
|
||||
<div>{value.description}</div>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Price:{" "}
|
||||
<span className="text-purple">
|
||||
{value.price * 0.01}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Duration:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.timeline_days} day(s)
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Expire:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.expire}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm text-thin-light-gray">
|
||||
Send to:{" "}
|
||||
<span className="text-purple">
|
||||
{" "}
|
||||
{value.job_to}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</td>
|
||||
|
||||
<td className="text-right py-4 px-2">
|
||||
<div className="flex justify-center items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigate("/manage-active-job", {
|
||||
state: {...value, pathname},
|
||||
});
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
<td className="text-right py-4 px-2">
|
||||
<div className="flex justify-center items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigate("/manage-active-job", {
|
||||
state: { ...value, pathname },
|
||||
});
|
||||
}}
|
||||
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
|
||||
<td className="p-2">No Active Task!</td>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
</tbody>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
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 MyPastDueJobs(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">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Pass 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>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
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">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
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>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -10,11 +10,10 @@ export default function MyActiveJobs(props) {
|
||||
setValue(value);
|
||||
};
|
||||
console.log("AMEYE LOC1", props.MyJobList);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<CommonHead
|
||||
commonHeadData={props.commonHeadData}
|
||||
/>
|
||||
<CommonHead commonHeadData={props.commonHeadData} />
|
||||
<div className="notification-page w-full mb-10">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import usersService from "../../services/UsersService";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { tableReload } from "../../store/TableReloads";
|
||||
|
||||
const CouponPopup = ({ popUpHandler, data }) => {
|
||||
const [loader, setLoader] = useState(false);
|
||||
const apiCall = useMemo(() => new usersService(), []);
|
||||
const [statusMsg, setStatusMsg] = useState({
|
||||
success: "",
|
||||
error: "",
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const redeemCouponHandler = async () => {
|
||||
setLoader(true);
|
||||
|
||||
try {
|
||||
const { code, coupon_id } = data;
|
||||
const reqData = { code_id: Number(coupon_id), code };
|
||||
|
||||
const res = await apiCall.getCouponRedeem(reqData);
|
||||
|
||||
if (res.data?.internal_return < 0)
|
||||
setStatusMsg({ error: "An error occurred" });
|
||||
else setStatusMsg({ success: res.data?.status_text });
|
||||
|
||||
dispatch(tableReload({ type: "COUPONTABLE" }));
|
||||
setTimeout(() => {
|
||||
popUpHandler();
|
||||
setLoader(false);
|
||||
}, 10000);
|
||||
} catch (error) {
|
||||
setLoader(false);
|
||||
if (error?.status !== 200)
|
||||
setStatusMsg({
|
||||
error: {
|
||||
status: true,
|
||||
msg:
|
||||
error?.statusText !== ""
|
||||
? error?.statusText
|
||||
: "An error occurred",
|
||||
},
|
||||
});
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
setStatusMsg({
|
||||
success: "",
|
||||
error: "",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="logout-modal-wrapper lg:w-[460px] 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 dark:border-[#5356fb29] border-light-purple">
|
||||
<h1 className="text-26 font-bold text-dark-gray dark:text-white tracking-wide">
|
||||
Redeem Coupon
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="text-[#374557] dark:text-red-500"
|
||||
onClick={popUpHandler}
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
<form className="logout-modal-body w-full flex flex-col items-center px-10 py-8 gap-4 border-b dark:border-[#5356fb29] border-light-purple">
|
||||
<div className="input-com mb-7 flex gap-1 items-center w-full">
|
||||
{/* Coupon */}
|
||||
<div className="flex items-center justify-between flex-[0.3]">
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
|
||||
htmlFor="coupon-token"
|
||||
>
|
||||
Coupon:
|
||||
</label>
|
||||
</div>
|
||||
<div className=" flex-[0.7] max-w-[150px]">{data?.code}</div>
|
||||
</div>
|
||||
|
||||
<div className="input-com mb-7 flex gap-1 items-center w-full">
|
||||
{/* Amount */}
|
||||
<div className="flex items-center justify-between flex-[0.3]">
|
||||
<label
|
||||
className="input-label text-[#181c32] dark:text-white text-[15px] font-semibold"
|
||||
htmlFor="amount"
|
||||
>
|
||||
Amount:
|
||||
</label>
|
||||
</div>
|
||||
<div className=" flex-[0.7] max-w-[150px]">{data?.thePrice}</div>
|
||||
</div>
|
||||
<div className="signin-area w-full">
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
onClick={redeemCouponHandler}
|
||||
className="text-white lg:w-[167px] btn-gradient flex justify-center items-center text-lg tracking-wide px-6 py-2 rounded-full"
|
||||
>
|
||||
{loader ? (
|
||||
<div className="signup btn-loader"></div>
|
||||
) : (
|
||||
<span className="font-semibold tracking-wider">
|
||||
Redeem Now!
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{statusMsg.success && (
|
||||
<p className="text-sm text-green-500 italic">{statusMsg.success}</p>
|
||||
)}
|
||||
{statusMsg.error && (
|
||||
<p className="text-sm text-red-500 italic">{statusMsg.error}</p>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
<div className="signin-area w-full px-5 py-4">
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
className="border-gradient text-lg tracking-wide px-6 py-2 rounded-full"
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CouponPopup;
|
||||
|
||||
const CloseIcon = () => (
|
||||
<svg
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,117 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import PaginatedList from "../Pagination/PaginatedList";
|
||||
import { handlePagingFunc } from "../Pagination/HandlePagination";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
import CouponPopup from "./CouponPopup";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { PriceFormatter } from "../Helpers/PriceFormatter";
|
||||
|
||||
function CouponTable({ coupon }) {
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const [couponPopup, setCouponPopup] = useState({ state: false, data: null });
|
||||
const indexOfFirstItem = Number(currentPage);
|
||||
const indexOfLastItem =
|
||||
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const currentCoupon = coupon?.data?.slice(indexOfFirstItem, indexOfLastItem);
|
||||
|
||||
const handlePagination = (e) => {
|
||||
handlePagingFunc(e, setCurrentPage);
|
||||
};
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleCouponPopUp = () =>
|
||||
setCouponPopup((prev) => ({ state: !prev.state }));
|
||||
|
||||
useEffect(() => {
|
||||
if (!coupon) navigate("/my-coupon", { replace: true });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<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">Coupon</th>
|
||||
<th className="p-2 text-center">Amount</th>
|
||||
<th className="p-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{coupon.data.length ? (
|
||||
<tbody>
|
||||
{currentCoupon.map((item, index) => {
|
||||
let thePrice = PriceFormatter(
|
||||
item?.amount * 0.01,
|
||||
item?.currency_code,
|
||||
item?.currency
|
||||
);
|
||||
return(
|
||||
<tr key={index} className="text-slate-500">
|
||||
<td className="p-2 cursor-default">
|
||||
{item.added} <br /> {item.code}
|
||||
</td>
|
||||
<td className="p-2 text-center cursor-default">{thePrice}</td>
|
||||
<td className="p-2 h-20 flex items-center justify-end">
|
||||
<button
|
||||
type="button"
|
||||
className="btn-gradient w-[116px] h-[46px] text-white rounded-full text-base bg-pink flex justify-center items-center"
|
||||
onClick={() => {
|
||||
setCouponPopup((prev) => ({
|
||||
state: !prev.state,
|
||||
data: {...item, thePrice},
|
||||
}));
|
||||
}}
|
||||
>
|
||||
Redeem
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
)})}
|
||||
</tbody>
|
||||
) : coupon.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>
|
||||
)}
|
||||
</table>
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList
|
||||
onClick={handlePagination}
|
||||
prev={currentPage === 0 ? true : false}
|
||||
next={
|
||||
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
|
||||
coupon?.data?.length
|
||||
? true
|
||||
: false
|
||||
}
|
||||
data={coupon?.data}
|
||||
start={indexOfFirstItem}
|
||||
stop={indexOfLastItem}
|
||||
/>
|
||||
{/* END OF PAGINATION BUTTON */}
|
||||
|
||||
{couponPopup.state && (
|
||||
<ModalCom action={handleCouponPopUp} situation={couponPopup.state}>
|
||||
<CouponPopup
|
||||
data={couponPopup.data}
|
||||
popUpHandler={handleCouponPopUp}
|
||||
/>
|
||||
</ModalCom>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default CouponTable;
|
||||