Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -1,4 +1,5 @@
|
|||||||
SKIP_PREFLIGHT_CHECK=true
|
REACT_APP_PANEL_NAME="MERMS Panel DEV"
|
||||||
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="development"
|
REACT_APP_NODE_ENV="development"
|
||||||
NODE_ENV="development"
|
NODE_ENV="development"
|
||||||
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
|
||||||
|
|||||||
+4
-1
@@ -1,7 +1,10 @@
|
|||||||
SKIP_PREFLIGHT_CHECK=true
|
REACT_APP_PANEL_NAME="MERMS Panel DEV"
|
||||||
|
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"
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
SKIP_PREFLIGHT_CHECK=true
|
REACT_APP_PANEL_NAME="MERMS Panel"
|
||||||
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
REACT_APP_NODE_ENV="production"
|
REACT_APP_NODE_ENV="production"
|
||||||
NODE_ENV="production"
|
NODE_ENV="production"
|
||||||
REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
|
REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
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"
|
NODE_ENV="development"
|
||||||
|
|||||||
+3
-3
@@ -126,10 +126,10 @@ 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"]
|
||||||
|
|
||||||
# start app
|
# start app
|
||||||
CMD /bin/sh ./run.sh
|
CMD /bin/sh ./run.sh
|
||||||
|
|||||||
+25
-21
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+43
-39
@@ -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';
|
||||||
@@ -23,47 +23,51 @@ import SubscriptionPage from './views/SubscriptionPage';
|
|||||||
import OnboardPage from "./views/OnboardPage";
|
import OnboardPage from "./views/OnboardPage";
|
||||||
import AccPWDResetPage from './views/AccPWDResetPage';
|
import AccPWDResetPage from './views/AccPWDResetPage';
|
||||||
import ProfileCompletePage from './views/ProfileCompletePage';
|
import ProfileCompletePage from './views/ProfileCompletePage';
|
||||||
import SubscribePage from './views/Subscribe'
|
import SubscribePage from './views/Subscribe'
|
||||||
|
import StartPage from "./views/StartPage";
|
||||||
|
import TrafficPage from "./views/TrafficPage";
|
||||||
|
|
||||||
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.accreset} element={<AccPWDResetPage />} />
|
<Route path={siteLinks.accreset} element={<AccPWDResetPage/>}/>
|
||||||
<Route path={siteLinks.error} element={<LoginPage />} />
|
<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.profile_complete} element={<ProfileCompletePage />} />
|
<Route path={siteLinks.dash} element={<HomePage/>}/>
|
||||||
<Route path={siteLinks.product} element={<ProductPage />} />
|
<Route path={siteLinks.traffic} element={<TrafficPage/>}/>
|
||||||
<Route path={siteLinks.reports} element={<ReportsPage />} />
|
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
||||||
<Route path={siteLinks.comments} element={<CommentsPage />} />
|
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
||||||
<Route path={siteLinks.contacts} element={<ContactsPage />} />
|
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
||||||
<Route path={siteLinks.user} element={<UserPage />} />
|
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
||||||
<Route path={siteLinks.subscription} element={<SubscriptionPage />} />
|
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
||||||
<Route path={siteLinks.subscription_success} element={<SubscriptionPage />} />
|
<Route path={siteLinks.user} element={<UserPage/>}/>
|
||||||
<Route path={siteLinks.onboard} element={<OnboardPage />} />
|
<Route path={siteLinks.subscription} element={<SubscriptionPage/>}/>
|
||||||
<Route path={siteLinks.calendar} element={<CalendarPage />} />
|
<Route path={siteLinks.subscription_success} element={<SubscriptionPage/>}/>
|
||||||
<Route path={siteLinks.settings} element={<SettingsPage />} />
|
<Route path={siteLinks.onboard} element={<OnboardPage/>}/>
|
||||||
<Route path={siteLinks.subscribe} element={<SubscribePage />} />
|
<Route path={siteLinks.calendar} element={<CalendarPage/>}/>
|
||||||
<Route path={siteLinks.help} element={<HelpPage />} />
|
<Route path={siteLinks.settings} element={<SettingsPage/>}/>
|
||||||
</Route>
|
<Route path={siteLinks.subscribe} element={<SubscribePage/>}/>
|
||||||
</Route>
|
<Route path={siteLinks.help} element={<HelpPage/>}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Route>
|
||||||
</div>
|
</Route>
|
||||||
);
|
</Routes>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppRouters;
|
export default AppRouters;
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -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
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function Forgetpwd2() {
|
|||||||
<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 p-5">
|
||||||
<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}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -86,20 +86,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,10 +124,18 @@ 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={{margin: '5px'}}>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
<div className="row" style={{marginTop: '20px'}}>
|
<div className="row" style={{marginTop: '20px'}}>
|
||||||
<div className="col-6">
|
<div className="col-6">
|
||||||
<div className="app-store-icons-wrap text-center">
|
<div className="app-store-icons-wrap text-center">
|
||||||
|
|||||||
@@ -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'
|
||||||
@@ -9,89 +9,102 @@ import TextInput from '../inputs/TextInput'
|
|||||||
|
|
||||||
export default function Signup() {
|
export default function Signup() {
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
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">
|
||||||
<div className="h-full w-full bg-white grid sm:grid-cols-2 lg:grid-cols-5 xl:grid-cols-8">
|
<div className="h-full w-full bg-white grid sm:grid-cols-2 lg:grid-cols-5 xl:grid-cols-8">
|
||||||
<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>
|
|
||||||
<form className="w-full text-14 text-left text-black-gray">
|
|
||||||
<div className="w-full flex flex-col gap-4 justify-start items-start">
|
|
||||||
<div className='w-full grid grid-cols-2 gap-8'>
|
|
||||||
<div className="w-full">
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<Label desc='First Name*' />
|
|
||||||
<TextInput type='text' placeholder='Firstname' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full">
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<Label desc='Last Name*' />
|
|
||||||
<TextInput type='text' placeholder='Lastname' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full">
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<Label desc='Email*' />
|
|
||||||
<TextInput type='text' placeholder='Email' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full">
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<Label desc='User Name*' />
|
|
||||||
<TextInput type='text' placeholder='Username' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full">
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<Label desc='Password*' />
|
|
||||||
<TextInput type='password' placeholder='Password' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full text-left">
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<input className="form-check-input" type="checkbox" id="gridCheck" />
|
|
||||||
<label className="font-semibold form-check-label" htmlFor="gridCheck">
|
|
||||||
I accept terms & policy
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
<div className="mt-3">
|
|
||||||
<p className='font-medium'>Already have an account ?<Link to={siteLinks.login} className=' hover:text-primary'> Sign In</Link></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<form className="w-full text-14 text-left text-black-gray">
|
||||||
|
<div className="w-full flex flex-col gap-4 justify-start items-start">
|
||||||
|
<div className='w-full grid grid-cols-2 gap-8'>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Label desc='First Name*'/>
|
||||||
|
<TextInput type='text' placeholder='Firstname'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Label desc='Last Name*'/>
|
||||||
|
<TextInput type='text' placeholder='Lastname'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Label desc='Email*'/>
|
||||||
|
<TextInput type='text' placeholder='Email'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Label desc='User Name*'/>
|
||||||
|
<TextInput type='text' placeholder='Username'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Label desc='Password*'/>
|
||||||
|
<TextInput type='password' placeholder='Password'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full text-left">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input className="form-check-input" type="checkbox" id="gridCheck"/>
|
||||||
|
<label className="font-semibold form-check-label" htmlFor="gridCheck">
|
||||||
|
I accept terms & policy of use.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<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>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</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">
|
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+150
-111
@@ -1,101 +1,119 @@
|
|||||||
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';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
email: Yup.string()
|
email: Yup.string()
|
||||||
.email("Wrong email format")
|
.email("Wrong email format")
|
||||||
// .matches(
|
// .matches(
|
||||||
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
||||||
// "Invalid email format"
|
// "Invalid email format"
|
||||||
// )
|
// )
|
||||||
.min(3, "Minimum 3 characters")
|
.min(3, "Minimum 3 characters")
|
||||||
.max(50, "Maximum 50 characters")
|
.max(50, "Maximum 50 characters")
|
||||||
.required("Email is required"),
|
.required("Email is required"),
|
||||||
firstname: Yup.string().required("Firstname is required"),
|
firstname: Yup.string().required("Firstname is required"),
|
||||||
lastname: Yup.string().required("Lastname is required"),
|
lastname: Yup.string().required("Lastname is required"),
|
||||||
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() {
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: (fields) => {
|
mutationFn: (fields) => {
|
||||||
return signUpUser(fields)
|
return signUpUser(fields)
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
console.log('res', res)
|
console.log('res', res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const signUp = (values) => {
|
||||||
|
// helpers.resetForm()
|
||||||
|
// console.log('values', values, helpers)
|
||||||
|
delete values.isChecked
|
||||||
|
mutation.mutate(values)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const signUp = (values) => {
|
return (
|
||||||
// helpers.resetForm()
|
<div className="app">
|
||||||
// console.log('values', values, helpers)
|
<div className="app-wrap">
|
||||||
delete values.isChecked
|
<div className="app-contant">
|
||||||
mutation.mutate(values)
|
<div className="vh-100 bg-white custom-bg">
|
||||||
}
|
<div className="container-fluid p-0">
|
||||||
|
<div className="row no-gutters justify-content-center">
|
||||||
return (
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1"
|
||||||
<div className="app">
|
style={{maxWidth: '520px'}}>
|
||||||
<div className="app-wrap">
|
<div className="mt-5 d-flex">
|
||||||
<div className="app-contant">
|
<div className="bg-white register p-5">
|
||||||
<div className="vh-100 bg-white custom-bg">
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<div className="container-fluid p-0">
|
<p>Welcome, Please create your account.</p>
|
||||||
<div className="row no-gutters justify-content-center">
|
<Formik
|
||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
initialValues={initialValues}
|
||||||
<div className="mt-5 d-flex">
|
validationSchema={validationSchema}
|
||||||
<div className="bg-white register p-5">
|
onSubmit={signUp}
|
||||||
<h1 className="mb-2">MERMS Panel</h1>
|
>
|
||||||
<p>Welcome, Please create your account.</p>
|
{(props) => {
|
||||||
<Formik
|
return (
|
||||||
initialValues={initialValues}
|
<Form className='mt-2 mt-sm-5'>
|
||||||
validationSchema={validationSchema}
|
<div className="row">
|
||||||
onSubmit={signUp}
|
{!mutation.isSuccess ?
|
||||||
>
|
<>
|
||||||
{(props) => {
|
<div className="col-12 col-md-6">
|
||||||
return (
|
<div className="form-group">
|
||||||
<Form className='mt-2 mt-sm-5'>
|
<label
|
||||||
<div className="row">
|
className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First
|
||||||
{!mutation.isSuccess ?
|
Name*</label>
|
||||||
<>
|
<input type="text" name='firstname'
|
||||||
<div className="col-12 col-md-6">
|
className="form-control"
|
||||||
<div className="form-group">
|
placeholder="First Name"
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First Name*</label>
|
value={props.values.firstname}
|
||||||
<input type="text" name='firstname' className="form-control" placeholder="First Name" value={props.values.firstname} onChange={props.handleChange} />
|
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
|
||||||
</div>
|
Name*</label>
|
||||||
</div>
|
<input type="text" name='lastname'
|
||||||
<div className="col-12">
|
className="form-control"
|
||||||
<div className="form-group">
|
placeholder="Last Name"
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.email && props.touched.email) && 'text-danger'}`}>Email*</label>
|
value={props.values.lastname}
|
||||||
<input type="email" name='email' className="form-control" placeholder="Email" value={props.values.email} onChange={props.handleChange} />
|
onChange={props.handleChange}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="col-12">
|
<div className="col-12">
|
||||||
|
<div className="form-group">
|
||||||
|
<label
|
||||||
|
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 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 ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Username*</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} />
|
||||||
@@ -107,62 +125,83 @@ export default function Signup2() {
|
|||||||
<input type="password" name='password' className="form-control" placeholder="Password" value={props.values.password} onChange={props.handleChange} />
|
<input type="password" name='password' className="form-control" placeholder="Password" value={props.values.password} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
</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"
|
||||||
I accept terms & policy
|
type="checkbox" id="gridCheck"
|
||||||
</label>
|
value={props.values.isChecked}
|
||||||
</div>
|
onChange={props.handleChange}/>
|
||||||
<span className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
<label className="form-check-label"
|
||||||
</div>
|
htmlFor="gridCheck">
|
||||||
|
I accept terms & policy
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{mutation.error &&
|
{mutation.error &&
|
||||||
<>
|
<>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-danger'>{mutation.error.message}</p>
|
<p className='text-danger'>{mutation.error.message}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="col-12 mt-3 text-end">
|
||||||
|
<button type='submit'
|
||||||
|
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
|
:
|
||||||
|
<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: '-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 className="col-12 mt-3 text-end">
|
<div className="col-12 mt-3">
|
||||||
<button type='submit' className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
<p>Already have an account ?<Link
|
||||||
</div>
|
to={siteLinks.login}>
|
||||||
</>
|
<button
|
||||||
:
|
className="btn btn-warning text-uppercase">
|
||||||
<div className='col-12'>
|
Sign In
|
||||||
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
|
</button>
|
||||||
<h4 className='p-4 text-black' style={{marginBottom: '-30px'}}>Check your email to continue.</h4>
|
</Link></p>
|
||||||
<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>
|
||||||
}
|
</Form>
|
||||||
|
);
|
||||||
<div className="col-12 mt-3">
|
}}
|
||||||
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Formik>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/* <div className="signup-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
|
||||||
{/* <div className="signup-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="row align-items-center h-100">
|
||||||
<div className="col-7 mx-auto ">
|
<div className="col-7 mx-auto ">
|
||||||
<img className="img-fluid" src={LoginImg} alt="" />
|
<img className="img-fluid" src={LoginImg} alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> */}
|
</div> */}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+323
-532
@@ -1,558 +1,349 @@
|
|||||||
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()
|
||||||
|
// })
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
||||||
<div className="row">
|
{getContactData?.isPending ? (
|
||||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
<>
|
||||||
<div className="col-12">
|
<div className="row">
|
||||||
<div className="card card-statistics mail-contant">
|
<div className="col-12">
|
||||||
<div className="card-body p-0">
|
<p className="text-mute">Loading...</p>
|
||||||
<div className="row no-gutters">
|
</div>
|
||||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
</div>
|
||||||
<div className="mail-sidebar">
|
</>
|
||||||
<div className="row justify-content-center">
|
) : getContactData?.error ? (
|
||||||
<div className="col-12">
|
<div className="row">
|
||||||
<div className="text-center mail-sidebar-title px-4">
|
<div className="col-12">
|
||||||
<a
|
<p className="text-danger">{getContactData?.error?.message}</p>
|
||||||
href="javascript:void(0)"
|
</div>
|
||||||
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
</div>
|
||||||
>
|
) : (
|
||||||
<i className="fa fa-plus pl-2"></i>
|
<div className="row">
|
||||||
</a>
|
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||||
</div>
|
<div className="col-12">
|
||||||
</div>
|
<div
|
||||||
<div className="col-12">
|
className="card card-statistics mail-contant"
|
||||||
<div className="px-4 py-4">
|
style={{ minHeight: "200px", borderRadius: "10px" }}
|
||||||
<ul className="pl-0">
|
>
|
||||||
<li className="py-2">
|
<div className="card-body p-0">
|
||||||
<a href="javascript:void(0)">
|
<div className="row no-gutters">
|
||||||
<span className="nav align-items-center">
|
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||||
<span>
|
<div className="mail-sidebar">
|
||||||
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
<div className="row justify-content-center">
|
||||||
</span>
|
<div className="d-none col-12">
|
||||||
<span>
|
<div className="text-center mail-sidebar-title px-4">
|
||||||
<span>Inbox</span>
|
<a
|
||||||
</span>
|
href="#"
|
||||||
<span className="nav-item ml-auto text-right">
|
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||||
<span className="badge badge-pill badge-primary float-right">
|
>
|
||||||
0+
|
<i className="fa fa-plus pl-2"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="px-4 py-4">
|
||||||
|
<ul className="pl-0">
|
||||||
|
<li className="py-2">
|
||||||
|
<a href="#">
|
||||||
|
<span className="nav align-items-center">
|
||||||
|
<span>
|
||||||
|
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span>Inbox</span>
|
||||||
|
</span>
|
||||||
|
<span className="nav-item ml-auto text-right">
|
||||||
|
<span className="badge badge-pill badge-primary float-right">
|
||||||
|
{contactsData?.length}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</a>
|
||||||
</a>
|
</li>
|
||||||
</li>
|
{/*<li className="py-2">*/}
|
||||||
<li className="py-2">
|
{/* <a href="#">*/}
|
||||||
<a href="javascript:void(0)">
|
{/* <span*/}
|
||||||
<span className="nav align-items-center">
|
{/* className="nav align-items-center">*/}
|
||||||
<span>
|
{/* <span>*/}
|
||||||
<i className="fa fa-paper-plane-o pr-4"></i>
|
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* <span>*/}
|
||||||
|
{/* <span>Replied Mail</span>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* </span>*/}
|
||||||
|
{/* </a>*/}
|
||||||
|
{/*</li>*/}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul className="pl-0 mt-5">
|
||||||
|
<li
|
||||||
|
className="py-2"
|
||||||
|
onClick={() => changeActiveCategoryUID("0")}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className="nav align-items-center">
|
||||||
|
<span>
|
||||||
|
<i
|
||||||
|
className={`fa fa-circle-o pr-4 ${
|
||||||
|
activeCategoryUID == "0"
|
||||||
|
? "text-primary"
|
||||||
|
: "text-warning"
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span>All</span>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
</div>
|
||||||
<span>Sent Mail</span>
|
</li>
|
||||||
</span>
|
{contactsCategory &&
|
||||||
</span>
|
contactsCategory.map((item) => (
|
||||||
</a>
|
<li
|
||||||
</li>
|
key={item?.cid}
|
||||||
</ul>
|
className="py-2"
|
||||||
<ul className="pl-0 mt-5">
|
onClick={() =>
|
||||||
<li className="py-2">
|
changeActiveCategoryUID(`${item?.cid}`)
|
||||||
<a href="javascript:void(0)">
|
}
|
||||||
<span className="nav align-items-center">
|
style={{ cursor: "pointer" }}
|
||||||
<span>
|
>
|
||||||
<i className="fa fa-circle-o text-danger pr-4"></i>
|
<div>
|
||||||
</span>
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<span>Personal</span>
|
<i
|
||||||
</span>
|
className={`fa fa-circle-o pr-4 ${
|
||||||
</span>
|
activeCategoryUID ==
|
||||||
</a>
|
`${item?.cid}`
|
||||||
</li>
|
? "text-primary"
|
||||||
<li className="py-2">
|
: "text-warning"
|
||||||
<a href="javascript:void(0)">
|
}`}
|
||||||
<span className="nav align-items-center">
|
></i>
|
||||||
<span>
|
</span>
|
||||||
<i className="fa fa-circle-o pr-4 text-warning"></i>
|
<span>
|
||||||
</span>
|
<span>{item?.description}</span>
|
||||||
<span>
|
</span>
|
||||||
<span>Work</span>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</span>
|
</li>
|
||||||
</a>
|
))}
|
||||||
</li>
|
</ul>
|
||||||
<li className="py-2">
|
</div>
|
||||||
<a href="javascript:void(0)">
|
</div>
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-md-8 col-xxl-4 border-md-t">
|
|
||||||
<div className="mail-content border-right border-n h-100">
|
|
||||||
<div className="mail-search border-bottom">
|
|
||||||
<div className="row align-items-center mx-0">
|
|
||||||
<div className="col-12">
|
|
||||||
<div className="form-group pt-3">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
id="search"
|
|
||||||
placeholder="Search.."
|
|
||||||
/>
|
|
||||||
<i className="fa fa-search"></i>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
|
||||||
<div className="mail-msg scrollbar scroll_dark">
|
<div className="mail-content border-right border-n h-100" style={{placeContent: 'center'}}>
|
||||||
<div className="mail-msg-item">
|
{/* <div className="mail-search border-bottom">
|
||||||
<a href="javascript:void(0)">
|
<div className="row align-items-center mx-0">
|
||||||
<div className="media align-items-center">
|
<div className="col-12">
|
||||||
<div className="mr-3">
|
<div className="form-group pt-3">
|
||||||
<div className="bg-img">
|
<input type="text" className="form-control" id="search" placeholder="Search.." />
|
||||||
<img
|
<i className="fa fa-search"></i>
|
||||||
src={getImage("avtar/01.jpg")}
|
|
||||||
className="img-fluid"
|
|
||||||
alt="user"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-100">
|
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
|
||||||
<p>Martin smith</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>
|
|
||||||
Since there is not an "all the above" category,
|
|
||||||
I'll take the opportunity to enthusiastically
|
|
||||||
congratulate you on the very high quality.
|
|
||||||
</p>
|
|
||||||
<p className="d-xl-none">
|
|
||||||
06:59 <span> PM </span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
|
</div> */}
|
||||||
|
<div className="mail-msg scrollbar scroll_dark">
|
||||||
|
{ filteredContactData.length ?
|
||||||
|
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="mr-3">
|
||||||
|
<div className="bg-img">
|
||||||
|
<img
|
||||||
|
src={getImage(avtarImage)}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-100">
|
||||||
|
<div className="mail-msg-item-titel justify-content-between">
|
||||||
|
<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>
|
||||||
|
<h5 className="mb-0 my-2">
|
||||||
|
{contact?.title}
|
||||||
|
</h5>
|
||||||
|
<p>
|
||||||
|
{contact?.message?.length < 100
|
||||||
|
? contact?.message
|
||||||
|
: contact?.message.substring(0, 101) +
|
||||||
|
" ..."}
|
||||||
|
</p>
|
||||||
|
<p className="d-xl-none">
|
||||||
|
<span>
|
||||||
|
{new Date(
|
||||||
|
contact?.added
|
||||||
|
).toDateString()}
|
||||||
|
{/* {getCustomTime(contact.added)} */}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<p className="text-center">Messages will appear here as soon as they are available for selection</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mail-msg-item">
|
{filteredContactData.length > 0 &&
|
||||||
<a href="javascript:void(0)">
|
<div className="col-xxl-6 border-t border-xxl-t">
|
||||||
<div className="media align-items-center">
|
<div className="mail-chat py-5 px-5">
|
||||||
<div className="mr-3">
|
<div className="media align-items-center">
|
||||||
<div className="bg-img">
|
<div className="bg-img mr-3">
|
||||||
<img
|
<img
|
||||||
src={getImage("avtar/02.jpg")}
|
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
||||||
className="img-fluid"
|
className="img-fluid"
|
||||||
alt="user"
|
alt="user"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 className="mb-0" style={{ color: "#148399" }}>
|
||||||
|
{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="w-100">
|
<div>
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
<h3>
|
||||||
<p>DutcaPatrick</p>
|
{activeContactUID
|
||||||
<p className="d-none d-xl-block">
|
? activeDetail[0]?.title
|
||||||
06:59 <span> PM </span>
|
: filteredContactData[0]?.title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<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-print font-22"></i></a>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.message
|
||||||
|
: filteredContactData[0]?.message}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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>
|
||||||
</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>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-xxl-6 border-t border-xxl-t">
|
|
||||||
<div className="mail-chat py-5 px-5">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="bg-img mr-3">
|
|
||||||
<img
|
|
||||||
src={getImage("avtar/03.jpg")}
|
|
||||||
className="img-fluid"
|
|
||||||
alt="user"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h4 className="mb-0">Dutca Patrick</h4>
|
|
||||||
<p>30 Min ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 d-flex justify-content-between">
|
|
||||||
<div>
|
|
||||||
<h3>Landing page Designer...</h3>
|
|
||||||
</div>
|
|
||||||
<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-print font-22"></i></a>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="my-4">hey adminjon...</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>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<div className="my-5">
|
|
||||||
<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>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default function Contacts() {
|
|||||||
if (id == "0") {
|
if (id == "0") {
|
||||||
filteredConData = contactsData;
|
filteredConData = contactsData;
|
||||||
} else {
|
} else {
|
||||||
filteredConData = contactsData.filter((item) => item.category == `A00000${id}`);
|
filteredConData = contactsData.filter((item) => item.category == id);
|
||||||
}
|
}
|
||||||
setFiltererdContactData(filteredConData);
|
setFiltererdContactData(filteredConData);
|
||||||
changeActiveUID(filteredConData[0]?.uid);
|
changeActiveUID(filteredConData[0]?.uid);
|
||||||
@@ -87,7 +87,7 @@ export default function Contacts() {
|
|||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div
|
<div
|
||||||
className="card card-statistics mail-contant"
|
className="card card-statistics mail-contant"
|
||||||
style={{ minHeight: "550px", borderRadius: "10px" }}
|
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">
|
||||||
@@ -197,20 +197,20 @@ export default function Contacts() {
|
|||||||
</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.length ?
|
||||||
filteredContactData?.map((contact, index) => {
|
filteredContactData?.map((contact, index) => {
|
||||||
const isActive =
|
const isActive =
|
||||||
contact?.uid == activeContactUID ||
|
contact?.uid == activeContactUID ||
|
||||||
@@ -282,16 +282,20 @@ export default function Contacts() {
|
|||||||
</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
|
<img
|
||||||
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : contactsData ? getImage("avtar/" + contactsData[0]?.category + ".png") : getImage("avtar/01.jpg")}
|
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
||||||
className="img-fluid"
|
className="img-fluid"
|
||||||
alt="user"
|
alt="user"
|
||||||
/>
|
/>
|
||||||
@@ -333,6 +337,7 @@ export default function Contacts() {
|
|||||||
</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>
|
||||||
</>;
|
</>;
|
||||||
|
|
||||||
|
|||||||
@@ -64,28 +64,30 @@ export default function TopBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 ${item?.extra_style} `} style={{borderRadius: '10px'}}>
|
<Link to={item?.link}>
|
||||||
<div className="card-body p-0">
|
<div className={`card card-statistics ecommerce-contant overflow-h ${item?.extra_style} `} style={{borderRadius: '10px'}}>
|
||||||
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
|
<div className="card-body p-0">
|
||||||
<div className="w-100">
|
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
|
||||||
<div className="row p-3">
|
<div className="w-100">
|
||||||
<div className="col">
|
<div className="row p-3">
|
||||||
<h3 className="mb-0">{item?.value || 0}</h3>
|
<div className="col">
|
||||||
<small className="d-block">{item?.extra_style ? dataSpan : item?.data_span}</small>
|
<h3 className="mb-0">{item?.value || 0}</h3>
|
||||||
|
<small className="d-block">{item?.extra_style ? dataSpan : item?.data_span}</small>
|
||||||
|
</div>
|
||||||
|
<div className="col text-right">
|
||||||
|
<h5 className="text-muted mb-0">{item?.description}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="apexchart-wrapper">
|
||||||
|
<div id="ecommercedemo3" className="chart-fit"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col text-right">
|
|
||||||
<h5 className="text-muted mb-0"><Link to={item?.link}>{item?.description}</Link></h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="apexchart-wrapper">
|
|
||||||
<div id="ecommercedemo3" className="chart-fit"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function UserMenu() {
|
|||||||
<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}>Sites 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}>Sites Comments</Link></li>
|
<li className={`${pathname == siteLinks.comments ? 'active' : ''}`}><Link to={siteLinks.comments}>Comments</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li className={`${pathname == siteLinks.reports ? 'active' : ''}`}>
|
<li className={`${pathname == siteLinks.reports ? 'active' : ''}`}>
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
import React, { useMemo, useRef, useState } from "react";
|
import React, {useEffect, useMemo, useRef, useState} from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { productRefreshSite, getSettingsData } from "../../services/services";
|
import { productRefreshSite, getSettingsData } from "../../services/services";
|
||||||
import Settings from "./settingsTab/Settings";
|
import Settings from "./settingsTab/Settings";
|
||||||
import queryKeys from "../../services/queryKeys";
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import {SocketContextValues} from "../context/SocketIOContext";
|
||||||
|
|
||||||
|
|
||||||
export default function ProductActive({productData}){
|
export default function ProductActive({productData}){
|
||||||
|
const {joinRoom} = SocketContextValues() // Destructures values from socket context
|
||||||
const iframe = useRef()
|
const iframe = useRef()
|
||||||
|
|
||||||
|
const [refreshMsg, setRefreshMsg] = useState('')
|
||||||
|
|
||||||
const refresh = useMutation({
|
const refresh = useMutation({
|
||||||
mutationFn: (fields) => {
|
mutationFn: (fields) => {
|
||||||
return productRefreshSite(fields)
|
return productRefreshSite(fields)
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
|
setRefreshMsg(res?.data?.message)
|
||||||
|
setTimeout(()=>{setRefreshMsg('')},3000)
|
||||||
iframe.current.src += ''
|
iframe.current.src += ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -31,6 +36,13 @@ export default function ProductActive({productData}){
|
|||||||
}
|
}
|
||||||
let externalUrl= 'https://'+productData?.internal_url
|
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(
|
||||||
<>
|
<>
|
||||||
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
|
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
|
||||||
@@ -46,7 +58,9 @@ export default function ProductActive({productData}){
|
|||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="card-heading d-flex justify-content-between">
|
<div className="card-heading d-flex justify-content-between">
|
||||||
<h4 className="card-title">{externalUrl}</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">
|
<button type="button" onClick={()=>iframe.current.src += ''} className="btn">
|
||||||
<img src={getImage('refresh.png')} style={{width: '30px', height: 'auto'}} alt='refresh page' />
|
<img src={getImage('refresh.png')} style={{width: '30px', height: 'auto'}} alt='refresh page' />
|
||||||
</button>
|
</button>
|
||||||
@@ -56,8 +70,13 @@ export default function ProductActive({productData}){
|
|||||||
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 ml-auto">
|
<div className="p-4 ml-auto">
|
||||||
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Loading...' : 'Refresh Site'}
|
<div className="d-flex justify-end gap-3">
|
||||||
</button>
|
{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>
|
||||||
|
|||||||
@@ -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,39 +1,41 @@
|
|||||||
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;
|
||||||
const productDescription = props?.productData?.description;
|
const productDescription = props?.productData?.description;
|
||||||
const productID = props?.productData?.product_id
|
const productID = props?.productData?.product_id
|
||||||
const productUID = props?.productData?.product_uid
|
const productUID = props?.productData?.product_uid
|
||||||
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 (
|
||||||
<>
|
<>
|
||||||
{isFetching ?
|
{isFetching ?
|
||||||
<>
|
<>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -42,82 +44,87 @@ export default function ProductProvision(props){
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
: isError ?
|
: isError ?
|
||||||
<div className="row">
|
|
||||||
<div className="col-12">
|
|
||||||
<p className='text-danger'>{error.message}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<>
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-12">
|
<div className="col-12">
|
||||||
<div className="card card-statistics">
|
<p className='text-danger'>{error.message}</p>
|
||||||
<div className="card-header">
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-header">
|
||||||
<div className="card-heading">
|
<div className="card-heading">
|
||||||
<h4 className="card-title">Creating - {productTitle} </h4>
|
<h4 className="card-title">Creating - {productTitle} </h4>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="row">
|
||||||
<div className="row">
|
<div className="col-md-12">
|
||||||
<div className="col-md-12">
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="row">
|
||||||
<div className="row">
|
<div className="col-lg-6">
|
||||||
<div className="col-lg-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">
|
||||||
<h4 className="card-title">Progress Information</h4>
|
<h4 className="card-title">Progress Information</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="card-body">
|
||||||
<div className="card-body">
|
<div className="table-responsive">
|
||||||
<div className="table-responsive">
|
<table className="table table-info mb-0">
|
||||||
<table className="table table-info mb-0">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th scope="col" style={{width: '10px'}}>#</th>
|
||||||
<th scope="col" style={{width: '10px'}}>#</th>
|
<th scope="col">Action</th>
|
||||||
<th scope="col">Action</th>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{provisionData?.activities?.map(item => (
|
|
||||||
<tr key={item.id}>
|
|
||||||
<th scope="row">{item.id}</th>
|
|
||||||
<td>{item.action}</td>
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{provisionData?.activities?.map(item => (
|
||||||
|
<tr key={item.id}>
|
||||||
|
<th scope="row">{item.id}</th>
|
||||||
|
<td>{item.action}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
||||||
{/* <div className="card-body">
|
<img className="card-img-top" src={getImage('widget/working.jpg')}
|
||||||
|
alt="Card image cap"/>
|
||||||
|
{/* <div className="card-body">
|
||||||
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
||||||
</div> */}
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const ColorStyleConfigure =()=>{
|
||||||
|
|
||||||
|
return <>COLOR CONFIG</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ColorStyleConfigure
|
||||||
@@ -1,126 +1,190 @@
|
|||||||
import React, {memo, useState} from 'react'
|
import React, {memo, useEffect, useMemo, useState} from 'react'
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import {useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
import { pageSettings } from "../../../services/services";
|
import {pageSettings} from "../../../services/services";
|
||||||
import SiteTemplateSelector from './SiteTemplateSelector';
|
import SiteTemplateSelector from './SiteTemplateSelector';
|
||||||
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
|
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
|
||||||
import { IoMdArrowDropdown } from 'react-icons/io';
|
import {IoMdArrowDropdown} from 'react-icons/io';
|
||||||
import queryKeys from '../../../services/queryKeys';
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder';
|
||||||
|
import URLConfiguration from "./URLConfiguration";
|
||||||
|
import ColorStyleConfigure from "./ColorStyleConfigure";
|
||||||
|
|
||||||
const GeneralTab = memo(({name='Full Name', data, isCustom, productData, backendValues, setFieldsChanged}) =>{
|
const GeneralTab = memo(({
|
||||||
|
name = 'Full Name',
|
||||||
|
data,
|
||||||
|
tabKey,
|
||||||
|
isCustom,
|
||||||
|
productData,
|
||||||
|
backendValues,
|
||||||
|
setFieldsChanged
|
||||||
|
}) => {
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const [reqStatus, setReqStatus] = useState({error: null, message: ''})
|
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 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(fieldData)
|
|
||||||
|
|
||||||
const handleChange = ({target:{name, value}}) => {
|
|
||||||
setFields(prev => ({...prev, [name]:value}))
|
|
||||||
setFieldsChanged(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const submitSettings = useMutation({
|
const [fields, setFields] = useState({})
|
||||||
mutationFn: (fields) => {
|
|
||||||
return pageSettings(fields)
|
const sortedData = sortObjectByListOrder(data ? data : {}) // SORTED SETTINGSCONFIG
|
||||||
},
|
|
||||||
onSuccess: (res) => {
|
useEffect(() => {
|
||||||
if(res?.data?.resultCode != '0'){
|
const fieldData = {}
|
||||||
return setReqStatus({error: true, message: 'Unable to complete, try again later'})
|
Object.entries(sortedData)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
|
||||||
}
|
fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
|
||||||
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(()=>{
|
backendValues?.data?.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
|
||||||
setReqStatus({error: null, message: ''})
|
fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
|
||||||
},3000)
|
})
|
||||||
},
|
setFields(fieldData)
|
||||||
})
|
}, [backendValues.data])
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleChange = ({target: {name, value}}) => {
|
||||||
const reqData = {
|
setFields(prev => ({...prev, [name]: value}))
|
||||||
token: localStorage.getItem('token'), // USER TOKEN
|
setFieldsChanged(true)
|
||||||
uid: localStorage.getItem('uid'), // USER UID
|
|
||||||
product_id: productData?.product_id,
|
|
||||||
settings : {
|
|
||||||
...fields
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// console.log('formInfo', reqData)
|
|
||||||
submitSettings.mutate(reqData)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCustom === true){
|
const submitSettings = useMutation({
|
||||||
return <SiteTemplateSelector name={name} data={data} isCustom={isCustom} productData={productData} />
|
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 = () => {
|
||||||
return (
|
const reqData = {
|
||||||
<div className="page-account-form">
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
<div className="p-0" style={{ minHeight: '500px'}}>
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
<form id='tab_form'>
|
settings: {
|
||||||
<div className="form-row">
|
...fields
|
||||||
<>
|
}
|
||||||
{Object.entries(data)?.map(([key, value]) => {
|
}
|
||||||
let fieldName = value.name.toLowerCase().replaceAll(" ", "_")
|
submitSettings.mutate(reqData)
|
||||||
let fieldValue = fields[value.name.toLowerCase().replaceAll(" ", "_")]
|
}
|
||||||
return (
|
console.log(tabKey);
|
||||||
<div key={key} className="form-group col-md-12">
|
return (
|
||||||
<label htmlFor="name1">{value.name}</label>
|
<>
|
||||||
{value.controls == 'TEXT' ?
|
{backendValues?.isFetching || !backendValues?.data ?
|
||||||
<input name={fieldName} type="text" className="form-control" id={key} value={fieldValue} onChange={handleChange} />
|
<>
|
||||||
:value.controls == 'TEXTAREA' ?
|
<div className="row">
|
||||||
<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">
|
<div className="col-12">
|
||||||
<p className={reqStatus.error ? 'text-danger' : 'text-success'}>{reqStatus.message}</p>
|
<p className='text-mute'>Loading...</p>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</>
|
||||||
</form>
|
: backendValues?.isError ?
|
||||||
</div>
|
<div className="row">
|
||||||
</div>
|
<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="p-0" style={{minHeight: '500px'}}>
|
||||||
|
|
||||||
|
<form id='tab_form'>
|
||||||
|
<div className="form-row">
|
||||||
|
<>
|
||||||
|
{Object.entries(sortedData)?.map(([key, value]) => {
|
||||||
|
let fieldName = key; // value.key.toLowerCase().replaceAll(" ", "_")
|
||||||
|
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>
|
||||||
|
:
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +1,35 @@
|
|||||||
import React, { memo, useMemo, useState } from 'react'
|
import React, { memo, useMemo, useState } from 'react'
|
||||||
import GeneralTab from './GeneralTab'
|
import GeneralTab from './GeneralTab'
|
||||||
import { getSettingsData } from '../../../services/services';
|
import { getSettingsData, getMyProductConfig } from '../../../services/services';
|
||||||
import queryKeys from '../../../services/queryKeys';
|
import queryKeys from '../../../services/queryKeys';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
||||||
|
|
||||||
const Settings = memo(({productData}) => {
|
const Settings = memo(({productData}) => {
|
||||||
|
|
||||||
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
|
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
|
||||||
|
|
||||||
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 ={
|
const {data:configData, isFetching:configIsFetching, configIsError, error:configError} = useQuery({
|
||||||
facebook: { name: 'Facebook', controls: 'TEXT', active: true },
|
queryKey: queryKeys.myProductConfig,
|
||||||
twitter: { name: 'Twitter', controls: 'TEXT', active: true },
|
queryFn: () => {
|
||||||
youtube: { name: 'Youtube', controls: 'TEXT', active: true },
|
let reqData = {
|
||||||
}
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
const homeFields ={
|
product_id: productData?.product_id
|
||||||
banner_text: { name: 'Banner Text', controls: 'TEXT', active: true },
|
}
|
||||||
banner_description: { name: 'Banner Description', controls: 'TEXTAREA', active: true },
|
return getMyProductConfig(reqData)
|
||||||
}
|
},
|
||||||
|
staleTime: 0,
|
||||||
const footerFields ={
|
})
|
||||||
footer_description: { name: 'Footer Description', controls: 'TEXTAREA', active: true },
|
const settingsConfig = configData?.data?.settings_items
|
||||||
boolean_footer_show_email: { name: 'Show email in footer', controls: 'SELECT_NO_YES', active: true },
|
// console.log('CONFIG DATA...', settingsConfig)
|
||||||
}
|
|
||||||
|
|
||||||
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 [fieldsChanged, setFieldsChanged] = useState(false)
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState(Object.entries(settingsObject)[0][1]?.controls)
|
// const [activeTab, setActiveTab] = useState(Object.entries(settingsConfig)[0][1]?.controls)
|
||||||
|
const [activeTab, setActiveTab] = useState(null)
|
||||||
|
|
||||||
const handleChangeTab = (value) => {
|
const handleChangeTab = (value) => {
|
||||||
// if(fieldsChanged){
|
// if(fieldsChanged){
|
||||||
@@ -97,15 +54,19 @@ const Settings = memo(({productData}) => {
|
|||||||
product_id: productData?.product_id
|
product_id: productData?.product_id
|
||||||
}
|
}
|
||||||
return getSettingsData(reqData)
|
return getSettingsData(reqData)
|
||||||
}
|
},
|
||||||
|
staleTime: 0,
|
||||||
|
enabled: settingsConfig ? true : false
|
||||||
})
|
})
|
||||||
|
|
||||||
const settingsData = data?.data?.settings
|
const settingsData = {data: data?.data?.settings, isFetching, isError, error}
|
||||||
// console.log('data', settingsData)
|
// console.log('data', settingsData)
|
||||||
|
|
||||||
|
const sortedSettingsConfig = sortObjectByListOrder(settingsConfig ? settingsConfig : {}) // SORTED SETTINGSCONFIG
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isFetching ?
|
{configIsFetching ?
|
||||||
<>
|
<>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -113,19 +74,19 @@ const Settings = memo(({productData}) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
: isError ?
|
: configIsError ?
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-danger'>{error.message}</p>
|
<p className='text-danger'>{configError.message}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="tab tab-vertical">
|
<div className="tab tab-vertical">
|
||||||
<ul className="nav nav-tabs" role="tablist">
|
<ul className="nav nav-tabs" role="tablist">
|
||||||
<>
|
<>
|
||||||
{Object.entries(settingsObject).map(([key, value]) => (
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
<li key={key} className="nav-item">
|
<li key={key} className="nav-item">
|
||||||
<a className={`nav-link ${activeTab == value.controls && 'active show'}`}
|
<a className={`nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||||
id={key}
|
id={key}
|
||||||
// data-bs-toggle="pill"
|
// data-bs-toggle="pill"
|
||||||
// data-bs-target={`#${value.controls}`}
|
// data-bs-target={`#${value.controls}`}
|
||||||
@@ -143,12 +104,12 @@ const Settings = memo(({productData}) => {
|
|||||||
</ul>
|
</ul>
|
||||||
<div className="tab-content">
|
<div className="tab-content">
|
||||||
<>
|
<>
|
||||||
{Object.entries(settingsObject).map(([key, value]) => (
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
<div key={key} className={`tab-pane fade ${activeTab == value.controls && 'active show'}`}
|
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||||
// id={value.controls} role="tabpanel"
|
// id={value.controls} role="tabpanel"
|
||||||
// aria-labelledby={key}
|
// aria-labelledby={key}
|
||||||
>
|
>
|
||||||
<GeneralTab name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
<GeneralTab tabKey={key} name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@@ -160,4 +121,4 @@ const Settings = memo(({productData}) => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export default Settings
|
export default Settings
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import React, {memo} from 'react'
|
import React, {memo} from 'react'
|
||||||
import getImage from "../../../utils/getImage";
|
import getImage from "../../../utils/getImage";
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
import queryKeys from '../../../services/queryKeys';
|
import queryKeys from '../../../services/queryKeys';
|
||||||
import { getProductTemplateData } from '../../../services/services';
|
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 SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
|
||||||
|
|
||||||
const {data:templateData, isFetching, isError, error} = useQuery({
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||||
queryKey: queryKeys.productTemplateData,
|
queryKey: queryKeys.productTemplateData,
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
let reqData = {
|
let reqData = {
|
||||||
@@ -14,56 +18,115 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
|||||||
uid: localStorage.getItem('uid'), // USER UID
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
product_id: productData?.product_id
|
product_id: productData?.product_id
|
||||||
}
|
}
|
||||||
return getProductTemplateData(reqData)
|
return getProductTemplateData(reqData)
|
||||||
},
|
},
|
||||||
staleTime: 0
|
staleTime: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const templateResponse = templateData?.data
|
const templateResponse = templateData?.data
|
||||||
|
const currentTemUID = templateResponse?.current_template_uid
|
||||||
const templates = templateResponse?.templates
|
const templates = templateResponse?.templates
|
||||||
|
const custom_template_name = templateResponse?.custom_template_name
|
||||||
|
|
||||||
// console.log('data Template', templates)
|
// console.log('data Template', templateResponse)
|
||||||
// console.log("Page data == ", data)
|
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 (
|
return (
|
||||||
<div className="page-account-form">
|
<div className="page-account-form">
|
||||||
<div className="p-0">
|
<div className="p-0">
|
||||||
{isFetching ?
|
{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">
|
|
||||||
<>
|
<>
|
||||||
{!templates.length ?
|
<div className="row">
|
||||||
<p>No data Found</p>
|
<div className="col-12">
|
||||||
:
|
<p className='text-mute'>Loading...</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>
|
|
||||||
<a href="#" className="btn btn-light">Activate</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))
|
</div>
|
||||||
}
|
</>
|
||||||
{/* {Object.entries(data)?.map(([key, value]) => (
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className="row">
|
||||||
|
<>
|
||||||
|
{!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 key={key} className="col-xl-6 col-sm-6">
|
||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
@@ -78,8 +141,25 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
|||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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,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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {useEffect, useMemo, useState} from "react";
|
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
// import { useLocation } from "react-router-dom";
|
// import { useLocation } from "react-router-dom";
|
||||||
// import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import {useMutation, useQuery} from "@tanstack/react-query";
|
import {useMutation, useQuery} from "@tanstack/react-query";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
@@ -13,17 +13,19 @@ import {updateUserDetails} from "../../store/UserDetails";
|
|||||||
import {useDispatch} from "react-redux";
|
import {useDispatch} from "react-redux";
|
||||||
|
|
||||||
|
|
||||||
// const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
// practice: Yup.string().required("Required"),
|
practice: Yup.string().required("Required"),
|
||||||
// specialization: Yup.string().required("Required"),
|
specialization: Yup.string().when('practice', {
|
||||||
// introduction: Yup.string().min(1, "Minimum 10 characters").max(50, "Maximum 50 characters").required("Required"),
|
is: (value) => typeof value === 'string' && value.trim().length > 0,
|
||||||
// })
|
then: (schema) => schema.required('Required'),
|
||||||
|
otherwise: (schema) => schema,
|
||||||
// const initialValues = {
|
}),
|
||||||
// practice: '',
|
introduction: Yup.string().min(1, "Minimum 1 character").max(50, "Maximum 50 characters"),
|
||||||
// specialization: '',
|
url_name: Yup.string().min(6, "Minimum 6 characters").max(16, "Maximum 16 characters").required("Required").matches(
|
||||||
// introduction: '',
|
/^[a-zA-Z0-9]+$/, // Regex for alphanumeric characters
|
||||||
// };
|
'Must contain only alphanumeric characters' // Custom error message
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
export default function ProfileCompleteCom() {
|
export default function ProfileCompleteCom() {
|
||||||
@@ -35,28 +37,27 @@ export default function ProfileCompleteCom() {
|
|||||||
const {state: {redirectLink}} = useLocation()
|
const {state: {redirectLink}} = useLocation()
|
||||||
|
|
||||||
const [practices, setPractices] = useState([])
|
const [practices, setPractices] = useState([])
|
||||||
|
const [specialties, setSpecialties] = useState([])
|
||||||
|
|
||||||
const [initialValues, setInitialValues] = useState({
|
const [initialValues, setInitialValues] = useState({
|
||||||
practice: '',
|
practice: '',
|
||||||
specialization: '',
|
specialization: '',
|
||||||
introduction: '',
|
introduction: '',
|
||||||
|
url_name: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const specialties = useMemo(() => { // FUNCTION TO UPDATE SPECIALITY ARRAY EACH TIME PRACTICE CHANGES
|
const handleUpdateSpecialties = (e) => {
|
||||||
setInitialValues(prev => ({...prev, specialization: ''}))
|
setInitialValues(prev => ({...prev, specialization: ''}))
|
||||||
if (!initialValues.practice) {
|
const specialtiesArr = practices.filter(item => item.practice == e.target.value)[0]?.specialties
|
||||||
return []
|
setSpecialties(specialtiesArr)
|
||||||
}
|
}
|
||||||
const specialtiesArr = practices.filter(item => item.practice == initialValues.practice)[0]?.specialties
|
|
||||||
return specialtiesArr
|
|
||||||
}, [initialValues.practice])
|
|
||||||
|
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: (fields) => {
|
mutationFn: (fields) => {
|
||||||
const {practice, specialization} = fields
|
const {practice, specialization, url_name} = fields
|
||||||
if (!practice || !specialization) {
|
if (!practice || !specialization || !url_name) {
|
||||||
throw new Error('Please select both practice and specialization fields')
|
throw new Error('Please Select both Practice, Specialization and Enter URL_Name')
|
||||||
}
|
}
|
||||||
return completeProfile(fields)
|
return completeProfile(fields)
|
||||||
},
|
},
|
||||||
@@ -93,15 +94,11 @@ export default function ProfileCompleteCom() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const handlePracticeChange = ({target: {name, value}}) => {
|
const handleCompleteProfile = (values) => { // FUNCTION TO COMPLETE PROFILE
|
||||||
setInitialValues(prev => ({...prev, [name]: value}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCompleteProfile = () => { // FUNCTION TO COMPLETE PROFILE
|
|
||||||
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
|
||||||
...initialValues
|
...values
|
||||||
}
|
}
|
||||||
mutation.mutate(reqData)
|
mutation.mutate(reqData)
|
||||||
}
|
}
|
||||||
@@ -145,89 +142,146 @@ export default function ProfileCompleteCom() {
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className='h-100 row flex-column'>
|
<div className='h-100 row flex-column'>
|
||||||
{/* <div className="row"> */}
|
{/* <div className="row"> */}
|
||||||
<>
|
<Formik
|
||||||
<div className="">
|
initialValues={initialValues}
|
||||||
<div className="form-group position-relative">
|
validationSchema={validationSchema}
|
||||||
<label className={`text-black fw-bold control-label`}>Practice :</label>
|
onSubmit={handleCompleteProfile}
|
||||||
<div className="position-relative">
|
enableReinitialize={true}
|
||||||
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
|
>
|
||||||
<option value=''>Select</option>
|
{(props) => {
|
||||||
{practices.map((practice, index)=>(
|
return (
|
||||||
<option key={index} value={practice.practice}>{practice.practice}</option>
|
<Form className='mt-2'>
|
||||||
))}
|
<>
|
||||||
</select> */}
|
<div className="">
|
||||||
<select onChange={handlePracticeChange} name='practice'
|
<div className="form-group position-relative">
|
||||||
value={initialValues.practice} className="form-control">
|
<label className={`text-black fw-bold control-label`}>Practice : <span className="text-danger">{(props.errors.practice && props.touched.practice) && props.errors.practice}</span></label>
|
||||||
<option value=''>Select</option>
|
<div className="position-relative">
|
||||||
{practices.map((practice, index) => (
|
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
|
||||||
<option key={index}
|
<option value=''>Select</option>
|
||||||
value={practice.practice}>{practice.practice}</option>
|
{practices.map((practice, index)=>(
|
||||||
))}
|
<option key={index} value={practice.practice}>{practice.practice}</option>
|
||||||
</select>
|
))}
|
||||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
</select> */}
|
||||||
top: '50%',
|
<select
|
||||||
right: '2px',
|
onChange={(e) => {props.handleChange(e); props.setFieldValue('specialization', ''); handleUpdateSpecialties(e)}}
|
||||||
transform: 'translateY(-50%)'
|
name='practice'
|
||||||
}}/>
|
value={props.values.practice} className="form-control">
|
||||||
</div>
|
<option value=''>Select</option>
|
||||||
</div>
|
{practices.map((practice, index) => (
|
||||||
</div>
|
<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="">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label`}>Your
|
<label className={`text-black fw-bold control-label`}>Your
|
||||||
Specialization :</label>
|
Specialization : <span className="text-danger">{(props.errors.specialization && props.touched.specialization) && props.errors.specialization}</span></label>
|
||||||
<div className="position-relative">
|
<div className="position-relative">
|
||||||
<select onChange={handlePracticeChange} name='specialization'
|
<select onChange={props.handleChange} name='specialization'
|
||||||
value={initialValues.specialization}
|
value={props.values.specialization}
|
||||||
className="form-control">
|
className="form-control">
|
||||||
<option value=''>Select</option>
|
<option value=''>Select</option>
|
||||||
{specialties.map((specialty, index) => (
|
{specialties.map((specialty, index) => (
|
||||||
<option key={index} value={specialty}>{specialty}</option>
|
<option key={index} value={specialty}>{specialty}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||||
top: '50%',
|
top: '50%',
|
||||||
right: '2px',
|
right: '2px',
|
||||||
transform: 'translateY(-50%)'
|
transform: 'translateY(-50%)'
|
||||||
}}/>
|
}}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="">
|
<div className="">
|
||||||
<div className="form-group position-relative">
|
<div className="form-group position-relative">
|
||||||
<label className={`text-black fw-bold control-label`}>Other General
|
<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>
|
||||||
Information :</label>
|
<textarea name='introduction' rows={5} style={{resize: 'none'}}
|
||||||
<textarea name='introduction' rows={10} style={{resize: 'none'}}
|
className="form-control" value={props.values.introduction}
|
||||||
className="form-control" value={initialValues.introduction}
|
onChange={props.handleChange}/>
|
||||||
onChange={handlePracticeChange}/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="">
|
<div className="">
|
||||||
<div className="form-group position-relativ'e">
|
<div className="form-group position-relativ'e">
|
||||||
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
|
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
|
||||||
{/* information for :</label>*/}
|
{/* information for :</label>*/}
|
||||||
<div style={{fontSize: '14px', borderRadius: '10px', backgroundColor: 'aliceblue', fontWeight:'bolder', padding: '15px' }}>
|
<div style={{
|
||||||
MERMS A.I. agents use the information supplied to help generate useful entries for your product settings.
|
fontSize: '14px',
|
||||||
</div>
|
borderRadius: '10px',
|
||||||
</div>
|
backgroundColor: 'aliceblue',
|
||||||
</div>
|
fontWeight: 'bolder',
|
||||||
|
padding: '15px'
|
||||||
|
}}>
|
||||||
|
MERMS A.I. agents use the information supplied to help generate
|
||||||
|
useful entries for your product settings.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{(mutation.isError || mutation.isSuccess) &&
|
<div className="">
|
||||||
<>
|
<div className="form-group position-relative">
|
||||||
<div className="">
|
<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>
|
||||||
<p className={`${mutation.isSuccess ? 'text-success' : 'text-danger'}`}>{mutation.isSuccess ? 'Completed successfully, redirecting...' : mutation.error.message}</p>
|
<div className="position-relative d-flex flex-column flex-xxl-row" style={{gap: '10px'}}>
|
||||||
</div>
|
{/* <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>
|
||||||
|
|
||||||
<div className="mt-auto text-end">
|
{(mutation.isError || mutation.isSuccess) &&
|
||||||
<button type='button' onClick={handleCompleteProfile}
|
<>
|
||||||
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Continue'}</button>
|
<div className="">
|
||||||
</div>
|
<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>
|
||||||
|
|||||||
+249
-168
@@ -1,192 +1,274 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
|
import queryKeys from "../../services/queryKeys";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { profileDetails } from "../../services/services";
|
||||||
|
|
||||||
|
|
||||||
export default function Settings(){
|
|
||||||
|
|
||||||
|
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"),
|
||||||
|
})
|
||||||
|
|
||||||
|
const linksValidationSchema = Yup.object().shape({
|
||||||
|
// facebook_url: Yup.string().required("facebook is required"),
|
||||||
|
// twitter_url: Yup.string().required("twitter is required"),
|
||||||
|
// blogger_url: Yup.string().required("blog is required"),
|
||||||
|
// google_url: Yup.string().required("google is required"),
|
||||||
|
// linked_url: Yup.string().required("linkedin is required"),
|
||||||
|
// website_url: Yup.string().required("website is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default function Settings() {
|
||||||
const avtarImage = "avtar/merms-user.png";
|
const avtarImage = "avtar/merms-user.png";
|
||||||
return(
|
|
||||||
|
const [intialData, setInitialData] = useState({
|
||||||
|
external_links: {},
|
||||||
|
personal_data: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
const updateProfile = (values, helpers) => {
|
||||||
|
console.log('Values', values)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateLinks = (values, helpers) => {
|
||||||
|
console.log('Values', values)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 account-contant">
|
<>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-mute">Loading...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="card card-statistics">
|
<p className="text-danger">{error?.message}</p>
|
||||||
<div className="card-body p-0" style={{backgroundColor:"#f9f9fb"}}>
|
</div>
|
||||||
<div className="row no-gutters">
|
</div>
|
||||||
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
:
|
||||||
<div className="page-account-profil pt-5">
|
<div className="row account-contant">
|
||||||
<div className="profile-img text-center rounded-circle">
|
<div className="col-12">
|
||||||
<div className="pt-5">
|
<div className="card card-statistics">
|
||||||
<div className="bg-img m-auto">
|
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
||||||
{/*<img src="assets/img/avtar/01.jpg" className="img-fluid"*/}
|
<div className="row no-gutters">
|
||||||
{/* alt="users-avatar" />*/}
|
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
||||||
<img src={getImage(avtarImage)}
|
<div className="page-account-profil pt-5">
|
||||||
className="img-fluid" alt="user"/>
|
<div className="profile-img text-center rounded-circle">
|
||||||
</div>
|
<div className="pt-5">
|
||||||
<div className="profile pt-4">
|
<div className="bg-img m-auto">
|
||||||
<h4 className="mb-1">Alice Williams</h4>
|
{/*<img src="assets/img/avtar/01.jpg" className="img-fluid"*/}
|
||||||
<div style={{padding: '10px'}}><hr /></div>
|
{/* alt="users-avatar" />*/}
|
||||||
|
<img src={getImage(avtarImage)}
|
||||||
|
className="img-fluid" alt="user"/>
|
||||||
|
</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>
|
</div>
|
||||||
</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="page-account-form">
|
|
||||||
<div className="form-titel border-bottom p-3">
|
|
||||||
<h5 className="mb-0 py-2">Edit Your Personal Settings</h5>
|
|
||||||
</div>
|
|
||||||
<div className="p-4">
|
|
||||||
<form>
|
|
||||||
<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="profile-btn text-center">
|
||||||
{/* <div className="form-group col-md-4">*/}
|
<div>
|
||||||
{/* <label htmlFor="inputState3">City</label>*/}
|
<button className="btn btn-light text-primary mb-2">Upload New Avatar
|
||||||
{/* <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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{/*<div>*/}
|
||||||
</form>
|
{/* <button className="btn btn-danger">Delete</button>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="col-xl-5 col-md-6 col-12 border-t border-right">
|
||||||
<div className="col-xl-4 col-md-6 border-t col-12">
|
<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">Your External Link</h5>
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<Formik
|
||||||
|
initialValues={intialData?.personal_data}
|
||||||
|
validationSchema={profileValidationSchema}
|
||||||
|
onSubmit={updateProfile}
|
||||||
|
>
|
||||||
|
{(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">*</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">*</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">*</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="title1">Email</label>*/}
|
||||||
|
{/* <input type="text" className="form-control" name="title1"*/}
|
||||||
|
{/* value="email@email.com" />*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="phone1">Phone Number {(props.errors.phone && props.touched.phone) && <span className="text-danger">*</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">*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="email" 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">*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="full_address" value={props.values?.full_address} onChange={props.handleChange} />
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
</div>
|
||||||
<form>
|
<div className="col-xl-4 col-md-6 border-t col-12">
|
||||||
<div className="form-group">
|
<div className="page-account-form">
|
||||||
<label htmlFor="fb">Facebook URL:</label>
|
<div className="form-titel border-bottom p-3">
|
||||||
<input type="text" className="form-control" id="fb"
|
<h5 className="mb-0 py-2">Your External Link</h5>
|
||||||
value="https://www.facebook.com/" />
|
</div>
|
||||||
</div>
|
<div className="p-4">
|
||||||
<div className="form-group">
|
<Formik
|
||||||
<label htmlFor="tr">Twitter URL:</label>
|
initialValues={intialData?.external_links}
|
||||||
<input type="text" className="form-control" id="tr"
|
validationSchema={linksValidationSchema}
|
||||||
value="https://twitter.com/" />
|
onSubmit={updateLinks}
|
||||||
</div>
|
>
|
||||||
|
{(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">*</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">*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="twitter_url" value={props.values?.twitter_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="br">Blogger URL:</label>
|
<label htmlFor="br">Blogger URL: {(props.errors.blogger_url && props.touched.blogger_url) && <span className="text-danger">*</span>}</label>
|
||||||
<input type="text" className="form-control" id="br"
|
<input type="text" className="form-control" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
||||||
value="https://www.blogger.com" />
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="go">Google+ URL:</label>
|
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">*</span>}</label>
|
||||||
<input type="text" className="form-control" id="go"
|
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
||||||
value="https://plus.google.com/discover" />
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="li">LinkedIn URL:</label>
|
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">*</span>}</label>
|
||||||
<input type="text" className="form-control" id="li"
|
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
||||||
value="https://in.linkedin.com/" />
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="we">Website URL:</label>
|
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">*</span>}</label>
|
||||||
<input type="text" className="form-control" id="we"
|
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
||||||
value="https://yourwebsite.com" />
|
</div>
|
||||||
</div>
|
<div style={{textAlign: "right"}}>
|
||||||
<div style={{textAlign:"right"}}>
|
<button type="submit" className="btn btn-primary">Update Links
|
||||||
<button type="submit" className="btn btn-primary">Update Links</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</Form>
|
||||||
</form>
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -194,8 +276,7 @@ export default function Settings(){
|
|||||||
</div>
|
</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,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
|
||||||
@@ -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,6 +3,8 @@ const siteLinks = {
|
|||||||
help: '/help',
|
help: '/help',
|
||||||
home: '/',
|
home: '/',
|
||||||
dash: '/dash',
|
dash: '/dash',
|
||||||
|
traffic: '/traffic',
|
||||||
|
start: '/start',
|
||||||
profile_complete: '/profile-complete',
|
profile_complete: '/profile-complete',
|
||||||
product: '/product/*',
|
product: '/product/*',
|
||||||
contacts: '/contacts',
|
contacts: '/contacts',
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
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'],
|
settingsData: ['settings_data'],
|
||||||
|
myProductConfig: ['myproduct_config'],
|
||||||
productTemplateData: ['product_template_data'],
|
productTemplateData: ['product_template_data'],
|
||||||
subscriptions: ['subscriptions'],
|
subscriptions: ['subscriptions'],
|
||||||
|
profile_data: ['profile_data'],
|
||||||
|
|
||||||
dashboard: ['dashboard'],
|
dashboard: ['dashboard'],
|
||||||
topBar: ['top-bar'],
|
topBar: ['top-bar'],
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ const postAuxEnd = (path, postData, media=false) => {
|
|||||||
return axios.post(`${basePath}${path}`, postData).then(res => {
|
return axios.post(`${basePath}${path}`, postData).then(res => {
|
||||||
return res
|
return res
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
throw new Error(err.response.data.msg);
|
// console.log('res', err.response.data)
|
||||||
|
throw new Error(err.response.data.error_message);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +76,14 @@ 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 GET PRODUCT BY ID
|
// FUNCTION TO GET PRODUCT BY ID
|
||||||
export const MyProductData = (reqData) => {
|
export const MyProductData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -98,7 +107,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,
|
||||||
@@ -106,6 +115,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 = {
|
||||||
@@ -114,6 +131,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 = {
|
||||||
@@ -173,6 +198,14 @@ export const getSettingsData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/myproduct/settings/values`, postData, false)
|
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
|
// FUNCTION TO GET SETTINGS DATA
|
||||||
export const getProductTemplateData = (reqData) => {
|
export const getProductTemplateData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -181,6 +214,14 @@ export const getProductTemplateData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO ACTIVATE TEMPLATE
|
||||||
|
export const activateTemplate = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/template/activate`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
||||||
export const completeProfile = (reqData) => {
|
export const completeProfile = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -205,6 +246,14 @@ export const getCommonPractice = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/common/practice`, postData, false)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import Start from "../component/start/Start";
|
||||||
|
|
||||||
|
|
||||||
|
export default function StartPage(){
|
||||||
|
return <Start />
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Traffic from "../component/traffic/Traffic";
|
||||||
|
|
||||||
|
export default function TrafficPage() {
|
||||||
|
return (
|
||||||
|
<Traffic />
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user