Compare commits
269 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ad75e412b | |||
| e9d6689418 | |||
| ed38e0db98 | |||
| 351f027a6f | |||
| 20d56ee307 | |||
| f5c798c6c1 | |||
| a11f5100ba | |||
| 7628a561f8 | |||
| 615acff0b7 | |||
| aea161ccaf | |||
| 66a2bcacd5 | |||
| ec9d84b779 | |||
| 8ee793d11e | |||
| 46f17cbdfe | |||
| 283994e43a | |||
| b7d242ff0a | |||
| f6bae30bdd | |||
| a7e2e865de | |||
| 51887cf0d6 | |||
| 5ea1047356 | |||
| 9b9a7cc5da | |||
| 290e1fbd7e | |||
| 6884aa19b2 | |||
| 597a45dcba | |||
| 4f7274c30c | |||
| 290356780c | |||
| bd1450887b | |||
| 923a2483ed | |||
| 7f0ccf35b2 | |||
| af2fdcede6 | |||
| a9f2136125 | |||
| 5d04abc0db | |||
| 26d095afda | |||
| cd030d8d12 | |||
| 4a0b7925d0 | |||
| 9d947f19b9 | |||
| 7a99beab57 | |||
| 02731c021a | |||
| fecae9d626 | |||
| a4867a1b73 | |||
| 51c2e4b568 | |||
| 756c084059 | |||
| 064973e190 | |||
| d165e9dc0f | |||
| 77109e8369 | |||
| 2924401c9b | |||
| f6c2b1129d | |||
| 8ba167a17c | |||
| 7f65b286b1 | |||
| afc9e5be0f | |||
| 7aefb555ed | |||
| 325d28c1a8 | |||
| 25269a44c3 | |||
| 47df35d076 | |||
| 1deb15029d | |||
| 30b284064d | |||
| 4cbe78efc3 | |||
| 92ac7d74f4 | |||
| f0382cea9e | |||
| 2123af0abe | |||
| a3c306bf89 | |||
| a61abe718a | |||
| 2b91506c61 | |||
| 253cace3fe | |||
| aa55a1a4e0 | |||
| 8b763882fa | |||
| 30540e46ba | |||
| b195b1f787 | |||
| 2ddd04a1a1 | |||
| 6ea26740a4 | |||
| f334ca49f0 | |||
| fa9d7f69e4 | |||
| a4db58ba97 | |||
| ddc747d9ca | |||
| ac337eb693 | |||
| f2c3415b1d | |||
| 37450925e1 | |||
| 3b20fcec68 | |||
| d87a083c3e | |||
| 3f8a7a6b3b | |||
| 91d82db40c | |||
| 2dc12d7d0a | |||
| 164195d4cc | |||
| 7ad1a585ea | |||
| a8c2dd84f1 | |||
| ddcc6f0cd2 | |||
| 683f81e8a6 | |||
| 8e09c30c5c | |||
| af0d4db5de | |||
| 6f3dae4116 | |||
| 13900793af | |||
| 698c89edfc | |||
| 4f5a383c99 | |||
| a5b6a11880 | |||
| 0f58da3dce | |||
| 1101e80d91 | |||
| b39a7ab58c | |||
| ad90def3c9 | |||
| 737430bf04 | |||
| d371ada805 | |||
| b77f1d6213 | |||
| 64085c6be5 | |||
| 3f8b45b6d6 | |||
| 4b6c927efc | |||
| 8a8adcbbc7 | |||
| 706baadb33 | |||
| 58128fdd96 | |||
| 14e8b1b01d | |||
| 504bfbcae4 | |||
| ec47aa5f9c | |||
| 9267ded0f1 | |||
| 0b24ca650d | |||
| b535a656a0 | |||
| e69cc9130e | |||
| daafb66cbb | |||
| 3852468afe | |||
| d32204e08f | |||
| 8372209923 | |||
| 6c3f96d9a3 | |||
| c25acecb1a | |||
| 3f5ae4685e | |||
| a80298c824 | |||
| e9bc1c1318 | |||
| 2543a91b19 | |||
| 4c38b0a31f | |||
| 6ed396a34c | |||
| 465a480f02 | |||
| 4409ed45f3 | |||
| 470c94ae5e | |||
| 52fd4275e9 | |||
| 0dadaf00b0 | |||
| 0fbe0f4c3f | |||
| 464182e583 | |||
| 517886df7e | |||
| 3db5d56410 | |||
| 6c107c8000 | |||
| 225a3d36e4 | |||
| f66f92c58d | |||
| 599e8a7715 | |||
| 97b75e0d9b | |||
| 4bc985892e | |||
| c951f925d8 | |||
| 1681ca1437 | |||
| d2cb38f141 | |||
| 67d26f6ab0 | |||
| 72dc343d01 | |||
| 4969ad1ae4 | |||
| 9e33578ef2 | |||
| be6dab1ec9 | |||
| aae69ffd3b | |||
| 6294d7cafd | |||
| be483c9451 | |||
| 6559d00052 | |||
| 6f3ed362b7 | |||
| fe88a6d7f2 | |||
| 6adb6aed1f | |||
| 373c5427c2 | |||
| a9473debdb | |||
| e4eb445059 | |||
| 44b2e08006 | |||
| 17239f9ea8 | |||
| 519b6e5585 | |||
| 56fb97eda1 | |||
| 1abc998120 | |||
| 858dd39936 | |||
| 292c8409d6 | |||
| 45c457e210 | |||
| 1e7014172d | |||
| 98bf50fcde | |||
| 4385d8bec0 | |||
| d1c86ec9b2 | |||
| dae4862db2 | |||
| d80bb55205 | |||
| 3205d5627e | |||
| bfea6b956b | |||
| 4ec74ff895 | |||
| 84b4523154 | |||
| c19cfdd524 | |||
| 2476c491be | |||
| ece281ef8a | |||
| 8ae0de1004 | |||
| 13ac1d1f85 | |||
| 5a408311ae | |||
| 9c64d8178e | |||
| be8f54bb42 | |||
| 2c6102dfa5 | |||
| bbd6ecac58 | |||
| 56ce8f0556 | |||
| 9e4de10251 | |||
| 777f3cbec4 | |||
| a6e9d507ae | |||
| c1af89919e | |||
| a8686ac2e7 | |||
| 591b1fa3b9 | |||
| 3d5bdc2afd | |||
| cdb676a047 | |||
| 34febdedfa | |||
| cb4f9fbb42 | |||
| ad4a92ceed | |||
| d71fe9cc01 | |||
| aeb9f0512c | |||
| 62c3a8be82 | |||
| c7c1da919d | |||
| 669a249499 | |||
| 2cc57f0b0a | |||
| 2be1f2ebd1 | |||
| 54be47e1c8 | |||
| 8eefbbede8 | |||
| fa6b53ede0 | |||
| a5ac576176 | |||
| b840f28667 | |||
| 66d1ae1609 | |||
| 9cfb4651af | |||
| 2d141b529c | |||
| b418ca7d58 | |||
| 9eea804f71 | |||
| f3ebb0a925 | |||
| 6421eb5b3e | |||
| 971624a358 | |||
| 21463ed501 | |||
| f450d0e868 | |||
| c880cccb5a | |||
| c776419dcf | |||
| 80d5c8ea12 | |||
| df6d2b570c | |||
| a802c1ca39 | |||
| 1a054a9fbc | |||
| 33eacecacf | |||
| a71017fae6 | |||
| 8969234fe5 | |||
| a0da97e14d | |||
| 4d1de18713 | |||
| 4fe66fd161 | |||
| 6028e4c617 | |||
| 398392062c | |||
| b84eac1299 | |||
| 52e3553aaa | |||
| 220e4952d5 | |||
| 59c90ea175 | |||
| 9838fc948e | |||
| cb4c741a90 | |||
| bba38affae | |||
| 9468793d91 | |||
| 44224e23ff | |||
| 5b926300ae | |||
| 9125730d2b | |||
| 00baa0b9bf | |||
| f5018bc6b7 | |||
| 59d9eb3df9 | |||
| 8f78011800 | |||
| 3c3f70fd3f | |||
| 4f62410e6d | |||
| b8c65ee091 | |||
| 5e1e97a2dd | |||
| f794e6d31c | |||
| a4e1376c27 | |||
| 16db88808b | |||
| 2e97ec9857 | |||
| 6ec537bebf | |||
| d84c266653 | |||
| bb5a886e47 | |||
| b5a37c4cc5 | |||
| ddde4bd0d5 | |||
| bf9c6c8b32 | |||
| 14e588b0a9 | |||
| dde01ab79a | |||
| a5f1c4b5bb | |||
| a16dd7af24 | |||
| 54d44e39d3 |
@@ -1,5 +1,7 @@
|
|||||||
|
REACT_APP_PANEL_NAME="MERMS Panel DEV"
|
||||||
SKIP_PREFLIGHT_CHECK=true
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="development"
|
REACT_APP_NODE_ENV="development"
|
||||||
|
NODE_ENV="development"
|
||||||
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
||||||
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
||||||
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
||||||
@@ -14,3 +16,6 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
|||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
REACT_APP_PANEL_NAME="MERMS Panel DEV"
|
||||||
SKIP_PREFLIGHT_CHECK=true
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="development"
|
REACT_APP_NODE_ENV="development"
|
||||||
|
NODE_ENV="development"
|
||||||
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
||||||
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
||||||
|
REACT_APP_MAIN_API_LL="http://localhost:14700"
|
||||||
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
||||||
REACT_APP_MAIN_SOCKET="https://devsocket.mermsemr.com"
|
REACT_APP_MAIN_SOCKET="https://devsocket.mermsemr.com"
|
||||||
|
|
||||||
@@ -14,3 +17,6 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
|||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
REACT_APP_PANEL_NAME="MERMS Panel"
|
||||||
SKIP_PREFLIGHT_CHECK=true
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="production"
|
REACT_APP_NODE_ENV="production"
|
||||||
|
NODE_ENV="production"
|
||||||
REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
|
||||||
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
REACT_APP_MAIN_API="https://api.mermsemr.com"
|
||||||
REACT_APP_MEDIA_SERVER="https://media.mermsemr.com"
|
REACT_APP_MEDIA_SERVER="https://media.mermsemr.com"
|
||||||
REACT_APP_MAIN_SOCKET="https://socket.mermsemr.com"
|
REACT_APP_MAIN_SOCKET="https://socket.mermsemr.com"
|
||||||
|
|
||||||
@@ -13,3 +15,6 @@ REACT_APP_TERMS_LINK='https://www.mermsemr.com/terms'
|
|||||||
|
|
||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
REACT_APP_PANEL_NAME="MERMS Panel QA"
|
||||||
SKIP_PREFLIGHT_CHECK=true
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="development"
|
REACT_APP_NODE_ENV="development"
|
||||||
|
NODE_ENV="development"
|
||||||
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
||||||
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
|
||||||
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
|
|||||||
# add app
|
# add app
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
|
||||||
# start app
|
# start appdpvle
|
||||||
# CMD ["npm","run", "start"]
|
#CMD ["npm","run", "start"]
|
||||||
|
|
||||||
# CMD ["yarn", "start"]
|
# CMD ["yarn", "start"]
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
"@fullcalendar/timegrid": "^6.1.15",
|
"@fullcalendar/timegrid": "^6.1.15",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@reduxjs/toolkit": "^2.4.0",
|
"@reduxjs/toolkit": "^2.4.0",
|
||||||
|
"@stripe/react-stripe-js": "^3.9.1",
|
||||||
|
"@stripe/stripe-js": "^7.8.0",
|
||||||
"@tanstack/react-query": "^5.62.3",
|
"@tanstack/react-query": "^5.62.3",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
@@ -33,8 +35,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start -e .env.development",
|
"start": "react-scripts start -e .env.development",
|
||||||
"build": "react-scripts start -e .env.development",
|
"build": "GENERATE_SOURCEMAP=false react-scripts build -e .env.production",
|
||||||
"build_real": "GENERATE_SOURCEMAP=false react-scripts build -e .env.production",
|
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,31 +1,35 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8"/>
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000"/>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="Empowering Healthcare Decision-Making with Artificial Intelligence"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||||
<title>MERMS-Panel</title>
|
<title>MERMS-Panel</title>
|
||||||
</head>
|
</head>
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Y9QSQFV003"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Y9QSQFV003"></script>
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
|
||||||
|
function gtag() {
|
||||||
|
dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'G-Y9QSQFV003');
|
gtag('config', 'G-Y9QSQFV003');
|
||||||
</script>
|
</script>
|
||||||
<body class="light-sidebar">
|
<body class="light-sidebar">
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
|
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script> -->
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script> -->
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,12 +4,17 @@ set -x
|
|||||||
|
|
||||||
export NODE_ENV="${NODE_ENV:-development}"
|
export NODE_ENV="${NODE_ENV:-development}"
|
||||||
|
|
||||||
if [ $NODE_ENV == "development" ]; then
|
if [ $NODE_ENV = "development" ]; then
|
||||||
# this runs webpack-dev-server with hot reloading
|
# this runs webpack-dev-server with hot reloading
|
||||||
echo "Development build"
|
echo "Development build"
|
||||||
npm install --legacy-peer-deps
|
npm install --legacy-peer-deps
|
||||||
npm start
|
npm start
|
||||||
# npm run build
|
# npm run build
|
||||||
|
elif [ $NODE_ENV = "qa" -o $NODE_ENV = "test" ]; then
|
||||||
|
echo "QA build"
|
||||||
|
export NODE_ENV="test"
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
npm start
|
||||||
else
|
else
|
||||||
# build the app and serve it via nginx
|
# build the app and serve it via nginx
|
||||||
echo "Production build"
|
echo "Production build"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.custom-bg {
|
.custom-bg {
|
||||||
background-image: url('./assets/bg/bg_1.jpg') !important;
|
background-image: url('./assets/bg/bg_2.jpg') !important;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,10 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-radius-10 {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.login-links{
|
.login-links{
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -48,3 +52,10 @@ button{
|
|||||||
.accordion-button, .accordion-button:not(.collapsed) {
|
.accordion-button, .accordion-button:not(.collapsed) {
|
||||||
background-color: transparent!important;
|
background-color: transparent!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.modal-50 {
|
||||||
|
min-width: 50%;
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Routes, Route } from 'react-router-dom';
|
import {Routes, Route} from 'react-router-dom';
|
||||||
|
|
||||||
import UserExist from './component/authorization/UserExist';
|
import UserExist from './component/authorization/UserExist';
|
||||||
import AuthLayout from './component/auth/AuthLayout';
|
import AuthLayout from './component/auth/AuthLayout';
|
||||||
@@ -19,34 +19,51 @@ import ProductPage from './views/ProductPage'
|
|||||||
import SocketIOContextProvider from './component/context/SocketIOContext';
|
import SocketIOContextProvider from './component/context/SocketIOContext';
|
||||||
import CSignupPage from './views/CSignupPage';
|
import CSignupPage from './views/CSignupPage';
|
||||||
import HelpPage from './views/HelpPage';
|
import HelpPage from './views/HelpPage';
|
||||||
|
import SubscriptionPage from './views/SubscriptionPage';
|
||||||
|
import OnboardPage from "./views/OnboardPage";
|
||||||
|
import AccPWDResetPage from './views/AccPWDResetPage';
|
||||||
|
import ProfileCompletePage from './views/ProfileCompletePage';
|
||||||
|
import SubscribePage from './views/Subscribe'
|
||||||
|
import StartPage from "./views/StartPage";
|
||||||
|
import TrafficPage from "./views/TrafficPage";
|
||||||
|
import MyMediaPage from './views/MyMediaPage.jsx';
|
||||||
|
|
||||||
function AppRouters() {
|
function AppRouters() {
|
||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<BearerToken />}>
|
<Route element={<BearerToken/>}>
|
||||||
{/* auth routes wrapper */}
|
{/* auth routes wrapper */}
|
||||||
<Route element={<AuthLayout />}>
|
<Route element={<AuthLayout/>}>
|
||||||
<Route path={siteLinks.home} element={<LoginPage />} />
|
<Route path={siteLinks.home} element={<LoginPage/>}/>
|
||||||
<Route path={siteLinks.login} element={<LoginPage />} />
|
<Route path={siteLinks.login} element={<LoginPage/>}/>
|
||||||
<Route path={siteLinks.signup} element={<SignupPage />} />
|
<Route path={siteLinks.signup} element={<SignupPage/>}/>
|
||||||
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage />} />
|
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage/>}/>
|
||||||
<Route path={siteLinks.csignup} element={<CSignupPage />} />
|
<Route path={siteLinks.csignup} element={<CSignupPage/>}/>
|
||||||
<Route path={siteLinks.error} element={<LoginPage />} />
|
<Route path={siteLinks.accreset} element={<AccPWDResetPage/>}/>
|
||||||
|
<Route path={siteLinks.error} element={<LoginPage/>}/>
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* protected routes */}
|
{/* protected routes */}
|
||||||
<Route element={<SocketIOContextProvider />}>
|
<Route element={<SocketIOContextProvider/>}>
|
||||||
<Route element={<UserExist />}>
|
<Route element={<UserExist/>}>
|
||||||
<Route path={siteLinks.dash} element={<HomePage />} />
|
<Route path={siteLinks.start} element={<StartPage/>}/>
|
||||||
<Route path={siteLinks.product} element={<ProductPage />} />
|
<Route path={siteLinks.dash} element={<HomePage/>}/>
|
||||||
<Route path={siteLinks.reports} element={<ReportsPage />} />
|
<Route path={siteLinks.traffic} element={<TrafficPage/>}/>
|
||||||
<Route path={siteLinks.comments} element={<CommentsPage />} />
|
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
||||||
<Route path={siteLinks.contacts} element={<ContactsPage />} />
|
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
||||||
<Route path={siteLinks.user} element={<UserPage />} />
|
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
||||||
<Route path={siteLinks.calendar} element={<CalendarPage />} />
|
<Route path={siteLinks.my_media} element={<MyMediaPage />}/>
|
||||||
<Route path={siteLinks.settings} element={<SettingsPage />} />
|
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
||||||
<Route path={siteLinks.help} element={<HelpPage />} />
|
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
||||||
|
<Route path={siteLinks.user} element={<UserPage/>}/>
|
||||||
|
<Route path={siteLinks.subscription} element={<SubscriptionPage/>}/>
|
||||||
|
<Route path={siteLinks.subscription_success} element={<SubscriptionPage/>}/>
|
||||||
|
<Route path={siteLinks.onboard} element={<OnboardPage/>}/>
|
||||||
|
<Route path={siteLinks.calendar} element={<CalendarPage/>}/>
|
||||||
|
<Route path={siteLinks.settings} element={<SettingsPage/>}/>
|
||||||
|
<Route path={siteLinks.subscribe} element={<SubscribePage/>}/>
|
||||||
|
<Route path={siteLinks.help} element={<HelpPage/>}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 390 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 417 KiB |
@@ -0,0 +1,220 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
|
||||||
|
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
import siteLinks from '../../links/siteLinks'
|
||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { completePWDReset, verifyResetToken } from '../../services/services';
|
||||||
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
|
import { IoMdArrowDropdown } from "react-icons/io";
|
||||||
|
import getImage from '../../utils/getImage';
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
password: Yup.string().required("Password is required"),
|
||||||
|
confirmpassword: Yup.string().required("Confirm Password is required").oneOf([Yup.ref('password')], 'Passwords must match')
|
||||||
|
})
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
password: '',
|
||||||
|
confirmpassword: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AccPWDReset() {
|
||||||
|
|
||||||
|
const {token} = useParams()
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const [user, setUser] = useState(null)
|
||||||
|
|
||||||
|
// API to verify email link
|
||||||
|
const verifyLink = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return verifyResetToken(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
// console.log('res', res.data)
|
||||||
|
if(res.data.resultCode != '0' || !res?.data?.pending_uid){
|
||||||
|
throw({message: res?.data?.resultDescription})
|
||||||
|
}
|
||||||
|
// setUser({user:'testaccount', ...res.data})
|
||||||
|
setUser(res.data)
|
||||||
|
},
|
||||||
|
// onError: (err) => {
|
||||||
|
// console.log('err', err)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
const resetPWD = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return completePWDReset(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if(res?.data?.resultCode != '0'){
|
||||||
|
throw({message: res?.data?.resultDescription})
|
||||||
|
}
|
||||||
|
// const {token, room, uid} = res?.data
|
||||||
|
// if(!token || !room){
|
||||||
|
// throw({message: 'something went wrong, try again!'})
|
||||||
|
// }
|
||||||
|
// localStorage.setItem('token', token)
|
||||||
|
// localStorage.setItem('room', room)
|
||||||
|
// localStorage.setItem('uid', uid)
|
||||||
|
// dispatch(updateUserDetails({ ...res?.data }));
|
||||||
|
// navigate('/dash') // later add redux to dispatch state
|
||||||
|
},
|
||||||
|
// onError: (err) => {
|
||||||
|
// console.log('err', err)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleCompletePWDReset = (values) => {
|
||||||
|
let reqData = {
|
||||||
|
reset_token: token,
|
||||||
|
reset_uid: user?.pending_uid,
|
||||||
|
new_password: values.password,
|
||||||
|
}
|
||||||
|
resetPWD.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(!token){
|
||||||
|
return navigate(siteLinks.login, {replace: true})
|
||||||
|
}
|
||||||
|
verifyLink.mutate({reset_token: token})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<div className="app-wrap">
|
||||||
|
<div className="app-contant">
|
||||||
|
<div className="vh-100 bg-white custom-bg">
|
||||||
|
<div className="container-fluid p-0">
|
||||||
|
<div className="row no-gutters justify-content-center">
|
||||||
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
||||||
|
<div className="mt-5 d-flex">
|
||||||
|
<div className="bg-white register p-5">
|
||||||
|
<h1 className="mb-2">MERMS Panel</h1>
|
||||||
|
{(verifyLink.isSuccess && !resetPWD.isSuccess) && <p>Complete your password reset</p>}
|
||||||
|
<div
|
||||||
|
>
|
||||||
|
<div className='mt-2'>
|
||||||
|
<div className="row">
|
||||||
|
{resetPWD.isSuccess ?
|
||||||
|
<>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
|
||||||
|
<h4 className='p-4 text-black'>Your password reset is completed</h4>
|
||||||
|
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
|
||||||
|
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 mt-3">
|
||||||
|
<p>Go <Link to={siteLinks.home}> Back</Link></p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
{verifyLink.isPending ?
|
||||||
|
<div className='col-12'>
|
||||||
|
<div className="rounded-2 d-flex flex-column justify-content-center align-items-center" style={{height: '200px', backgroundColor: '#F2FAF7'}}>
|
||||||
|
<div className="col-12 d-flex flex-column justify-content-center align-items-center">
|
||||||
|
<p className='text-black'>loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: verifyLink.isSuccess ?
|
||||||
|
<div className='col-12'>
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={handleCompletePWDReset}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className='mt-2'>
|
||||||
|
<div className="row">
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className={`text-black fw-bold control-label`}>Username: {user?.user}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className={`text-black fw-bold control-label ${(props.errors.password && props.touched.password) && 'text-danger'}`}>Password*</label>
|
||||||
|
<input type="password" name='password' className="form-control" placeholder="password" value={props.values.password} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className={`text-black fw-bold control-label`}>Confirm Password* <span className={`${(props.errors.confirmpassword && props.touched.confirmpassword) && 'text-danger'}`}>{(props.errors.confirmpassword && props.touched.confirmpassword) && props.errors.confirmpassword}</span></label>
|
||||||
|
<input type="password" name='confirmpassword' className="form-control" placeholder="confirmpassword" value={props.values.confirmpassword} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{resetPWD.error &&
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{resetPWD.error.message}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="col-12 mt-3 text-end">
|
||||||
|
<button type='submit' className="btn btn-primary text-uppercase">{resetPWD.isPending ? 'loading...' : 'reset password'}</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
|
: verifyLink.error ?
|
||||||
|
<>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#E9D0DD'}}>
|
||||||
|
<h4 className='p-4 text-black'>Unable to continue password reset. Please start again</h4>
|
||||||
|
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
|
||||||
|
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 mt-3">
|
||||||
|
<p>Go <Link to={siteLinks.home}> Back</Link></p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
|
||||||
|
<div className="row align-items-center h-100">
|
||||||
|
<div className="col-7 mx-auto ">
|
||||||
|
<img className="img-fluid" src={LoginImg} alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
||||||
|
import IOSDownload from '../../assets/img/download/apple.jpg'
|
||||||
|
|
||||||
|
export default function AuthFooter() {
|
||||||
|
return (
|
||||||
|
<div className='w-100'>
|
||||||
|
{Number(process.env.REACT_APP_SHOW_DOWNLOAD) == 100 &&
|
||||||
|
<>
|
||||||
|
<div className="row" style={{margin: '5px'}}>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<div className="row" style={{marginTop: '20px'}}>
|
||||||
|
<div className="col-6">
|
||||||
|
<div className="app-store-icons-wrap text-center">
|
||||||
|
<a className="icon google"
|
||||||
|
href='#' >
|
||||||
|
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-6">
|
||||||
|
<div className="app-store-icons-wrap text-center">
|
||||||
|
<a className="icon apple" href='#'>
|
||||||
|
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="login-links">
|
||||||
|
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
||||||
|
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
||||||
|
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
||||||
|
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ export default function CSignup() {
|
|||||||
localStorage.setItem('room', room)
|
localStorage.setItem('room', room)
|
||||||
localStorage.setItem('uid', uid)
|
localStorage.setItem('uid', uid)
|
||||||
dispatch(updateUserDetails({ ...res?.data }));
|
dispatch(updateUserDetails({ ...res?.data }));
|
||||||
navigate('/dash') // later add redux to dispatch state
|
navigate(siteLinks.start, {replace: true}) // later add redux to dispatch state
|
||||||
},
|
},
|
||||||
// onError: (err) => {
|
// onError: (err) => {
|
||||||
// console.log('err', err)
|
// console.log('err', err)
|
||||||
@@ -100,7 +100,7 @@ export default function CSignup() {
|
|||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register p-5">
|
<div className="bg-white register p-5">
|
||||||
<h1 className="mb-2">MERMS Panel</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
{/* <p>Welcome, Enter your password.</p> */}
|
{/* <p>Welcome, Enter your password.</p> */}
|
||||||
<div
|
<div
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import siteLinks from '../../links/siteLinks'
|
|||||||
import { useMutation } from '@tanstack/react-query'
|
import { useMutation } from '@tanstack/react-query'
|
||||||
import { recoverPWD } from '../../services/services';
|
import { recoverPWD } from '../../services/services';
|
||||||
import getImage from '../../utils/getImage';
|
import getImage from '../../utils/getImage';
|
||||||
|
import AuthFooter from './AuthFooter';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
username: Yup.string()
|
username: Yup.string()
|
||||||
@@ -17,7 +18,7 @@ const validationSchema = Yup.object().shape({
|
|||||||
// "Invalid email format"
|
// "Invalid email format"
|
||||||
// )
|
// )
|
||||||
.min(3, "Minimum 3 characters")
|
.min(3, "Minimum 3 characters")
|
||||||
.max(50, "Maximum 50 characters")
|
.max(25, "Maximum 25 characters")
|
||||||
.required("Email is required"),
|
.required("Email is required"),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -49,8 +50,8 @@ export default function Forgetpwd2() {
|
|||||||
<div className="row no-gutters justify-content-center">
|
<div className="row no-gutters justify-content-center">
|
||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1h" style={{maxWidth: '520px'}}>
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1h" style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register p-5">
|
<div className="bg-white register px-5 pt-5 pb-3">
|
||||||
<h1 className="mb-2">MERMS Panel</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
{!mutation.isSuccess && <p>Please enter your username.</p>}
|
{!mutation.isSuccess && <p>Please enter your username.</p>}
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@@ -65,7 +66,7 @@ export default function Forgetpwd2() {
|
|||||||
<>
|
<>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Username*</label>
|
<label className={`text-black fw-bold control-label`}>Username* <span className='text-danger' style={{fontSize: '12px'}}>{(props.errors.username && props.touched.username) && props.errors.username}</span></label>
|
||||||
<input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
|
<input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,6 +98,7 @@ export default function Forgetpwd2() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
<AuthFooter />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function Login() {
|
|||||||
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
|
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
|
||||||
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
|
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
|
||||||
<div className='w-full text-left'>
|
<div className='w-full text-left'>
|
||||||
<h1 className="mb-2 text-black text-4xl font-semibold">MERMS Panel</h1>
|
<h1 className="mb-2 text-black text-4xl font-semibold">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<p className='text-black-gray text-base'>Welcome back, please login to your account.</p>
|
<p className='text-black-gray text-base'>Welcome back, please login to your account.</p>
|
||||||
</div>
|
</div>
|
||||||
<form className="w-full text-14 text-left text-black-gray">
|
<form className="w-full text-14 text-left text-black-gray">
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ import siteLinks from '../../links/siteLinks'
|
|||||||
import { loginUser } from '../../services/services'
|
import { loginUser } from '../../services/services'
|
||||||
import { updateUserDetails } from '../../store/UserDetails'
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
import AuthFooter from './AuthFooter'
|
||||||
import IOSDownload from '../../assets/img/download/apple.jpg'
|
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
|
|
||||||
@@ -47,12 +46,12 @@ export default function Login() {
|
|||||||
console.log(error)
|
console.log(error)
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if(res?.data?.error_message){
|
if(res?.data && res?.data?.error_message){
|
||||||
throw({message: res?.data?.error_message})
|
throw({message: res?.data?.error_message})
|
||||||
}
|
}
|
||||||
const {token, room, uid} = res?.data
|
const {token, room, uid} = res?.data
|
||||||
if(!token || !room){
|
if(!token || !room){
|
||||||
throw({message: 'something went wrong, try again!'})
|
throw({message: 'Unable to complete your login, Please try again!'})
|
||||||
}
|
}
|
||||||
localStorage.setItem('token', token)
|
localStorage.setItem('token', token)
|
||||||
localStorage.setItem('room', room)
|
localStorage.setItem('room', room)
|
||||||
@@ -86,20 +85,20 @@ export default function Login() {
|
|||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register px-5 pt-5 pb-3">
|
<div className="bg-white register px-5 pt-5 pb-3">
|
||||||
<h1 className="mb-2">MERMS Panel</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<p>Welcome back, please login to your account.</p>
|
<p>Welcome back, please login to your account.</p>
|
||||||
<form className="mt-3 mt-sm-5">
|
<form className="mt-3 mt-sm-5">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className="control-label text-black fw-bold">User Name*</label>
|
<label className="control-label text-black fw-bold">User Name*</label>
|
||||||
<input maxLength={55} name='username' value={fields.username} onChange={handleChange} type="text" className="form-control" placeholder="Username" />
|
<input maxLength={25} name='username' value={fields.username} onChange={handleChange} type="text" className="form-control" placeholder="Username" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className="control-label text-black fw-bold">Password*</label>
|
<label className="control-label text-black fw-bold">Password*</label>
|
||||||
<input maxLength={55} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
|
<input maxLength={25} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -124,36 +123,16 @@ export default function Login() {
|
|||||||
<button type='button' onClick={()=>{login.mutate(fields)}} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
|
<button type='button' onClick={()=>{login.mutate(fields)}} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 mt-3">
|
<div className="col-12 mt-3">
|
||||||
<p>Don't have an account ?<Link to={siteLinks.signup}><span style={{fontWeight: 'bolder'}}>Sign Up</span></Link></p>
|
<p> <Link to={siteLinks.signup}>
|
||||||
|
{/*<span style={{fontWeight: 'bolder'}}>Sign Up</span>*/}
|
||||||
|
<button className="btn btn-warning text-uppercase">
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
</Link><span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}> if you don't have an account yet.</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div className="row" style={{marginTop: '20px'}}>
|
<AuthFooter />
|
||||||
<div className="col-6">
|
|
||||||
<div className="app-store-icons-wrap text-center">
|
|
||||||
<a className="icon google"
|
|
||||||
href='#' >
|
|
||||||
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-6">
|
|
||||||
<div className="app-store-icons-wrap text-center">
|
|
||||||
<a className="icon apple" href='#'>
|
|
||||||
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="login-links">
|
|
||||||
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
|
||||||
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
|
||||||
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
|
||||||
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import LoginImg from '../../assets/bg/login.svg'
|
import LoginImg from '../../assets/bg/login.svg'
|
||||||
import MainLoader from '../loaders/MainLoader'
|
import MainLoader from '../loaders/MainLoader'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import {Link, useNavigate} from 'react-router-dom'
|
||||||
import siteLinks from '../../links/siteLinks'
|
import siteLinks from '../../links/siteLinks'
|
||||||
import Label from '../Label'
|
import Label from '../Label'
|
||||||
import TextInput from '../inputs/TextInput'
|
import TextInput from '../inputs/TextInput'
|
||||||
@@ -13,13 +13,13 @@ export default function Signup() {
|
|||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(() => {
|
||||||
const timer = setTimeout(()=>{
|
const timer = setTimeout(() => {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
},1000)
|
}, 1000)
|
||||||
|
|
||||||
return () => clearTimeout(timer)
|
return () => clearTimeout(timer)
|
||||||
},[])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen bg-white w-full flex justify-center items-center">
|
<div className="h-screen bg-white w-full flex justify-center items-center">
|
||||||
@@ -27,7 +27,7 @@ export default function Signup() {
|
|||||||
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
|
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
|
||||||
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
|
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
|
||||||
<div className='w-full text-left'>
|
<div className='w-full text-left'>
|
||||||
<h1 className="mb-2 text-black text-4xl font-semibold">MERMS Panel</h1>
|
<h1 className="mb-2 text-black text-4xl font-semibold">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<p className='text-black-gray text-base'>Welcome, Please create your account.</p>
|
<p className='text-black-gray text-base'>Welcome, Please create your account.</p>
|
||||||
</div>
|
</div>
|
||||||
<form className="w-full text-14 text-left text-black-gray">
|
<form className="w-full text-14 text-left text-black-gray">
|
||||||
@@ -35,59 +35,72 @@ export default function Signup() {
|
|||||||
<div className='w-full grid grid-cols-2 gap-8'>
|
<div className='w-full grid grid-cols-2 gap-8'>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<Label desc='First Name*' />
|
<Label desc='First Name*'/>
|
||||||
<TextInput type='text' placeholder='Firstname' />
|
<TextInput type='text' placeholder='Firstname'/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<Label desc='Last Name*' />
|
<Label desc='Last Name*'/>
|
||||||
<TextInput type='text' placeholder='Lastname' />
|
<TextInput type='text' placeholder='Lastname'/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<Label desc='Email*' />
|
<Label desc='Email*'/>
|
||||||
<TextInput type='text' placeholder='Email' />
|
<TextInput type='text' placeholder='Email'/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<Label desc='User Name*' />
|
<Label desc='User Name*'/>
|
||||||
<TextInput type='text' placeholder='Username' />
|
<TextInput type='text' placeholder='Username'/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<Label desc='Password*' />
|
<Label desc='Password*'/>
|
||||||
<TextInput type='password' placeholder='Password' />
|
<TextInput type='password' placeholder='Password'/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full text-left">
|
<div className="w-full text-left">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<input className="form-check-input" type="checkbox" id="gridCheck" />
|
<input className="form-check-input" type="checkbox" id="gridCheck"/>
|
||||||
<label className="font-semibold form-check-label" htmlFor="gridCheck">
|
<label className="font-semibold form-check-label" htmlFor="gridCheck">
|
||||||
I accept terms & policy
|
I accept terms & policy of use.
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-3">
|
<div className="w-full mt-3">
|
||||||
<button onClick={()=>{navigate(siteLinks.home)}} className="bg-primary rounded-sm px-4 py-2 text-white font-medium uppercase">Sign Up</button>
|
<button onClick={() => {
|
||||||
|
navigate(siteLinks.home)
|
||||||
|
}} className="bg-primary rounded-sm px-4 py-2 text-white font-medium uppercase">Sign
|
||||||
|
Up
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<p className='font-medium'>Already have an account ?<Link to={siteLinks.login} className=' hover:text-primary'> Sign In</Link></p>
|
<hr />
|
||||||
|
<p className='font-medium'>Already have an account ?
|
||||||
|
<Link to={siteLinks.login}
|
||||||
|
className='bg-secondary; hover:text-primary font-bold' style={{paddingRight: '10px'}}>
|
||||||
|
<button className="btn btn-warning text-uppercase">
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-login_gradient h-full col-span-1 lg:col-span-3 xl:col-span-6 place-content-center order-1 sm:order-2">
|
<div
|
||||||
|
className="bg-login_gradient h-full col-span-1 lg:col-span-3 xl:col-span-6 place-content-center order-1 sm:order-2">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-2/3 mx-auto">
|
<div className="w-2/3 mx-auto">
|
||||||
<img className="w-[80%]" src={LoginImg} alt="" />
|
<img className="w-[80%]" src={LoginImg} alt=""/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import React, { useState } from 'react'
|
import React, {useState} from 'react'
|
||||||
import { Form, Formik } from "formik";
|
import {Form, Formik} from "formik";
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
|
|
||||||
// import LoginImg from '../../assets/bg/login.svg'
|
// import LoginImg from '../../assets/bg/login.svg'
|
||||||
|
|
||||||
import { Link } from 'react-router-dom'
|
import {Link} from 'react-router-dom'
|
||||||
import siteLinks from '../../links/siteLinks'
|
import siteLinks from '../../links/siteLinks'
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import {useMutation} from '@tanstack/react-query';
|
||||||
import { signUpUser } from '../../services/services';
|
import {signUpUser} from '../../services/services';
|
||||||
import getImage from '../../utils/getImage';
|
import getImage from '../../utils/getImage';
|
||||||
|
import AuthFooter from './AuthFooter';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
email: Yup.string()
|
email: Yup.string()
|
||||||
@@ -25,16 +26,16 @@ const validationSchema = Yup.object().shape({
|
|||||||
isChecked: Yup.bool().oneOf([true], "Please accept the terms & policy"), // use bool instead of boolean
|
isChecked: Yup.bool().oneOf([true], "Please accept the terms & policy"), // use bool instead of boolean
|
||||||
// username: Yup.string().min(3, "Minimum 3 characters").max(50, "Maximum 50 characters").required("Email is required"),
|
// username: Yup.string().min(3, "Minimum 3 characters").max(50, "Maximum 50 characters").required("Email is required"),
|
||||||
// password: Yup.string().min(3, "Minimum 3 characters").max(50, "Maximum 50 characters").required("Email is required"),
|
// password: Yup.string().min(3, "Minimum 3 characters").max(50, "Maximum 50 characters").required("Email is required"),
|
||||||
})
|
})
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
email: '',
|
email: '',
|
||||||
firstname: '',
|
firstname: '',
|
||||||
lastname: '',
|
lastname: '',
|
||||||
isChecked: false,
|
isChecked: false,
|
||||||
// username: '',
|
// username: '',
|
||||||
// password: ''
|
// password: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Signup2() {
|
export default function Signup2() {
|
||||||
|
|
||||||
@@ -61,11 +62,12 @@ export default function Signup2() {
|
|||||||
<div className="vh-100 bg-white custom-bg">
|
<div className="vh-100 bg-white custom-bg">
|
||||||
<div className="container-fluid p-0">
|
<div className="container-fluid p-0">
|
||||||
<div className="row no-gutters justify-content-center">
|
<div className="row no-gutters justify-content-center">
|
||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1"
|
||||||
|
style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register p-5">
|
<div className="bg-white register px-5 pt-5 pb-3">
|
||||||
<h1 className="mb-2">MERMS Panel</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<p>Welcome, Please create your account.</p>
|
<p>Welcome, please create your account.</p>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
@@ -79,20 +81,37 @@ export default function Signup2() {
|
|||||||
<>
|
<>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First Name*</label>
|
<label
|
||||||
<input type="text" name='firstname' className="form-control" placeholder="First Name" value={props.values.firstname} onChange={props.handleChange} />
|
className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First
|
||||||
|
Name*</label>
|
||||||
|
<input type="text" name='firstname'
|
||||||
|
className="form-control"
|
||||||
|
placeholder="First Name"
|
||||||
|
value={props.values.firstname}
|
||||||
|
onChange={props.handleChange}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.lastname && props.touched.lastname) && 'text-danger'}`}>Last Name*</label>
|
<label
|
||||||
<input type="text" name='lastname' className="form-control" placeholder="Last Name" value={props.values.lastname} onChange={props.handleChange} />
|
className={`text-black fw-bold control-label ${(props.errors.lastname && props.touched.lastname) && 'text-danger'}`}>Last
|
||||||
|
Name*</label>
|
||||||
|
<input type="text" name='lastname'
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Last Name"
|
||||||
|
value={props.values.lastname}
|
||||||
|
onChange={props.handleChange}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.email && props.touched.email) && 'text-danger'}`}>Email*</label>
|
<label
|
||||||
<input type="email" name='email' className="form-control" placeholder="Email" value={props.values.email} onChange={props.handleChange} />
|
className={`text-black fw-bold control-label ${(props.errors.email && props.touched.email) && 'text-danger'}`}>Email*</label>
|
||||||
|
<input type="email" name='email'
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Email"
|
||||||
|
value={props.values.email}
|
||||||
|
onChange={props.handleChange}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="col-12">
|
{/* <div className="col-12">
|
||||||
@@ -109,12 +128,18 @@ export default function Signup2() {
|
|||||||
</div> */}
|
</div> */}
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-check">
|
<div className="form-check">
|
||||||
<input name='isChecked' className="form-check-input" type="checkbox" id="gridCheck" value={props.values.isChecked} onChange={props.handleChange} />
|
<input name='isChecked'
|
||||||
<label className="form-check-label" htmlFor="gridCheck">
|
className="form-check-input"
|
||||||
|
type="checkbox" id="gridCheck"
|
||||||
|
value={props.values.isChecked}
|
||||||
|
onChange={props.handleChange}/>
|
||||||
|
<label className="form-check-label"
|
||||||
|
htmlFor="gridCheck">
|
||||||
I accept terms & policy
|
I accept terms & policy
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<span className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
<span
|
||||||
|
className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{mutation.error &&
|
{mutation.error &&
|
||||||
@@ -126,27 +151,46 @@ export default function Signup2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className="col-12 mt-3 text-end">
|
<div className="col-12 mt-3 text-end">
|
||||||
<button type='submit' className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
<button type='submit'
|
||||||
|
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
<div className='col-12'>
|
<div className='col-12'>
|
||||||
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
|
<div
|
||||||
<h4 className='p-4 text-black' style={{marginBottom: '-30px'}}>Check your email to continue.</h4>
|
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||||
<img className='' style={{width: '200px'}} src={getImage('check-mail.png')} alt='mail-alert' />
|
style={{backgroundColor: '#F2FAF7'}}>
|
||||||
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginBottom: '-30px'}}>Check
|
||||||
|
your email to continue.</h4>
|
||||||
|
<img className='' style={{width: '200px'}}
|
||||||
|
src={getImage('check-mail.png')}
|
||||||
|
alt='mail-alert'/>
|
||||||
|
<Link to={siteLinks.login}
|
||||||
|
className='p-2 text-primary'
|
||||||
|
style={{color: '#6FCAEF'}}>Home</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className="col-12 mt-3">
|
<div className="col-12 mt-3">
|
||||||
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
|
<p>
|
||||||
|
<span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}>Already have an account? </span>
|
||||||
|
<Link
|
||||||
|
to={siteLinks.login}>
|
||||||
|
<button
|
||||||
|
className="btn btn-warning text-uppercase">
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
<AuthFooter />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export default function Calendar(){
|
|||||||
}
|
}
|
||||||
const {data, isFetching, isError, error} = useQuery({
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
queryKey: queryKeys.calendar_events,
|
queryKey: queryKeys.calendar_events,
|
||||||
queryFn: () => getCalendarEvents(reqData)
|
queryFn: () => getCalendarEvents(reqData),
|
||||||
|
staleTime: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const receievedEvents = data?.data
|
const receievedEvents = data?.data
|
||||||
@@ -87,7 +88,7 @@ export default function Calendar(){
|
|||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="card-heading">
|
<div className="card-heading">
|
||||||
<h4 className="card-title">Event Calendar</h4>
|
<h4 className="card-title">Events</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
|
|||||||
@@ -1,31 +1,114 @@
|
|||||||
import React from "react";
|
"use client";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
import { commentsData } from "../../services/services";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import getCustomTime from "../../utils/getCustomTime";
|
||||||
|
|
||||||
export default function Comments(){
|
export default function Comments() {
|
||||||
|
// const {data:contacts, isFetching, isError, error} = useQuery({
|
||||||
|
// queryKey: queryKeys.contacts,
|
||||||
|
// queryFn: () => contactData()
|
||||||
|
// })
|
||||||
|
|
||||||
return(
|
const [activeCategoryUID, setActiveCategoryUID] = useState("0"); // HOLDS VALUE OF THE ACTIVE CATEGORY
|
||||||
|
|
||||||
|
const [activeContactUID, setActiveContactUID] = useState("");
|
||||||
|
const [activeDetail, setActiveDetail] = useState([]);
|
||||||
|
|
||||||
|
const [filteredContactData, setFiltererdContactData] = useState([]);
|
||||||
|
|
||||||
|
const getContactData = useMutation({
|
||||||
|
mutationFn: (reqData) => {
|
||||||
|
return commentsData(reqData);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.log(error);
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res?.data?.resultCode != "0") {
|
||||||
|
throw { message: "Something went wrong" };
|
||||||
|
}
|
||||||
|
setFiltererdContactData(res?.data?.contacts);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeActiveUID = (uid) => {
|
||||||
|
setActiveContactUID(uid);
|
||||||
|
let detail = contactsData.filter((item) => item.uid == uid);
|
||||||
|
setActiveDetail(detail);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeActiveCategoryUID = (id) => {
|
||||||
|
let filteredConData = [];
|
||||||
|
setActiveCategoryUID(id);
|
||||||
|
if (id == "0") {
|
||||||
|
filteredConData = contactsData;
|
||||||
|
} else {
|
||||||
|
filteredConData = contactsData.filter((item) => item.category == id);
|
||||||
|
}
|
||||||
|
setFiltererdContactData(filteredConData);
|
||||||
|
changeActiveUID(filteredConData[0]?.uid);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
|
uid: localStorage.getItem("uid"), // USER UID
|
||||||
|
};
|
||||||
|
getContactData.mutate(reqData);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const contactsData = getContactData?.data?.data?.contacts; // LIST OF CONTACTS
|
||||||
|
const contactsCategory = getContactData?.data?.data?.category; // LIST OF CATEGORY
|
||||||
|
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Comments' paths={['Dashboard', 'Comments']} />
|
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
||||||
|
{getContactData?.isPending ? (
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-mute">Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : getContactData?.error ? (
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-danger">{getContactData?.error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="card card-statistics mail-contant">
|
<div
|
||||||
|
className="card card-statistics mail-contant"
|
||||||
|
style={{ minHeight: "200px", borderRadius: "10px" }}
|
||||||
|
>
|
||||||
<div className="card-body p-0">
|
<div className="card-body p-0">
|
||||||
<div className="row no-gutters">
|
<div className="row no-gutters">
|
||||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||||
<div className="mail-sidebar">
|
<div className="mail-sidebar">
|
||||||
<div className="row justify-content-center">
|
<div className="row justify-content-center">
|
||||||
<div className="col-12">
|
<div className="d-none col-12">
|
||||||
<div className="text-center mail-sidebar-title px-4">
|
<div className="text-center mail-sidebar-title px-4">
|
||||||
<a href="javascript:void(0)" className="btn btn-primary btn-block py-3 font-weight-bold font-18"><i className="fa fa-plus pl-2"></i></a>
|
<a
|
||||||
|
href="#"
|
||||||
|
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||||
|
>
|
||||||
|
<i className="fa fa-plus pl-2"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="px-4 py-4">
|
<div className="px-4 py-4">
|
||||||
<ul className="pl-0">
|
<ul className="pl-0">
|
||||||
<li className="py-2">
|
<li className="py-2">
|
||||||
<a href="javascript:void(0)">
|
<a href="#">
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
||||||
@@ -34,71 +117,89 @@ export default function Comments(){
|
|||||||
<span>Inbox</span>
|
<span>Inbox</span>
|
||||||
</span>
|
</span>
|
||||||
<span className="nav-item ml-auto text-right">
|
<span className="nav-item ml-auto text-right">
|
||||||
<span className="badge badge-pill badge-primary float-right">0+</span>
|
<span className="badge badge-pill badge-primary float-right">
|
||||||
</span>
|
{contactsData?.length}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li className="py-2">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<span className="nav align-items-center">
|
|
||||||
<span>
|
|
||||||
<i className="fa fa-paper-plane-o pr-4"></i>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span>Sent Mail</span>
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{/*<li className="py-2">*/}
|
||||||
|
{/* <a href="#">*/}
|
||||||
|
{/* <span*/}
|
||||||
|
{/* className="nav align-items-center">*/}
|
||||||
|
{/* <span>*/}
|
||||||
|
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* <span>*/}
|
||||||
|
{/* <span>Replied Mail</span>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* </a>*/}
|
||||||
|
{/*</li>*/}
|
||||||
|
</ul>
|
||||||
|
|
||||||
</ul>
|
|
||||||
<ul className="pl-0 mt-5">
|
<ul className="pl-0 mt-5">
|
||||||
<li className="py-2">
|
<li
|
||||||
<a href="javascript:void(0)">
|
className="py-2"
|
||||||
|
onClick={() => changeActiveCategoryUID("0")}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className="fa fa-circle-o text-danger pr-4"></i>
|
<i
|
||||||
|
className={`fa fa-circle-o pr-4 ${
|
||||||
|
activeCategoryUID == "0"
|
||||||
|
? "text-primary"
|
||||||
|
: "text-warning"
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>Personal</span>
|
<span>All</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li className="py-2">
|
{contactsCategory &&
|
||||||
<a href="javascript:void(0)">
|
contactsCategory.map((item) => (
|
||||||
|
<li
|
||||||
|
key={item?.cid}
|
||||||
|
className="py-2"
|
||||||
|
onClick={() =>
|
||||||
|
changeActiveCategoryUID(`${item?.cid}`)
|
||||||
|
}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className="fa fa-circle-o pr-4 text-warning"></i>
|
<i
|
||||||
|
className={`fa fa-circle-o pr-4 ${
|
||||||
|
activeCategoryUID ==
|
||||||
|
`${item?.cid}`
|
||||||
|
? "text-primary"
|
||||||
|
: "text-warning"
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>Work</span>
|
<span>{item?.description}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</div>
|
||||||
</li>
|
|
||||||
<li className="py-2">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<span className="nav align-items-center">
|
|
||||||
<span>
|
|
||||||
<i className="fa fa-plus pr-4"></i>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span>Add Category</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-8 col-xxl-4 border-md-t">
|
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
|
||||||
<div className="mail-content border-right border-n h-100">
|
<div className="mail-content border-right border-n h-100" style={{placeContent: 'center'}}>
|
||||||
<div className="mail-search border-bottom">
|
{/* <div className="mail-search border-bottom">
|
||||||
<div className="row align-items-center mx-0">
|
<div className="row align-items-center mx-0">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group pt-3">
|
<div className="form-group pt-3">
|
||||||
@@ -107,205 +208,120 @@ export default function Comments(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
<div className="mail-msg scrollbar scroll_dark">
|
<div className="mail-msg scrollbar scroll_dark">
|
||||||
<div className="mail-msg-item">
|
{ filteredContactData.length ?
|
||||||
<a href="javascript:void(0)">
|
filteredContactData?.map((contact, index) => {
|
||||||
|
const isActive =
|
||||||
|
contact?.uid == activeContactUID ||
|
||||||
|
(!activeContactUID && index == 0);
|
||||||
|
const avtarImage =
|
||||||
|
contact?.category === undefined
|
||||||
|
? "avtar/01.jpg"
|
||||||
|
: "avtar/" + contact.category + ".png";
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={contact?.uid}
|
||||||
|
onClick={() => changeActiveUID(contact?.uid)}
|
||||||
|
className={`mail-msg-item ${
|
||||||
|
isActive && "bg-light"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<a href="#">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="mr-3">
|
<div className="mr-3">
|
||||||
<div className="bg-img">
|
<div className="bg-img">
|
||||||
<img src={getImage("avtar/01.jpg")} className="img-fluid" alt="user" />
|
<img
|
||||||
|
src={getImage(avtarImage)}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
<div className="mail-msg-item-titel justify-content-between">
|
||||||
<p>Martin smith</p>
|
<p>
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "#148399",
|
||||||
|
fontWeight: "bolder",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{contact?.sender}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
|
||||||
|
<p className="d-none d-xl-block">
|
||||||
|
<span style={{ fontSize: "14px" }}>
|
||||||
|
{new Date(
|
||||||
|
contact?.added
|
||||||
|
).toDateString()}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h5 className="mb-0 my-2">Saas Designer</h5>
|
<h5 className="mb-0 my-2">
|
||||||
<p>Since there is not an "all the above" category, I'll take the opportunity to enthusiastically congratulate you on the very high quality.</p>
|
{contact?.title}
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
</h5>
|
||||||
</div>
|
<p>
|
||||||
</div>
|
{contact?.message?.length < 100
|
||||||
</a>
|
? contact?.message
|
||||||
</div>
|
: contact?.message.substring(0, 101) +
|
||||||
<div className="mail-msg-item">
|
" ..."}
|
||||||
<a href="javascript:void(0)">
|
</p>
|
||||||
<div className="media align-items-center">
|
<p className="d-xl-none">
|
||||||
<div className="mr-3">
|
<span>
|
||||||
<div className="bg-img">
|
{new Date(
|
||||||
<img src={getImage("avtar/02.jpg")} className="img-fluid" alt="user" />
|
contact?.added
|
||||||
</div>
|
).toDateString()}
|
||||||
</div>
|
{/* {getCustomTime(contact.added)} */}
|
||||||
<div className="w-100">
|
</span>
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
</p>
|
||||||
<p>DutcaPatrick</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Mobile app Designer </h5>
|
|
||||||
<p>Very nice template, lots of pages and good documentation.</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/03.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>m_morsch</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Landing page Designer</h5>
|
|
||||||
<p>Excellent and at a great price... thank you very much!</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/04.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>AnnaHorno</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Re-Design ios app</h5>
|
|
||||||
<p>Solved my theme problem in 10 minutes. We thank you.</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/05.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Wdcorbitt</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Mobil UX/UI Designer</h5>
|
|
||||||
<p>Asked for information and received it EXTREMELY quickly. Great layout - good code - great price! </p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/06.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Anne Smith</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Jobly Opportunity</h5>
|
|
||||||
<p>Mentor has so many features and layouts. Its a great choice.</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/07.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Paul Flavius</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Saas Designer</h5>
|
|
||||||
<p>There are many people in the world with amazing talents who realize only a small percentage of their potential. </p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/08.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Sara Lisbon</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">UI Designer</h5>
|
|
||||||
<p>We can look a bit further back in time to Albert Einstein or even further back to Abraham Lincoln.</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mail-msg-item">
|
|
||||||
<a href="javascript:void(0)">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="mr-3">
|
|
||||||
<div className="bg-img">
|
|
||||||
<img src={getImage("avtar/09.jpg")} className="img-fluid" alt="user" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Annahorno</p>
|
|
||||||
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
|
||||||
<h5 className="mb-0 my-2">Saas Designer</h5>
|
|
||||||
<p>One of the most difficult aspects of achieving success is staying motivated over the long haul.</p>
|
|
||||||
<p className="d-xl-none">06:59 <span> PM </span></p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<p className="text-center">Messages will appear here as soon as they are available for selection</p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{filteredContactData.length > 0 &&
|
||||||
<div className="col-xxl-6 border-t border-xxl-t">
|
<div className="col-xxl-6 border-t border-xxl-t">
|
||||||
<div className="mail-chat py-5 px-5">
|
<div className="mail-chat py-5 px-5">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="bg-img mr-3">
|
<div className="bg-img mr-3">
|
||||||
<img src={getImage("avtar/03.jpg")} className="img-fluid" alt="user" />
|
<img
|
||||||
|
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-0">Dutca Patrick</h4>
|
<h4 className="mb-0" style={{ color: "#148399" }}>
|
||||||
<p>30 Min ago</p>
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.sender
|
||||||
|
: filteredContactData[0]?.sender}
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
{activeContactUID
|
||||||
|
? new Date(activeDetail[0]?.added).toDateString()
|
||||||
|
: new Date(
|
||||||
|
filteredContactData[0]?.added
|
||||||
|
).toDateString()}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 d-flex justify-content-between">
|
<div className="mt-4 d-flex justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<h3>Landing page Designer...</h3>
|
<h3>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.title
|
||||||
|
: filteredContactData[0]?.title}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex">
|
<div className="d-flex">
|
||||||
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
||||||
@@ -313,60 +329,21 @@ export default function Comments(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="my-4">hey adminjon...</p>
|
<p>
|
||||||
<p className="mb-2">I truly believe Augustine’s words are true and if you look at history you know it is true. There are many people in the world with amazing talents who realize only a small percentage of their potential. We all know people who live this truth.</p>
|
{activeContactUID
|
||||||
<p>We also know those epic stories, those modern-day legends surrounding the early failures of such supremely successful folks as Michael Jordan and Bill Gates. We can look a bit further back in time to Albert Einstein or even further back to Abraham Lincoln. What made each of these people so successful? Motivation.</p>
|
? activeDetail[0]?.message
|
||||||
<p>We know this in our gut, but what can we do about it? How can we motivate ourselves? One of the most difficult aspects of achieving success is staying motivated over the long haul.</p>
|
: filteredContactData[0]?.message}
|
||||||
<div className="my-5">
|
</p>
|
||||||
<p>Have lovely Day,</p>
|
|
||||||
<p>adminjon</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/*<div className="d-md-flex px-5 py-4">*/}
|
|
||||||
{/* <div className="flex-fill align-items-center">*/}
|
|
||||||
{/* <div className="d-flex">*/}
|
|
||||||
{/* <i className="ti ti-clip pr-3 font-22"></i>*/}
|
|
||||||
{/* <p className="pr-3 font-weight-bold">Wireframe</p>*/}
|
|
||||||
{/* <p>(220.MB)</p>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* <div className="flex-fill text-left text-md-right"><a href="javascript:void(0)" className="text-primary"><i className="ti ti-download pr-2"></i><span>Download</span></a></div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div className="bg-light mail-f px-4 py-3">
|
|
||||||
<div className="py-2 bg-white px-4 py-3 d-flex justify-content-between">
|
|
||||||
<p>Click here to <a href="#editer" data-toggle="collapse" className="text-primary px-1">Reply</a>or<a href="#forward" data-toggle="collapse" className="text-primary px-1">Forward</a></p>
|
|
||||||
<a href="javascript:void(0)" className="text-primary"><i className="fa fa-microphone"></i></a>
|
|
||||||
</div>
|
|
||||||
<div className="collapse" id="editer">
|
|
||||||
<div className="form-group">
|
|
||||||
<textarea className="form-control mt-3" id="exampleFormControlTextarea1" rows="3" placeholder="Type here..."></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="collapse" id="forward">
|
|
||||||
<div className="form-group">
|
|
||||||
<input className="form-control mt-3" id="exampleFormControl" placeholder="Email Address" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex align-items-center justify-content-between py-2">
|
|
||||||
<div>
|
|
||||||
<ul className="nav">
|
|
||||||
<li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-clip font-20"></i></a></li>
|
|
||||||
<li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-face-smile font-20"></i></a></li>
|
|
||||||
<li className="nav-item"><a href="javascript:void(0)"><i className="ti ti-gallery font-20"></i></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="javascript:void(0)" className="btn btn-primary"><span>Send</span> <i className="fa fa-paper-plane"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"use client"
|
"use client";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
@@ -7,87 +7,88 @@ import { contactData } from "../../services/services";
|
|||||||
import queryKeys from "../../services/queryKeys";
|
import queryKeys from "../../services/queryKeys";
|
||||||
import getCustomTime from "../../utils/getCustomTime";
|
import getCustomTime from "../../utils/getCustomTime";
|
||||||
|
|
||||||
export default function Contacts(){
|
export default function Contacts() {
|
||||||
|
|
||||||
// const {data:contacts, isFetching, isError, error} = useQuery({
|
// const {data:contacts, isFetching, isError, error} = useQuery({
|
||||||
// queryKey: queryKeys.contacts,
|
// queryKey: queryKeys.contacts,
|
||||||
// queryFn: () => contactData()
|
// queryFn: () => contactData()
|
||||||
// })
|
// })
|
||||||
|
|
||||||
const [activeCategoryUID, setActiveCategoryUID] = useState('0') // HOLDS VALUE OF THE ACTIVE CATEGORY
|
const [activeCategoryUID, setActiveCategoryUID] = useState("0"); // HOLDS VALUE OF THE ACTIVE CATEGORY
|
||||||
|
|
||||||
const [activeContactUID, setActiveContactUID] = useState('')
|
const [activeContactUID, setActiveContactUID] = useState("");
|
||||||
const [activeDetail, setActiveDetail] = useState([])
|
const [activeDetail, setActiveDetail] = useState([]);
|
||||||
|
|
||||||
const [filteredContactData, setFiltererdContactData] = useState([])
|
|
||||||
|
|
||||||
|
const [filteredContactData, setFiltererdContactData] = useState([]);
|
||||||
|
|
||||||
const getContactData = useMutation({
|
const getContactData = useMutation({
|
||||||
mutationFn: (reqData) => {
|
mutationFn: (reqData) => {
|
||||||
return contactData(reqData)
|
return contactData(reqData);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.log(error)
|
console.log(error);
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if(res?.data?.resultCode != '0'){
|
if (res?.data?.resultCode != "0") {
|
||||||
throw({message: 'Something went wrong'})
|
throw { message: "Something went wrong" };
|
||||||
}
|
}
|
||||||
setFiltererdContactData(res?.data?.contacts)
|
setFiltererdContactData(res?.data?.contacts);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const changeActiveUID = (uid) => {
|
const changeActiveUID = (uid) => {
|
||||||
setActiveContactUID(uid)
|
setActiveContactUID(uid);
|
||||||
let detail = contactsData.filter(item => item.uid == uid)
|
let detail = contactsData.filter((item) => item.uid == uid);
|
||||||
setActiveDetail(detail)
|
setActiveDetail(detail);
|
||||||
}
|
};
|
||||||
|
|
||||||
const changeActiveCategoryUID = (id) => {
|
const changeActiveCategoryUID = (id) => {
|
||||||
let filteredConData = []
|
let filteredConData = [];
|
||||||
setActiveCategoryUID(id)
|
setActiveCategoryUID(id);
|
||||||
if(id == '0'){
|
if (id == "0") {
|
||||||
filteredConData = contactsData
|
filteredConData = contactsData;
|
||||||
}else{
|
} else {
|
||||||
filteredConData = contactsData.filter(item => item.category == id)
|
filteredConData = contactsData.filter((item) => item.category == id);
|
||||||
}
|
|
||||||
setFiltererdContactData(filteredConData)
|
|
||||||
changeActiveUID(filteredConData[0]?.uid)
|
|
||||||
}
|
}
|
||||||
|
setFiltererdContactData(filteredConData);
|
||||||
|
changeActiveUID(filteredConData[0]?.uid);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(() => {
|
||||||
let reqData = {
|
let reqData = {
|
||||||
token: localStorage.getItem('token'), // USER TOKEN
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
uid: localStorage.getItem('uid') // USER UID
|
uid: localStorage.getItem("uid"), // USER UID
|
||||||
}
|
};
|
||||||
getContactData.mutate(reqData)
|
getContactData.mutate(reqData);
|
||||||
},[])
|
}, []);
|
||||||
|
|
||||||
const contactsData = getContactData?.data?.data?.contacts // LIST OF CONTACTS
|
const contactsData = getContactData?.data?.data?.contacts; // LIST OF CONTACTS
|
||||||
const contactsCategory = getContactData?.data?.data?.category // LIST OF CATEGORY
|
const contactsCategory = getContactData?.data?.data?.category; // LIST OF CATEGORY
|
||||||
|
|
||||||
return(
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Contacts' paths={['Dashboard', 'Contacts']} />
|
<BreadcrumbComBS title="Contacts" paths={["Dashboard", "Contacts"]} />
|
||||||
{getContactData?.isPending ?
|
{getContactData?.isPending ? (
|
||||||
<>
|
<>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-mute'>Loading...</p>
|
<p className="text-mute">Loading...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
: getContactData?.error ?
|
) : getContactData?.error ? (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-danger'>{getContactData?.error?.message}</p>
|
<p className="text-danger">{getContactData?.error?.message}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
) : (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="card card-statistics mail-contant">
|
<div
|
||||||
|
className="card card-statistics mail-contant"
|
||||||
|
style={{ minHeight: "200px", borderRadius: "10px" }}
|
||||||
|
>
|
||||||
<div className="card-body p-0">
|
<div className="card-body p-0">
|
||||||
<div className="row no-gutters">
|
<div className="row no-gutters">
|
||||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||||
@@ -95,7 +96,12 @@ export default function Contacts(){
|
|||||||
<div className="row justify-content-center">
|
<div className="row justify-content-center">
|
||||||
<div className="d-none col-12">
|
<div className="d-none col-12">
|
||||||
<div className="text-center mail-sidebar-title px-4">
|
<div className="text-center mail-sidebar-title px-4">
|
||||||
<a href="#" className="btn btn-primary btn-block py-3 font-weight-bold font-18"><i className="fa fa-plus pl-2"></i></a>
|
<a
|
||||||
|
href="#"
|
||||||
|
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||||
|
>
|
||||||
|
<i className="fa fa-plus pl-2"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -111,32 +117,44 @@ export default function Contacts(){
|
|||||||
<span>Inbox</span>
|
<span>Inbox</span>
|
||||||
</span>
|
</span>
|
||||||
<span className="nav-item ml-auto text-right">
|
<span className="nav-item ml-auto text-right">
|
||||||
<span className="badge badge-pill badge-primary float-right">{contactsData?.length}</span>
|
<span className="badge badge-pill badge-primary float-right">
|
||||||
|
{contactsData?.length}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="py-2">
|
{/*<li className="py-2">*/}
|
||||||
<a href="#">
|
{/* <a href="#">*/}
|
||||||
<span className="nav align-items-center">
|
{/* <span*/}
|
||||||
<span>
|
{/* className="nav align-items-center">*/}
|
||||||
<i className="fa fa-paper-plane-o pr-4"></i>
|
{/* <span>*/}
|
||||||
</span>
|
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
||||||
<span>
|
{/* </span>*/}
|
||||||
<span>Replied Mail</span>
|
{/* <span>*/}
|
||||||
</span>
|
{/* <span>Replied Mail</span>*/}
|
||||||
</span>
|
{/* </span>*/}
|
||||||
</a>
|
{/* </span>*/}
|
||||||
</li>
|
{/* </a>*/}
|
||||||
|
{/*</li>*/}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul className="pl-0 mt-5">
|
<ul className="pl-0 mt-5">
|
||||||
<li className="py-2" onClick={()=>changeActiveCategoryUID('0')} style={{cursor: 'pointer'}}>
|
<li
|
||||||
|
className="py-2"
|
||||||
|
onClick={() => changeActiveCategoryUID("0")}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className={`fa fa-circle-o pr-4 ${activeCategoryUID == '0' ? 'text-primary' : 'text-warning'}`}></i>
|
<i
|
||||||
|
className={`fa fa-circle-o pr-4 ${
|
||||||
|
activeCategoryUID == "0"
|
||||||
|
? "text-primary"
|
||||||
|
: "text-warning"
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>All</span>
|
<span>All</span>
|
||||||
@@ -144,12 +162,27 @@ export default function Contacts(){
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{contactsCategory && contactsCategory.map(item => (
|
{contactsCategory &&
|
||||||
<li key={item?.cid} className="py-2" onClick={()=>changeActiveCategoryUID(`A00000${item?.cid}`)} style={{cursor: 'pointer'}}>
|
contactsCategory.map((item) => (
|
||||||
|
<li
|
||||||
|
key={item?.cid}
|
||||||
|
className="py-2"
|
||||||
|
onClick={() =>
|
||||||
|
changeActiveCategoryUID(`${item?.cid}`)
|
||||||
|
}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className={`fa fa-circle-o pr-4 ${activeCategoryUID == `A00000${item?.cid}` ? 'text-primary' : 'text-warning'}`}></i>
|
<i
|
||||||
|
className={`fa fa-circle-o pr-4 ${
|
||||||
|
activeCategoryUID ==
|
||||||
|
`${item?.cid}`
|
||||||
|
? "text-primary"
|
||||||
|
: "text-warning"
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>{item?.description}</span>
|
<span>{item?.description}</span>
|
||||||
@@ -158,71 +191,89 @@ export default function Contacts(){
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
{/* <li className="py-2">
|
|
||||||
<a href="#">
|
|
||||||
<span className="nav align-items-center">
|
|
||||||
<span>
|
|
||||||
<i className="fa fa-circle-o pr-4 text-warning"></i>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span>Work</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li className="py-2">
|
|
||||||
<a href="#">
|
|
||||||
<span className="nav align-items-center">
|
|
||||||
<span>
|
|
||||||
<i className="fa fa-plus pr-4"></i>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span>Add Category</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li> */}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-8 col-xxl-4 border-md-t">
|
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
|
||||||
<div className="mail-content border-right border-n h-100">
|
<div className="mail-content border-right border-n h-100" style={{placeContent: 'center'}}>
|
||||||
<div className="mail-search border-bottom">
|
{/* <div className="mail-search border-bottom">
|
||||||
<div className="row align-items-center mx-0">
|
<div className="row align-items-center mx-0">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
{/*<div className="form-group pt-3">*/}
|
<div className="form-group pt-3">
|
||||||
{/* <input type="text" className="form-control" id="search" placeholder="Search.." />*/}
|
<input type="text" className="form-control" id="search" placeholder="Search.." />
|
||||||
{/* <i className="fa fa-search"></i>*/}
|
<i className="fa fa-search"></i>
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div> */}
|
||||||
<div className="mail-msg scrollbar scroll_dark">
|
<div className="mail-msg scrollbar scroll_dark">
|
||||||
{contactsData && filteredContactData?.map((contact, index)=> {
|
{ filteredContactData.length ?
|
||||||
const isActive = (contact?.uid == activeContactUID) || (!activeContactUID && index == 0)
|
filteredContactData?.map((contact, index) => {
|
||||||
|
const isActive =
|
||||||
|
contact?.uid == activeContactUID ||
|
||||||
|
(!activeContactUID && index == 0);
|
||||||
|
const avtarImage =
|
||||||
|
contact?.category === undefined
|
||||||
|
? "avtar/01.jpg"
|
||||||
|
: "avtar/" + contact.category + ".png";
|
||||||
return (
|
return (
|
||||||
<div key={contact?.uid} onClick={()=>changeActiveUID(contact?.uid)} className={`mail-msg-item ${isActive && 'bg-light'}`}>
|
<div
|
||||||
|
key={contact?.uid}
|
||||||
|
onClick={() => changeActiveUID(contact?.uid)}
|
||||||
|
className={`mail-msg-item ${
|
||||||
|
isActive && "bg-light"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="mr-3">
|
<div className="mr-3">
|
||||||
<div className="bg-img">
|
<div className="bg-img">
|
||||||
<img src={getImage("avtar/01.jpg")} className="img-fluid" alt="user" />
|
<img
|
||||||
|
src={getImage(avtarImage)}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
<div className="mail-msg-item-titel justify-content-between">
|
||||||
<p>{contact?.sender}</p>
|
<p>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "#148399",
|
||||||
|
fontWeight: "bolder",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{contact?.sender}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
|
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
|
||||||
<p className="d-none d-xl-block"><span>{new Date(contact?.added).toDateString()}</span></p>
|
<p className="d-none d-xl-block">
|
||||||
|
<span style={{ fontSize: "14px" }}>
|
||||||
|
{new Date(
|
||||||
|
contact?.added
|
||||||
|
).toDateString()}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h5 className="mb-0 my-2">{contact?.title}</h5>
|
<h5 className="mb-0 my-2">
|
||||||
<p>{contact?.message?.length < 100 ? contact?.message : contact?.message.substring(0,101) + ' ...' }</p>
|
{contact?.title}
|
||||||
|
</h5>
|
||||||
|
<p>
|
||||||
|
{contact?.message?.length < 100
|
||||||
|
? contact?.message
|
||||||
|
: contact?.message.substring(0, 101) +
|
||||||
|
" ..."}
|
||||||
|
</p>
|
||||||
<p className="d-xl-none">
|
<p className="d-xl-none">
|
||||||
<span>
|
<span>
|
||||||
{new Date(contact?.added).toDateString()}
|
{new Date(
|
||||||
|
contact?.added
|
||||||
|
).toDateString()}
|
||||||
{/* {getCustomTime(contact.added)} */}
|
{/* {getCustomTime(contact.added)} */}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
@@ -230,26 +281,47 @@ export default function Contacts(){
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
})}
|
})
|
||||||
|
:
|
||||||
|
<p className="text-center">Messages will appear here as soon as they are available for selection</p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{filteredContactData.length > 0 &&
|
||||||
<div className="col-xxl-6 border-t border-xxl-t">
|
<div className="col-xxl-6 border-t border-xxl-t">
|
||||||
|
|
||||||
<div className="mail-chat py-5 px-5">
|
<div className="mail-chat py-5 px-5">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="bg-img mr-3">
|
<div className="bg-img mr-3">
|
||||||
<img src={getImage("avtar/03.jpg")} className="img-fluid" alt="user" />
|
<img
|
||||||
|
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-0">{activeContactUID ? activeDetail[0]?.sender : filteredContactData[0]?.sender}</h4>
|
<h4 className="mb-0" style={{ color: "#148399" }}>
|
||||||
<p>{activeContactUID ? new Date(activeDetail[0]?.added).toDateString() : new Date(filteredContactData[0]?.added).toDateString()}</p>
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.sender
|
||||||
|
: filteredContactData[0]?.sender}
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
{activeContactUID
|
||||||
|
? new Date(activeDetail[0]?.added).toDateString()
|
||||||
|
: new Date(
|
||||||
|
filteredContactData[0]?.added
|
||||||
|
).toDateString()}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 d-flex justify-content-between">
|
<div className="mt-4 d-flex justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<h3>{activeContactUID ? activeDetail[0]?.title : filteredContactData[0]?.title}</h3>
|
<h3>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.title
|
||||||
|
: filteredContactData[0]?.title}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex">
|
<div className="d-flex">
|
||||||
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
||||||
@@ -257,53 +329,21 @@ export default function Contacts(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>{activeContactUID ? activeDetail[0]?.message : filteredContactData[0]?.message}</p>
|
<p>
|
||||||
{/* <p className="my-4">hey adminjon...</p>
|
{activeContactUID
|
||||||
<p className="mb-2">I truly believe Augustine’s words are true and if you look at history you know it is true. There are many people in the world with amazing talents who realize only a small percentage of their potential. We all know people who live this truth.</p>
|
? activeDetail[0]?.message
|
||||||
<p>We also know those epic stories, those modern-day legends surrounding the early failures of such supremely successful folks as Michael Jordan and Bill Gates. We can look a bit further back in time to Albert Einstein or even further back to Abraham Lincoln. What made each of these people so successful? Motivation.</p>
|
: filteredContactData[0]?.message}
|
||||||
<p>We know this in our gut, but what can we do about it? How can we motivate ourselves? One of the most difficult aspects of achieving success is staying motivated over the long haul.</p> */}
|
</p>
|
||||||
{/*<div className="my-5">*/}
|
|
||||||
{/* <p>Have lovely Day,</p>*/}
|
|
||||||
{/* <p>adminjon</p>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-light mail-f px-4 py-3">
|
|
||||||
<div className="py-2 bg-white px-4 py-3 d-flex justify-content-between">
|
|
||||||
<p>Click here to <a href="#editer" data-toggle="collapse" className="text-primary px-1">Reply</a>or<a href="#forward" data-toggle="collapse" className="text-primary px-1">Forward</a></p>
|
|
||||||
<a href="#" className="text-primary"><i className="fa fa-microphone"></i></a>
|
|
||||||
</div>
|
|
||||||
<div className="collapse" id="editer">
|
|
||||||
<div className="form-group">
|
|
||||||
<textarea className="form-control mt-3" id="exampleFormControlTextarea1" rows="3" placeholder="Type here..."></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="collapse" id="forward">
|
|
||||||
<div className="form-group">
|
|
||||||
<input className="form-control mt-3" id="exampleFormControl" placeholder="Email Address" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex align-items-center justify-content-between py-2">
|
|
||||||
<div>
|
|
||||||
{/*<ul className="nav">*/}
|
|
||||||
{/* <li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-clip font-20"></i></a></li>*/}
|
|
||||||
{/* <li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-face-smile font-20"></i></a></li>*/}
|
|
||||||
{/* <li className="nav-item"><a href="javascript:void(0)"><i className="ti ti-gallery font-20"></i></a></li>*/}
|
|
||||||
{/*</ul>*/}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{/*<a href="javascript:void(0)" className="btn btn-primary"><span>Send</span> <i className="fa fa-paper-plane"></i></a>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ export default function SocketIOContextProvider({children}) {
|
|||||||
socket.on(socketOnEvents.receive_message, (data) => {
|
socket.on(socketOnEvents.receive_message, (data) => {
|
||||||
// setSocketMsgReceived(data.message);
|
// setSocketMsgReceived(data.message);
|
||||||
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
|
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
|
||||||
console.log('DATA', data)
|
console.log('SOCKET RECEIVED DATA *** ', data)
|
||||||
queryClient.refetchQueries({
|
queryClient.refetchQueries({
|
||||||
queryKey: [...queryKeys.recentAction],
|
queryKey: [...queryKeys.recentAction],
|
||||||
// type: 'active',
|
// type: 'active',
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { getDashPayments } from '../../services/services'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import queryKeys from '../../services/queryKeys'
|
||||||
|
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString'
|
||||||
|
import getImage from '../../utils/getImage'
|
||||||
|
|
||||||
|
export default function DashPayments() {
|
||||||
|
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.dash_payments,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return getDashPayments(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const payments = data?.data?.member_payments
|
||||||
|
// console.log('data', payments)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="col-xxl-4 m-b-30" style={{minHeight: '300px'}}>
|
||||||
|
<div className="card card-statistics h-100 mb-0 panel_round_c3">
|
||||||
|
<div className="card-header d-flex justify-content-between">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Payments</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
||||||
|
<div className="datatable-wrapper table-responsive">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="p-4">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="p-4">
|
||||||
|
<p className='text-danger'>{error.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<table id="datatable" className="table table-borderless table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{/* <th style={{width: '30px'}}>#</th> */}
|
||||||
|
<th>Date</th>
|
||||||
|
|
||||||
|
<th style={{width: '130px'}}>Description</th>
|
||||||
|
<th style={{width: '80px'}}>Amount</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{payments && payments?.length > 0 ?
|
||||||
|
payments.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
{/* <td>{Number(item?.id).toString().padStart(6,'0')}</td> */}
|
||||||
|
<td>
|
||||||
|
{getDateTimeFromDateString(item?.added)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{item?.option_name}</td>
|
||||||
|
<td className='text-right'>${item?.amount}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<td colSpan={3} className='text-center'>No record found</td>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import Products from "./Products";
|
|||||||
import TopBar from "./TopBar";
|
import TopBar from "./TopBar";
|
||||||
import ProductsURL from "./ProductsURL";
|
import ProductsURL from "./ProductsURL";
|
||||||
import { SocketContextValues } from "../context/SocketIOContext";
|
import { SocketContextValues } from "../context/SocketIOContext";
|
||||||
|
import DashPayments from "./DashPayments";
|
||||||
|
|
||||||
export default function HomeSections(){
|
export default function HomeSections(){
|
||||||
|
|
||||||
@@ -52,41 +53,7 @@ export default function HomeSections(){
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<ProductsURL />
|
<ProductsURL />
|
||||||
|
|
||||||
<div className="col-xxl-4 m-b-30" style={{minHeight: '300px'}}>
|
<DashPayments />
|
||||||
<div className="card card-statistics h-100 mb-0 panel_round_c3">
|
|
||||||
<div className="card-header d-flex justify-content-between">
|
|
||||||
<div className="card-heading">
|
|
||||||
<h4 className="card-title">Payments</h4>
|
|
||||||
</div>
|
|
||||||
{/*<div className="dropdown">*/}
|
|
||||||
{/* <a className="p-2" href="#!" data-toggle="dropdown" aria-haspopup="true"*/}
|
|
||||||
{/* aria-expanded="false">*/}
|
|
||||||
{/* <i className="fe fe-circle"></i>*/}
|
|
||||||
{/* </a>*/}
|
|
||||||
{/* <div className="dropdown-menu custom-dropdown dropdown-menu-right p-4">*/}
|
|
||||||
{/* <h6 className="mb-1">Action</h6>*/}
|
|
||||||
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-o pr-2"></i>View*/}
|
|
||||||
{/* reports</a>*/}
|
|
||||||
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-edit pr-2"></i>Edit reports</a>*/}
|
|
||||||
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-bar-chart-o pr-2"></i>Statistics</a>*/}
|
|
||||||
{/* <h6 className="mb-1 mt-3">Export</h6>*/}
|
|
||||||
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-pdf-o pr-2"></i>Export*/}
|
|
||||||
{/* to PDF</a>*/}
|
|
||||||
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-excel-o pr-2"></i>Export*/}
|
|
||||||
{/* to CSV</a>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
|
||||||
<div className="card-body">
|
|
||||||
{/*<h5>We only started collecting data from February 2019 </h5>*/}
|
|
||||||
{/*<p>Questions about the Net Earnings number? <a*/}
|
|
||||||
{/* className="btn btn-square btn-inverse-success btn-xs ml-1" href="#">Click here</a></p>*/}
|
|
||||||
<div className="row mt-4">
|
|
||||||
.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>;
|
</>;
|
||||||
|
|
||||||
|
|||||||
@@ -41,22 +41,27 @@ export default function Products() {
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="row m-b-20">
|
<div className="row m-b-20">
|
||||||
{products && products.map((product, index) => (
|
{products && products.map((product, index) =>
|
||||||
<div key={product.uid+index} className="col-xxs-6 col-xl-4 col-xxl-6 mb-2 mb-xxl-0 ">
|
{
|
||||||
|
// let productName = product?.name?.length > 14 ? product?.name?.substring(0, 14) + '...' : product?.name
|
||||||
|
return (
|
||||||
|
<div key={product.uid+index} className={`col-12 col-lg-6 mb-2 mb-xxl-0`}>
|
||||||
<Link to={productPath(product?.product_id)} >
|
<Link to={productPath(product?.product_id)} >
|
||||||
<div className="d-flex align-items-center extraProductCard">
|
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
||||||
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
||||||
<i className="fa fa-cart-plus text-primary"></i>
|
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
||||||
</div>
|
</div>
|
||||||
<div className="report-details">
|
<div className="report-details overflow-hidden">
|
||||||
<p>{product?.status_text}</p>
|
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||||
<h4>{product?.name}</h4>
|
<h4><span className='w-100 d-inline-block text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="apexchart-wrapper">
|
<div className="apexchart-wrapper">
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function ProductsURL() {
|
|||||||
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
|
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
<div className="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
||||||
<div className="datatable-wrapper table-responsive">
|
<div className="datatable-wrapper table-responsive">
|
||||||
{isFetching ?
|
{isFetching ?
|
||||||
<>
|
<>
|
||||||
@@ -60,7 +60,8 @@ export default function ProductsURL() {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{urlData && urlData.map((item, index) => {
|
{urlData && urlData.map((item, index) => {
|
||||||
let statusColor = item?.status === 'Preparing' ? 'badge-success-inverse' : item?.status === 'Active' ? 'badge-success-inverse' : item?.status == 'Refreshing' ? 'badge-danger-inverse' : 'badge-info-inverse'
|
let statusColor = item?.status === '1' ? 'badge-success-inverse' : item?.status === '6' ? 'badge-success-inverse' : item?.status == '7' ? 'badge-danger-inverse' : 'badge-info-inverse'
|
||||||
|
let statusText = item?.status === '1' ? 'Preparing' : item?.status === '6' ? 'Provisioning' : item?.status == '7' ? 'Ready' : 'Started'
|
||||||
let productUrl = '/product/'+ item?.product_id
|
let productUrl = '/product/'+ item?.product_id
|
||||||
let externalUrl= item?.url_protocol +"://"+ item?.internal_url;
|
let externalUrl= item?.url_protocol +"://"+ item?.internal_url;
|
||||||
return (
|
return (
|
||||||
@@ -70,7 +71,7 @@ export default function ProductsURL() {
|
|||||||
<a className="mr-3" href={externalUrl} target='_blank'><b>{externalUrl}</b></a> - {item?.description}
|
<a className="mr-3" href={externalUrl} target='_blank'><b>{externalUrl}</b></a> - {item?.description}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td><span className={`badge ${statusColor}`}>{item?.status}</span></td>
|
<td><span className={`badge ${statusColor}`}>{statusText}</span></td>
|
||||||
{/* <td><a className="mr-3" href={productUrl}><i className="fe fe-edit"></i></a></td> */}
|
{/* <td><a className="mr-3" href={productUrl}><i className="fe fe-edit"></i></a></td> */}
|
||||||
<td>
|
<td>
|
||||||
<a className="mr-3" href={productUrl}>
|
<a className="mr-3" href={productUrl}>
|
||||||
@@ -81,16 +82,6 @@ export default function ProductsURL() {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Price</th>
|
|
||||||
<th>In stock</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Action</th>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
</table>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export default function RecentActions() {
|
|||||||
<h4>{dataAction?.data?.completed}</h4>
|
<h4>{dataAction?.data?.completed}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="table-responsive m-t-20">
|
<div className="overflow-y-auto table-responsive m-t-20">
|
||||||
<table id="datatable-buttons" className="table">
|
<table id="datatable-buttons" className="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -94,7 +94,7 @@ export default function RecentActions() {
|
|||||||
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
|
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
|
||||||
return (
|
return (
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td>{action?.id}</td>
|
<td>{(action?.id).toString().slice(-4)}</td>
|
||||||
<td>{action?.action_label}</td>
|
<td>{action?.action_label}</td>
|
||||||
<td>{new Date(action?.added).toDateString()}</td>
|
<td>{new Date(action?.added).toDateString()}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { topBar } from '../../services/services'
|
import { topBar } from '../../services/services'
|
||||||
import queryKeys from '../../services/queryKeys'
|
import queryKeys from '../../services/queryKeys'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
export default function TopBar() {
|
export default function TopBar() {
|
||||||
|
|
||||||
@@ -56,21 +57,26 @@ export default function TopBar() {
|
|||||||
<>
|
<>
|
||||||
{data && data?.map((item, index)=>{
|
{data && data?.map((item, index)=>{
|
||||||
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
|
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
|
||||||
|
let dataSpan = ''
|
||||||
|
if(item?.extra_style){
|
||||||
|
const data = item.data_span.split(' ')
|
||||||
|
dataSpan = `${data[0]} ${data[1]}`
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={item.id + index} className="col-sm-6 col-xxl-3">
|
<div key={item.id + index} className="col-sm-6 col-xxl-3">
|
||||||
<div className="card card-statistics ecommerce-contant overflow-h">
|
<Link to={item?.link}>
|
||||||
|
<div className={`card card-statistics ecommerce-contant overflow-h ${item?.extra_style} `} style={{borderRadius: '10px'}}>
|
||||||
<div className="card-body p-0">
|
<div className="card-body p-0">
|
||||||
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
|
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<div className="row p-3">
|
<div className="row p-3">
|
||||||
<div className="col">
|
<div className="col">
|
||||||
<h3 className="mb-0">{item?.value || 0}</h3>
|
<h3 className="mb-0">{item?.value || 0}</h3>
|
||||||
<small className="d-block">{item?.data_span}</small>
|
<small className="d-block">{item?.extra_style ? dataSpan : item?.data_span}</small>
|
||||||
</div>
|
</div>
|
||||||
<div className="col text-right">
|
<div className="col text-right">
|
||||||
<h5 className="text-muted mb-0">{item?.description}</h5>
|
<h5 className="text-muted mb-0">{item?.description}</h5>
|
||||||
<strong className={`${textColor} m-t-5`}><i
|
|
||||||
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> N/A</strong>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="apexchart-wrapper">
|
<div className="apexchart-wrapper">
|
||||||
@@ -80,6 +86,7 @@ export default function TopBar() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { Outlet, useLocation } from 'react-router-dom';
|
||||||
import UserMenu from "./layoutcom/UserMenu";
|
import UserMenu from "./layoutcom/UserMenu";
|
||||||
import UserHeader from "./layoutcom/UserHeader";
|
import UserHeader from "./layoutcom/UserHeader";
|
||||||
import UserFooter from "./layoutcom/UserFooter";
|
import UserFooter from "./layoutcom/UserFooter";
|
||||||
import { Outlet } from 'react-router-dom';
|
import siteLinks from '../../links/siteLinks';
|
||||||
|
|
||||||
|
|
||||||
export default function Layout() {
|
export default function Layout() {
|
||||||
|
|
||||||
|
const {pathname} = useLocation()
|
||||||
|
// const isProfileComplete = pathname == siteLinks.profile_complete
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
<div className="app-wrap">
|
<div className="app-wrap">
|
||||||
<UserHeader />
|
<UserHeader />
|
||||||
<div className="app-container">
|
<div className="app-container">
|
||||||
|
|
||||||
<aside className="app-navbar">
|
<aside className="app-navbar">
|
||||||
<UserMenu />
|
<UserMenu />
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ export default function UserFooter(){
|
|||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<footer className="footer">
|
<footer className={`footer`}>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 col-sm-6 text-center text-sm-left">
|
<div className="col-12 col-sm-6 text-center text-sm-left">
|
||||||
<p>© Copyright {year}. All rights reserved.</p>
|
<p>© Copyright {year}. All rights reserved.</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
|
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
|
||||||
<p>A division of <i className="fa fa-key text-danger mx-1"></i> autoMedSys A.I.</p>
|
<p>A division of autoMedSys A.I.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import siteLinks from "../../../links/siteLinks";
|
|||||||
|
|
||||||
export default function UserHeader(){
|
export default function UserHeader(){
|
||||||
|
|
||||||
const { userDetails } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
|
const { userDetails } = useSelector((state) => state?.userDetails); // USER Details
|
||||||
|
|
||||||
const nav_menu = useRef(null)
|
const nav_menu = useRef(null)
|
||||||
|
|
||||||
@@ -73,16 +73,21 @@ export default function UserHeader(){
|
|||||||
|
|
||||||
<ul className="navbar-nav nav-right ml-auto">
|
<ul className="navbar-nav nav-right ml-auto">
|
||||||
<li className="nav-item user-profile">
|
<li className="nav-item user-profile">
|
||||||
<a onClick={toggleMenu} href="#" className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdow">
|
<a onClick={toggleMenu} className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdow">
|
||||||
<img src={getImage('profile-pic-circle.png')} alt="avtar-img" />
|
<img
|
||||||
|
src={userDetails?.picture ? userDetails?.picture : getImage('profile-pic-circle.png')}
|
||||||
|
// src={getImage('profile-pic-circle.png')}
|
||||||
|
alt="avtar-img"
|
||||||
|
/>
|
||||||
<span className="bg-success user-status"></span>
|
<span className="bg-success user-status"></span>
|
||||||
</a>
|
</a>
|
||||||
<div ref={nav_menu} className="dropdown-menu animated fadeIn">
|
<div ref={nav_menu} onClick={toggleMenu} className="dropdown-menu animated fadeIn">
|
||||||
|
<div className="position-fixed" style={{top: '0px', left: '0px', right: '0px', bottom: '0px'}}></div>
|
||||||
<div className="bg-gradient px-4 py-3">
|
<div className="bg-gradient px-4 py-3">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<div className="d-flex align-items-center justify-content-between">
|
||||||
<div className="mr-1">
|
<div className="mr-1">
|
||||||
<h4 className="text-white mb-0 font-600">{userDetails?.firstname} {userDetails?.lastname}</h4>
|
{/* <h4 className="text-white mb-0 font-600">{userDetails?.username}</h4> */}
|
||||||
<p className="text-white font-600">{userDetails.email}</p>
|
<p className="text-white font-600">{userDetails.username}</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="#" onClick={logout} className="text-white font-20 tooltip-wrapper" data-toggle="tooltip"
|
<a href="#" onClick={logout} className="text-white font-20 tooltip-wrapper" data-toggle="tooltip"
|
||||||
data-placement="top" title="" data-original-title="Logout"> <i
|
data-placement="top" title="" data-original-title="Logout"> <i
|
||||||
@@ -90,8 +95,8 @@ export default function UserHeader(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Link className="dropdown-item d-flex nav-link" to={siteLinks.user}>
|
<Link className="dropdown-item d-flex nav-link" to={siteLinks.subscription}>
|
||||||
<i className="fa fa-user pr-2 text-success"></i> Users</Link>
|
<i className="fa fa-user pr-2 text-success"></i> Subscription</Link>
|
||||||
<Link className="dropdown-item d-flex nav-link" to={siteLinks.contacts}>
|
<Link className="dropdown-item d-flex nav-link" to={siteLinks.contacts}>
|
||||||
<i className="fa fa-envelope pr-2 text-primary"></i> Contacts
|
<i className="fa fa-envelope pr-2 text-primary"></i> Contacts
|
||||||
<span className="badge badge-primary ml-auto">6</span>
|
<span className="badge badge-primary ml-auto">6</span>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export default function UserMenu() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="sidebar-nav scrollbar scroll_dark">
|
<div className="sidebar-nav scrollbar scroll_dark">
|
||||||
<ul className="metismenu " id="sidebarNav">
|
<ul className="metismenu h-100" id="sidebarNav">
|
||||||
<li className="nav-static-title">Panel</li>
|
<li className="nav-static-title">Panel</li>
|
||||||
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}>
|
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}>
|
||||||
<Link className="has-arrow" to='#' data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
<Link className="has-arrow" to='#' data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||||
@@ -30,7 +30,7 @@ export default function UserMenu() {
|
|||||||
<ul id="collapseOne" className="collapse show" aria-labelledby="headingOne" data-bs-parent="#sidebarNav">
|
<ul id="collapseOne" className="collapse show" aria-labelledby="headingOne" data-bs-parent="#sidebarNav">
|
||||||
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}><Link to={siteLinks.dash}>Home</Link></li>
|
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}><Link to={siteLinks.dash}>Home</Link></li>
|
||||||
<li className={`${pathname == siteLinks.calendar ? 'active' : ''}`}><Link to={siteLinks.calendar}>Calendar</Link></li>
|
<li className={`${pathname == siteLinks.calendar ? 'active' : ''}`}><Link to={siteLinks.calendar}>Calendar</Link></li>
|
||||||
<li className={`${pathname == siteLinks.contacts ? 'active' : ''}`}><Link to={siteLinks.contacts}>Contacts</Link></li>
|
<li className={`${pathname == siteLinks.contacts ? 'active' : ''}`}><Link to={siteLinks.contacts}>Sites Contacts</Link></li>
|
||||||
<li className={`${pathname == siteLinks.comments ? 'active' : ''}`}><Link to={siteLinks.comments}>Comments</Link></li>
|
<li className={`${pathname == siteLinks.comments ? 'active' : ''}`}><Link to={siteLinks.comments}>Comments</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -48,13 +48,14 @@ export default function UserMenu() {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
|
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
|
||||||
<li className={`${pathname == siteLinks.user ? 'active' : ''}`}><Link to={siteLinks.user}>Users</Link></li>
|
<li className={`${pathname == siteLinks.my_media ? 'active' : ''}`}><Link to={siteLinks.my_media}>Files and Media</Link></li>
|
||||||
|
<li className={`${pathname == siteLinks.subscription ? 'active' : ''}`}><Link to={siteLinks.subscription}>Subscription</Link></li>
|
||||||
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
<li className="sidebar-banner p-4 bg-gradient text-center m-3 d-block rounded">
|
<li className="sidebar-banner p-4 bg-gradient text-center m-3 mt-auto d-block rounded">
|
||||||
<h5 className="text-white mb-1">MERMS Panel</h5>
|
<h5 className="text-white mb-1">MERMS Panel</h5>
|
||||||
<Link className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0" to='' onClick={logout}> Log Out</Link>
|
<Link className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0" to='' onClick={logout}> Log Out</Link>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
import React from "react";
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import {useState, useRef} from "react";
|
||||||
|
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import {getMediaFileList, uploadFile} from "../../services/services";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
|
||||||
|
|
||||||
|
export default function MyMedia() {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const basePath = process.env.REACT_APP_MAIN_API
|
||||||
|
const [selectedFile, setSelectedFile] = useState(null);
|
||||||
|
const [message, setMessage] = useState('');
|
||||||
|
const [imageLink, setImageLink] = useState('')
|
||||||
|
console.log('imageLink', imageLink)
|
||||||
|
// Function to handle file selection
|
||||||
|
const handleFileChange = (event) => {
|
||||||
|
setSelectedFile(event.target.files[0]);
|
||||||
|
setMessage('');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle the upload to the API
|
||||||
|
const _handleUpload = async () => {
|
||||||
|
if (!selectedFile) {
|
||||||
|
setMessage('Please select a file first!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
// 'file' is the field name that your API endpoint expects
|
||||||
|
formData.append('file', selectedFile);
|
||||||
|
formData.append("member_uid", localStorage.getItem('uid'));
|
||||||
|
formData.append("token", localStorage.getItem('token'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Replace with your actual API endpoint URL
|
||||||
|
const apiEndpoint = basePath + '/upload/webfiles';
|
||||||
|
const response = await fetch(apiEndpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
// The browser automatically sets the 'Content-Type' header to
|
||||||
|
// 'multipart/form-data' when you provide a FormData object as the body,
|
||||||
|
// which is required for file uploads.
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json();
|
||||||
|
setMessage('File uploaded successfully!');
|
||||||
|
console.log('Success:', result);
|
||||||
|
} else {
|
||||||
|
setMessage('Upload failed.');
|
||||||
|
console.error('Upload failed:', response.statusText);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setMessage('An error occurred during the upload.');
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFileMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
if (!fields.file) {
|
||||||
|
throw({message: 'Please select a file first!'})
|
||||||
|
}
|
||||||
|
return uploadFile(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
// console.log('res', res.data)
|
||||||
|
// if(res.data.resultCode != '0' || !res?.data?.pending_uid){
|
||||||
|
// throw({message: res?.data?.resultDescription})
|
||||||
|
// }
|
||||||
|
setSelectedFile(null)
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.my_files],
|
||||||
|
// type: 'active',
|
||||||
|
// exact: true,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
uploadFileMutation.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleUpload = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
|
member_uid: localStorage.getItem("uid"), // USER UID
|
||||||
|
file: selectedFile
|
||||||
|
};
|
||||||
|
// console.log(reqData)
|
||||||
|
uploadFileMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.my_files,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return getMediaFileList(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mediaFileList = data?.data
|
||||||
|
|
||||||
|
//debugger;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Files' paths={['Dashboard', 'Files']}/>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||||
|
<div className="card card-statistics mb-0 widget-support-list">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Upload File</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body pl-0 pr-0 scrollbar scroll_dark">
|
||||||
|
<div className="widget-text">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input className="form-control form-control-sm" type="file"
|
||||||
|
onChange={handleFileChange}/>
|
||||||
|
|
||||||
|
{selectedFile && (
|
||||||
|
<div>
|
||||||
|
<h4>Selected File Details:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Name: {selectedFile.name}</li>
|
||||||
|
<li>Type: {selectedFile.type}</li>
|
||||||
|
<li>Size: {selectedFile.size} bytes</li>
|
||||||
|
</ul>
|
||||||
|
<div style={{width: '100%', textAlign: 'right'}}>
|
||||||
|
<button
|
||||||
|
className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0"
|
||||||
|
onClick={handleUpload}
|
||||||
|
disabled={!selectedFile || uploadFileMutation.isPending || uploadFileMutation.isSuccess}>
|
||||||
|
Upload
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<>
|
||||||
|
{/* {message && <p>{message}</p>} */}
|
||||||
|
<p>{uploadFileMutation.isPending ? 'uploading...' : uploadFileMutation.isError ? uploadFileMutation?.error?.message : uploadFileMutation.isSuccess ? 'File Uploaded' : ''}</p>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||||
|
<div className="card card-statistics h-100 mb-0 widget-downloads-list" style={{}}>
|
||||||
|
<div className="card-header d-flex justify-content-between">
|
||||||
|
<div className="card-heading">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Files List</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="card-body scrollbar scroll_dark"
|
||||||
|
style={{minHeight: '400px', maxHeight: '500px', overflowY: 'auto'}}>
|
||||||
|
{mediaFileList && mediaFileList?.file_list && mediaFileList?.file_list.map((item, index) => {
|
||||||
|
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
|
||||||
|
const avtarImage =
|
||||||
|
item?.file_type === undefined
|
||||||
|
? "icons/01.png"
|
||||||
|
: "icons/" + item.file_type + ".png";
|
||||||
|
return (<div key={index}
|
||||||
|
className={`widget-text ${imageLink == file_url && 'bg-light'}`}>
|
||||||
|
<div className={`media align-items-center`}
|
||||||
|
onClick={() => setImageLink(file_url)} style={{cursor: 'pointer'}}>
|
||||||
|
<img src={getImage(avtarImage)}
|
||||||
|
// src={`assets/img/file-icon/${item.file_type}.png`}
|
||||||
|
className="img-fluid"
|
||||||
|
alt={`${item.file_type}`}/>
|
||||||
|
<div className="media-body">
|
||||||
|
<h4 className="mb-0 ml-3">{item.filename}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a href={`${file_url}`} target='_blank'
|
||||||
|
className="btn btn-icon btn-round btn-outline-success">
|
||||||
|
<i className="ti ti-download"></i>
|
||||||
|
</a>
|
||||||
|
<a href=""
|
||||||
|
className="btn btn-icon btn-round btn-outline-danger ml-2">
|
||||||
|
<i className="ti ti-close"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||||
|
<div className="card card-statistics h-100 mb-0 widget-branches-list">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Preview</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="card-body d-flex justify-content-center align-items-center pl-0 pr-0 scrollbar scroll_dark">
|
||||||
|
{imageLink &&
|
||||||
|
<img className="w-100 h-auto" src={imageLink} alt='file-image'/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="card-header d-flex justify-content-between align-items-center">
|
||||||
|
{imageLink &&
|
||||||
|
<>
|
||||||
|
<p>0 x 0 px</p>
|
||||||
|
<p>size: 0 bytes</p>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
|
||||||
|
export default function Onboard() {
|
||||||
|
|
||||||
|
const pricingFields ={
|
||||||
|
starter: { name: 'Starter', price: 5.99, active: true },
|
||||||
|
basic: { name: 'Basic', price: 12.99, active: true },
|
||||||
|
premium: { name: 'Premium', price: 20.00, active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Subscription' paths={['Dashboard', 'Subscription']} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-xl-3 col-md-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>Current Subscription(s)</h5>
|
||||||
|
<h2 className="text-primary pt-3">Basic</h2>
|
||||||
|
{/*<p className="text-primary pb-3">/ Monthly</p>*/}
|
||||||
|
{/*<ul className="py-2">*/}
|
||||||
|
{/* <li>post jobs</li>*/}
|
||||||
|
{/* <li>advanced instructors search</li>*/}
|
||||||
|
{/* <li>invite candidates</li>*/}
|
||||||
|
{/* <li>post events</li>*/}
|
||||||
|
{/* <li>cancel any time</li>*/}
|
||||||
|
{/*</ul>*/}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<>
|
||||||
|
{Object.entries(pricingFields)?.map(([key, value]) => (
|
||||||
|
|
||||||
|
<div key={key} className="col-xl-3 col-md-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>{value.name}</h5>
|
||||||
|
<h2 className="text-primary pt-3">${value.price}</h2>
|
||||||
|
<p className="text-primary pb-3">/ Monthly</p>
|
||||||
|
<ul className="py-2">
|
||||||
|
<li>post jobs</li>
|
||||||
|
<li>advanced instructors search</li>
|
||||||
|
<li>invite candidates</li>
|
||||||
|
<li>post events</li>
|
||||||
|
<li>cancel any time</li>
|
||||||
|
</ul>
|
||||||
|
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go {value.name}</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,19 +1,47 @@
|
|||||||
import React from "react";
|
import React, {useEffect, useMemo, useRef, useState} from "react";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import GeneralTab from "./settingsTab/GeneralTab";
|
import { productRefreshSite, getSettingsData } from "../../services/services";
|
||||||
|
import Settings from "./settingsTab/Settings";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import {SocketContextValues} from "../context/SocketIOContext";
|
||||||
|
|
||||||
|
|
||||||
export default function ProductActive({productData}){
|
export default function ProductActive({productData}){
|
||||||
const settingsObject = {
|
const {joinRoom} = SocketContextValues() // Destructures values from socket context
|
||||||
home_tab: { title: 'Home Page', controls: 'home', active: 'active show' , data: {}},
|
const iframe = useRef()
|
||||||
footer_tab: { title: 'Footer', controls: 'footer', active: '', data: {} },
|
|
||||||
about_tab: { title: 'About Page', controls: 'about', active: '', data: {} },
|
const [refreshMsg, setRefreshMsg] = useState('')
|
||||||
contact_tab: { title: 'Contact Page', controls: 'contact', active: '', data: {} },
|
|
||||||
social_tab: { title: 'Socials', controls: 'social', active: '', data: {} },
|
const refresh = useMutation({
|
||||||
template_tab: { title: 'Template', controls: 'template', active: '', data: {} },
|
mutationFn: (fields) => {
|
||||||
color_scheme_tab: { title: 'Color Scheme', controls: 'color-scheme', active: '', data: {} },
|
return productRefreshSite(fields)
|
||||||
};
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
setRefreshMsg(res?.data?.message)
|
||||||
|
setTimeout(()=>{setRefreshMsg('')},3000)
|
||||||
|
iframe.current.src += ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData.product_id,
|
||||||
|
subscription_uid: productData.subscription_uid
|
||||||
|
}
|
||||||
|
refresh.mutate(reqData)
|
||||||
|
}
|
||||||
|
let externalUrl= 'https://'+productData?.internal_url
|
||||||
|
|
||||||
|
const productSubUID = productData.subscription_uid;
|
||||||
|
useEffect(() => {
|
||||||
|
const provision_room = "PROVISION_"+productSubUID;
|
||||||
|
console.log("JOINING ROOM ON ACTIVE *** ", provision_room);
|
||||||
|
joinRoom(provision_room); // provision subscription room
|
||||||
|
}, [])
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<>
|
<>
|
||||||
@@ -24,20 +52,31 @@ export default function ProductActive({productData}){
|
|||||||
|
|
||||||
|
|
||||||
<div className="row account-contant">
|
<div className="row account-contant">
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
|
||||||
<div className="row tabs-contant">
|
<div className="row tabs-contant">
|
||||||
<div className="col-xxl-6">
|
<div className="col-xxl-6">
|
||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="card-heading">
|
<div className="card-heading d-flex justify-content-between">
|
||||||
<h4 className="card-title">{productData?.internal_url ? productData?.internal_url : 'https://25681.devprov.mermsemr.com/'}</h4>
|
{/*<h4 className="card-title">{externalUrl}</h4>*/}
|
||||||
|
<h4 style={{color: '#148399', fontWeight: 'bolder'}}>
|
||||||
|
<a href={externalUrl} target='_blank'>{externalUrl}</a></h4>
|
||||||
|
<button type="button" onClick={()=>iframe.current.src += ''} className="btn">
|
||||||
|
<img src={getImage('refresh.png')} style={{width: '30px', height: 'auto'}} alt='refresh page' />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body" style={{minHeight: '600px', maxHeight: '600px'}}>
|
||||||
<iframe style={{borderWidth: '0px;'}} src={productData?.internal_url ? productData?.internal_url : 'https://25681.devprov.mermsemr.com/'} width="100%" height="600" title={productData?.internal_url ? productData?.internal_url : 'https://25681.devprov.mermsemr.com/'}></iframe>
|
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 ml-auto">
|
||||||
|
<div className="d-flex justify-end gap-3">
|
||||||
|
{refreshMsg &&
|
||||||
|
<p className="text-success text-center">{refreshMsg}</p>
|
||||||
|
}
|
||||||
|
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Initiating...' : 'Rebuild Site'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,50 +87,14 @@ export default function ProductActive({productData}){
|
|||||||
<h4 className="card-title"> Site Settings </h4>
|
<h4 className="card-title"> Site Settings </h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body" style={{minHeight: '680px'}}>
|
||||||
<div className="tab tab-vertical">
|
<Settings productData={productData} />
|
||||||
<ul className="nav nav-tabs" role="tablist">
|
</div>
|
||||||
<>
|
</div>
|
||||||
{Object.entries(settingsObject).map(([key, value]) => (
|
</div>
|
||||||
<li className="nav-item">
|
|
||||||
<a className={`nav-link ${value.active}`}
|
|
||||||
id={key} data-bs-toggle="pill"
|
|
||||||
data-bs-target={`#${value.controls}`}
|
|
||||||
type="button" role="tab"
|
|
||||||
aria-controls={value.controls}
|
|
||||||
aria-selected="true">{value.title}</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
</ul>
|
|
||||||
<div className="tab-content">
|
|
||||||
<>
|
|
||||||
{Object.entries(settingsObject).map(([key, value]) => (
|
|
||||||
<div className={`tab-pane fade ${value.active}`}
|
|
||||||
id={value.controls} role="tabpanel"
|
|
||||||
aria-labelledby={key}>
|
|
||||||
<GeneralTab name={value.title} data={value.data} />
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,16 @@ import { useQuery } from '@tanstack/react-query'
|
|||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
// import getImage from "../../utils/getImage";
|
// import getImage from "../../utils/getImage";
|
||||||
import ProductStart from "./ProductStart";
|
import ProductStart from "./ProductStart";
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import {MyProductData} from "../../services/services";
|
import {MyProductData} from "../../services/services";
|
||||||
import ProductActive from "./ProductActive";
|
import ProductActive from "./ProductActive";
|
||||||
import ProductProvision from "./ProductProvision";
|
import ProductProvision from "./ProductProvision";
|
||||||
import {productConst} from "../../constants/products";
|
import {productConst} from "../../constants/products";
|
||||||
import queryKeys from "../../services/queryKeys";
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import siteLinks from '../../links/siteLinks';
|
||||||
|
|
||||||
export default function ProductFactory(){
|
export default function ProductFactory(){
|
||||||
|
const navigate = useNavigate()
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const pathname = location.pathname;
|
const pathname = location.pathname;
|
||||||
|
|
||||||
@@ -45,8 +47,9 @@ export default function ProductFactory(){
|
|||||||
</>
|
</>
|
||||||
: isError ?
|
: isError ?
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="text-center col-12" style={{minHeight: '500px', placeContent: 'center'}}>
|
||||||
<p className='text-danger'>{error?.message}</p>
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
<button onClick={() => navigate(siteLinks.home)} className='mt-3 btn btn-primary'>Return Home</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { useEffect } from "react";
|
import {useEffect} from "react";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import {useQuery} from "@tanstack/react-query";
|
||||||
import queryKeys from "../../services/queryKeys";
|
import queryKeys from "../../services/queryKeys";
|
||||||
import { productProvision } from "../../services/services";
|
import {productProvision} from "../../services/services";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
import { SocketContextValues } from "../context/SocketIOContext";
|
import {SocketContextValues} from "../context/SocketIOContext";
|
||||||
|
|
||||||
|
|
||||||
export default function ProductProvision(props){
|
export default function ProductProvision(props) {
|
||||||
const {joinRoom} = SocketContextValues() // Destructures values from socket context
|
const {joinRoom} = SocketContextValues() // Destructures values from socket context
|
||||||
|
|
||||||
const productTitle = props?.productData?.title;
|
const productTitle = props?.productData?.title;
|
||||||
@@ -16,20 +16,22 @@ export default function ProductProvision(props){
|
|||||||
const productSubUID = props?.productData?.product_subscription_uid
|
const productSubUID = props?.productData?.product_subscription_uid
|
||||||
|
|
||||||
const reqData = {
|
const reqData = {
|
||||||
product_id : productID,
|
product_id: productID,
|
||||||
product_subscription_uid: productSubUID
|
product_subscription_uid: productSubUID
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data:provision, isFetching, isError, error} = useQuery({
|
const {data: provision, isFetching, isError, error} = useQuery({
|
||||||
queryKey: queryKeys.myproduct_provision,
|
queryKey: queryKeys.myproduct_provision,
|
||||||
queryFn: () => productProvision(reqData)
|
queryFn: () => productProvision(reqData)
|
||||||
})
|
})
|
||||||
|
|
||||||
const provisionData = provision?.data
|
const provisionData = provision?.data
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(() => {
|
||||||
joinRoom(productSubUID); // provision subscription room
|
const provision_room = "PROVISION_" + productSubUID;
|
||||||
},[])
|
console.log("JOINING ROOM ON START *** ", provision_room);
|
||||||
|
joinRoom(provision_room); // provision subscription room
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -59,8 +61,11 @@ export default function ProductProvision(props){
|
|||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
<div className="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
<div className="progress-bar progress-bar-striped progress-bar-animated"
|
||||||
aria-valuenow={`${provisionData?.percent_completed}%`} aria-valuemin="0" aria-valuemax="100" style={{width:`${provisionData?.percent_completed}%`}} ></div>
|
role="progressbar"
|
||||||
|
aria-valuenow={`${provisionData?.percent_completed}%`}
|
||||||
|
aria-valuemin="0" aria-valuemax="100"
|
||||||
|
style={{width: `${provisionData?.percent_completed}%`}}></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,8 +113,10 @@ export default function ProductProvision(props){
|
|||||||
|
|
||||||
<div className="col-lg-6">
|
<div className="col-lg-6">
|
||||||
<div className="card card-statistics ">
|
<div className="card card-statistics ">
|
||||||
<h4 className="card-title" style={{padding:'10px'}}>Started creating your selection</h4>
|
<h4 className="card-title" style={{padding: '10px'}}>Started creating your
|
||||||
<img className="card-img-top" src={getImage('widget/working.jpg')} alt="Card image cap" />
|
selection</h4>
|
||||||
|
<img className="card-img-top" src={getImage('widget/working.jpg')}
|
||||||
|
alt="Card image cap"/>
|
||||||
{/* <div className="card-body">
|
{/* <div className="card-body">
|
||||||
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
||||||
</div> */}
|
</div> */}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export default function ProductStart(props){
|
|||||||
<img className="card-img-top" src={getImage(productBanner)} alt="Card image cap" />
|
<img className="card-img-top" src={getImage(productBanner)} alt="Card image cap" />
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h4 className="card-title">{productTitle}</h4>
|
<h4 className="card-title">{productTitle}</h4>
|
||||||
<div className="card-text" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
<div className="card-text" style={{fontSize: '14px'}} dangerouslySetInnerHTML={{__html: productDescription}}/>
|
||||||
{/* <p className="card-text">{productDescription}</p> */}
|
{/* <p className="card-text">{productDescription}</p> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,7 +97,7 @@ export default function ProductStart(props){
|
|||||||
</>
|
</>
|
||||||
|
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<p className="card-text">Start with your goals in mind and then work possible. </p>
|
<p className="card-text">We are actively working to launch this feature soon and will keep you informed every step of the way. </p>
|
||||||
</div>
|
</div>
|
||||||
<ul className="list-group list-group-flush">
|
<ul className="list-group list-group-flush">
|
||||||
<li className="list-group-item"><h4>Coming soon!!!</h4></li>
|
<li className="list-group-item"><h4>Coming soon!!!</h4></li>
|
||||||
@@ -109,19 +109,15 @@ export default function ProductStart(props){
|
|||||||
{/*<img className="card-img-top" src={getImage('widget/01.jpg')} alt="Card image cap" />*/}
|
{/*<img className="card-img-top" src={getImage('widget/01.jpg')} alt="Card image cap" />*/}
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h4 className="card-title">Subscription</h4>
|
<h4 className="card-title">Subscription</h4>
|
||||||
<p className="card-text">Start with your goals in mind and then work possible.ith yand Goals. If the plan doesn’t support the vision then change it! </p>
|
<p className="card-text">Launch your <span style={{color: '#148399' , fontWeight: 'bolder'}}>{productTitle}</span> with us for free! Benefit from our dedicated support and customize features that align perfectly with your goals. Experience everything at no cost! </p>
|
||||||
</div>
|
</div>
|
||||||
<ul className="list-group list-group-flush">
|
<ul className="list-group list-group-flush">
|
||||||
<li className="list-group-item"><h4>{promotion_text}</h4></li>
|
<li className="list-group-item"><h4>{promotion_text}</h4></li>
|
||||||
<li className="list-group-item">90 days free and 3.95/Month</li>
|
<li className="list-group-item">90 days free and $5.99/Month</li>
|
||||||
<li className="list-group-item"></li>
|
<li className="list-group-item"></li>
|
||||||
</ul>
|
</ul>
|
||||||
{/*<div className="card-body">*/}
|
|
||||||
{/* <a href="javascript:void(0)" className="card-link">Card link</a>*/}
|
|
||||||
{/* <a href="javascript:void(0)" className="card-link">Another link</a>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div className="subscribe-box">
|
<div className="subscribe-box">
|
||||||
<button className="btn btn-primary mt-2" data-bs-toggle="modal" data-bs-target="#verticalCenter">Start Subscription</button>
|
<button className="btn btn-primary mt-2" data-bs-toggle="modal" data-bs-target="#verticalCenter">Activate Now!</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -130,17 +126,17 @@ export default function ProductStart(props){
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Vertical Center Modal */}
|
{/* Vertical Center Modal */}
|
||||||
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="true">
|
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
|
||||||
<div className="modal-dialog modal-dialog-centered" role="document">
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
<div className="modal-content">
|
<div className="modal-content">
|
||||||
<div className="modal-header">
|
<div className="modal-header">
|
||||||
<h5 className="modal-title" id="verticalCenterTitle">{productTitle}</h5>
|
<h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{productTitle}</h5>
|
||||||
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
<div className="" dangerouslySetInnerHTML={{__html: saleText}}/>
|
<div style={{fontSize: '18px'}} className="" dangerouslySetInnerHTML={{__html: saleText}}/>
|
||||||
{/* {mutation.error &&
|
{/* {mutation.error &&
|
||||||
<>
|
<>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -162,8 +158,8 @@ export default function ProductStart(props){
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-footer">
|
<div className="modal-footer">
|
||||||
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Close</button>
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="button" className="btn btn-success" disabled={mutation.isSuccess} onClick={handleSubscribe}>{mutation.isPending ? 'loading...' : 'Start'}</button>
|
<button type="button" className="btn btn-primary" disabled={mutation.isSuccess} onClick={handleSubscribe}>{mutation.isPending ? 'activating...' : 'Start Activation'}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import React, {memo} from 'react'
|
||||||
|
import getImage from "../../../utils/getImage";
|
||||||
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import {
|
||||||
|
getProductcolorStyleCss,
|
||||||
|
activateTemplate,
|
||||||
|
getProductColorStyles,
|
||||||
|
activateColorStyle
|
||||||
|
} from '../../../services/services';
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import siteLinks from "../../../links/siteLinks";
|
||||||
|
|
||||||
|
const ColorStyleConfigure = memo(({name = 'Full Name', data, productData}) => {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const {data: colorStyleCss, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.productcolorStyleCss,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getProductColorStyles(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateResponse = colorStyleCss?.data
|
||||||
|
const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||||
|
const color_styles = templateResponse?.color_styles
|
||||||
|
const custom_template_name = templateResponse?.custom_template_name
|
||||||
|
|
||||||
|
// console.log('data Template', templateResponse)
|
||||||
|
console.log("Page data == ", data)
|
||||||
|
|
||||||
|
const handleActivateTemplate = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return activateColorStyle(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res?.data?.resultCode != '0') {
|
||||||
|
throw new Error(res.data.resultDescription)
|
||||||
|
}
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.settingsData],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleActivateTemplate.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (style_uid) => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
|
color_style_uid: style_uid
|
||||||
|
}
|
||||||
|
// console.log(reqData)
|
||||||
|
handleActivateTemplate.mutate(reqData)
|
||||||
|
}
|
||||||
|
if (custom_template_name && custom_template_name != '') {
|
||||||
|
// This implies we have a custom template , just return here
|
||||||
|
return <>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div
|
||||||
|
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||||
|
style={{backgroundColor: '#F2FAF7'}}>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
|
||||||
|
<img className='' style={{width: '200px'}}
|
||||||
|
src={getImage('custom-template.png')}
|
||||||
|
alt='mail-alert'/>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginTop: '20px'}}>This product is using a custom template named <span
|
||||||
|
style={{color: 'darkred'}}>“{custom_template_name}”</span> .</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="page-account-form">
|
||||||
|
<div className="p-0">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||||
|
<>
|
||||||
|
{!color_styles?.length ?
|
||||||
|
<p>No data Found</p>
|
||||||
|
:
|
||||||
|
color_styles.map(color_style => (
|
||||||
|
<div key={color_style.color_style_uid} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body" style={{
|
||||||
|
backgroundColor: `#${color_style.color_code}`,
|
||||||
|
opacity: '0.85',
|
||||||
|
borderRadius: '10px'
|
||||||
|
}}>
|
||||||
|
<div className="text-center p-2">
|
||||||
|
{/*<div className="mb-2">*/}
|
||||||
|
{/* <img src={getImage('file-icon/svg.png')}*/}
|
||||||
|
{/* alt={template.title}/>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
<h4 className="mb-0">{color_style.title}</h4>
|
||||||
|
{currentColorUID === color_style.color_style_uid ?
|
||||||
|
<button className="btn btn-light"
|
||||||
|
disabled={true}>Active</button>
|
||||||
|
:
|
||||||
|
<button
|
||||||
|
onClick={() => handleSubmit(color_style.color_style_uid)}
|
||||||
|
className="btn btn-primary">Select</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||||
|
<div key={key} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="text-center p-2">
|
||||||
|
<div className="mb-2">
|
||||||
|
<img src={getImage(value.banner)} alt={value.title} />
|
||||||
|
</div>
|
||||||
|
<h4 className="mb-0">{value.title}</h4>
|
||||||
|
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))} */}
|
||||||
|
</>
|
||||||
|
|
||||||
|
<div className="col-12">
|
||||||
|
<>
|
||||||
|
{handleActivateTemplate.isPending ?
|
||||||
|
<p className={'text-center '}>loading...</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isError ?
|
||||||
|
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isSuccess ?
|
||||||
|
<p className={'text-center text-success'}>Templated activated
|
||||||
|
successfully</p>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
export default ColorStyleConfigure
|
||||||
@@ -1,49 +1,198 @@
|
|||||||
import React from 'react'
|
import React, {memo, useEffect, useMemo, useState} from 'react'
|
||||||
|
import {useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {pageSettings} from "../../../services/services";
|
||||||
|
import SiteTemplateSelector from './SiteTemplateSelector';
|
||||||
|
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
|
||||||
|
import {IoMdArrowDropdown} from 'react-icons/io';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder';
|
||||||
|
import URLConfiguration from "./URLConfiguration";
|
||||||
|
import ColorStyleConfigure from "./ColorStyleConfigure";
|
||||||
|
|
||||||
export default function GeneralTab({name='Full Name'}) {
|
const GeneralTab = memo(({
|
||||||
|
name = 'Full Name',
|
||||||
|
data,
|
||||||
|
tabKey,
|
||||||
|
isCustom,
|
||||||
|
productData,
|
||||||
|
backendValues,
|
||||||
|
setFieldsChanged
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [reqStatus, setReqStatus] = useState({error: null, message: ''})
|
||||||
|
|
||||||
|
|
||||||
|
// const computeFieldData = useMemo(()=>{
|
||||||
|
// const fieldData = {}
|
||||||
|
// Object.entries(data)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
|
||||||
|
// fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
|
||||||
|
// })
|
||||||
|
// backendValues?.data?.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
|
||||||
|
// fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
|
||||||
|
// })
|
||||||
|
// return fieldData
|
||||||
|
// },[backendValues.data])
|
||||||
|
|
||||||
|
|
||||||
|
const [fields, setFields] = useState({})
|
||||||
|
|
||||||
|
const sortedData = sortObjectByListOrder(data ? data : {}) // SORTED SETTINGSCONFIG
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fieldData = {}
|
||||||
|
Object.entries(sortedData)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
|
||||||
|
fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
|
||||||
|
})
|
||||||
|
backendValues?.data?.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
|
||||||
|
fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
|
||||||
|
})
|
||||||
|
setFields(fieldData)
|
||||||
|
}, [backendValues.data])
|
||||||
|
|
||||||
|
const handleChange = ({target: {name, value}}) => {
|
||||||
|
setFields(prev => ({...prev, [name]: value}))
|
||||||
|
setFieldsChanged(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitSettings = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return pageSettings(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res?.data?.resultCode != '0') {
|
||||||
|
return setReqStatus({error: true, message: 'Unable to complete, try again later'})
|
||||||
|
}
|
||||||
|
setFieldsChanged(false)
|
||||||
|
setReqStatus({error: false, message: 'Completed successfully'})
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
setReqStatus({error: true, message: 'Unable to complete, try again later'})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.settingsData],
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
setReqStatus({error: null, message: ''})
|
||||||
|
}, 3000)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
|
settings: {
|
||||||
|
...fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitSettings.mutate(reqData)
|
||||||
|
}
|
||||||
|
console.log(tabKey);
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{backendValues?.isFetching || !backendValues?.data ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: backendValues?.isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{backendValues?.error.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
{isCustom === true ?
|
||||||
|
<>
|
||||||
|
{(tabKey === 'template_tab') &&
|
||||||
|
<SiteTemplateSelector name={name} data={sortedData} isCustom={isCustom}
|
||||||
|
productData={productData}/>}
|
||||||
|
{(tabKey === 'url_config_tab') &&
|
||||||
|
<URLConfiguration name={name} data={sortedData} isCustom={isCustom}
|
||||||
|
productData={productData}/>}
|
||||||
|
{(tabKey === 'color_scheme_tab') &&
|
||||||
|
<ColorStyleConfigure name={name} data={sortedData} isCustom={isCustom}
|
||||||
|
productData={productData}/>}
|
||||||
|
</>
|
||||||
|
:
|
||||||
<div className="page-account-form">
|
<div className="page-account-form">
|
||||||
<div className="p-0">
|
<div className="p-0" style={{minHeight: '500px'}}>
|
||||||
<form>
|
|
||||||
<h4>{name}</h4>
|
<form id='tab_form'>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<div className="form-group col-md-12">
|
<>
|
||||||
<label htmlFor="name1">Full Name</label>
|
{Object.entries(sortedData)?.map(([key, value]) => {
|
||||||
<input type="text" className="form-control" id="name1"
|
let fieldName = key; // value.key.toLowerCase().replaceAll(" ", "_")
|
||||||
value="Alice Williams" />
|
let fieldValue = fields[key]; //fields[value.name.toLowerCase().replaceAll(" ", "_")]
|
||||||
|
return (
|
||||||
|
<div key={key} className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">{value.name}</label>
|
||||||
|
{value.controls === 'TEXT' ?
|
||||||
|
<input name={fieldName} type="text"
|
||||||
|
className="form-control" id={key}
|
||||||
|
value={fieldValue} onChange={handleChange}/>
|
||||||
|
: value.controls === 'TEXTAREA' ?
|
||||||
|
<textarea name={fieldName} rows={5}
|
||||||
|
style={{resize: 'none'}} type="text"
|
||||||
|
className="form-control" id={key}
|
||||||
|
value={fieldValue}
|
||||||
|
onChange={handleChange}/>
|
||||||
|
: value.controls === 'SELECT_NO_YES' ?
|
||||||
|
// <NoYesBooleanDropdown name={fieldName} value={fieldValue} onChange={handleChange} />
|
||||||
|
<div className='position-relative'>
|
||||||
|
<select onChange={handleChange}
|
||||||
|
name={fieldName} value={fieldValue}
|
||||||
|
className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
<option value='0'>No</option>
|
||||||
|
<option value='1'>Yes</option>
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown
|
||||||
|
className='position-absolute w-auto'
|
||||||
|
style={{
|
||||||
|
top: '50%',
|
||||||
|
right: '2px',
|
||||||
|
transform: 'translateY(-50%)'
|
||||||
|
}}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group col-md-12">
|
:
|
||||||
<label htmlFor="title1">Title</label>
|
null
|
||||||
<input type="text" className="form-control" id="title1"
|
}
|
||||||
value="Marketing expert" />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group col-md-12">
|
)
|
||||||
<label htmlFor="phone1">Phone Number</label>
|
}
|
||||||
<input type="text" className="form-control" id="phone1"
|
)}
|
||||||
value="(01) 97 563 15613" />
|
</>
|
||||||
|
{reqStatus.message &&
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={reqStatus.error ? 'text-danger' : 'text-success'}>{reqStatus.message}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group col-md-12">
|
</>
|
||||||
<label htmlFor="email1">Email</label>
|
}
|
||||||
<input type="email" className="form-control" id="email1"
|
<div className="form-group col-md-12" style={{textAlign: 'right'}}>
|
||||||
value="alicewilliams@gmail.com" />
|
<button onClick={handleSubmit} type="button" className="btn btn-primary"
|
||||||
|
disabled={submitSettings.isPending}>{submitSettings.isPending ? 'Loading...' : 'Update'}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="add1">Address</label>
|
|
||||||
<input type="text" className="form-control" id="add1"
|
|
||||||
value="17504 Carlton Cuevas Rd, Gulfport, MS, 39503" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="add2">Address 2</label>
|
|
||||||
<input type="text" className="form-control" id="add2"
|
|
||||||
value="1234 North Avenue Luke Lane, South Bend, IN 360001" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<button type="submit" className="btn btn-primary">Update Information
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
export default GeneralTab
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import React, {memo} from 'react'
|
||||||
|
|
||||||
|
export default function NoYesBooleanDropdown(name, value, onChange) {
|
||||||
|
return (
|
||||||
|
<select onChange={onChange} name={name} value={value} className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
<option value='0'>No</option>
|
||||||
|
<option value='1'>Yes</option>
|
||||||
|
</select>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import React, { memo, useMemo, useState } from 'react'
|
||||||
|
import GeneralTab from './GeneralTab'
|
||||||
|
import { getSettingsData, getMyProductConfig } from '../../../services/services';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
||||||
|
import TemplateConfigure from './TemplateConfigure';
|
||||||
|
|
||||||
|
const Settings = memo(({productData}) => {
|
||||||
|
|
||||||
|
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
|
||||||
|
|
||||||
|
const {data:configData, isFetching:configIsFetching, configIsError, error:configError} = useQuery({
|
||||||
|
queryKey: queryKeys.myProductConfig,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getMyProductConfig(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0,
|
||||||
|
})
|
||||||
|
const settingsConfig = configData?.data?.settings_items
|
||||||
|
// console.log('CONFIG DATA...', settingsConfig)
|
||||||
|
// console.log('configData', configData?.data?.subscription_template)
|
||||||
|
|
||||||
|
const [fieldsChanged, setFieldsChanged] = useState(false)
|
||||||
|
|
||||||
|
// const [activeTab, setActiveTab] = useState(Object.entries(settingsConfig)[0][1]?.controls)
|
||||||
|
const [activeTab, setActiveTab] = useState(null)
|
||||||
|
|
||||||
|
const handleChangeTab = (value) => {
|
||||||
|
// if(fieldsChanged){
|
||||||
|
// const proceed = confirm('Continue without saving changes')
|
||||||
|
// if(proceed){
|
||||||
|
// setActiveTab(value)
|
||||||
|
// setFieldsChanged(false)
|
||||||
|
// }
|
||||||
|
// }else{
|
||||||
|
// setActiveTab(value)
|
||||||
|
// }
|
||||||
|
setActiveTab(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.settingsData,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getSettingsData(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0,
|
||||||
|
enabled: settingsConfig ? true : false
|
||||||
|
})
|
||||||
|
|
||||||
|
const settingsData = {data: data?.data?.settings, isFetching, isError, error}
|
||||||
|
// console.log('data', settingsData)
|
||||||
|
|
||||||
|
const sortedSettingsConfig = sortObjectByListOrder(settingsConfig ? settingsConfig : {}) // SORTED SETTINGSCONFIG
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{configIsFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: configIsError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{configError.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="d-flex">
|
||||||
|
<ul className="bg-body-secondary flex-column nav" role="tablist" style={{width: '25%', minHeight: '670px', maxHeight: '670px'}}>
|
||||||
|
<>
|
||||||
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
|
<li key={key} className="nav-item">
|
||||||
|
<p className={`text-black nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show bg-primary text-white'}`}
|
||||||
|
id={key}
|
||||||
|
// data-bs-toggle="pill"
|
||||||
|
// data-bs-target={`#${value.controls}`}
|
||||||
|
type="button"
|
||||||
|
// role="tab"
|
||||||
|
// aria-controls={value.controls}
|
||||||
|
// aria-selected="true"
|
||||||
|
onClick={()=>handleChangeTab(value.controls)}
|
||||||
|
>
|
||||||
|
{value.title}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
{configData?.data?.subscription_template &&
|
||||||
|
<li className="mt-auto nav-item">
|
||||||
|
<p className={`text-black nav-link ${(activeTab == 'config_temp') && 'active show bg-primary text-white'}`}
|
||||||
|
// data-bs-toggle="pill"
|
||||||
|
// data-bs-target={`#${value.controls}`}
|
||||||
|
type="button"
|
||||||
|
// role="tab"
|
||||||
|
// aria-controls={value.controls}
|
||||||
|
// aria-selected="true"
|
||||||
|
onClick={()=>handleChangeTab('config_temp')}
|
||||||
|
>
|
||||||
|
Configure Template
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
</ul>
|
||||||
|
<div className="p-3 tab-content" style={{width: '75%'}}>
|
||||||
|
<>
|
||||||
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
|
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||||
|
// id={value.controls} role="tabpanel"
|
||||||
|
// aria-labelledby={key}
|
||||||
|
>
|
||||||
|
<GeneralTab tabKey={key} name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className={`tab-pane fade ${(activeTab == 'config_temp') && 'active show'}`}
|
||||||
|
>
|
||||||
|
<TemplateConfigure productData={productData} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Settings
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
import React, {memo} from 'react'
|
||||||
|
import getImage from "../../../utils/getImage";
|
||||||
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import {getProductTemplateData, activateTemplate} from '../../../services/services';
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import siteLinks from "../../../links/siteLinks";
|
||||||
|
|
||||||
|
const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.productTemplateData,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getProductTemplateData(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateResponse = templateData?.data
|
||||||
|
const currentTemUID = templateResponse?.current_template_uid
|
||||||
|
const templates = templateResponse?.templates
|
||||||
|
const custom_template_name = templateResponse?.custom_template_name
|
||||||
|
|
||||||
|
// console.log('data Template', templateResponse)
|
||||||
|
console.log("Page data == ", data)
|
||||||
|
|
||||||
|
const handleActivateTemplate = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return activateTemplate(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res?.data?.resultCode != '0') {
|
||||||
|
throw new Error(res.data.resultDescription)
|
||||||
|
}
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.settingsData],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleActivateTemplate.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (tem_uid) => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
|
template_uid: tem_uid
|
||||||
|
}
|
||||||
|
// console.log(reqData)
|
||||||
|
handleActivateTemplate.mutate(reqData)
|
||||||
|
}
|
||||||
|
if (custom_template_name && custom_template_name != '') {
|
||||||
|
// This implies we have a custom template , just return here
|
||||||
|
return <>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div
|
||||||
|
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||||
|
style={{backgroundColor: '#F2FAF7'}}>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
|
||||||
|
<img className='' style={{width: '200px'}}
|
||||||
|
src={getImage('custom-template.png')}
|
||||||
|
alt='mail-alert'/>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginTop: '20px'}}>This product is using a custom template named <span
|
||||||
|
style={{color: 'darkred'}}>“{custom_template_name}”</span> .</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="page-account-form">
|
||||||
|
<div className="p-0">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||||
|
<>
|
||||||
|
{!templates?.length ?
|
||||||
|
<p>No data Found</p>
|
||||||
|
:
|
||||||
|
templates.map(template => (
|
||||||
|
<div key={template.template_uid} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="text-center p-2">
|
||||||
|
<div className="mb-2">
|
||||||
|
<img src={getImage('file-icon/svg.png')}
|
||||||
|
alt={template.title}/>
|
||||||
|
</div>
|
||||||
|
<h4 className="mb-0">{template.title}</h4>
|
||||||
|
{currentTemUID == template.template_uid ?
|
||||||
|
<button className="btn btn-light"
|
||||||
|
disabled={true}>Active</button>
|
||||||
|
:
|
||||||
|
<button onClick={() => handleSubmit(template.template_uid)}
|
||||||
|
className="btn btn-primary">Activate</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||||
|
<div key={key} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="text-center p-2">
|
||||||
|
<div className="mb-2">
|
||||||
|
<img src={getImage(value.banner)} alt={value.title} />
|
||||||
|
</div>
|
||||||
|
<h4 className="mb-0">{value.title}</h4>
|
||||||
|
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))} */}
|
||||||
|
</>
|
||||||
|
|
||||||
|
<div className="col-12">
|
||||||
|
<>
|
||||||
|
{handleActivateTemplate.isPending ?
|
||||||
|
<p className={'text-center '}>loading...</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isError ?
|
||||||
|
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isSuccess ?
|
||||||
|
<p className={'text-center text-success'}>Templated activated
|
||||||
|
successfully</p>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
export default SiteTemplateSelector
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import React, {memo, useState} from 'react'
|
||||||
|
import getImage from "../../../utils/getImage";
|
||||||
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import {getTemplateConfig} from '../../../services/services';
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import siteLinks from "../../../links/siteLinks";
|
||||||
|
import UploadModal from './UploadModal';
|
||||||
|
|
||||||
|
const TemplateConfigure = ({productData}) => {
|
||||||
|
|
||||||
|
const [selectedSectionDetails, setSelectedSectionDetails] = useState({})
|
||||||
|
|
||||||
|
// /panel/myproduct/template-config
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.myTemplateConfig,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getTemplateConfig(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateResponse = templateData?.data
|
||||||
|
const templateImages = templateResponse?.template_images?.data;
|
||||||
|
// debugger;
|
||||||
|
console.log("templateResponse", templateResponse);
|
||||||
|
// const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||||
|
// const color_styles = templateResponse?.color_styles
|
||||||
|
// const custom_template_name = templateResponse?.custom_template_name
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className="card card-statistics">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title"
|
||||||
|
style={{textTransform: 'none'}}>{templateResponse?.template_name}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h4>Image List</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul className="list-unstyled">
|
||||||
|
{templateImages && templateImages.map(
|
||||||
|
(item) => {
|
||||||
|
const currImage = item?.default_val;
|
||||||
|
return (
|
||||||
|
<li className="media">
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
padding: '5px',
|
||||||
|
backgroundColor: 'aliceblue',
|
||||||
|
margin: '2px',
|
||||||
|
maxHeight: '150px'
|
||||||
|
}}>
|
||||||
|
<div className='d-flex justify-content-center align-items-center' style={{padding: '6px', width: '120px', height: '100px'}}>
|
||||||
|
<img className="mb-xxs-0 img-fluid"
|
||||||
|
style={{height: 'auto', maxHeight: '100px'}}
|
||||||
|
src={currImage} alt="image"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="media-body" style={{padding: '2px'}}>
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}>
|
||||||
|
<div style={{textAlign: 'right',width: '100%'}}></div>
|
||||||
|
{/* [Change Image] */}
|
||||||
|
<label onClick={()=>setSelectedSectionDetails(item)} className='w-100 text-end' data-bs-toggle="modal" data-bs-target="#verticalCenter" style={{cursor: 'pointer'}}>[Change Image]</label>
|
||||||
|
{/* <input id={item?.id} name={item?.id} className="d-none form-control form-control-sm" type="file" onChange={handleFileChange}/> */}
|
||||||
|
<div>
|
||||||
|
<h5 className="mt-0 mb-1">{item?.name}</h5>
|
||||||
|
{item?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
|
||||||
|
} </div>
|
||||||
|
<UploadModal productId={productData?.product_id} selectedSectionDetails={selectedSectionDetails} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TemplateConfigure
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import {Form, Formik} from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import {useMutation} from '@tanstack/react-query';
|
||||||
|
import {setExternalURL} from '../../../services/services';
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
url: Yup.string().required("URL is required").matches(/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/, 'Must be like: https://example.mysite.com'),
|
||||||
|
})
|
||||||
|
|
||||||
|
// const initialValues = {
|
||||||
|
// url: '',
|
||||||
|
// };
|
||||||
|
|
||||||
|
const URLConfiguration = ({productData}) => {
|
||||||
|
|
||||||
|
const [externalURLChanged, setExternalURLChanged] = useState(true)
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
url: productData?.external_url || '',
|
||||||
|
};
|
||||||
|
|
||||||
|
let defaultUrl = 'https://' + productData?.internal_url
|
||||||
|
let externalUrl = productData?.external_url
|
||||||
|
|
||||||
|
const handleExternalURLChanged = (e) => {
|
||||||
|
if(e.target.value == externalUrl){
|
||||||
|
setExternalURLChanged(true)
|
||||||
|
}else{
|
||||||
|
setExternalURLChanged(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API to set url
|
||||||
|
const setURL = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return setExternalURL(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res.data.resultCode != '0') {
|
||||||
|
// throw({message: res?.data?.resultDescription})
|
||||||
|
throw({message: 'Something went wrong!'})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setURL.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
// onError: (err) => {
|
||||||
|
// console.log('err', err)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (values) => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
subscription_uid: productData?.subscription_uid,
|
||||||
|
external_url: values.url
|
||||||
|
}
|
||||||
|
setURL.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/*<div className="card-body">*/}
|
||||||
|
{/* <div className="form-group">*/}
|
||||||
|
{/* /!*<label htmlFor="exampleInputEmail1">Email address</label>*!/*/}
|
||||||
|
{/* <input type="email" className="form-control"*/}
|
||||||
|
{/* aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} />*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className='w-full'>
|
||||||
|
<div className="card card-statistics" style={{backgroundColor: '#b6e5ef'}}>
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title" style={{textTransform: 'none'}}>Set your own URL</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="exampleInputEmail1">Enter your full URL <span
|
||||||
|
className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label>
|
||||||
|
<input value={props.values.url} onChange={(e)=>{props.handleChange(e); handleExternalURLChanged(e)}} type="text"
|
||||||
|
className="form-control" id="url" aria-describedby="url"
|
||||||
|
placeholder="https://example.mysite.com"/>
|
||||||
|
</div>
|
||||||
|
<div style={{width: '100%', textAlign: 'right'}}>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={setURL.isPending || externalURLChanged}
|
||||||
|
className="btn btn-primary"
|
||||||
|
>
|
||||||
|
{setURL.isPending ? 'Loading...' : 'Submit'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{setURL.error &&
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{setURL.error.message}</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{setURL.isSuccess &&
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-success'>{'Completed successfully'}</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div style={{backgroundColor: '#94b8c0', borderRadius: '10px', padding: '10px'}}>
|
||||||
|
Final steps to configure your URL:<br/>
|
||||||
|
DNS:<br/>
|
||||||
|
DNS:<br/>
|
||||||
|
DNS:<br/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default URLConfiguration
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import {getMediaFileList, templateMediaSet} from '../../../services/services';
|
||||||
|
|
||||||
|
export default function UploadModal({productId, selectedSectionDetails}) {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [selectedFile, setSelectedFile] = useState('')
|
||||||
|
|
||||||
|
const handleSelectedFile = (file_uid) => {
|
||||||
|
// if(selectedFile.length && selectedFile.includes(file_uid)){
|
||||||
|
// let indexOfItem = selectedFile.indexOf(file_uid)
|
||||||
|
// let oldFiles = [...selectedFile]
|
||||||
|
// oldFiles.splice(indexOfItem, 1)
|
||||||
|
// setSelectedFile(oldFiles)
|
||||||
|
// }else{
|
||||||
|
// setSelectedFile(prev => [...prev, file_uid])
|
||||||
|
// }
|
||||||
|
setSelectedFile(file_uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalRef = useRef(null)
|
||||||
|
|
||||||
|
const dismissModal = () => {
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
body.removeAttribute('style')
|
||||||
|
// body.classList.toggle('modal-open')
|
||||||
|
|
||||||
|
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||||
|
modalBackdrop.forEach(item => {
|
||||||
|
if (item) {
|
||||||
|
item.remove();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const modal = Modal.getInstance(modalRef.current);
|
||||||
|
modal && modal.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeTemplateMediaSet = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
if(!fields.file_uid){
|
||||||
|
throw({message: 'Please select a file first!'})
|
||||||
|
}
|
||||||
|
return templateMediaSet(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
// console.log('res', res.data)
|
||||||
|
if(res.data.resultCode != '0'){
|
||||||
|
throw({message: res?.data?.resultDescription})
|
||||||
|
}
|
||||||
|
setSelectedFile('')
|
||||||
|
dismissModal() // to close modal
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.myTemplateConfig],
|
||||||
|
// type: 'active',
|
||||||
|
// exact: true,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(()=>{
|
||||||
|
changeTemplateMediaSet.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleUpload = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
|
uid: localStorage.getItem("uid"), // USER UID
|
||||||
|
product_id: productId,
|
||||||
|
file_uid: selectedFile,
|
||||||
|
image_id: selectedSectionDetails?.id
|
||||||
|
};
|
||||||
|
// console.log('reqData', reqData)
|
||||||
|
changeTemplateMediaSet.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.my_files,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return getMediaFileList(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mediaFileList = data?.data
|
||||||
|
// console.log('mediaFileList', mediaFileList) //file_list
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Vertical Center Modal */}
|
||||||
|
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
|
||||||
|
<div className="modal-50 modal-dialog modal-dialog-centered modal-50" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
<h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">Select New Picture</h5>
|
||||||
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className='row g-5 justify-content-center'>
|
||||||
|
{mediaFileList?.file_list?.length ?
|
||||||
|
<>
|
||||||
|
{mediaFileList?.file_list?.map(item => {
|
||||||
|
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
|
||||||
|
return(
|
||||||
|
<div onClick={()=>handleSelectedFile(item?.file_uid)} className={`p-3 text-center col-4`} style={{cursor: 'pointer'}}>
|
||||||
|
<div className={`p-3 ${(selectedFile == item?.file_uid) && 'bg-light'}`} style={{Height: '250px'}}>
|
||||||
|
<img key={item?.file_uid} className="img-fluid" style={{}} src={file_url} alt='file-image' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<p>No File(s) found!</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{changeTemplateMediaSet.error &&
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{changeTemplateMediaSet.error.message}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
{changeTemplateMediaSet.isSuccess &&
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-success'>{'subscription is successful'}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
{selectedFile &&
|
||||||
|
<button type="button" className="btn btn-primary" disabled={changeTemplateMediaSet?.isPending || changeTemplateMediaSet?.isSuccess} onClick={handleUpload}>{changeTemplateMediaSet?.isPending ? 'Applying...' : changeTemplateMediaSet?.isSuccess ? 'Applied' : 'Apply'}</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* END of Vertical Center Modal */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import React, {memo, useState} from 'react'
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { pageSettings } from "../../../services/services";
|
||||||
|
import SiteTemplateSelector from './SiteTemplateSelector';
|
||||||
|
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
|
||||||
|
import { IoMdArrowDropdown } from 'react-icons/io';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
|
||||||
|
const GeneralTab = memo(({name='Full Name', data, isCustom, productData, backendValues, setFieldsChanged}) =>{
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [reqStatus, setReqStatus] = useState({error: null, message: ''})
|
||||||
|
|
||||||
|
const fieldData = {}
|
||||||
|
Object.entries(data)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
|
||||||
|
fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
|
||||||
|
})
|
||||||
|
backendValues.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
|
||||||
|
fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('fieldData', fieldData)
|
||||||
|
|
||||||
|
const [fields, setFields] = useState(fieldData)
|
||||||
|
|
||||||
|
const handleChange = ({target:{name, value}}) => {
|
||||||
|
setFields(prev => ({...prev, [name]:value}))
|
||||||
|
setFieldsChanged(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitSettings = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return pageSettings(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if(res?.data?.resultCode != '0'){
|
||||||
|
return setReqStatus({error: true, message: 'Unable to complete, try again later'})
|
||||||
|
}
|
||||||
|
setFieldsChanged(false)
|
||||||
|
setReqStatus({error: false, message: 'Completed successfully'})
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
setReqStatus({error: true, message: 'Unable to complete, try again later'})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.settingsData],
|
||||||
|
})
|
||||||
|
setTimeout(()=>{
|
||||||
|
setReqStatus({error: null, message: ''})
|
||||||
|
},3000)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
|
settings : {
|
||||||
|
...fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log('formInfo', reqData)
|
||||||
|
submitSettings.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCustom === true){
|
||||||
|
return <SiteTemplateSelector name={name} data={data} isCustom={isCustom} productData={productData} />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page-account-form">
|
||||||
|
<div className="p-0" style={{ minHeight: '500px'}}>
|
||||||
|
|
||||||
|
<form id='tab_form'>
|
||||||
|
<div className="form-row">
|
||||||
|
<>
|
||||||
|
{Object.entries(data)?.map(([key, value]) => {
|
||||||
|
let fieldName = value.name.toLowerCase().replaceAll(" ", "_")
|
||||||
|
let fieldValue = fields[value.name.toLowerCase().replaceAll(" ", "_")]
|
||||||
|
return (
|
||||||
|
<div key={key} className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">{value.name}</label>
|
||||||
|
{value.controls == 'TEXT' ?
|
||||||
|
<input name={fieldName} type="text" className="form-control" id={key} value={fieldValue} onChange={handleChange} />
|
||||||
|
:value.controls == 'TEXTAREA' ?
|
||||||
|
<textarea name={fieldName} rows={5} style={{resize: 'none'}} type="text" className="form-control" id={key} value={fieldValue} onChange={handleChange} />
|
||||||
|
: value.controls == 'SELECT_NO_YES' ?
|
||||||
|
// <NoYesBooleanDropdown name={fieldName} value={fieldValue} onChange={handleChange} />
|
||||||
|
<div className='position-relative'>
|
||||||
|
<select onChange={handleChange} name={fieldName} value={fieldValue} className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
<option value='0'>No</option>
|
||||||
|
<option value='1'>Yes</option>
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{top: '50%', right: '2px', transform: 'translateY(-50%)'}} />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
{reqStatus.message &&
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={reqStatus.error ? 'text-danger' : 'text-success'}>{reqStatus.message}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
<div className="form-group col-md-12" style={{textAlign:'right'}}>
|
||||||
|
<button onClick={handleSubmit} type="button" className="btn btn-primary" disabled={submitSettings.isPending}>{submitSettings.isPending ? 'Loading...' : 'Update'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
export default GeneralTab
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import React, { memo, useMemo, useState } from 'react'
|
||||||
|
import GeneralTab from './GeneralTab'
|
||||||
|
import { getSettingsData, getMyProductConfig } from '../../../services/services';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
const Settings = memo(({productData}) => {
|
||||||
|
|
||||||
|
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
|
||||||
|
|
||||||
|
const {data:configData, isFetching:configIsFetching, configIsError, error:configError} = useQuery({
|
||||||
|
queryKey: queryKeys.myProductConfig,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getMyProductConfig(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const settingsConfig = configData?.data?.settings_items
|
||||||
|
// console.log('CONFIG DATA...', settingsConfig)
|
||||||
|
|
||||||
|
const dataFields ={
|
||||||
|
site_title: { name: 'Title', controls: 'TEXT', active: true },
|
||||||
|
site_description: { name: 'Description', controls: 'TEXTAREA', active: true },
|
||||||
|
site_logo_text: { name: 'Logo Text', controls: 'TEXT', active: true },
|
||||||
|
site_contact_email: { name: 'Email', controls: 'TEXT', active: true },
|
||||||
|
site_contact_phone: { name: 'Phone', controls: 'TEXT', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const socialFields ={
|
||||||
|
facebook: { name: 'Facebook', controls: 'TEXT', active: true },
|
||||||
|
twitter: { name: 'Twitter', controls: 'TEXT', active: true },
|
||||||
|
youtube: { name: 'Youtube', controls: 'TEXT', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const homeFields ={
|
||||||
|
banner_text: { name: 'Banner Text', controls: 'TEXT', active: true },
|
||||||
|
banner_description: { name: 'Banner Description', controls: 'TEXTAREA', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const footerFields ={
|
||||||
|
footer_description: { name: 'Footer Description', controls: 'TEXTAREA', active: true },
|
||||||
|
boolean_footer_show_email: { name: 'Show email in footer', controls: 'SELECT_NO_YES', active: true },
|
||||||
|
boolean_footer_show_made_by: { name: 'Show made by in footer', controls: 'SELECT_NO_YES', active: true },
|
||||||
|
boolean_footer_show_socials: { name: 'Show social in footer', controls: 'SELECT_NO_YES', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const aboutFields ={
|
||||||
|
about_title: { name: 'About Title', controls: 'TEXT', active: true },
|
||||||
|
about_description: { name: 'About Details', controls: 'TEXTAREA', active: true },
|
||||||
|
about_extra_1: { name: 'Extra About us', controls: 'TEXTAREA', active: true },
|
||||||
|
about_extra_2: { name: 'More About us', controls: 'TEXTAREA', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateData = {
|
||||||
|
template_16 : { title: 'Template Name-16', template_id: '02af24fd-2b1a-46ed-af21-87018e726408', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_22 : { title: 'Template Name-22', template_id: '8b296894-42e4-4f2e-abd1-7c2a38d6e07b', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_47 : { title: 'Template Name-47', template_id: 'ef2ffa1c-9272-42cd-9d33-0e614047b4f8', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_25 : { title: 'Template Name-25', template_id: 'b3a7ba31-dc47-4a40-a5cc-fd1ff27d6b78', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_49 : { title: 'Template Name-49', template_id: '60959c69-6672-4f69-a006-eeb7d210e605', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_27 : { title: 'Template Name-27', template_id: 'e4acb98a-c584-45f2-bece-af677dcf0a1f', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_51 : { title: 'Template Name-51', template_id: '975ee42e-3169-4978-92d7-d28e7e2ac014', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
template_9 : { title: 'Template Name-9', template_id: 'fc8f0738-6500-4775-9895-2047cd275302', banner: 'file-icon/svg.png', active: '' },
|
||||||
|
}
|
||||||
|
|
||||||
|
const contactFields ={
|
||||||
|
contact_title : { name: 'Contact Title', controls: 'TEXT', active: true },
|
||||||
|
contact_introduction: { name: 'Extra Introduction', controls: 'TEXTAREA', active: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsObject = useMemo(()=>{
|
||||||
|
return {
|
||||||
|
settings: { title: 'Settings', controls: 'settings', active: 'active show' , custom: false, data: dataFields},
|
||||||
|
home_tab: { title: 'Home Page', controls: 'home', active: '', custom: false, data: homeFields},
|
||||||
|
footer_tab: { title: 'Footer', controls: 'footer', active: '', custom: false, data: footerFields },
|
||||||
|
about_tab: { title: 'About Page', controls: 'about', active: '', custom: false, data: aboutFields },
|
||||||
|
contact_tab: { title: 'Contact Page', controls: 'contact', active: '', custom: false, data: contactFields },
|
||||||
|
social_tab: { title: 'Socials', controls: 'social', active: '', custom: false, data: socialFields },
|
||||||
|
template_tab: { title: 'Template', controls: 'template', active: '', custom: true, data: templateData },
|
||||||
|
color_scheme_tab: { title: 'Color Scheme', controls: 'color-scheme', active: '', custom: true, data: {} },
|
||||||
|
};
|
||||||
|
},[])
|
||||||
|
|
||||||
|
|
||||||
|
const [fieldsChanged, setFieldsChanged] = useState(false)
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState(Object.entries(settingsObject)[0][1]?.controls)
|
||||||
|
|
||||||
|
const handleChangeTab = (value) => {
|
||||||
|
// if(fieldsChanged){
|
||||||
|
// const proceed = confirm('Continue without saving changes')
|
||||||
|
// if(proceed){
|
||||||
|
// setActiveTab(value)
|
||||||
|
// setFieldsChanged(false)
|
||||||
|
// }
|
||||||
|
// }else{
|
||||||
|
// setActiveTab(value)
|
||||||
|
// }
|
||||||
|
setActiveTab(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.settingsData,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
|
}
|
||||||
|
return getSettingsData(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const settingsData = data?.data?.settings
|
||||||
|
// console.log('data', settingsData)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="tab tab-vertical">
|
||||||
|
<ul className="nav nav-tabs" role="tablist">
|
||||||
|
<>
|
||||||
|
{Object.entries(settingsObject).map(([key, value]) => (
|
||||||
|
<li key={key} className="nav-item">
|
||||||
|
<a className={`nav-link ${activeTab == value.controls && 'active show'}`}
|
||||||
|
id={key}
|
||||||
|
// data-bs-toggle="pill"
|
||||||
|
// data-bs-target={`#${value.controls}`}
|
||||||
|
type="button"
|
||||||
|
// role="tab"
|
||||||
|
// aria-controls={value.controls}
|
||||||
|
// aria-selected="true"
|
||||||
|
onClick={()=>handleChangeTab(value.controls)}
|
||||||
|
>
|
||||||
|
{value.title}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
</ul>
|
||||||
|
<div className="tab-content">
|
||||||
|
<>
|
||||||
|
{Object.entries(settingsObject).map(([key, value]) => (
|
||||||
|
<div key={key} className={`tab-pane fade ${activeTab == value.controls && 'active show'}`}
|
||||||
|
// id={value.controls} role="tabpanel"
|
||||||
|
// aria-labelledby={key}
|
||||||
|
>
|
||||||
|
<GeneralTab name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Settings
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
// import { useLocation } from "react-router-dom";
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import {useMutation, useQuery} from "@tanstack/react-query";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
import {IoMdArrowDropdown} from "react-icons/io";
|
||||||
|
import {completeProfile, getCommonPractice} from '../../services/services';
|
||||||
|
import siteLinks from "../../links/siteLinks";
|
||||||
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
|
import {updateUserDetails} from "../../store/UserDetails";
|
||||||
|
import {useDispatch} from "react-redux";
|
||||||
|
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
practice: Yup.string().required("Required"),
|
||||||
|
specialization: Yup.string().when('practice', {
|
||||||
|
is: (value) => typeof value === 'string' && value.trim().length > 0,
|
||||||
|
then: (schema) => schema.required('Required'),
|
||||||
|
otherwise: (schema) => schema,
|
||||||
|
}),
|
||||||
|
introduction: Yup.string().min(1, "Minimum 1 character").max(50, "Maximum 50 characters"),
|
||||||
|
url_name: Yup.string().min(6, "Minimum 6 characters").max(16, "Maximum 16 characters").required("Required").matches(
|
||||||
|
/^[a-zA-Z0-9]+$/, // Regex for alphanumeric characters
|
||||||
|
'Must contain only alphanumeric characters' // Custom error message
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default function ProfileCompleteCom() {
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const {state: {redirectLink}} = useLocation()
|
||||||
|
|
||||||
|
const [practices, setPractices] = useState([])
|
||||||
|
const [specialties, setSpecialties] = useState([])
|
||||||
|
|
||||||
|
const [initialValues, setInitialValues] = useState({
|
||||||
|
practice: '',
|
||||||
|
specialization: '',
|
||||||
|
introduction: '',
|
||||||
|
url_name: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleUpdateSpecialties = (e) => {
|
||||||
|
setInitialValues(prev => ({...prev, specialization: ''}))
|
||||||
|
const specialtiesArr = practices.filter(item => item.practice == e.target.value)[0]?.specialties
|
||||||
|
setSpecialties(specialtiesArr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
const {practice, specialization, url_name} = fields
|
||||||
|
if (!practice || !specialization || !url_name) {
|
||||||
|
throw new Error('Please Select both Practice, Specialization and Enter URL_Name')
|
||||||
|
}
|
||||||
|
return completeProfile(fields)
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
mutation.reset()
|
||||||
|
}, 4000)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res.data.resultCode != '0') {
|
||||||
|
throw({message: res?.data?.resultDescription})
|
||||||
|
}
|
||||||
|
dispatch(updateUserDetails({profile_completed: res?.data?.profile_completed}));
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate(redirectLink)
|
||||||
|
}, 2000)
|
||||||
|
// console.log('res', res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const commonPractices = useMutation({ // FUNCTION TO GET COMMON PRACTICES
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return getCommonPractice(fields)
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
setPractices([])
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (!res?.data) {
|
||||||
|
return setPractices([])
|
||||||
|
}
|
||||||
|
let returnPractices = Object.entries(res?.data).filter(([key, value]) => typeof value == 'object')?.map(item => item[1])
|
||||||
|
setPractices(returnPractices)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleCompleteProfile = (values) => { // FUNCTION TO COMPLETE PROFILE
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
...values
|
||||||
|
}
|
||||||
|
mutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
commonPractices.mutate(reqData)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <>
|
||||||
|
|
||||||
|
<BreadcrumbComBS title='Tell us more about your practice.' paths={['Dashboard', 'Profile']}/>
|
||||||
|
|
||||||
|
{commonPractices?.isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: commonPractices?.isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{commonPractices?.error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="row pt-1">
|
||||||
|
<div className="col-md-6 m-b-30">
|
||||||
|
<div className="card card-statistics h-100 mb-0" style={{borderRadius: '10px'}}>
|
||||||
|
{/* <div className="card-header d-flex align-items-center justify-content-between">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">My Product URLs</h4>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
{/* <div style={{minHeight: '400px'}}></div> */}
|
||||||
|
<div className="card-body">
|
||||||
|
<div className='h-100 row flex-column'>
|
||||||
|
{/* <div className="row"> */}
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={handleCompleteProfile}
|
||||||
|
enableReinitialize={true}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className='mt-2'>
|
||||||
|
<>
|
||||||
|
<div className="">
|
||||||
|
<div className="form-group position-relative">
|
||||||
|
<label className={`text-black fw-bold control-label`}>Practice : <span className="text-danger">{(props.errors.practice && props.touched.practice) && props.errors.practice}</span></label>
|
||||||
|
<div className="position-relative">
|
||||||
|
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
{practices.map((practice, index)=>(
|
||||||
|
<option key={index} value={practice.practice}>{practice.practice}</option>
|
||||||
|
))}
|
||||||
|
</select> */}
|
||||||
|
<select
|
||||||
|
onChange={(e) => {props.handleChange(e); props.setFieldValue('specialization', ''); handleUpdateSpecialties(e)}}
|
||||||
|
name='practice'
|
||||||
|
value={props.values.practice} className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
{practices.map((practice, index) => (
|
||||||
|
<option key={index}
|
||||||
|
value={practice.practice}>{practice.practice}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||||
|
top: '50%',
|
||||||
|
right: '2px',
|
||||||
|
transform: 'translateY(-50%)'
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className={`text-black fw-bold control-label`}>Your
|
||||||
|
Specialization : <span className="text-danger">{(props.errors.specialization && props.touched.specialization) && props.errors.specialization}</span></label>
|
||||||
|
<div className="position-relative">
|
||||||
|
<select onChange={props.handleChange} name='specialization'
|
||||||
|
value={props.values.specialization}
|
||||||
|
className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
{specialties.map((specialty, index) => (
|
||||||
|
<option key={index} value={specialty}>{specialty}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||||
|
top: '50%',
|
||||||
|
right: '2px',
|
||||||
|
transform: 'translateY(-50%)'
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<div className="form-group position-relative">
|
||||||
|
<label className={`text-black fw-bold control-label`}>Other General Information : <span className="text-danger">{(props.errors.introduction && props.touched.introduction) && props.errors.introduction}</span></label>
|
||||||
|
<textarea name='introduction' rows={5} style={{resize: 'none'}}
|
||||||
|
className="form-control" value={props.values.introduction}
|
||||||
|
onChange={props.handleChange}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<div className="form-group position-relativ'e">
|
||||||
|
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
|
||||||
|
{/* information for :</label>*/}
|
||||||
|
<div style={{
|
||||||
|
fontSize: '14px',
|
||||||
|
borderRadius: '10px',
|
||||||
|
backgroundColor: 'aliceblue',
|
||||||
|
fontWeight: 'bolder',
|
||||||
|
padding: '15px'
|
||||||
|
}}>
|
||||||
|
MERMS A.I. agents use the information supplied to help generate
|
||||||
|
useful entries for your product settings.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<div className="form-group position-relative">
|
||||||
|
<label className={`text-black fw-bold control-label`}>URL Name : <span className="text-danger">{(props.errors.url_name && props.touched.url_name) && props.errors.url_name}</span></label>
|
||||||
|
<div className="position-relative d-flex flex-column flex-xxl-row" style={{gap: '10px'}}>
|
||||||
|
{/* <select onChange={handlePracticeChange} name='url_name'
|
||||||
|
value={initialValues.url_name} className="form-control">
|
||||||
|
<option value=''>Select</option>
|
||||||
|
{practices.map((practice, index) => (
|
||||||
|
<option key={index}
|
||||||
|
value={practice.practice}>{practice.practice}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||||
|
top: '50%',
|
||||||
|
right: '2px',
|
||||||
|
transform: 'translateY(-50%)'
|
||||||
|
}}/> */}
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
onChange={props.handleChange} name='url_name'
|
||||||
|
value={props.values.url_name}
|
||||||
|
minLength={6}
|
||||||
|
maxLength={16}
|
||||||
|
/>
|
||||||
|
<p className="border-radius-10 p-2 border border-warning"
|
||||||
|
style={{fontSize: "1.0rem"}}>We use the URL Name to form part of
|
||||||
|
your default URL when we configure
|
||||||
|
a new URL for your products. You can always change your product
|
||||||
|
URL. <br/>
|
||||||
|
<b>Example : <span style={{color: 'red'}}>url_name</span>.product.mermsemr.com
|
||||||
|
</b>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{(mutation.isError || mutation.isSuccess) &&
|
||||||
|
<>
|
||||||
|
<div className="">
|
||||||
|
<p className={`${mutation.isSuccess ? 'text-success' : 'text-danger'}`}>{mutation.isSuccess ? 'Completed successfully, redirecting...' : mutation.error.message}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="mt-auto text-end">
|
||||||
|
<button type='submit'
|
||||||
|
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Continue'}</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
{/* </div> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-6 m-b-30">
|
||||||
|
<div className="text-center img-block left-column wow fadeInRight">
|
||||||
|
<img className="img-fluid" src={getImage('tell-us-more.png')} alt="content-image"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {getPaymentReports} from "../../services/services";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
|
||||||
|
export default function PaymentReportTable() {
|
||||||
|
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: [...queryKeys.payment_report, page],
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
page
|
||||||
|
}
|
||||||
|
return getPaymentReports(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const paymentReportData = data?.data?.payment || []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 m-b-30">
|
||||||
|
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||||
|
<div className="page-title mb-2 mb-sm-0">
|
||||||
|
<h4>Payments Report</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="col-lg-12">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="export-table-wrapper table-responsive">
|
||||||
|
<table id="export-table" className="table table-bordered">
|
||||||
|
<thead className="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Added</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{paymentReportData.length > 0 ? paymentReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.option_name}</td>
|
||||||
|
<td>{item?.currency}{item?.amount}</td>
|
||||||
|
<td>{item?.status}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {getProductReports} from "../../services/services";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
|
||||||
|
export default function ProductReportTable() {
|
||||||
|
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: [...queryKeys.product_report, page],
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
page
|
||||||
|
}
|
||||||
|
return getProductReports(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const productReportData = data?.data?.product || []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 m-b-30">
|
||||||
|
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||||
|
<div className="page-title mb-2 mb-sm-0">
|
||||||
|
<h4>Products Report</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="col-lg-12">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="export-table-wrapper table-responsive">
|
||||||
|
<table id="export-table" className="table table-bordered">
|
||||||
|
<thead className="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Added</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{productReportData.length > 0 ? productReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.product_id}</td>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.product_name}</td>
|
||||||
|
<td>{item?.status}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,14 +1,99 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import {getReportsTopicsList} from "../../services/services";
|
||||||
|
import PaymentReportTable from "./PaymentReportTable";
|
||||||
|
import ProductReportTable from "./ProductReportTable";
|
||||||
|
import sortArrayByListOrder from "../../helpers/sortArrayByLIstOrder";
|
||||||
|
import SystemReportTable from "./SystemReportTable";
|
||||||
|
|
||||||
|
|
||||||
export default function Reports(){
|
export default function Reports() {
|
||||||
|
|
||||||
return(
|
const [activeTab, setActiveTab] = useState('payment')
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.topics,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return getReportsTopicsList(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const reportTopicList = data?.data?.topics?.topics;
|
||||||
|
|
||||||
|
const renderedTable = {
|
||||||
|
payment: <PaymentReportTable />,
|
||||||
|
product: <ProductReportTable />,
|
||||||
|
system: <SystemReportTable />
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedReportTopicList= sortArrayByListOrder(reportTopicList ? reportTopicList : []) // SORTED SETTINGSCONFIG
|
||||||
|
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']} />
|
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div className="card card-statistics" style={{minHeight: '500px'}}>
|
||||||
|
{/*<div className="card-header">*/}
|
||||||
|
{/* <div className="card-heading">*/}
|
||||||
|
{/* <h4 className="card-title"> Tab vertical </h4>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="tab tab-vertical">
|
||||||
|
|
||||||
|
{/* <!-- Tabs --> */}
|
||||||
|
<ul className="nav nav-tabs" id="myTab" role="tablist">
|
||||||
|
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<li key={index} className="nav-item" role="presentation" onClick={() => setActiveTab(item?.url)}>
|
||||||
|
<a className={`nav-link ${index == 0 && 'active'}`} id={`tab-${item?.url}`} href="#" data-bs-toggle="tab" data-bs-target={`#content-${item?.url}`} type="button" role="tab">
|
||||||
|
{item?.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{/* <!-- Tab Content --> */}
|
||||||
|
{/* <div className="tab-content">
|
||||||
|
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel" style={{minHeight: '400px'}}>
|
||||||
|
{renderedTable[item?.url]}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div> */}
|
||||||
|
<div className="tab-content">
|
||||||
|
<div className={`tab-pane fade show active`} style={{minHeight: '400px'}}>
|
||||||
|
{renderedTable[activeTab]}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {getSystemReports} from "../../services/services";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
|
||||||
|
export default function SystemReportTable() {
|
||||||
|
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: [...queryKeys.system_report, page],
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
page
|
||||||
|
}
|
||||||
|
return getSystemReports(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const systemReportData = data?.data?.system || []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 m-b-30">
|
||||||
|
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||||
|
<div className="page-title mb-2 mb-sm-0">
|
||||||
|
<h4>Systems Report</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="col-lg-12">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="export-table-wrapper table-responsive">
|
||||||
|
<table id="export-table" className="table table-bordered">
|
||||||
|
<thead className="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Added</th>
|
||||||
|
<th>Action Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{systemReportData.length > 0 ? systemReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.action_name}</td>
|
||||||
|
<td>{item?.status_description}</td>
|
||||||
|
<td>{item?.updated}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { updateLinks } from "../../services/services";
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
|
||||||
|
|
||||||
|
const linksValidationSchema = Yup.object().shape({
|
||||||
|
facebook_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
twitter_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
blogger_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
google_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
linked_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
website_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function LinksForm({data}) {
|
||||||
|
const modalRef = useRef(null)
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [intialData] = useState(data)
|
||||||
|
|
||||||
|
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||||
|
|
||||||
|
const dismissModal = () => {
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
body.removeAttribute('style')
|
||||||
|
// body.classList.toggle('modal-open')
|
||||||
|
|
||||||
|
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||||
|
modalBackdrop.forEach(item => {
|
||||||
|
if (item) {
|
||||||
|
item.remove();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const modal = Modal.getInstance(modalRef.current);
|
||||||
|
modal && modal.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// UPDATE LINKS MUTATION
|
||||||
|
const updateLinksMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return updateLinks(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if(res.data.resultCode != '0'){
|
||||||
|
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'En error occured'})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
dismissModal() //CLOSE MODAL HERE
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
})
|
||||||
|
updateLinksMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleSetInfoToUpdate = (values, helpers) => {
|
||||||
|
setInfoToUpdate(values)
|
||||||
|
var modal = new Modal(document.getElementById('modal_links'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const proceed = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
url_list: {...infoToUpdate}
|
||||||
|
}
|
||||||
|
// console.log(reqData)
|
||||||
|
updateLinksMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Formik
|
||||||
|
initialValues={intialData}
|
||||||
|
validationSchema={linksValidationSchema}
|
||||||
|
onSubmit={handleSetInfoToUpdate}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className=''>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="fb">Facebook URL: {(props.errors.facebook_url && props.touched.facebook_url) && <span className="text-danger">{props.errors.facebook_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="facebook_url" value={props.values?.facebook_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="tr">Twitter URL: {(props.errors.twitter_url && props.touched.twitter_url) && <span className="text-danger">{props.errors.twitter_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="twitter_url" value={props.values?.twitter_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="br">Blogger URL: {(props.errors.blogger_url && props.touched.blogger_url) && <span className="text-danger">{props.errors.blogger_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">{props.errors.google_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">{props.errors.linked_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">{props.errors.website_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div style={{textAlign: "right"}}>
|
||||||
|
<button type="submit" className="btn btn-primary">Update Links
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
{/* Vertical Center Modal */}
|
||||||
|
<div ref={modalRef} className="modal fade" id="modal_links" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||||
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||||
|
{(updateLinksMutation.error || updateLinksMutation.isSuccess) && (
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={`p-2 text-center ${updateLinksMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{updateLinksMutation.isSuccess ? 'Updated Successfully' : updateLinksMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" className="btn btn-primary" disabled={updateLinksMutation.isSuccess} onClick={proceed}>{updateLinksMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* END of Vertical Center Modal */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { updateProfile } from "../../services/services";
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
|
const profileValidationSchema = Yup.object().shape({
|
||||||
|
firstname: Yup.string().required("firstname is required"),
|
||||||
|
lastname: Yup.string().required("lastname is required"),
|
||||||
|
email: Yup.string().required("email is required"),
|
||||||
|
account_name: Yup.string().required("account name is required"),
|
||||||
|
phone: Yup.string().required("phone is required"),
|
||||||
|
full_address: Yup.string().required("full address is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function ProfileForm({data}) {
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const modalRef = useRef(null)
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [intialData] = useState(data)
|
||||||
|
|
||||||
|
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||||
|
|
||||||
|
const dismissModal = () => {
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
body.removeAttribute('style')
|
||||||
|
// body.classList.toggle('modal-open')
|
||||||
|
|
||||||
|
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||||
|
modalBackdrop.forEach(item => {
|
||||||
|
if (item) {
|
||||||
|
item.remove();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const modal = Modal.getInstance(modalRef.current);
|
||||||
|
modal && modal.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// UPDATE PROFILE MUTATION
|
||||||
|
const updateProfileMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return updateProfile(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if(res.data.resultCode != '0'){
|
||||||
|
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||||
|
}
|
||||||
|
const account_name = res?.data?.personal_data?.account_name
|
||||||
|
dispatch(updateUserDetails({ account_name }));
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
dismissModal() //CLOSE MODAL HERE
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
})
|
||||||
|
updateProfileMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleSetInfoToUpdate = (values, helpers) => {
|
||||||
|
delete values.email
|
||||||
|
delete values.country
|
||||||
|
setInfoToUpdate(values)
|
||||||
|
var modal = new Modal(document.getElementById('modal'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const proceed = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
...infoToUpdate
|
||||||
|
}
|
||||||
|
updateProfileMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Formik
|
||||||
|
initialValues={intialData}
|
||||||
|
validationSchema={profileValidationSchema}
|
||||||
|
onSubmit={handleSetInfoToUpdate}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className=''>
|
||||||
|
<div className="form-row">
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">First Name {(props.errors.firstname && props.touched.firstname) && <span className="text-danger">{props.errors.firstname}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="firstname" value={props.values?.firstname} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">Last Name {(props.errors.lastname && props.touched.lastname) && <span className="text-danger">{props.errors.lastname}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="lastname" value={props.values?.lastname} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">Account Name {(props.errors.account_name && props.touched.account_name) && <span className="text-danger">{props.errors.account_name}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="account_name" value={props.values?.account_name} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="phone1">Phone Number {(props.errors.phone && props.touched.phone) && <span className="text-danger">{props.errors.phone}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="phone" value={props.values?.phone} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="email1">Email {(props.errors.email && props.touched.email) && <span className="text-danger">{props.errors.email}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="email" readOnly value={props.values?.email} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="add1">Address {(props.errors.full_address && props.touched.full_address) && <span className="text-danger">{props.errors.full_address}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="full_address" value={props.values?.full_address} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div style={{textAlign: "right"}}>
|
||||||
|
<button type="submit" className="btn btn-primary">Update Profile
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
{/* Vertical Center Modal */}
|
||||||
|
<div ref={modalRef} className="modal fade" id="modal" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||||
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||||
|
{(updateProfileMutation.error || updateProfileMutation.isSuccess) && (
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={`p-2 text-center ${updateProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{updateProfileMutation.isSuccess ? 'Updated Successfully' : updateProfileMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" className="btn btn-primary" disabled={updateProfileMutation.isSuccess} onClick={proceed}>{updateProfileMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* END of Vertical Center Modal */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import React, { memo, useRef, useState } from 'react'
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
import getImage from '../../utils/getImage';
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { uploadProfileImg } from '../../services/services';
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
|
const ProfileImage = memo(({intialData}) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [selectedImg, setSelectedImg] = useState(null)
|
||||||
|
|
||||||
|
// const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS FOR ACTIVE USER DETAILS
|
||||||
|
|
||||||
|
const avtarImage = "avtar/merms-user.png";
|
||||||
|
|
||||||
|
// browser profile img
|
||||||
|
const browserImg = useRef(null);
|
||||||
|
const browseProfileImg = () => {
|
||||||
|
browserImg.current.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const profileImgChangeHandler = (event) => {
|
||||||
|
setSelectedImg(event.target.files[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadProfileMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
if(!fields.file){
|
||||||
|
throw new Error('Please, select an image')
|
||||||
|
}
|
||||||
|
return uploadProfileImg(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
console.log('res', res)
|
||||||
|
if(res?.data?.picture){
|
||||||
|
dispatch(updateUserDetails({ picture: res?.data?.picture }));
|
||||||
|
}
|
||||||
|
// if(res.data.resultCode != '0'){
|
||||||
|
// throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||||
|
// }
|
||||||
|
// const account_name = res?.data?.personal_data?.account_name
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
// queryClient.refetchQueries({
|
||||||
|
// queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
// })
|
||||||
|
uploadProfileMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const proceedToUpload = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
member_uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
file: selectedImg
|
||||||
|
}
|
||||||
|
// console.log('reqData', reqData)
|
||||||
|
uploadProfileMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
||||||
|
<div className="page-account-profil pt-5">
|
||||||
|
<div className="profile-img text-center rounded-circle">
|
||||||
|
<div className="pt-5">
|
||||||
|
<div className="bg-img m-auto">
|
||||||
|
<img
|
||||||
|
src={selectedImg ? URL.createObjectURL(selectedImg) : intialData?.personal_data?.picture ? intialData?.personal_data?.picture : getImage(avtarImage)}
|
||||||
|
// src={getImage(avtarImage)}
|
||||||
|
className="img-fluid" alt="user"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
ref={browserImg}
|
||||||
|
className='d-none'
|
||||||
|
type='file'
|
||||||
|
accept="image/*"
|
||||||
|
onChange={(e) => profileImgChangeHandler(e)}
|
||||||
|
id='profile-image'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="profile pt-4">
|
||||||
|
<h4 className="mb-1">{intialData?.personal_data?.lastname} {intialData?.personal_data?.firstname}</h4>
|
||||||
|
<div style={{padding: '10px'}}>
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="profile-btn text-center">
|
||||||
|
<div>
|
||||||
|
<button onClick={browseProfileImg} className="btn btn-light text-primary mb-2">Change
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{selectedImg &&
|
||||||
|
<div>
|
||||||
|
<button onClick={proceedToUpload} disabled={uploadProfileMutation.isSuccess || uploadProfileMutation.isPending} className="btn btn-light text-primary mb-2">
|
||||||
|
{uploadProfileMutation.isPending ? 'Upload...' : 'Upload New Avatar'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{/* success or error message */}
|
||||||
|
{(uploadProfileMutation.isSuccess || uploadProfileMutation.isError) &&
|
||||||
|
<div>
|
||||||
|
<p className={`${uploadProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{uploadProfileMutation.isSuccess ? 'Uploaded successfully' : uploadProfileMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default ProfileImage
|
||||||
@@ -1,165 +1,72 @@
|
|||||||
import React from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { profileDetails } from "../../services/services";
|
||||||
|
import ProfileForm from "./ProfileForm";
|
||||||
|
import LinksForm from "./LinksForm";
|
||||||
|
import ProfileImage from "./ProfileImage";
|
||||||
|
|
||||||
|
export default function Settings() {
|
||||||
|
|
||||||
export default function Settings(){
|
const [intialData, setInitialData] = useState({
|
||||||
|
external_links: {},
|
||||||
|
personal_data: {},
|
||||||
|
})
|
||||||
|
|
||||||
return(
|
const {data:profileInfo, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.profile_data,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return profileDetails(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// const profileData = profileInfo?.data // profile data
|
||||||
|
useMemo(()=>{
|
||||||
|
const data = profileInfo?.data
|
||||||
|
setInitialData({external_links: data?.external_links, personal_data: data?.personal_data})
|
||||||
|
},[profileInfo])
|
||||||
|
// console.log('INI', intialData)
|
||||||
|
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']} />
|
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']}/>
|
||||||
{/*<div className="row">*/}
|
{/*<div className="row">*/}
|
||||||
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||||
{/*</div>*/}
|
{/*</div>*/}
|
||||||
|
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-mute">Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-danger">{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
<div className="row account-contant">
|
<div className="row account-contant">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-body p-0" style={{backgroundColor:"#f9f9fb"}}>
|
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
||||||
<div className="row no-gutters">
|
<div className="row no-gutters">
|
||||||
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
<ProfileImage intialData={intialData} />
|
||||||
<div className="page-account-profil pt-5">
|
|
||||||
<div className="profile-img text-center rounded-circle">
|
|
||||||
<div className="pt-5">
|
|
||||||
<div className="bg-img m-auto">
|
|
||||||
<img src="assets/img/avtar/01.jpg" className="img-fluid"
|
|
||||||
alt="users-avatar" />
|
|
||||||
</div>
|
|
||||||
<div className="profile pt-4">
|
|
||||||
<h4 className="mb-1">Alice Williams</h4>
|
|
||||||
<p>Enthusiast</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="py-5 profile-counter">
|
|
||||||
<ul className="nav justify-content-center text-center">
|
|
||||||
<li className="nav-item border-right px-3">
|
|
||||||
<div>
|
|
||||||
<h4 className="mb-0">90</h4>
|
|
||||||
<p>Post</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className="nav-item border-right px-3">
|
|
||||||
<div>
|
|
||||||
<h4 className="mb-0">1.5K</h4>
|
|
||||||
<p>Messages</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className="nav-item px-3">
|
|
||||||
<div>
|
|
||||||
<h4 className="mb-0">4.4K</h4>
|
|
||||||
<p>Members</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="profile-btn text-center">
|
|
||||||
<div>
|
|
||||||
<button className="btn btn-light text-primary mb-2">Upload New Avatar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/*<div>*/}
|
|
||||||
{/* <button className="btn btn-danger">Delete</button>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-xl-5 col-md-6 col-12 border-t border-right">
|
<div className="col-xl-5 col-md-6 col-12 border-t border-right">
|
||||||
<div className="page-account-form">
|
<div className="page-account-form">
|
||||||
<div className="form-titel border-bottom p-3">
|
<div className="form-titel border-bottom p-3">
|
||||||
<h5 className="mb-0 py-2">Edit Your Personal Settings</h5>
|
<h5 className="mb-0 py-2">Edit Your Personal Settings</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<form>
|
<ProfileForm data={intialData.personal_data} />
|
||||||
<div className="form-row">
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">First Name</label>
|
|
||||||
<input type="text" className="form-control" id="name1"
|
|
||||||
value="Alice" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">Last Name</label>
|
|
||||||
<input type="text" className="form-control" id="name1"
|
|
||||||
value="Williams" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">Account Name</label>
|
|
||||||
<input type="text" className="form-control" id="name1"
|
|
||||||
value="This is the best hospital name" />
|
|
||||||
</div>
|
|
||||||
{/*<div className="form-group col-md-12">*/}
|
|
||||||
{/* <label htmlFor="title1">Email</label>*/}
|
|
||||||
{/* <input type="text" className="form-control" id="title1"*/}
|
|
||||||
{/* value="email@email.com" />*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="phone1">Phone Number</label>
|
|
||||||
<input type="text" className="form-control" id="phone1"
|
|
||||||
value="(01) 97 563 15613" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="email1">Email</label>
|
|
||||||
<input type="email" className="form-control" id="email1"
|
|
||||||
value="alicewilliams@gmail.com" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="add1">Address</label>
|
|
||||||
<input type="text" className="form-control" id="add1"
|
|
||||||
value="17504 Carlton Cuevas Rd, Gulfport, MS, 39503" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="add2">Address 2</label>
|
|
||||||
<input type="text" className="form-control" id="add2"
|
|
||||||
value="1234 North Avenue Luke Lane, South Bend, IN 360001" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/*<div className="form-row">*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputState3">City</label>*/}
|
|
||||||
{/* <select id="inputState3" className="form-control">*/}
|
|
||||||
{/* <option>Choose...</option>*/}
|
|
||||||
{/* <option selected="">London</option>*/}
|
|
||||||
{/* <option>Montreal</option>*/}
|
|
||||||
{/* <option>Delhi</option>*/}
|
|
||||||
{/* <option>Tokyo</option>*/}
|
|
||||||
{/* </select>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputState4">State</label>*/}
|
|
||||||
{/* <select id="inputState4" className="form-control">*/}
|
|
||||||
{/* <option>Choose...</option>*/}
|
|
||||||
{/* <option selected="">England</option>*/}
|
|
||||||
{/* <option>California</option>*/}
|
|
||||||
{/* <option>Texas</option>*/}
|
|
||||||
{/* <option>Scotland</option>*/}
|
|
||||||
{/* </select>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputZip">Zip</label>*/}
|
|
||||||
{/* <input type="text" className="form-control" id="inputZip"*/}
|
|
||||||
{/* value="EC1A 1BB" />*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
{/*<div className="form-group">*/}
|
|
||||||
{/* <div className="form-check">*/}
|
|
||||||
{/* <input className="form-check-input" type="checkbox"*/}
|
|
||||||
{/* id="gridCheck" />*/}
|
|
||||||
{/* <label className="form-check-label" htmlFor="gridCheck">*/}
|
|
||||||
{/* I agree to receive email notification.*/}
|
|
||||||
{/* </label>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div style={{textAlign:"right"}}>
|
|
||||||
<button type="submit" className="btn btn-primary">Update Profile
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,46 +76,7 @@ export default function Settings(){
|
|||||||
<h5 className="mb-0 py-2">Your External Link</h5>
|
<h5 className="mb-0 py-2">Your External Link</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<form>
|
<LinksForm data={intialData.external_links} />
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="fb">Facebook URL:</label>
|
|
||||||
<input type="text" className="form-control" id="fb"
|
|
||||||
value="https://www.facebook.com/" />
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="tr">Twitter URL:</label>
|
|
||||||
<input type="text" className="form-control" id="tr"
|
|
||||||
value="https://twitter.com/" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="br">Blogger URL:</label>
|
|
||||||
<input type="text" className="form-control" id="br"
|
|
||||||
value="https://www.blogger.com" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="go">Google+ URL:</label>
|
|
||||||
<input type="text" className="form-control" id="go"
|
|
||||||
value="https://plus.google.com/discover" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="li">LinkedIn URL:</label>
|
|
||||||
<input type="text" className="form-control" id="li"
|
|
||||||
value="https://in.linkedin.com/" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="we">Website URL:</label>
|
|
||||||
<input type="text" className="form-control" id="we"
|
|
||||||
value="https://yourwebsite.com" />
|
|
||||||
</div>
|
|
||||||
<div style={{textAlign:"right"}}>
|
|
||||||
<button type="submit" className="btn btn-primary">Update Links</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -217,7 +85,7 @@ export default function Settings(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import React from "react";
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
|
||||||
|
export default function Start() {
|
||||||
|
|
||||||
|
const bgImg = getImage("side-banner.jpg");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Get Started...' paths={['Dashboard', 'Start']}/>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-xl-3 col-md-6">
|
||||||
|
<div className="card card-statistics text-center py-3"
|
||||||
|
style={{minHeight: '550px', borderRadius: '10px', backgroundImage: `url(${bgImg})`}}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-xl-3 col-md-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>Start with</h5>
|
||||||
|
<h2 className="text-primary pt-3"><a href="/product/A000001">Personal Website</a></h2>
|
||||||
|
<ul className="py-2">
|
||||||
|
<li>post jobs</li>
|
||||||
|
<li>advanced instructors search</li>
|
||||||
|
<li>invite candidates</li>
|
||||||
|
<li>post events</li>
|
||||||
|
<li>cancel any time</li>
|
||||||
|
</ul>
|
||||||
|
<div className="pt-2"><a href="/product/A000001"
|
||||||
|
className="btn btn-primary btn-round btn-sm">Start</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-xl-3 col-md-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>Start with</h5>
|
||||||
|
<h2 className="text-primary pt-3"><a href="/product/A000002">Business Website</a></h2>
|
||||||
|
<ul className="py-2">
|
||||||
|
<li>post jobs</li>
|
||||||
|
<li>advanced instructors search</li>
|
||||||
|
<li>invite candidates</li>
|
||||||
|
<li>post events</li>
|
||||||
|
<li>cancel any time</li>
|
||||||
|
</ul>
|
||||||
|
<div className="pt-2"><a href="/product/A000001"
|
||||||
|
className="btn btn-primary btn-round btn-sm">Start</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-xl-3 col-md-6">
|
||||||
|
{/*<div className="card card-statistics text-center py-3">*/}
|
||||||
|
{/*<div className="card-body pricing-content">*/}
|
||||||
|
{/*<div className="pricing-content-card">*/}
|
||||||
|
{/* <h5>small</h5>*/}
|
||||||
|
{/* <h2 className="text-primary pt-3">$80</h2>*/}
|
||||||
|
{/* <p className="text-primary pb-3">/ Monthly</p>*/}
|
||||||
|
{/* <ul className="py-2">*/}
|
||||||
|
{/* <li>post jobs</li>*/}
|
||||||
|
{/* <li>advanced instructors search</li>*/}
|
||||||
|
{/* <li>invite candidates</li>*/}
|
||||||
|
{/* <li>post events</li>*/}
|
||||||
|
{/* <li>cancel any time</li>*/}
|
||||||
|
{/* </ul>*/}
|
||||||
|
{/* <div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go premium</a></div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { loadStripe } from '@stripe/stripe-js';
|
||||||
|
import { Elements, useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
|
||||||
|
import {MyProductData, StripeSubscriptionCreate} from '../../services/services';
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
//const stripePromise = loadStripe('your_stripe_publishable_key');
|
||||||
|
const stripePromise = loadStripe('pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT');
|
||||||
|
|
||||||
|
const CheckoutForm = ({ priceId, customerId ,option_name }) => {
|
||||||
|
const stripe = useStripe();
|
||||||
|
const elements = useElements();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const handleSubmit = async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (!stripe || !elements) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let reqData = {
|
||||||
|
priceId : priceId,
|
||||||
|
customerId: customerId,
|
||||||
|
option_name: option_name,
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
|
||||||
|
StripeSubscriptionCreate(reqData).then( (res)=>{
|
||||||
|
console.log(res);
|
||||||
|
console.log(res.data.stripe_session);
|
||||||
|
//navigate(res.data.stripe_session)
|
||||||
|
window.location.replace(res.data.stripe_session);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<CardElement />
|
||||||
|
<button type="submit" disabled={!stripe}>
|
||||||
|
Subscribe
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const StripeSubscriptionButton = ({ priceId, customerId ,option_name}) => {
|
||||||
|
return (
|
||||||
|
<Elements stripe={stripePromise}>
|
||||||
|
<CheckoutForm priceId={priceId} customerId={customerId} option_name={option_name} />
|
||||||
|
</Elements>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StripeSubscriptionButton;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export default function SubcribePaymentOptions({activePaymentType, setActivePaymentType}){
|
||||||
|
|
||||||
|
const handleSwitch = ({target:{name, value}}) => {
|
||||||
|
console.log('SWITCH', name, value)
|
||||||
|
setActivePaymentType(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Select Payment Option</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
|
||||||
|
<div className="form-check form-check-inline">
|
||||||
|
<input onChange={handleSwitch} className="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1"
|
||||||
|
value="previous" checked={activePaymentType == 'previous'} />
|
||||||
|
<label className="form-check-label" htmlFor="inlineRadio1">Previous Cards</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-check form-check-inline">
|
||||||
|
<input onChange={handleSwitch} className="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2"
|
||||||
|
value="new" checked={activePaymentType == 'new'} />
|
||||||
|
<label className="form-check-label" htmlFor="inlineRadio2">Add New card</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/*<div className="card card-statistics"> </div>*/}
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import React, {useState} from 'react'
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import {Link, useLocation} from 'react-router-dom'
|
||||||
|
import SubscribeNewCard from "./SubscribeNewCard";
|
||||||
|
import SubscribePreviousCard from "./SubscribePreviousCard";
|
||||||
|
import SubcribePaymentOptions from "./SubcribePaymentOptions";
|
||||||
|
import StripeSubscriptionButton from "./StripeSubscriptionButton";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function Subscribe() {
|
||||||
|
const {state: {selectedSubscription,customerId}} = useLocation()
|
||||||
|
|
||||||
|
console.log('selectedSubscription', selectedSubscription)
|
||||||
|
console.log('selectedSubscription.option_name',selectedSubscription.option_name)
|
||||||
|
console.log('customerId', customerId)
|
||||||
|
|
||||||
|
let [activePaymentType, setActivePaymentType] = useState('previous')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Activate or Update your Subscription' paths={['Dashboard', 'subscribe']}/>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12 col-lg-6 col-xl-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>Current Subscription(s)</h5>
|
||||||
|
{/*<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>*/}
|
||||||
|
<SubcribePaymentOptions activePaymentType={activePaymentType}
|
||||||
|
setActivePaymentType={setActivePaymentType}/>
|
||||||
|
{activePaymentType == 'new' ?
|
||||||
|
<SubscribeNewCard/>
|
||||||
|
:
|
||||||
|
<SubscribePreviousCard/>
|
||||||
|
}
|
||||||
|
<>
|
||||||
|
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id} customerId={customerId} option_name={selectedSubscription.option_name} />
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<>
|
||||||
|
<div key="basic" className="col-12 col-lg-6 col-xl-6">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card">
|
||||||
|
<h5>{selectedSubscription.display_name}</h5>
|
||||||
|
<h2 className="text-primary pt-3">${selectedSubscription.monthly}</h2>
|
||||||
|
<p className="text-primary pb-3">/ Monthly</p>
|
||||||
|
<ol className="py-2"
|
||||||
|
style={{fontSize: '16px', fontWeight: 'bold', textAlign: 'left'}}>
|
||||||
|
{selectedSubscription?.items?.map(item => (
|
||||||
|
<li key={item.description}>{item.description}</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
{/*<div className="pt-2">*/}
|
||||||
|
{/* <button className="btn btn-inverse-secondary btn-round btn-sm">Go {subscriptionSelection.display_name}</button>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react'
|
||||||
|
export default function SubscribeNewCard(){
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 col-12 selects-contant">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading" style={{textAlign: 'left'}}>
|
||||||
|
<h4 className="card-title">Pay with New Card</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="form-group mb-0">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { IoMdArrowDropdown } from 'react-icons/io'
|
||||||
|
|
||||||
|
export default function SubscribePreviousCard() {
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{/*<div className="row select-wrapper">*/}
|
||||||
|
{/* <div className="col-md-12 col-12 selects-contant">*/}
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 col-12 selects-contant">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading" style={{textAlign: 'left'}}>
|
||||||
|
<h4 className="card-title">Pay with Previous Card</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="position-relative form-group mb-0">
|
||||||
|
<select className="js-basic-single form-control" name="state">
|
||||||
|
<option value="AK">Visa xxxx xxxx xxxx 1234</option>
|
||||||
|
<option value="HI">Mastercard xxxx xxxx xxxx 1234</option>
|
||||||
|
</select>
|
||||||
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{top: '50%', right: '2px', transform: 'translateY(-50%)'}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* </div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import getImage from "../../utils/getImage";
|
||||||
|
import {getSubscriptions} from '../../services/services';
|
||||||
|
import {useQuery} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
import siteLinks from "../../links/siteLinks";
|
||||||
|
import {Link, useNavigate} from 'react-router-dom'
|
||||||
|
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
|
||||||
|
|
||||||
|
export default function Subscription() {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const pricingFields = {
|
||||||
|
starter: {name: 'Starter', price: 5.99, active: true},
|
||||||
|
basic: {name: 'Basic', price: 12.99, active: true},
|
||||||
|
premium: {name: 'Premium', price: 20.00, active: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.subscriptions,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid') // USER UID
|
||||||
|
}
|
||||||
|
return getSubscriptions(reqData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentSubscription = data?.data?.current_product
|
||||||
|
const otherSubscriptions = data?.data?.options
|
||||||
|
const stripe_customer_id = data?.data.stripe_customer_id
|
||||||
|
|
||||||
|
// console.log('urlData', data?.data)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Subscription' paths={['Dashboard', 'Subscription']}/>
|
||||||
|
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12 col-lg-6 col-xl-3">
|
||||||
|
<div className="card card-statistics text-center py-3" style={{backgroundColor: '#e6f5f4'}}>
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card" style={{minHeight: '350px'}}>
|
||||||
|
<h5>Your Subscription(s)</h5>
|
||||||
|
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
|
||||||
|
</div>
|
||||||
|
<div className="pt-2" style={{textAlign: 'left'}}>
|
||||||
|
<div style={{fontSize: '12px', fontWeight: 'bolder', color: "#3E3699"}}>
|
||||||
|
Next Payment: {getDateTimeFromDateString(currentSubscription?.next_payment)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<>
|
||||||
|
{Object.entries(otherSubscriptions)?.map(([key, value]) => (
|
||||||
|
|
||||||
|
<div key={key} className="col-12 col-lg-6 col-xl-3">
|
||||||
|
<div className="card card-statistics text-center py-3">
|
||||||
|
<div className="card-body pricing-content">
|
||||||
|
<div className="pricing-content-card" style={{minHeight: '350px'}}>
|
||||||
|
<h5>{value.display_name}</h5>
|
||||||
|
<h2 className="text-primary pt-3">${value.monthly}</h2>
|
||||||
|
<p className="text-primary pb-3">/ Monthly</p>
|
||||||
|
<ol className="py-2"
|
||||||
|
style={{fontSize: '16px', fontWeight: 'bold', textAlign: 'left'}}>
|
||||||
|
{value?.items?.map(item => (
|
||||||
|
<li key={item.description}>{item.description}</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="pt-2" style={{fontWeight: 'bolder'}}>
|
||||||
|
{
|
||||||
|
(currentSubscription?.display_name == value.option_name) ? 'Current Subscription' :
|
||||||
|
<button onClick={() => {
|
||||||
|
navigate(siteLinks.subscribe, {
|
||||||
|
state: {
|
||||||
|
selectedSubscription: value,
|
||||||
|
customerId: stripe_customer_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
className="btn btn-inverse-secondary btn-round btn-sm">Go {value.display_name}</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import React from "react";
|
||||||
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
|
import TrafficChart from "./TrafficChart";
|
||||||
|
|
||||||
|
|
||||||
|
export default function Traffic() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BreadcrumbComBS title='Traffic' paths={['Dashboard', 'Traffic']}/>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-lg-4">
|
||||||
|
<div className="card card-statistics" style={{minHeight: '350px', borderRadius: '10px', backgroundColor: 'aliceblue'}}>
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Site Traffic Monitoring</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-lg-8">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="card-heading">
|
||||||
|
<h4 className="card-title">Plot</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="apexchart-wrapper">
|
||||||
|
<TrafficChart />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import ReactApexChart from "react-apexcharts";
|
||||||
|
|
||||||
|
const TrafficChart = () => {
|
||||||
|
const [state, setState] = useState({
|
||||||
|
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
// name: "High - 2013",
|
||||||
|
name: 'Professional Website',
|
||||||
|
data: [28, 29, 33, 36, 32, 32, 33, 33, 36, 32, 32, 33]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// name: "Low - 2013",
|
||||||
|
name: 'Personal Website',
|
||||||
|
data: [12, 11, 14, 18, 17, 13, 13, 14, 18, 17, 13, 13]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// name: "Low - 2013",
|
||||||
|
name: 'Personal Forum',
|
||||||
|
data: [10, 11, 14, 19, 18, 23, 17, 14, 10, 17, 23, 10]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// name: "High - 2013",
|
||||||
|
name: 'Professional Forum',
|
||||||
|
data: [20, 19, 30, 36, 30, 35, 33, 33, 36, 32, 32, 30]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
chart: {
|
||||||
|
height: 350,
|
||||||
|
type: 'line',
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
color: '#000',
|
||||||
|
top: 18,
|
||||||
|
left: 7,
|
||||||
|
blur: 10,
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: ['#77B6EA', '#545454', '#F50898','#213ece'],
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
curve: 'smooth'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: 'Recent Sites Traffic',
|
||||||
|
align: 'left'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: '#e7e7e7',
|
||||||
|
row: {
|
||||||
|
colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
size: 1
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'],
|
||||||
|
title: {
|
||||||
|
text: 'Month'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: 'Visits'
|
||||||
|
},
|
||||||
|
min: 5,
|
||||||
|
max: 40
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
horizontalAlign: 'right',
|
||||||
|
floating: true,
|
||||||
|
offsetY: -25,
|
||||||
|
offsetX: -5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div id="chart">
|
||||||
|
<ReactApexChart options={state.options} series={state.series} type="line" height={450} />
|
||||||
|
</div>
|
||||||
|
<div id="html-dist"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default TrafficChart
|
||||||
@@ -2063,6 +2063,8 @@ ul.activity {
|
|||||||
.img-icon{
|
.img-icon{
|
||||||
width:60px;
|
width:60px;
|
||||||
height:60px;
|
height:60px;
|
||||||
|
min-width:60px;
|
||||||
|
min-height:60px;
|
||||||
border-radius:100px;
|
border-radius:100px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
|
|||||||
@@ -90,7 +90,23 @@ $today-highlight-bg: #fcf8e3;
|
|||||||
$btn-bg: #8e54e9;
|
$btn-bg: #8e54e9;
|
||||||
$btn-border: #8e54e9;
|
$btn-border: #8e54e9;
|
||||||
$event-padding: 10px;
|
$event-padding: 10px;
|
||||||
|
.manage{
|
||||||
|
background-color:lightgreen !important;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
.creating{
|
||||||
|
background-color: lightyellow !important;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
.billing{
|
||||||
|
background-color: #b9c2c5;
|
||||||
|
color: #77117a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next_billing{
|
||||||
|
background-color: #cff1f0;
|
||||||
|
color: #19548e;
|
||||||
|
}
|
||||||
.extraProductCard{
|
.extraProductCard{
|
||||||
background-color: aliceblue;
|
background-color: aliceblue;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function getDateFromDateString(dateString) {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
|
||||||
|
// Ensure the date is valid
|
||||||
|
if (isNaN(date)) {
|
||||||
|
return "Invalid date string";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the year, month, and day
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed, so we add 1
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getDateFromDateString
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
function getDateTimeFromDateString(dateString) {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
|
||||||
|
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||||
|
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||||
|
|
||||||
|
const dayName = days[date.getDay()];
|
||||||
|
const monthName = months[date.getMonth()];
|
||||||
|
const day = date.getDate();
|
||||||
|
const year = date.getFullYear();
|
||||||
|
|
||||||
|
// Add ordinal suffix
|
||||||
|
function getOrdinal(n) {
|
||||||
|
if (n > 3 && n < 21) return "th"; // 4-20 are all "th"
|
||||||
|
switch (n % 10) {
|
||||||
|
case 1: return "st";
|
||||||
|
case 2: return "nd";
|
||||||
|
case 3: return "rd";
|
||||||
|
default: return "th";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format time in 12hr with AM/PM
|
||||||
|
let hours = date.getHours();
|
||||||
|
const minutes = date.getMinutes().toString().padStart(2, "0");
|
||||||
|
const ampm = hours >= 12 ? "PM" : "AM";
|
||||||
|
hours = hours % 12 || 12;
|
||||||
|
|
||||||
|
return `${dayName}, ${monthName} ${day}${getOrdinal(day)} ${year} ${hours}:${minutes}${ampm}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getDateTimeFromDateString
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function sortArrayByListOrder(data) {
|
||||||
|
// Convert object to array if needed
|
||||||
|
const array = Array.isArray(data)
|
||||||
|
? [...data]
|
||||||
|
: Object.values(data);
|
||||||
|
|
||||||
|
// Sort ascending by list_order
|
||||||
|
array.sort((a, b) => {
|
||||||
|
const orderA = a.list_order ?? 0;
|
||||||
|
const orderB = b.list_order ?? 0;
|
||||||
|
return orderA - orderB;
|
||||||
|
});
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default sortArrayByListOrder
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const sortObjectByListOrder = (data) => {
|
||||||
|
const sortedEntriesByValue = Object.entries(data).sort((a, b) => {
|
||||||
|
if(a[1].list_order > b[1].list_order){
|
||||||
|
return 1
|
||||||
|
}else{
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}); // Sorts numerically by value
|
||||||
|
|
||||||
|
const sortedObjectByValue = Object.fromEntries(sortedEntriesByValue);
|
||||||
|
return sortedObjectByValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export default sortObjectByListOrder
|
||||||
@@ -3,17 +3,26 @@ const siteLinks = {
|
|||||||
help: '/help',
|
help: '/help',
|
||||||
home: '/',
|
home: '/',
|
||||||
dash: '/dash',
|
dash: '/dash',
|
||||||
|
traffic: '/traffic',
|
||||||
|
start: '/start',
|
||||||
|
profile_complete: '/profile-complete',
|
||||||
product: '/product/*',
|
product: '/product/*',
|
||||||
contacts: '/contacts',
|
contacts: '/contacts',
|
||||||
comments: '/comments',
|
comments: '/comments',
|
||||||
reports: '/reports',
|
reports: '/reports',
|
||||||
|
subscription: '/subscription',
|
||||||
|
my_media: '/my-files',
|
||||||
|
subscription_success:'/subscription-success',
|
||||||
|
subscribe: '/subscribe',
|
||||||
|
onboard: '/subscription',
|
||||||
user: '/user',
|
user: '/user',
|
||||||
calendar: '/calendar',
|
calendar: '/calendar',
|
||||||
settings: '/settings',
|
settings: '/settings',
|
||||||
login: '/auth/login',
|
login: '/auth/login',
|
||||||
signup: '/auth/signup',
|
signup: '/auth/signup',
|
||||||
forgetpwd: '/auth/forgetpwd',
|
forgetpwd: '/auth/forgetpwd',
|
||||||
csignup: '/csignup/:jwt'
|
csignup: '/csignup/:jwt',
|
||||||
|
accreset: '/accreset/:token'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default siteLinks
|
export default siteLinks
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
const queryKeys = {
|
const queryKeys = {
|
||||||
user_details: ['user_details'],
|
user_details: ['user_details'],
|
||||||
product_url: ['product_url'],
|
product_url: ['product_url'],
|
||||||
|
dash_payments: ['dash_payments'],
|
||||||
products: ['product-data'],
|
products: ['product-data'],
|
||||||
myproduct_provision: ['myproduct_provision'],
|
myproduct_provision: ['myproduct_provision'],
|
||||||
product_page: ['product_page'],
|
product_page: ['product_page'],
|
||||||
recentAction: ['recent-action'],
|
recentAction: ['recent-action'],
|
||||||
|
settingsData: ['settings_data'],
|
||||||
|
myProductConfig: ['myproduct_config'],
|
||||||
|
myTemplateConfig: ['mytemplate_config'],
|
||||||
|
productTemplateData: ['product_template_data'],
|
||||||
|
subscriptions: ['subscriptions'],
|
||||||
|
profile_data: ['profile_data'],
|
||||||
|
my_files: ['my_files'],
|
||||||
|
topics: ['topics'],
|
||||||
|
payment_report: ['payment_report'],
|
||||||
|
product_report: ['product_report'],
|
||||||
|
system_report: ['system_report'],
|
||||||
|
|
||||||
dashboard: ['dashboard'],
|
dashboard: ['dashboard'],
|
||||||
topBar: ['top-bar'],
|
topBar: ['top-bar'],
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
config.headers = {
|
config.headers = {
|
||||||
Accept: "application/json",
|
// Accept: "application/json",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
|
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
|
||||||
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
|
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
|
||||||
@@ -23,10 +22,20 @@ axios.interceptors.request.use(
|
|||||||
|
|
||||||
const postAuxEnd = (path, postData, media=false) => {
|
const postAuxEnd = (path, postData, media=false) => {
|
||||||
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
|
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
|
||||||
return axios.post(`${basePath}${path}`, postData).then(res => {
|
let newPostData = {}
|
||||||
|
if(!media){
|
||||||
|
newPostData = {...postData}
|
||||||
|
}else{
|
||||||
|
newPostData = new FormData();
|
||||||
|
for (let data in postData) {
|
||||||
|
newPostData.append(data, postData[data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return axios.post(`${basePath}${path}`, newPostData).then(res => {
|
||||||
return res
|
return res
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
throw new Error(err.response.data.msg);
|
// throw new Error(err.response.data.error_message);
|
||||||
|
throw new Error(err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +84,30 @@ export const topBar = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/bar`, postData, false)
|
return postAuxEnd(`/panel/account/bar`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET PROFILE DATA
|
||||||
|
export const profileDetails = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/profile`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPDATE PROFILE
|
||||||
|
export const updateProfile = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/profile-update`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPDATE LINKS
|
||||||
|
export const updateLinks = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/profilelinks-update`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET PRODUCT BY ID
|
// FUNCTION TO GET PRODUCT BY ID
|
||||||
export const MyProductData = (reqData) => {
|
export const MyProductData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -83,6 +116,13 @@ export const MyProductData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/myproduct/dash`, postData, false)
|
return postAuxEnd(`/panel/myproduct/dash`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const StripeSubscriptionCreate = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/subscription/start`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET CALENDAR EVENTS
|
// FUNCTION TO GET CALENDAR EVENTS
|
||||||
export const getCalendarEvents = (reqData) => {
|
export const getCalendarEvents = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -91,7 +131,7 @@ export const getCalendarEvents = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/calendar`, postData, false)
|
return postAuxEnd(`/panel/account/calendar`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
|
// FUNCTION TO GET CONTACT DATA
|
||||||
export const contactData = (reqData) => {
|
export const contactData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
...reqData,
|
...reqData,
|
||||||
@@ -99,6 +139,14 @@ export const contactData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/contacts`, postData, false)
|
return postAuxEnd(`/panel/contacts`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET COMMENTS DATA
|
||||||
|
export const commentsData = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/comments`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION
|
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION
|
||||||
export const productsURL = (reqData) => {
|
export const productsURL = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -107,6 +155,14 @@ export const productsURL = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/products/url`, postData, false)
|
return postAuxEnd(`/panel/account/products/url`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET DASHBOARD PAYMENTS
|
||||||
|
export const getDashPayments = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/payments`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
|
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
|
||||||
export const productsData = (reqData) => {
|
export const productsData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -115,6 +171,14 @@ export const productsData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/products`, postData, false)
|
return postAuxEnd(`/panel/account/products`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO REFRESH SITE
|
||||||
|
export const productRefreshSite = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/products/refresh`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION
|
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION
|
||||||
export const recentActions = (reqData) => {
|
export const recentActions = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -126,8 +190,177 @@ export const recentActions = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/actions`, postData, false)
|
return postAuxEnd(`/panel/account/actions`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO VERIFY RESET TOKEN
|
||||||
|
export const verifyResetToken = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData
|
||||||
|
}
|
||||||
|
return postAuxEnd('/panel/auth/resetverify', postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO COMPLETE PASSWORD RESET
|
||||||
|
export const completePWDReset = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData
|
||||||
|
}
|
||||||
|
return postAuxEnd('/panel/auth/resetcomplete', postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO SUBMIT PAGE TAB SETTINGS
|
||||||
|
export const pageSettings = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/myproduct/settings`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET SETTINGS DATA
|
||||||
|
export const getSettingsData = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/myproduct/settings/values`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET MY PRODUCT CONFIGURATION
|
||||||
|
export const getMyProductConfig = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/myproduct/configuration`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET SETTINGS DATA
|
||||||
|
export const getProductTemplateData = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProductColorStyles = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/products/color-styles`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTemplateConfig = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/myproduct/template-config`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO ACTIVATE TEMPLATE
|
||||||
|
export const activateTemplate = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/template/activate`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const activateColorStyle = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/colorstyle/activate`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
||||||
|
export const completeProfile = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/startprofile`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO COMPLETE PROFILE
|
||||||
|
export const getSubscriptions = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/subscription/products`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMediaFileList = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/media-files`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uploadFile = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/upload/webfiles`, postData, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO CHANGE TEMPLATE MEDIA SET
|
||||||
|
export const templateMediaSet = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/myproduct/template-media-set`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getReportsTopicsList = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/report/topics`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET PAYMENT REPORTS
|
||||||
|
export const getPaymentReports = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/report/item/payment`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET PRODUCT REPORTS
|
||||||
|
export const getProductReports = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/report/item/product`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET SYSTEM REPORTS
|
||||||
|
export const getSystemReports = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/report/item/system`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO GET COMMON PRACTICE
|
||||||
|
export const getCommonPractice = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/common/practice`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO SET EXTERNAL URL
|
||||||
|
export const setExternalURL = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData
|
||||||
|
}
|
||||||
|
return postAuxEnd('/panel/myproduct/external-url', postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPLOAD PROFILE IMAGE
|
||||||
|
export const uploadProfileImg = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/upload/profile-picture`, postData, true)
|
||||||
|
// throw new Error('Opps')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const userSlice = createSlice({
|
|||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
updateUserDetails: (state, action) => {
|
updateUserDetails: (state, action) => {
|
||||||
state.userDetails = { ...action.payload };
|
state.userDetails = { ...state.userDetails, ...action.payload };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import AccPWDReset from '../component/auth/AccPWDReset'
|
||||||
|
|
||||||
|
export default function AccPWDResetPage() {
|
||||||
|
return (
|
||||||
|
<AccPWDReset />
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import MyMedia from "../component/mymedia/MyMedia";
|
||||||
|
|
||||||
|
export default function MyMediaPage() {
|
||||||
|
return (
|
||||||
|
<MyMedia />
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import Onboard from '../component/onboard/Onboard';
|
||||||
|
|
||||||
|
|
||||||
|
export default function OnboardPage(){
|
||||||
|
return <Onboard />
|
||||||
|
}
|
||||||
@@ -1,6 +1,23 @@
|
|||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import ProductFactory from '../component/product/ProductFactory'
|
import ProductFactory from '../component/product/ProductFactory'
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import siteLinks from '../links/siteLinks';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
export default function ProductPage() {
|
export default function ProductPage() {
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
|
let {pathname} = useLocation()
|
||||||
|
|
||||||
|
const { userDetails: { profile_completed }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(!profile_completed){
|
||||||
|
navigate(siteLinks.profile_complete, {replace: true, state:{redirectLink: pathname}})
|
||||||
|
}
|
||||||
|
},[])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProductFactory />
|
<ProductFactory />
|
||||||
)
|
)
|
||||||
|
|||||||