Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6884aa19b2 | |||
| 597a45dcba | |||
| 4f7274c30c | |||
| 290356780c | |||
| bd1450887b | |||
| 923a2483ed | |||
| 7f0ccf35b2 | |||
| af2fdcede6 | |||
| a9f2136125 | |||
| 5d04abc0db | |||
| 26d095afda | |||
| cd030d8d12 | |||
| 4a0b7925d0 | |||
| 9d947f19b9 | |||
| 7a99beab57 | |||
| 02731c021a | |||
| fecae9d626 | |||
| a4867a1b73 | |||
| 51c2e4b568 | |||
| 756c084059 | |||
| 064973e190 | |||
| d165e9dc0f | |||
| 77109e8369 | |||
| 2924401c9b | |||
| f6c2b1129d | |||
| 8ba167a17c | |||
| 7f65b286b1 | |||
| afc9e5be0f | |||
| 7aefb555ed | |||
| 325d28c1a8 | |||
| 25269a44c3 | |||
| 47df35d076 | |||
| 1deb15029d | |||
| 30b284064d | |||
| 4cbe78efc3 | |||
| 92ac7d74f4 | |||
| f0382cea9e | |||
| 2123af0abe | |||
| a3c306bf89 | |||
| a61abe718a | |||
| 2b91506c61 | |||
| 253cace3fe | |||
| aa55a1a4e0 | |||
| 8b763882fa | |||
| 30540e46ba | |||
| b195b1f787 | |||
| 2ddd04a1a1 | |||
| 6ea26740a4 | |||
| f334ca49f0 | |||
| fa9d7f69e4 | |||
| a4db58ba97 | |||
| ddc747d9ca | |||
| ac337eb693 | |||
| f2c3415b1d | |||
| 37450925e1 | |||
| 3b20fcec68 | |||
| d87a083c3e | |||
| 3f8a7a6b3b | |||
| 91d82db40c | |||
| 2dc12d7d0a | |||
| 164195d4cc | |||
| 7ad1a585ea | |||
| a8c2dd84f1 | |||
| ddcc6f0cd2 | |||
| 683f81e8a6 | |||
| 8e09c30c5c | |||
| af0d4db5de | |||
| 6f3dae4116 | |||
| 13900793af | |||
| 698c89edfc | |||
| 4f5a383c99 | |||
| a5b6a11880 | |||
| 0f58da3dce | |||
| 1101e80d91 | |||
| b39a7ab58c | |||
| ad90def3c9 | |||
| 737430bf04 | |||
| d371ada805 | |||
| b77f1d6213 | |||
| 64085c6be5 | |||
| 3f8b45b6d6 | |||
| 4b6c927efc | |||
| 8a8adcbbc7 | |||
| 706baadb33 | |||
| 58128fdd96 | |||
| 14e8b1b01d | |||
| 504bfbcae4 | |||
| ec47aa5f9c | |||
| 9267ded0f1 | |||
| 0b24ca650d | |||
| b535a656a0 | |||
| e69cc9130e | |||
| daafb66cbb | |||
| 3852468afe | |||
| d32204e08f | |||
| 8372209923 | |||
| 6c3f96d9a3 | |||
| c25acecb1a | |||
| 3f5ae4685e | |||
| a80298c824 | |||
| e9bc1c1318 | |||
| 2543a91b19 | |||
| 4c38b0a31f | |||
| 6ed396a34c | |||
| 465a480f02 | |||
| 4409ed45f3 | |||
| 470c94ae5e | |||
| 52fd4275e9 | |||
| 0dadaf00b0 | |||
| 0fbe0f4c3f | |||
| 464182e583 | |||
| 517886df7e |
@@ -16,3 +16,6 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
||||
# Inactivity timeout/logout AT 10MINS
|
||||
REACT_APP_TIMEOUT=600000
|
||||
|
||||
# show download button
|
||||
REACT_APP_SHOW_DOWNLOAD=0
|
||||
|
||||
|
||||
@@ -17,3 +17,6 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
||||
# Inactivity timeout/logout AT 10MINS
|
||||
REACT_APP_TIMEOUT=600000
|
||||
|
||||
# show download button
|
||||
REACT_APP_SHOW_DOWNLOAD=0
|
||||
|
||||
|
||||
+4
-1
@@ -14,4 +14,7 @@ REACT_APP_CONTACTS_LINK='https://www.mermsemr.com/contacts'
|
||||
REACT_APP_TERMS_LINK='https://www.mermsemr.com/terms'
|
||||
|
||||
# Inactivity timeout/logout AT 10MINS
|
||||
REACT_APP_TIMEOUT=600000
|
||||
REACT_APP_TIMEOUT=600000
|
||||
|
||||
# show download button
|
||||
REACT_APP_SHOW_DOWNLOAD=0
|
||||
@@ -14,6 +14,10 @@
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.border-radius-10 {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.login-links{
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
|
||||
@@ -25,6 +25,8 @@ import AccPWDResetPage from './views/AccPWDResetPage';
|
||||
import ProfileCompletePage from './views/ProfileCompletePage';
|
||||
import SubscribePage from './views/Subscribe'
|
||||
import StartPage from "./views/StartPage";
|
||||
import TrafficPage from "./views/TrafficPage";
|
||||
import MyMediaPage from './views/MyMediaPage.jsx';
|
||||
|
||||
function AppRouters() {
|
||||
return (
|
||||
@@ -47,9 +49,11 @@ function AppRouters() {
|
||||
<Route element={<UserExist/>}>
|
||||
<Route path={siteLinks.start} element={<StartPage/>}/>
|
||||
<Route path={siteLinks.dash} element={<HomePage/>}/>
|
||||
<Route path={siteLinks.traffic} element={<TrafficPage/>}/>
|
||||
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
||||
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
||||
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
||||
<Route path={siteLinks.my_media} element={<MyMediaPage />}/>
|
||||
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
||||
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
||||
<Route path={siteLinks.user} element={<UserPage/>}/>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
@@ -0,0 +1,42 @@
|
||||
import React from 'react'
|
||||
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
||||
import IOSDownload from '../../assets/img/download/apple.jpg'
|
||||
|
||||
export default function AuthFooter() {
|
||||
return (
|
||||
<div className='w-100'>
|
||||
{Number(process.env.REACT_APP_SHOW_DOWNLOAD) == 100 &&
|
||||
<>
|
||||
<div className="row" style={{margin: '5px'}}>
|
||||
<hr />
|
||||
</div>
|
||||
<div className="row" style={{marginTop: '20px'}}>
|
||||
<div className="col-6">
|
||||
<div className="app-store-icons-wrap text-center">
|
||||
<a className="icon google"
|
||||
href='#' >
|
||||
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-6">
|
||||
<div className="app-store-icons-wrap text-center">
|
||||
<a className="icon apple" href='#'>
|
||||
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
<div className="login-links">
|
||||
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
||||
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
||||
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
||||
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import siteLinks from '../../links/siteLinks'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { recoverPWD } from '../../services/services';
|
||||
import getImage from '../../utils/getImage';
|
||||
import AuthFooter from './AuthFooter';
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
username: Yup.string()
|
||||
@@ -17,7 +18,7 @@ const validationSchema = Yup.object().shape({
|
||||
// "Invalid email format"
|
||||
// )
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(50, "Maximum 50 characters")
|
||||
.max(25, "Maximum 25 characters")
|
||||
.required("Email is required"),
|
||||
})
|
||||
|
||||
@@ -49,7 +50,7 @@ export default function Forgetpwd2() {
|
||||
<div className="row no-gutters justify-content-center">
|
||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1h" style={{maxWidth: '520px'}}>
|
||||
<div className="mt-5 d-flex">
|
||||
<div className="bg-white register p-5">
|
||||
<div className="bg-white register px-5 pt-5 pb-3">
|
||||
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||
{!mutation.isSuccess && <p>Please enter your username.</p>}
|
||||
<Formik
|
||||
@@ -65,7 +66,7 @@ export default function Forgetpwd2() {
|
||||
<>
|
||||
<div className="col-12">
|
||||
<div className="form-group">
|
||||
<label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Username*</label>
|
||||
<label className={`text-black fw-bold control-label`}>Username* <span className='text-danger' style={{fontSize: '12px'}}>{(props.errors.username && props.touched.username) && props.errors.username}</span></label>
|
||||
<input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,6 +98,7 @@ export default function Forgetpwd2() {
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
<AuthFooter />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,8 +9,7 @@ import siteLinks from '../../links/siteLinks'
|
||||
import { loginUser } from '../../services/services'
|
||||
import { updateUserDetails } from '../../store/UserDetails'
|
||||
|
||||
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
||||
import IOSDownload from '../../assets/img/download/apple.jpg'
|
||||
import AuthFooter from './AuthFooter'
|
||||
|
||||
export default function Login() {
|
||||
|
||||
@@ -47,12 +46,12 @@ export default function Login() {
|
||||
console.log(error)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res?.data?.error_message){
|
||||
if(res?.data && res?.data?.error_message){
|
||||
throw({message: res?.data?.error_message})
|
||||
}
|
||||
const {token, room, uid} = res?.data
|
||||
if(!token || !room){
|
||||
throw({message: 'something went wrong, try again!'})
|
||||
throw({message: 'Unable to complete your login, Please try again!'})
|
||||
}
|
||||
localStorage.setItem('token', token)
|
||||
localStorage.setItem('room', room)
|
||||
@@ -93,13 +92,13 @@ export default function Login() {
|
||||
<div className="col-12">
|
||||
<div className="form-group">
|
||||
<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 className="col-12">
|
||||
<div className="form-group">
|
||||
<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 className="col-12">
|
||||
@@ -133,35 +132,7 @@ export default function Login() {
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div className="row" style={{margin: '5px'}}>
|
||||
<hr />
|
||||
</div>
|
||||
<div className="row" style={{marginTop: '20px'}}>
|
||||
<div className="col-6">
|
||||
<div className="app-store-icons-wrap text-center">
|
||||
<a className="icon google"
|
||||
href='#' >
|
||||
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-6">
|
||||
<div className="app-store-icons-wrap text-center">
|
||||
<a className="icon apple" href='#'>
|
||||
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="login-links">
|
||||
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
||||
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
||||
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
||||
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
||||
</div>
|
||||
|
||||
<AuthFooter />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -82,9 +82,13 @@ export default function Signup() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<hr />
|
||||
<p className='font-medium'>Already have an account ?
|
||||
<Link to={siteLinks.login}
|
||||
className='hover:text-primary font-bold'> Sign In
|
||||
className='bg-secondary; hover:text-primary font-bold' style={{paddingRight: '10px'}}>
|
||||
<button className="btn btn-warning text-uppercase">
|
||||
Sign In
|
||||
</button>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
+155
-111
@@ -1,101 +1,120 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Form, Formik } from "formik";
|
||||
import React, {useState} from 'react'
|
||||
import {Form, Formik} from "formik";
|
||||
import * as Yup from "yup";
|
||||
|
||||
// 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 { useMutation } from '@tanstack/react-query';
|
||||
import { signUpUser } from '../../services/services';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {signUpUser} from '../../services/services';
|
||||
import getImage from '../../utils/getImage';
|
||||
import AuthFooter from './AuthFooter';
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email("Wrong email format")
|
||||
// .matches(
|
||||
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
||||
// "Invalid email format"
|
||||
// )
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(50, "Maximum 50 characters")
|
||||
.required("Email is required"),
|
||||
.email("Wrong email format")
|
||||
// .matches(
|
||||
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
||||
// "Invalid email format"
|
||||
// )
|
||||
.min(3, "Minimum 3 characters")
|
||||
.max(50, "Maximum 50 characters")
|
||||
.required("Email is required"),
|
||||
firstname: Yup.string().required("Firstname is required"),
|
||||
lastname: Yup.string().required("Lastname is required"),
|
||||
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"),
|
||||
// password: Yup.string().min(3, "Minimum 3 characters").max(50, "Maximum 50 characters").required("Email is required"),
|
||||
})
|
||||
})
|
||||
|
||||
const initialValues = {
|
||||
const initialValues = {
|
||||
email: '',
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
isChecked: false,
|
||||
// username: '',
|
||||
// password: ''
|
||||
};
|
||||
};
|
||||
|
||||
export default function Signup2() {
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return signUpUser(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
console.log('res', res)
|
||||
const mutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return signUpUser(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
console.log('res', res)
|
||||
}
|
||||
})
|
||||
|
||||
const signUp = (values) => {
|
||||
// helpers.resetForm()
|
||||
// console.log('values', values, helpers)
|
||||
delete values.isChecked
|
||||
mutation.mutate(values)
|
||||
}
|
||||
})
|
||||
|
||||
const signUp = (values) => {
|
||||
// helpers.resetForm()
|
||||
// console.log('values', values, helpers)
|
||||
delete values.isChecked
|
||||
mutation.mutate(values)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="app-wrap">
|
||||
<div className="app-contant">
|
||||
<div className="vh-100 bg-white custom-bg">
|
||||
<div className="container-fluid p-0">
|
||||
<div className="row no-gutters justify-content-center">
|
||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
|
||||
<div className="mt-5 d-flex">
|
||||
<div className="bg-white register p-5">
|
||||
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||
<p>Welcome, Please create your account.</p>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={signUp}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className='mt-2 mt-sm-5'>
|
||||
<div className="row">
|
||||
{!mutation.isSuccess ?
|
||||
<>
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="form-group">
|
||||
<label className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First Name*</label>
|
||||
<input type="text" name='firstname' className="form-control" placeholder="First Name" value={props.values.firstname} onChange={props.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="form-group">
|
||||
<label className={`text-black fw-bold control-label ${(props.errors.lastname && props.touched.lastname) && 'text-danger'}`}>Last Name*</label>
|
||||
<input type="text" name='lastname' className="form-control" placeholder="Last Name" value={props.values.lastname} onChange={props.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
<div 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">
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="app-wrap">
|
||||
<div className="app-contant">
|
||||
<div className="vh-100 bg-white custom-bg">
|
||||
<div className="container-fluid p-0">
|
||||
<div className="row no-gutters justify-content-center">
|
||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1"
|
||||
style={{maxWidth: '520px'}}>
|
||||
<div className="mt-5 d-flex">
|
||||
<div className="bg-white register px-5 pt-5 pb-3">
|
||||
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||
<p>Welcome, please create your account.</p>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={signUp}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className='mt-2 mt-sm-5'>
|
||||
<div className="row">
|
||||
{!mutation.isSuccess ?
|
||||
<>
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="form-group">
|
||||
<label
|
||||
className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First
|
||||
Name*</label>
|
||||
<input type="text" name='firstname'
|
||||
className="form-control"
|
||||
placeholder="First Name"
|
||||
value={props.values.firstname}
|
||||
onChange={props.handleChange}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="form-group">
|
||||
<label
|
||||
className={`text-black fw-bold control-label ${(props.errors.lastname && props.touched.lastname) && 'text-danger'}`}>Last
|
||||
Name*</label>
|
||||
<input type="text" name='lastname'
|
||||
className="form-control"
|
||||
placeholder="Last Name"
|
||||
value={props.values.lastname}
|
||||
onChange={props.handleChange}/>
|
||||
</div>
|
||||
</div>
|
||||
<div 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">
|
||||
<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} />
|
||||
@@ -107,62 +126,87 @@ export default function Signup2() {
|
||||
<input type="password" name='password' className="form-control" placeholder="Password" value={props.values.password} onChange={props.handleChange} />
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="col-12">
|
||||
<div className="form-check">
|
||||
<input name='isChecked' className="form-check-input" type="checkbox" id="gridCheck" value={props.values.isChecked} onChange={props.handleChange} />
|
||||
<label className="form-check-label" htmlFor="gridCheck">
|
||||
I accept terms & policy
|
||||
</label>
|
||||
</div>
|
||||
<span className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<div className="form-check">
|
||||
<input name='isChecked'
|
||||
className="form-check-input"
|
||||
type="checkbox" id="gridCheck"
|
||||
value={props.values.isChecked}
|
||||
onChange={props.handleChange}/>
|
||||
<label className="form-check-label"
|
||||
htmlFor="gridCheck">
|
||||
I accept terms & policy
|
||||
</label>
|
||||
</div>
|
||||
<span
|
||||
className={`${(props.errors.isChecked && props.touched.isChecked) && 'text-danger'}`}>{props.errors.isChecked}</span>
|
||||
</div>
|
||||
|
||||
{mutation.error &&
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{mutation.error.message}</p>
|
||||
</div>
|
||||
{mutation.error &&
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{mutation.error.message}</p>
|
||||
</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">
|
||||
<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 className="col-12 mt-3">
|
||||
<p>
|
||||
<span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}>Already have an account? </span>
|
||||
<Link
|
||||
to={siteLinks.login}>
|
||||
<button
|
||||
className="btn btn-warning text-uppercase">
|
||||
Sign In
|
||||
</button>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className="col-12 mt-3">
|
||||
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
<AuthFooter />
|
||||
</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="col-7 mx-auto ">
|
||||
<img className="img-fluid" src={LoginImg} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ export default function Calendar(){
|
||||
}
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.calendar_events,
|
||||
queryFn: () => getCalendarEvents(reqData)
|
||||
queryFn: () => getCalendarEvents(reqData),
|
||||
staleTime: 0
|
||||
})
|
||||
|
||||
const receievedEvents = data?.data
|
||||
|
||||
+323
-532
@@ -1,558 +1,349 @@
|
||||
import React from "react";
|
||||
"use client";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
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() {
|
||||
// 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 (
|
||||
<>
|
||||
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
||||
<div className="row">
|
||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||
<div className="col-12">
|
||||
<div className="card card-statistics mail-contant">
|
||||
<div className="card-body p-0">
|
||||
<div className="row no-gutters">
|
||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||
<div className="mail-sidebar">
|
||||
<div className="row justify-content-center">
|
||||
<div className="col-12">
|
||||
<div className="text-center mail-sidebar-title px-4">
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||
>
|
||||
<i className="fa fa-plus pl-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<div className="px-4 py-4">
|
||||
<ul className="pl-0">
|
||||
<li className="py-2">
|
||||
<a href="javascript:void(0)">
|
||||
<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">
|
||||
0+
|
||||
<>
|
||||
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
||||
{getContactData?.isPending ? (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className="text-mute">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : getContactData?.error ? (
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className="text-danger">{getContactData?.error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="row">
|
||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||
<div className="col-12">
|
||||
<div
|
||||
className="card card-statistics mail-contant"
|
||||
style={{ minHeight: "200px", borderRadius: "10px" }}
|
||||
>
|
||||
<div className="card-body p-0">
|
||||
<div className="row no-gutters">
|
||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||
<div className="mail-sidebar">
|
||||
<div className="row justify-content-center">
|
||||
<div className="d-none col-12">
|
||||
<div className="text-center mail-sidebar-title px-4">
|
||||
<a
|
||||
href="#"
|
||||
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||
>
|
||||
<i className="fa fa-plus pl-2"></i>
|
||||
</a>
|
||||
</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>
|
||||
</a>
|
||||
</li>
|
||||
<li className="py-2">
|
||||
<a href="javascript:void(0)">
|
||||
<span className="nav align-items-center">
|
||||
<span>
|
||||
<i className="fa fa-paper-plane-o pr-4"></i>
|
||||
</a>
|
||||
</li>
|
||||
{/*<li className="py-2">*/}
|
||||
{/* <a href="#">*/}
|
||||
{/* <span*/}
|
||||
{/* className="nav align-items-center">*/}
|
||||
{/* <span>*/}
|
||||
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
||||
{/* </span>*/}
|
||||
{/* <span>*/}
|
||||
{/* <span>Replied Mail</span>*/}
|
||||
{/* </span>*/}
|
||||
{/* </span>*/}
|
||||
{/* </a>*/}
|
||||
{/*</li>*/}
|
||||
</ul>
|
||||
|
||||
<ul 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>Sent Mail</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="pl-0 mt-5">
|
||||
<li className="py-2">
|
||||
<a href="javascript:void(0)">
|
||||
<span className="nav align-items-center">
|
||||
<span>
|
||||
<i className="fa fa-circle-o text-danger pr-4"></i>
|
||||
</span>
|
||||
<span>
|
||||
<span>Personal</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className="py-2">
|
||||
<a href="javascript:void(0)">
|
||||
<span className="nav align-items-center">
|
||||
<span>
|
||||
<i className="fa fa-circle-o pr-4 text-warning"></i>
|
||||
</span>
|
||||
<span>
|
||||
<span>Work</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className="py-2">
|
||||
<a href="javascript:void(0)">
|
||||
<span className="nav align-items-center">
|
||||
<span>
|
||||
<i className="fa fa-plus pr-4"></i>
|
||||
</span>
|
||||
<span>
|
||||
<span>Add Category</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</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>
|
||||
</li>
|
||||
{contactsCategory &&
|
||||
contactsCategory.map((item) => (
|
||||
<li
|
||||
key={item?.cid}
|
||||
className="py-2"
|
||||
onClick={() =>
|
||||
changeActiveCategoryUID(`${item?.cid}`)
|
||||
}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<div>
|
||||
<span className="nav align-items-center">
|
||||
<span>
|
||||
<i
|
||||
className={`fa fa-circle-o pr-4 ${
|
||||
activeCategoryUID ==
|
||||
`${item?.cid}`
|
||||
? "text-primary"
|
||||
: "text-warning"
|
||||
}`}
|
||||
></i>
|
||||
</span>
|
||||
<span>
|
||||
<span>{item?.description}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mail-msg scrollbar scroll_dark">
|
||||
<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/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 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" style={{placeContent: 'center'}}>
|
||||
{/* <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>
|
||||
</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 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/02.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
{filteredContactData.length > 0 &&
|
||||
<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={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<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 className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>DutcaPatrick</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
<div className="mt-4 d-flex justify-content-between">
|
||||
<div>
|
||||
<h3>
|
||||
{activeContactUID
|
||||
? activeDetail[0]?.title
|
||||
: 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>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">
|
||||
Mobile app Designer{" "}
|
||||
</h5>
|
||||
<p>
|
||||
Very nice template, lots of pages and good
|
||||
documentation.
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/03.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>m_morsch</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">
|
||||
Landing page Designer
|
||||
</h5>
|
||||
<p>
|
||||
Excellent and at a great price... thank you very
|
||||
much!
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/04.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>AnnaHorno</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">Re-Design ios app</h5>
|
||||
<p>
|
||||
Solved my theme problem in 10 minutes. We thank
|
||||
you.
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/05.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>Wdcorbitt</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">
|
||||
Mobil UX/UI Designer
|
||||
</h5>
|
||||
<p>
|
||||
Asked for information and received it EXTREMELY
|
||||
quickly. Great layout - good code - great price!{" "}
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/06.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>Anne Smith</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">Jobly Opportunity</h5>
|
||||
<p>
|
||||
Mentor has so many features and layouts. Its a
|
||||
great choice.
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/07.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>Paul Flavius</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">Saas Designer</h5>
|
||||
<p>
|
||||
There are many people in the world with amazing
|
||||
talents who realize only a small percentage of
|
||||
their potential.{" "}
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/08.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>Sara Lisbon</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">UI Designer</h5>
|
||||
<p>
|
||||
We can look a bit further back in time to Albert
|
||||
Einstein or even further back to Abraham
|
||||
Lincoln.
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mail-msg-item">
|
||||
<a href="javascript:void(0)">
|
||||
<div className="media align-items-center">
|
||||
<div className="mr-3">
|
||||
<div className="bg-img">
|
||||
<img
|
||||
src={getImage("avtar/09.jpg")}
|
||||
className="img-fluid"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<div className="mail-msg-item-titel justify-content-between">
|
||||
<p>Annahorno</p>
|
||||
<p className="d-none d-xl-block">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
<h5 className="mb-0 my-2">Saas Designer</h5>
|
||||
<p>
|
||||
One of the most difficult aspects of achieving
|
||||
success is staying motivated over the long haul.
|
||||
</p>
|
||||
<p className="d-xl-none">
|
||||
06:59 <span> PM </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function SocketIOContextProvider({children}) {
|
||||
socket.on(socketOnEvents.receive_message, (data) => {
|
||||
// setSocketMsgReceived(data.message);
|
||||
// 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({
|
||||
queryKey: [...queryKeys.recentAction],
|
||||
// type: 'active',
|
||||
|
||||
@@ -54,12 +54,12 @@ export default function DashPayments() {
|
||||
{/* <th style={{width: '30px'}}>#</th> */}
|
||||
<th>Date</th>
|
||||
|
||||
<th style={{width: '130px'}}>Subscription</th>
|
||||
<th style={{width: '130px'}}>Description</th>
|
||||
<th style={{width: '80px'}}>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{payments.length > 0 ?
|
||||
{payments && payments?.length > 0 ?
|
||||
payments.map((item, index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
|
||||
@@ -50,7 +50,7 @@ export default function Products() {
|
||||
</div>
|
||||
<div className="report-details">
|
||||
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||
<h4><span style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||
<h4><span className='text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function ProductsURL() {
|
||||
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
||||
<div className="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
||||
<div className="datatable-wrapper table-responsive">
|
||||
{isFetching ?
|
||||
<>
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function RecentActions() {
|
||||
<h4>{dataAction?.data?.completed}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive m-t-20">
|
||||
<div className="overflow-y-auto table-responsive m-t-20">
|
||||
<table id="datatable-buttons" className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -94,7 +94,7 @@ export default function RecentActions() {
|
||||
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td>{action?.id}</td>
|
||||
<td>{(action?.id).toString().slice(-4)}</td>
|
||||
<td>{action?.action_label}</td>
|
||||
<td>{new Date(action?.added).toDateString()}</td>
|
||||
<td>
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function UserFooter(){
|
||||
<p>© Copyright {year}. All rights reserved.</p>
|
||||
</div>
|
||||
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
|
||||
<p>A division of <i className="fa fa-key text-danger mx-1"></i> autoMedSys A.I.</p>
|
||||
<p>A division of autoMedSys A.I.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -7,7 +7,7 @@ import siteLinks from "../../../links/siteLinks";
|
||||
|
||||
export default function UserHeader(){
|
||||
|
||||
const { userDetails } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
|
||||
const { userDetails } = useSelector((state) => state?.userDetails); // USER Details
|
||||
|
||||
const nav_menu = useRef(null)
|
||||
|
||||
@@ -74,10 +74,15 @@ export default function UserHeader(){
|
||||
<ul className="navbar-nav nav-right ml-auto">
|
||||
<li className="nav-item user-profile">
|
||||
<a onClick={toggleMenu} className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdow">
|
||||
<img src={getImage('profile-pic-circle.png')} alt="avtar-img" />
|
||||
<img
|
||||
src={userDetails?.picture ? userDetails?.picture : getImage('profile-pic-circle.png')}
|
||||
// src={getImage('profile-pic-circle.png')}
|
||||
alt="avtar-img"
|
||||
/>
|
||||
<span className="bg-success user-status"></span>
|
||||
</a>
|
||||
<div ref={nav_menu} onClick={toggleMenu} className="dropdown-menu animated fadeIn">
|
||||
<div className="position-fixed" style={{top: '0px', left: '0px', right: '0px', bottom: '0px'}}></div>
|
||||
<div className="bg-gradient px-4 py-3">
|
||||
<div className="d-flex align-items-center justify-content-between">
|
||||
<div className="mr-1">
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function UserMenu() {
|
||||
</div>
|
||||
</Link>
|
||||
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
|
||||
<li className={`${pathname == siteLinks.my_media ? 'active' : ''}`}><Link to={siteLinks.my_media}>Files and Media</Link></li>
|
||||
<li className={`${pathname == siteLinks.subscription ? 'active' : ''}`}><Link to={siteLinks.subscription}>Subscription</Link></li>
|
||||
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
import React from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import {useState, useRef} from "react";
|
||||
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import {getMediaFileList, uploadFile} from "../../services/services";
|
||||
import getImage from "../../utils/getImage";
|
||||
|
||||
|
||||
export default function MyMedia() {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const basePath = process.env.REACT_APP_MAIN_API
|
||||
const [selectedFile, setSelectedFile] = useState(null);
|
||||
const [message, setMessage] = useState('');
|
||||
const [imageLink, setImageLink] = useState('')
|
||||
console.log('imageLink', imageLink)
|
||||
// Function to handle file selection
|
||||
const handleFileChange = (event) => {
|
||||
setSelectedFile(event.target.files[0]);
|
||||
setMessage('');
|
||||
};
|
||||
|
||||
// Function to handle the upload to the API
|
||||
const _handleUpload = async () => {
|
||||
if (!selectedFile) {
|
||||
setMessage('Please select a file first!');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
// 'file' is the field name that your API endpoint expects
|
||||
formData.append('file', selectedFile);
|
||||
formData.append("member_uid", localStorage.getItem('uid'));
|
||||
formData.append("token", localStorage.getItem('token'));
|
||||
|
||||
try {
|
||||
// Replace with your actual API endpoint URL
|
||||
const apiEndpoint = basePath + '/upload/webfiles';
|
||||
const response = await fetch(apiEndpoint, {
|
||||
method: 'POST',
|
||||
// The browser automatically sets the 'Content-Type' header to
|
||||
// 'multipart/form-data' when you provide a FormData object as the body,
|
||||
// which is required for file uploads.
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
setMessage('File uploaded successfully!');
|
||||
console.log('Success:', result);
|
||||
} else {
|
||||
setMessage('Upload failed.');
|
||||
console.error('Upload failed:', response.statusText);
|
||||
}
|
||||
} catch (error) {
|
||||
setMessage('An error occurred during the upload.');
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.file){
|
||||
throw({message: 'Please select a file first!'})
|
||||
}
|
||||
return uploadFile(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
// console.log('res', res.data)
|
||||
// if(res.data.resultCode != '0' || !res?.data?.pending_uid){
|
||||
// throw({message: res?.data?.resultDescription})
|
||||
// }
|
||||
setSelectedFile(null)
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.my_files],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
uploadFileMutation.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem("token"), // USER TOKEN
|
||||
member_uid: localStorage.getItem("uid"), // USER UID
|
||||
file: selectedFile
|
||||
};
|
||||
// console.log(reqData)
|
||||
uploadFileMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.my_files,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid') // USER UID
|
||||
}
|
||||
return getMediaFileList(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
const mediaFileList = data?.data
|
||||
|
||||
//debugger;
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Files' paths={['Dashboard', 'Files']}/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics h-50 mb-0 widget-support-list">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Upload File</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body pl-0 pr-0 scrollbar scroll_dark">
|
||||
<div className="widget-text">
|
||||
|
||||
<div>
|
||||
<input className="form-control form-control-sm" type="file"
|
||||
onChange={handleFileChange}/>
|
||||
|
||||
{selectedFile && (
|
||||
<div>
|
||||
<h4>Selected File Details:</h4>
|
||||
<ul>
|
||||
<li>Name: {selectedFile.name}</li>
|
||||
<li>Type: {selectedFile.type}</li>
|
||||
<li>Size: {selectedFile.size} bytes</li>
|
||||
</ul>
|
||||
<div style={{width: '100%', textAlign: 'right'}}>
|
||||
<button
|
||||
className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0"
|
||||
onClick={handleUpload} disabled={!selectedFile || uploadFileMutation.isPending || uploadFileMutation.isSuccess}>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<>
|
||||
{/* {message && <p>{message}</p>} */}
|
||||
<p>{uploadFileMutation.isPending ? 'uploading...' : uploadFileMutation.isError ? uploadFileMutation?.error?.message : uploadFileMutation.isSuccess ? 'File Uploaded' : ''}</p>
|
||||
</>
|
||||
</div>
|
||||
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics h-100 mb-0 widget-downloads-list" style={{}}>
|
||||
<div className="card-header d-flex justify-content-between">
|
||||
<div className="card-heading">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Files List</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="card-body scrollbar scroll_dark" style={{minHeight: '400px', maxHeight: '500px', overflowY: 'auto'}}>
|
||||
{mediaFileList && mediaFileList?.file_list && mediaFileList?.file_list.map((item, index) => {
|
||||
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
|
||||
const avtarImage =
|
||||
item?.file_type === undefined
|
||||
? "icons/01.png"
|
||||
: "icons/" + item.file_type + ".png";
|
||||
return (<div key={index} className={`widget-text ${imageLink == file_url && 'bg-light'}`}>
|
||||
<div className={`media align-items-center`} onClick={()=>setImageLink(file_url)} style={{cursor: 'pointer'}}>
|
||||
<img src={getImage(avtarImage)}
|
||||
// src={`assets/img/file-icon/${item.file_type}.png`}
|
||||
className="img-fluid"
|
||||
alt={`${item.file_type}`}/>
|
||||
<div className="media-body">
|
||||
<h4 className="mb-0 ml-3">{item.filename}</h4>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href={`${file_url}`} target='_blank'
|
||||
className="btn btn-icon btn-round btn-outline-success">
|
||||
<i className="ti ti-download"></i>
|
||||
</a>
|
||||
<a href="" className="btn btn-icon btn-round btn-outline-danger ml-2">
|
||||
<i className="ti ti-close"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics h-100 mb-0 widget-branches-list">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Preview</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body d-flex justify-content-center align-items-center pl-0 pr-0 scrollbar scroll_dark">
|
||||
{imageLink &&
|
||||
<img className="w-100 h-auto" src={imageLink} alt='file-image' />
|
||||
}
|
||||
</div>
|
||||
<div className="card-header d-flex justify-content-between align-items-center">
|
||||
{imageLink &&
|
||||
<>
|
||||
<p>0 x 0 px</p>
|
||||
<p>size: 0 bytes</p>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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 getImage from "../../utils/getImage";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { productRefreshSite, getSettingsData } from "../../services/services";
|
||||
import Settings from "./settingsTab/Settings";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import {SocketContextValues} from "../context/SocketIOContext";
|
||||
|
||||
|
||||
export default function ProductActive({productData}){
|
||||
|
||||
const {joinRoom} = SocketContextValues() // Destructures values from socket context
|
||||
const iframe = useRef()
|
||||
|
||||
const [refreshMsg, setRefreshMsg] = useState('')
|
||||
|
||||
const refresh = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return productRefreshSite(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
setRefreshMsg(res?.data?.message)
|
||||
setTimeout(()=>{setRefreshMsg('')},3000)
|
||||
iframe.current.src += ''
|
||||
}
|
||||
})
|
||||
@@ -31,6 +36,13 @@ export default function ProductActive({productData}){
|
||||
}
|
||||
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(
|
||||
<>
|
||||
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
|
||||
@@ -54,12 +66,17 @@ export default function ProductActive({productData}){
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="card-body" style={{minHeight: '600px', maxHeight: '600px'}}>
|
||||
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
||||
</div>
|
||||
<div className="p-4 ml-auto">
|
||||
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Loading...' : 'Refresh Site'}
|
||||
</button>
|
||||
<div className="d-flex justify-end gap-3">
|
||||
{refreshMsg &&
|
||||
<p className="text-success text-center">{refreshMsg}</p>
|
||||
}
|
||||
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Initiating...' : 'Rebuild Site'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,7 +87,7 @@ export default function ProductActive({productData}){
|
||||
<h4 className="card-title"> Site Settings </h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="card-body" style={{minHeight: '680px'}}>
|
||||
<Settings productData={productData} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,39 +1,41 @@
|
||||
import { useEffect } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {useEffect} from "react";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import { productProvision } from "../../services/services";
|
||||
import {productProvision} from "../../services/services";
|
||||
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 productTitle = props?.productData?.title;
|
||||
const productDescription = props?.productData?.description;
|
||||
const productTitle = props?.productData?.title;
|
||||
const productDescription = props?.productData?.description;
|
||||
const productID = props?.productData?.product_id
|
||||
const productUID = props?.productData?.product_uid
|
||||
const productSubUID = props?.productData?.product_subscription_uid
|
||||
|
||||
const reqData = {
|
||||
product_id : productID,
|
||||
product_id: productID,
|
||||
product_subscription_uid: productSubUID
|
||||
}
|
||||
|
||||
const {data:provision, isFetching, isError, error} = useQuery({
|
||||
const {data: provision, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.myproduct_provision,
|
||||
queryFn: () => productProvision(reqData)
|
||||
})
|
||||
|
||||
const provisionData = provision?.data
|
||||
|
||||
useEffect(()=>{
|
||||
joinRoom(productSubUID); // provision subscription room
|
||||
},[])
|
||||
useEffect(() => {
|
||||
const provision_room = "PROVISION_" + productSubUID;
|
||||
console.log("JOINING ROOM ON START *** ", provision_room);
|
||||
joinRoom(provision_room); // provision subscription room
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isFetching ?
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
@@ -42,82 +44,87 @@ export default function ProductProvision(props){
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Creating - {productTitle} </h4>
|
||||
<h4 className="card-title">Creating - {productTitle} </h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="progress">
|
||||
<div className="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
||||
aria-valuenow={`${provisionData?.percent_completed}%`} aria-valuemin="0" aria-valuemax="100" style={{width:`${provisionData?.percent_completed}%`}} ></div>
|
||||
<div className="progress-bar progress-bar-striped progress-bar-animated"
|
||||
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 className="row">
|
||||
<div className="col-md-12">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-lg-6">
|
||||
<div className="row">
|
||||
<div className="col-lg-6">
|
||||
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Progress Information</h4>
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Progress Information</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="table-responsive">
|
||||
<table className="table table-info mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style={{width: '10px'}}>#</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>
|
||||
<div className="card-body">
|
||||
<div className="table-responsive">
|
||||
<table className="table table-info mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style={{width: '10px'}}>#</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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<div className="card card-statistics ">
|
||||
<h4 className="card-title" style={{padding:'10px'}}>Started creating your selection</h4>
|
||||
<img className="card-img-top" src={getImage('widget/working.jpg')} alt="Card image cap" />
|
||||
{/* <div className="card-body">
|
||||
<div className="col-lg-6">
|
||||
<div className="card card-statistics ">
|
||||
<h4 className="card-title" style={{padding: '10px'}}>Started creating your
|
||||
selection</h4>
|
||||
<img className="card-img-top" src={getImage('widget/working.jpg')}
|
||||
alt="Card image cap"/>
|
||||
{/* <div className="card-body">
|
||||
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function ProductStart(props){
|
||||
</div>
|
||||
|
||||
{/* Vertical Center Modal */}
|
||||
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
|
||||
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import React, {memo} from 'react'
|
||||
import getImage from "../../../utils/getImage";
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import {
|
||||
getProductcolorStyleCss,
|
||||
activateTemplate,
|
||||
getProductColorStyles,
|
||||
activateColorStyle
|
||||
} from '../../../services/services';
|
||||
import {Link} from "react-router-dom";
|
||||
import siteLinks from "../../../links/siteLinks";
|
||||
|
||||
const ColorStyleConfigure = memo(({name = 'Full Name', data, productData}) => {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const {data: colorStyleCss, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.productcolorStyleCss,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
product_id: productData?.product_id
|
||||
}
|
||||
return getProductColorStyles(reqData)
|
||||
},
|
||||
staleTime: 0
|
||||
})
|
||||
|
||||
const templateResponse = colorStyleCss?.data
|
||||
const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||
const color_styles = templateResponse?.color_styles
|
||||
const custom_template_name = templateResponse?.custom_template_name
|
||||
|
||||
// console.log('data Template', templateResponse)
|
||||
console.log("Page data == ", data)
|
||||
|
||||
const handleActivateTemplate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return activateColorStyle(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if (res?.data?.resultCode != '0') {
|
||||
throw new Error(res.data.resultDescription)
|
||||
}
|
||||
queryClient.refetchQueries({ // refetches productProvision API call
|
||||
queryKey: [...queryKeys.settingsData],
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(() => {
|
||||
handleActivateTemplate.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = (style_uid) => {
|
||||
const reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
product_id: productData?.product_id,
|
||||
color_style_uid: style_uid
|
||||
}
|
||||
// console.log(reqData)
|
||||
handleActivateTemplate.mutate(reqData)
|
||||
}
|
||||
if (custom_template_name && custom_template_name != '') {
|
||||
// This implies we have a custom template , just return here
|
||||
return <>
|
||||
<div className='col-12'>
|
||||
<div
|
||||
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||
style={{backgroundColor: '#F2FAF7'}}>
|
||||
<h4 className='p-4 text-black'
|
||||
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
|
||||
<img className='' style={{width: '200px'}}
|
||||
src={getImage('custom-template.png')}
|
||||
alt='mail-alert'/>
|
||||
<h4 className='p-4 text-black'
|
||||
style={{marginTop: '20px'}}>This product is using a custom template named <span
|
||||
style={{color: 'darkred'}}>“{custom_template_name}”</span> .</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
}
|
||||
return (
|
||||
<div className="page-account-form">
|
||||
<div className="p-0">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||
<>
|
||||
{!color_styles?.length ?
|
||||
<p>No data Found</p>
|
||||
:
|
||||
color_styles.map(color_style => (
|
||||
<div key={color_style.color_style_uid} className="col-xl-6 col-sm-6">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body" style={{
|
||||
backgroundColor: `#${color_style.color_code}`,
|
||||
opacity: '0.85',
|
||||
borderRadius: '10px'
|
||||
}}>
|
||||
<div className="text-center p-2">
|
||||
{/*<div className="mb-2">*/}
|
||||
{/* <img src={getImage('file-icon/svg.png')}*/}
|
||||
{/* alt={template.title}/>*/}
|
||||
{/*</div>*/}
|
||||
<h4 className="mb-0">{color_style.title}</h4>
|
||||
{currentColorUID === color_style.color_style_uid ?
|
||||
<button className="btn btn-light"
|
||||
disabled={true}>Active</button>
|
||||
:
|
||||
<button
|
||||
onClick={() => handleSubmit(color_style.color_style_uid)}
|
||||
className="btn btn-primary">Select</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||
<div key={key} className="col-xl-6 col-sm-6">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="text-center p-2">
|
||||
<div className="mb-2">
|
||||
<img src={getImage(value.banner)} alt={value.title} />
|
||||
</div>
|
||||
<h4 className="mb-0">{value.title}</h4>
|
||||
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))} */}
|
||||
</>
|
||||
|
||||
<div className="col-12">
|
||||
<>
|
||||
{handleActivateTemplate.isPending ?
|
||||
<p className={'text-center '}>loading...</p>
|
||||
:
|
||||
handleActivateTemplate.isError ?
|
||||
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
|
||||
:
|
||||
handleActivateTemplate.isSuccess ?
|
||||
<p className={'text-center text-success'}>Templated activated
|
||||
successfully</p>
|
||||
:
|
||||
null
|
||||
}
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
export default ColorStyleConfigure
|
||||
@@ -6,8 +6,18 @@ import NoYesBooleanDropdown from './NoYesBooleanDropdown';
|
||||
import {IoMdArrowDropdown} from 'react-icons/io';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder';
|
||||
import URLConfiguration from "./URLConfiguration";
|
||||
import ColorStyleConfigure from "./ColorStyleConfigure";
|
||||
|
||||
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()
|
||||
|
||||
@@ -81,7 +91,7 @@ const GeneralTab = memo(({name = 'Full Name', data, isCustom, productData, backe
|
||||
}
|
||||
submitSettings.mutate(reqData)
|
||||
}
|
||||
|
||||
console.log(tabKey);
|
||||
return (
|
||||
<>
|
||||
{backendValues?.isFetching || !backendValues?.data ?
|
||||
@@ -101,8 +111,17 @@ const GeneralTab = memo(({name = 'Full Name', data, isCustom, productData, backe
|
||||
:
|
||||
<>
|
||||
{isCustom === true ?
|
||||
<SiteTemplateSelector name={name} data={sortedData} isCustom={isCustom}
|
||||
productData={productData}/>
|
||||
<>
|
||||
{(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'}}>
|
||||
|
||||
@@ -5,6 +5,7 @@ import queryKeys from '../../../services/queryKeys';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
||||
import TemplateConfigure from './TemplateConfigure';
|
||||
|
||||
const Settings = memo(({productData}) => {
|
||||
|
||||
@@ -24,7 +25,7 @@ const Settings = memo(({productData}) => {
|
||||
})
|
||||
const settingsConfig = configData?.data?.settings_items
|
||||
// console.log('CONFIG DATA...', settingsConfig)
|
||||
|
||||
// console.log('configData', configData?.data?.subscription_template)
|
||||
|
||||
const [fieldsChanged, setFieldsChanged] = useState(false)
|
||||
|
||||
@@ -81,12 +82,12 @@ const Settings = memo(({productData}) => {
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="tab tab-vertical">
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<div className="d-flex">
|
||||
<ul className="bg-body-secondary flex-column nav" role="tablist" style={{width: '25%', minHeight: '670px', maxHeight: '670px'}}>
|
||||
<>
|
||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||
<li key={key} className="nav-item">
|
||||
<a className={`nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||
<p className={`text-black nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show bg-primary text-white'}`}
|
||||
id={key}
|
||||
// data-bs-toggle="pill"
|
||||
// data-bs-target={`#${value.controls}`}
|
||||
@@ -97,21 +98,40 @@ const Settings = memo(({productData}) => {
|
||||
onClick={()=>handleChangeTab(value.controls)}
|
||||
>
|
||||
{value.title}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
))}
|
||||
{configData?.data?.subscription_template &&
|
||||
<li className="mt-auto nav-item">
|
||||
<p className={`text-black nav-link ${(activeTab == 'config_temp') && 'active show bg-primary text-white'}`}
|
||||
// data-bs-toggle="pill"
|
||||
// data-bs-target={`#${value.controls}`}
|
||||
type="button"
|
||||
// role="tab"
|
||||
// aria-controls={value.controls}
|
||||
// aria-selected="true"
|
||||
onClick={()=>handleChangeTab('config_temp')}
|
||||
>
|
||||
Configure Template
|
||||
</p>
|
||||
</li>
|
||||
}
|
||||
</>
|
||||
</ul>
|
||||
<div className="tab-content">
|
||||
<div className="p-3 tab-content" style={{width: '75%'}}>
|
||||
<>
|
||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||
// id={value.controls} role="tabpanel"
|
||||
// aria-labelledby={key}
|
||||
>
|
||||
<GeneralTab 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 className={`tab-pane fade ${(activeTab == 'config_temp') && 'active show'}`}
|
||||
>
|
||||
<TemplateConfigure productData={productData} />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React, {memo} from 'react'
|
||||
import getImage from "../../../utils/getImage";
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import { getProductTemplateData, activateTemplate } 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 queryClient = useQueryClient()
|
||||
|
||||
const {data:templateData, isFetching, isError, error} = useQuery({
|
||||
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.productTemplateData,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
@@ -16,7 +18,7 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
product_id: productData?.product_id
|
||||
}
|
||||
return getProductTemplateData(reqData)
|
||||
return getProductTemplateData(reqData)
|
||||
},
|
||||
staleTime: 0
|
||||
})
|
||||
@@ -24,16 +26,17 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
||||
const templateResponse = templateData?.data
|
||||
const currentTemUID = templateResponse?.current_template_uid
|
||||
const templates = templateResponse?.templates
|
||||
const custom_template_name = templateResponse?.custom_template_name
|
||||
|
||||
// console.log('data Template', templateResponse)
|
||||
// console.log("Page data == ", data)
|
||||
console.log("Page data == ", data)
|
||||
|
||||
const handleActivateTemplate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return activateTemplate(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res?.data?.resultCode != '0'){
|
||||
if (res?.data?.resultCode != '0') {
|
||||
throw new Error(res.data.resultDescription)
|
||||
}
|
||||
queryClient.refetchQueries({ // refetches productProvision API call
|
||||
@@ -41,7 +44,7 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
handleActivateTemplate.reset()
|
||||
}, 3000)
|
||||
}
|
||||
@@ -57,51 +60,73 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
||||
// console.log(reqData)
|
||||
handleActivateTemplate.mutate(reqData)
|
||||
}
|
||||
if (custom_template_name && custom_template_name != '') {
|
||||
// This implies we have a custom template , just return here
|
||||
return <>
|
||||
<div className='col-12'>
|
||||
<div
|
||||
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||
style={{backgroundColor: '#F2FAF7'}}>
|
||||
<h4 className='p-4 text-black'
|
||||
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
|
||||
<img className='' style={{width: '200px'}}
|
||||
src={getImage('custom-template.png')}
|
||||
alt='mail-alert'/>
|
||||
<h4 className='p-4 text-black'
|
||||
style={{marginTop: '20px'}}>This product is using a custom template named <span
|
||||
style={{color: 'darkred'}}>“{custom_template_name}”</span> .</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
}
|
||||
return (
|
||||
<div className="page-account-form">
|
||||
<div className="p-0">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
{!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 className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||
<>
|
||||
{!templates?.length ?
|
||||
<p>No data Found</p>
|
||||
:
|
||||
templates.map(template => (
|
||||
<div key={template.template_uid} className="col-xl-6 col-sm-6">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="text-center p-2">
|
||||
<div className="mb-2">
|
||||
<img src={getImage('file-icon/svg.png')}
|
||||
alt={template.title}/>
|
||||
</div>
|
||||
<h4 className="mb-0">{template.title}</h4>
|
||||
{currentTemUID == template.template_uid ?
|
||||
<button className="btn btn-light"
|
||||
disabled={true}>Active</button>
|
||||
:
|
||||
<button onClick={() => handleSubmit(template.template_uid)}
|
||||
className="btn btn-primary">Activate</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||
<div key={key} className="col-xl-6 col-sm-6">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
@@ -116,24 +141,25 @@ const SiteTemplateSelector = memo(({name='Full Name', data, productData}) =>{
|
||||
</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 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>
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
import React, {memo, useState} from 'react'
|
||||
import getImage from "../../../utils/getImage";
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import {
|
||||
getTemplateConfig,
|
||||
uploadFile,
|
||||
} from '../../../services/services';
|
||||
import {Link} from "react-router-dom";
|
||||
import siteLinks from "../../../links/siteLinks";
|
||||
|
||||
const TemplateConfigure = ({productData}) => {
|
||||
|
||||
const [selectedFile, setSelectedFile] = useState({id: '', img: ''});
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
setSelectedFile({id: event.target.id, img:event.target.files[0]});
|
||||
};
|
||||
|
||||
// /panel/myproduct/template-config
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.templateConfigItems,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
product_id: productData?.product_id
|
||||
}
|
||||
return getTemplateConfig(reqData)
|
||||
},
|
||||
staleTime: 0
|
||||
})
|
||||
|
||||
const templateResponse = templateData?.data
|
||||
const templateImages = templateResponse?.template_images?.data;
|
||||
// debugger;
|
||||
console.log("templateResponse", templateResponse);
|
||||
// const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||
// const color_styles = templateResponse?.color_styles
|
||||
// const custom_template_name = templateResponse?.custom_template_name
|
||||
//
|
||||
|
||||
const uploadFileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.file){
|
||||
throw({message: 'Please select a file first!'})
|
||||
}
|
||||
// return uploadFile(fields)
|
||||
setTimeout(()=>{
|
||||
uploadFileMutation.reset()
|
||||
}, 3000)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
// console.log('res', res.data)
|
||||
// if(res.data.resultCode != '0' || !res?.data?.pending_uid){
|
||||
// throw({message: res?.data?.resultDescription})
|
||||
// }
|
||||
setSelectedFile({id: '', img: ''})
|
||||
// queryClient.refetchQueries({
|
||||
// queryKey: [...queryKeys.my_files],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
// })
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
uploadFileMutation.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem("token"), // USER TOKEN
|
||||
member_uid: localStorage.getItem("uid"), // USER UID
|
||||
file: selectedFile?.img
|
||||
};
|
||||
uploadFileMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className="card card-statistics">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title"
|
||||
style={{textTransform: 'none'}}>{templateResponse?.template_name}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<div className="col-12">
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<h4>Image List</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-unstyled">
|
||||
{templateImages && templateImages.map(
|
||||
(item) => {
|
||||
const currImage = item?.default_val;
|
||||
return (
|
||||
<li className="media">
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
padding: '5px',
|
||||
backgroundColor: 'aliceblue',
|
||||
margin: '2px',
|
||||
maxHeight: '150px'
|
||||
}}>
|
||||
<div style={{padding: '2px'}}>
|
||||
<img className="mr-5 mb-3 mb-xxs-0 img-fluid"
|
||||
style={{width: 'auto', height: '100px',}}
|
||||
src={(selectedFile?.img && selectedFile?.id == item?.id) ? URL.createObjectURL(selectedFile?.img) : currImage} alt="image"/>
|
||||
</div>
|
||||
|
||||
<div className="media-body" style={{padding: '2px'}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<div style={{textAlign: 'right',width: '100%'}}></div>
|
||||
{/* [Change Image] */}
|
||||
<label htmlFor={item?.id}>[Change Image]</label>
|
||||
<input id={item?.id} name={item?.id} className="d-none form-control form-control-sm" type="file" onChange={handleFileChange}/>
|
||||
<div>
|
||||
<h5 className="mt-0 mb-1">{item?.name}</h5>
|
||||
{item?.description}
|
||||
</div>
|
||||
</div>
|
||||
{(selectedFile.img && selectedFile?.id == item?.id) &&
|
||||
<div style={{width: '100%', textAlign: 'right'}}>
|
||||
<button
|
||||
className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0"
|
||||
onClick={handleUpload}
|
||||
disabled={!selectedFile?.img || uploadFileMutation.isPending || uploadFileMutation.isSuccess}
|
||||
>
|
||||
{uploadFileMutation.isPending ? 'Loading' : uploadFileMutation.isSuccess ? 'Uploaded' : 'Upload'}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
|
||||
|
||||
} </div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default TemplateConfigure
|
||||
@@ -0,0 +1,141 @@
|
||||
import {Form, Formik} from "formik";
|
||||
import * as Yup from "yup";
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {setExternalURL} from '../../../services/services';
|
||||
import { useState } from "react";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
url: Yup.string().required("URL is required").matches(/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/, 'Must be like: https://example.mysite.com'),
|
||||
})
|
||||
|
||||
// const initialValues = {
|
||||
// url: '',
|
||||
// };
|
||||
|
||||
const URLConfiguration = ({productData}) => {
|
||||
|
||||
const [externalURLChanged, setExternalURLChanged] = useState(true)
|
||||
|
||||
const initialValues = {
|
||||
url: productData?.external_url || '',
|
||||
};
|
||||
|
||||
let defaultUrl = 'https://' + productData?.internal_url
|
||||
let externalUrl = productData?.external_url
|
||||
|
||||
const handleExternalURLChanged = (e) => {
|
||||
if(e.target.value == externalUrl){
|
||||
setExternalURLChanged(true)
|
||||
}else{
|
||||
setExternalURLChanged(false)
|
||||
}
|
||||
}
|
||||
|
||||
// API to set url
|
||||
const setURL = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return setExternalURL(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if (res.data.resultCode != '0') {
|
||||
// throw({message: res?.data?.resultDescription})
|
||||
throw({message: 'Something went wrong!'})
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(() => {
|
||||
setURL.reset()
|
||||
}, 3000)
|
||||
}
|
||||
// onError: (err) => {
|
||||
// console.log('err', err)
|
||||
// }
|
||||
})
|
||||
|
||||
const handleSubmit = (values) => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
subscription_uid: productData?.subscription_uid,
|
||||
external_url: values.url
|
||||
}
|
||||
setURL.mutate(reqData)
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4>
|
||||
</div>
|
||||
</div>
|
||||
{/*<div className="card-body">*/}
|
||||
{/* <div className="form-group">*/}
|
||||
{/* /!*<label htmlFor="exampleInputEmail1">Email address</label>*!/*/}
|
||||
{/* <input type="email" className="form-control"*/}
|
||||
{/* aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} />*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className='w-full'>
|
||||
<div className="card card-statistics" style={{backgroundColor: '#b6e5ef'}}>
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title" style={{textTransform: 'none'}}>Set your own URL</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="form-group">
|
||||
<label htmlFor="exampleInputEmail1">Enter your full URL <span
|
||||
className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label>
|
||||
<input value={props.values.url} onChange={(e)=>{props.handleChange(e); handleExternalURLChanged(e)}} type="text"
|
||||
className="form-control" id="url" aria-describedby="url"
|
||||
placeholder="https://example.mysite.com"/>
|
||||
</div>
|
||||
<div style={{width: '100%', textAlign: 'right'}}>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={setURL.isPending || externalURLChanged}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
{setURL.isPending ? 'Loading...' : 'Submit'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{setURL.error &&
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{setURL.error.message}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
{setURL.isSuccess &&
|
||||
<div className="col-12">
|
||||
<p className='text-success'>{'Completed successfully'}</p>
|
||||
</div>
|
||||
}
|
||||
<div style={{backgroundColor: '#94b8c0', borderRadius: '10px', padding: '10px'}}>
|
||||
Final steps to configure your URL:<br/>
|
||||
DNS:<br/>
|
||||
DNS:<br/>
|
||||
DNS:<br/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
|
||||
</>
|
||||
}
|
||||
|
||||
export default URLConfiguration
|
||||
@@ -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 { useLocation } from "react-router-dom";
|
||||
// import { Form, Formik } from "formik";
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import {useMutation, useQuery} from "@tanstack/react-query";
|
||||
import getImage from "../../utils/getImage";
|
||||
@@ -13,17 +13,19 @@ import {updateUserDetails} from "../../store/UserDetails";
|
||||
import {useDispatch} from "react-redux";
|
||||
|
||||
|
||||
// const validationSchema = Yup.object().shape({
|
||||
// practice: Yup.string().required("Required"),
|
||||
// specialization: Yup.string().required("Required"),
|
||||
// introduction: Yup.string().min(1, "Minimum 10 characters").max(50, "Maximum 50 characters").required("Required"),
|
||||
// })
|
||||
|
||||
// const initialValues = {
|
||||
// practice: '',
|
||||
// specialization: '',
|
||||
// introduction: '',
|
||||
// };
|
||||
const validationSchema = Yup.object().shape({
|
||||
practice: Yup.string().required("Required"),
|
||||
specialization: Yup.string().when('practice', {
|
||||
is: (value) => typeof value === 'string' && value.trim().length > 0,
|
||||
then: (schema) => schema.required('Required'),
|
||||
otherwise: (schema) => schema,
|
||||
}),
|
||||
introduction: Yup.string().min(1, "Minimum 1 character").max(50, "Maximum 50 characters"),
|
||||
url_name: Yup.string().min(6, "Minimum 6 characters").max(16, "Maximum 16 characters").required("Required").matches(
|
||||
/^[a-zA-Z0-9]+$/, // Regex for alphanumeric characters
|
||||
'Must contain only alphanumeric characters' // Custom error message
|
||||
),
|
||||
})
|
||||
|
||||
|
||||
export default function ProfileCompleteCom() {
|
||||
@@ -35,28 +37,27 @@ export default function ProfileCompleteCom() {
|
||||
const {state: {redirectLink}} = useLocation()
|
||||
|
||||
const [practices, setPractices] = useState([])
|
||||
const [specialties, setSpecialties] = useState([])
|
||||
|
||||
const [initialValues, setInitialValues] = useState({
|
||||
practice: '',
|
||||
specialization: '',
|
||||
introduction: '',
|
||||
url_name: ''
|
||||
})
|
||||
|
||||
const specialties = useMemo(() => { // FUNCTION TO UPDATE SPECIALITY ARRAY EACH TIME PRACTICE CHANGES
|
||||
const handleUpdateSpecialties = (e) => {
|
||||
setInitialValues(prev => ({...prev, specialization: ''}))
|
||||
if (!initialValues.practice) {
|
||||
return []
|
||||
}
|
||||
const specialtiesArr = practices.filter(item => item.practice == initialValues.practice)[0]?.specialties
|
||||
return specialtiesArr
|
||||
}, [initialValues.practice])
|
||||
const specialtiesArr = practices.filter(item => item.practice == e.target.value)[0]?.specialties
|
||||
setSpecialties(specialtiesArr)
|
||||
}
|
||||
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
const {practice, specialization} = fields
|
||||
if (!practice || !specialization) {
|
||||
throw new Error('Please select both practice and specialization fields')
|
||||
const {practice, specialization, url_name} = fields
|
||||
if (!practice || !specialization || !url_name) {
|
||||
throw new Error('Please Select both Practice, Specialization and Enter URL_Name')
|
||||
}
|
||||
return completeProfile(fields)
|
||||
},
|
||||
@@ -93,15 +94,11 @@ export default function ProfileCompleteCom() {
|
||||
}
|
||||
})
|
||||
|
||||
const handlePracticeChange = ({target: {name, value}}) => {
|
||||
setInitialValues(prev => ({...prev, [name]: value}))
|
||||
}
|
||||
|
||||
const handleCompleteProfile = () => { // FUNCTION TO COMPLETE PROFILE
|
||||
const handleCompleteProfile = (values) => { // FUNCTION TO COMPLETE PROFILE
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
...initialValues
|
||||
...values
|
||||
}
|
||||
mutation.mutate(reqData)
|
||||
}
|
||||
@@ -145,89 +142,146 @@ export default function ProfileCompleteCom() {
|
||||
<div className="card-body">
|
||||
<div className='h-100 row flex-column'>
|
||||
{/* <div className="row"> */}
|
||||
<>
|
||||
<div className="">
|
||||
<div className="form-group position-relative">
|
||||
<label className={`text-black fw-bold control-label`}>Practice :</label>
|
||||
<div className="position-relative">
|
||||
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{practices.map((practice, index)=>(
|
||||
<option key={index} value={practice.practice}>{practice.practice}</option>
|
||||
))}
|
||||
</select> */}
|
||||
<select onChange={handlePracticeChange} name='practice'
|
||||
value={initialValues.practice} className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{practices.map((practice, index) => (
|
||||
<option key={index}
|
||||
value={practice.practice}>{practice.practice}</option>
|
||||
))}
|
||||
</select>
|
||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||
top: '50%',
|
||||
right: '2px',
|
||||
transform: 'translateY(-50%)'
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleCompleteProfile}
|
||||
enableReinitialize={true}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className='mt-2'>
|
||||
<>
|
||||
<div className="">
|
||||
<div className="form-group position-relative">
|
||||
<label className={`text-black fw-bold control-label`}>Practice : <span className="text-danger">{(props.errors.practice && props.touched.practice) && props.errors.practice}</span></label>
|
||||
<div className="position-relative">
|
||||
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{practices.map((practice, index)=>(
|
||||
<option key={index} value={practice.practice}>{practice.practice}</option>
|
||||
))}
|
||||
</select> */}
|
||||
<select
|
||||
onChange={(e) => {props.handleChange(e); props.setFieldValue('specialization', ''); handleUpdateSpecialties(e)}}
|
||||
name='practice'
|
||||
value={props.values.practice} className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{practices.map((practice, index) => (
|
||||
<option key={index}
|
||||
value={practice.practice}>{practice.practice}</option>
|
||||
))}
|
||||
</select>
|
||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||
top: '50%',
|
||||
right: '2px',
|
||||
transform: 'translateY(-50%)'
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<div className="form-group">
|
||||
<label className={`text-black fw-bold control-label`}>Your
|
||||
Specialization :</label>
|
||||
<div className="position-relative">
|
||||
<select onChange={handlePracticeChange} name='specialization'
|
||||
value={initialValues.specialization}
|
||||
className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{specialties.map((specialty, index) => (
|
||||
<option key={index} value={specialty}>{specialty}</option>
|
||||
))}
|
||||
</select>
|
||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||
top: '50%',
|
||||
right: '2px',
|
||||
transform: 'translateY(-50%)'
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="form-group">
|
||||
<label className={`text-black fw-bold control-label`}>Your
|
||||
Specialization : <span className="text-danger">{(props.errors.specialization && props.touched.specialization) && props.errors.specialization}</span></label>
|
||||
<div className="position-relative">
|
||||
<select onChange={props.handleChange} name='specialization'
|
||||
value={props.values.specialization}
|
||||
className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{specialties.map((specialty, index) => (
|
||||
<option key={index} value={specialty}>{specialty}</option>
|
||||
))}
|
||||
</select>
|
||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||
top: '50%',
|
||||
right: '2px',
|
||||
transform: 'translateY(-50%)'
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<div className="form-group position-relative">
|
||||
<label className={`text-black fw-bold control-label`}>Other General
|
||||
Information :</label>
|
||||
<textarea name='introduction' rows={10} style={{resize: 'none'}}
|
||||
className="form-control" value={initialValues.introduction}
|
||||
onChange={handlePracticeChange}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="form-group position-relative">
|
||||
<label className={`text-black fw-bold control-label`}>Other General Information : <span className="text-danger">{(props.errors.introduction && props.touched.introduction) && props.errors.introduction}</span></label>
|
||||
<textarea name='introduction' rows={5} style={{resize: 'none'}}
|
||||
className="form-control" value={props.values.introduction}
|
||||
onChange={props.handleChange}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<div className="form-group position-relativ'e">
|
||||
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
|
||||
{/* information for :</label>*/}
|
||||
<div style={{fontSize: '14px', borderRadius: '10px', backgroundColor: 'aliceblue', fontWeight:'bolder', padding: '15px' }}>
|
||||
MERMS A.I. agents use the information supplied to help generate useful entries for your product settings.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="form-group position-relativ'e">
|
||||
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
|
||||
{/* information for :</label>*/}
|
||||
<div style={{
|
||||
fontSize: '14px',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: 'aliceblue',
|
||||
fontWeight: 'bolder',
|
||||
padding: '15px'
|
||||
}}>
|
||||
MERMS A.I. agents use the information supplied to help generate
|
||||
useful entries for your product settings.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(mutation.isError || mutation.isSuccess) &&
|
||||
<>
|
||||
<div className="">
|
||||
<p className={`${mutation.isSuccess ? 'text-success' : 'text-danger'}`}>{mutation.isSuccess ? 'Completed successfully, redirecting...' : mutation.error.message}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<div className="">
|
||||
<div className="form-group position-relative">
|
||||
<label className={`text-black fw-bold control-label`}>URL Name : <span className="text-danger">{(props.errors.url_name && props.touched.url_name) && props.errors.url_name}</span></label>
|
||||
<div className="position-relative d-flex flex-column flex-xxl-row" style={{gap: '10px'}}>
|
||||
{/* <select onChange={handlePracticeChange} name='url_name'
|
||||
value={initialValues.url_name} className="form-control">
|
||||
<option value=''>Select</option>
|
||||
{practices.map((practice, index) => (
|
||||
<option key={index}
|
||||
value={practice.practice}>{practice.practice}</option>
|
||||
))}
|
||||
</select>
|
||||
<IoMdArrowDropdown className='position-absolute w-auto' style={{
|
||||
top: '50%',
|
||||
right: '2px',
|
||||
transform: 'translateY(-50%)'
|
||||
}}/> */}
|
||||
<input
|
||||
className="form-control"
|
||||
onChange={props.handleChange} name='url_name'
|
||||
value={props.values.url_name}
|
||||
minLength={6}
|
||||
maxLength={16}
|
||||
/>
|
||||
<p className="border-radius-10 p-2 border border-warning"
|
||||
style={{fontSize: "1.0rem"}}>We use the URL Name to form part of
|
||||
your default URL when we configure
|
||||
a new URL for your products. You can always change your product
|
||||
URL. <br/>
|
||||
<b>Example : <span style={{color: 'red'}}>url_name</span>.product.mermsemr.com
|
||||
</b>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-auto text-end">
|
||||
<button type='button' onClick={handleCompleteProfile}
|
||||
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Continue'}</button>
|
||||
</div>
|
||||
</>
|
||||
{(mutation.isError || mutation.isSuccess) &&
|
||||
<>
|
||||
<div className="">
|
||||
<p className={`${mutation.isSuccess ? 'text-success' : 'text-danger'}`}>{mutation.isSuccess ? 'Completed successfully, redirecting...' : mutation.error.message}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
<div className="mt-auto text-end">
|
||||
<button type='submit'
|
||||
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Continue'}</button>
|
||||
</div>
|
||||
</>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
{/* </div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getPaymentReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function PaymentReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.payment_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getPaymentReports(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Payments Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getProductReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function ProductReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.product_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getProductReports(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Products Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,92 @@
|
||||
import React from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import {getReportsTopicsList} from "../../services/services";
|
||||
import PaymentReportTable from "./PaymentReportTable";
|
||||
import ProductReportTable from "./ProductReportTable";
|
||||
import sortArrayByListOrder from "../../helpers/sortArrayByLIstOrder";
|
||||
import SystemReportTable from "./SystemReportTable";
|
||||
|
||||
|
||||
export default function Reports(){
|
||||
export default function Reports() {
|
||||
|
||||
return(
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.topics,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid') // USER UID
|
||||
}
|
||||
return getReportsTopicsList(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
const reportTopicList = data?.data?.topics?.topics;
|
||||
|
||||
const renderedTable = {
|
||||
payment: <PaymentReportTable />,
|
||||
product: <ProductReportTable />,
|
||||
system: <SystemReportTable />
|
||||
}
|
||||
|
||||
const sortedReportTopicList= sortArrayByListOrder(reportTopicList ? reportTopicList : []) // SORTED SETTINGSCONFIG
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']} />
|
||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
||||
<div className="row">
|
||||
<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div>
|
||||
<div>
|
||||
<div className="card card-statistics" style={{minHeight: '550px'}}>
|
||||
{/*<div className="card-header">*/}
|
||||
{/* <div className="card-heading">*/}
|
||||
{/* <h4 className="card-title"> Tab vertical </h4>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
<div className="card-body">
|
||||
<div className="tab tab-vertical">
|
||||
|
||||
{/* <!-- Tabs --> */}
|
||||
<ul className="nav nav-tabs" id="myTab" role="tablist">
|
||||
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||
return (
|
||||
<li key={index} className="nav-item" role="presentation">
|
||||
<a className={`nav-link ${index == 0 && 'active'}`} id={`tab-${item?.url}`} href="#" data-bs-toggle="tab" data-bs-target={`#content-${item?.url}`} type="button" role="tab">
|
||||
{item?.name}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
||||
{/* <!-- Tab Content --> */}
|
||||
<div className="tab-content">
|
||||
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel">
|
||||
{renderedTable[item?.url]}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getSystemReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function SystemReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.system_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getSystemReports(reqData)
|
||||
},
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Systems Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { Modal } from "bootstrap";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { updateLinks } from "../../services/services";
|
||||
import queryKeys from '../../services/queryKeys';
|
||||
|
||||
|
||||
const linksValidationSchema = Yup.object().shape({
|
||||
// facebook_url: Yup.string().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 LinksForm({data}) {
|
||||
const modalRef = useRef(null)
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [intialData] = useState(data)
|
||||
|
||||
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||
|
||||
const dismissModal = () => {
|
||||
const body = document.querySelector('body')
|
||||
body.removeAttribute('style')
|
||||
// body.classList.toggle('modal-open')
|
||||
|
||||
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||
modalBackdrop.forEach(item => {
|
||||
if (item) {
|
||||
item.remove();
|
||||
}
|
||||
})
|
||||
|
||||
const modal = Modal.getInstance(modalRef.current);
|
||||
modal && modal.hide();
|
||||
};
|
||||
|
||||
// UPDATE LINKS MUTATION
|
||||
const updateLinksMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return updateLinks(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res.data.resultCode != '0'){
|
||||
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'En error occured'})
|
||||
}
|
||||
},
|
||||
onSettled: ()=>{
|
||||
setTimeout(() => {
|
||||
dismissModal() //CLOSE MODAL HERE
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||
})
|
||||
updateLinksMutation.reset()
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const handleSetInfoToUpdate = (values, helpers) => {
|
||||
setInfoToUpdate(values)
|
||||
var modal = new Modal(document.getElementById('modal_links'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
const proceed = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
...infoToUpdate
|
||||
}
|
||||
console.log(reqData)
|
||||
// updateLinksMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Formik
|
||||
initialValues={intialData}
|
||||
validationSchema={linksValidationSchema}
|
||||
onSubmit={handleSetInfoToUpdate}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className=''>
|
||||
<div className="form-group">
|
||||
<label htmlFor="fb">Facebook URL: {(props.errors.facebook_url && props.touched.facebook_url) && <span className="text-danger">*</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">
|
||||
<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" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">*</span>}</label>
|
||||
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">*</span>}</label>
|
||||
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">*</span>}</label>
|
||||
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div style={{textAlign: "right"}}>
|
||||
<button type="submit" className="btn btn-primary">Update Links
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
|
||||
{/* Vertical Center Modal */}
|
||||
<div ref={modalRef} className="modal fade" id="modal_links" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update? gg</h5>
|
||||
{(updateLinksMutation.error || updateLinksMutation.isSuccess) && (
|
||||
<div className="col-12">
|
||||
<p className={`p-2 text-center ${updateLinksMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||
{updateLinksMutation.isSuccess ? 'Updated Successfully' : updateLinksMutation.error.message}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" className="btn btn-primary" disabled={updateLinksMutation.isSuccess} onClick={proceed}>{updateLinksMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* END of Vertical Center Modal */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { Modal } from "bootstrap";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { updateProfile } from "../../services/services";
|
||||
import queryKeys from '../../services/queryKeys';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateUserDetails } from '../../store/UserDetails'
|
||||
|
||||
const profileValidationSchema = Yup.object().shape({
|
||||
firstname: Yup.string().required("firstname is required"),
|
||||
lastname: Yup.string().required("lastname is required"),
|
||||
email: Yup.string().required("email is required"),
|
||||
account_name: Yup.string().required("account name is required"),
|
||||
phone: Yup.string().required("phone is required"),
|
||||
full_address: Yup.string().required("full address is required"),
|
||||
})
|
||||
|
||||
export default function ProfileForm({data}) {
|
||||
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const modalRef = useRef(null)
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [intialData] = useState(data)
|
||||
|
||||
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||
|
||||
const dismissModal = () => {
|
||||
const body = document.querySelector('body')
|
||||
body.removeAttribute('style')
|
||||
// body.classList.toggle('modal-open')
|
||||
|
||||
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||
modalBackdrop.forEach(item => {
|
||||
if (item) {
|
||||
item.remove();
|
||||
}
|
||||
})
|
||||
|
||||
const modal = Modal.getInstance(modalRef.current);
|
||||
modal && modal.hide();
|
||||
};
|
||||
|
||||
// UPDATE PROFILE MUTATION
|
||||
const updateProfileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return updateProfile(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res.data.resultCode != '0'){
|
||||
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||
}
|
||||
const account_name = res?.data?.personal_data?.account_name
|
||||
dispatch(updateUserDetails({ account_name }));
|
||||
},
|
||||
onSettled: ()=>{
|
||||
setTimeout(() => {
|
||||
dismissModal() //CLOSE MODAL HERE
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||
})
|
||||
updateProfileMutation.reset()
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const handleSetInfoToUpdate = (values, helpers) => {
|
||||
delete values.email
|
||||
delete values.country
|
||||
setInfoToUpdate(values)
|
||||
var modal = new Modal(document.getElementById('modal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
const proceed = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
...infoToUpdate
|
||||
}
|
||||
updateProfileMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Formik
|
||||
initialValues={intialData}
|
||||
validationSchema={profileValidationSchema}
|
||||
onSubmit={handleSetInfoToUpdate}
|
||||
>
|
||||
{(props) => {
|
||||
return (
|
||||
<Form className=''>
|
||||
<div className="form-row">
|
||||
<div className="form-group col-md-12">
|
||||
<label htmlFor="name1">First Name {(props.errors.firstname && props.touched.firstname) && <span className="text-danger">{props.errors.firstname}*</span>}</label>
|
||||
<input type="text" className="form-control" name="firstname" value={props.values?.firstname} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div className="form-group col-md-12">
|
||||
<label htmlFor="name1">Last Name {(props.errors.lastname && props.touched.lastname) && <span className="text-danger">{props.errors.lastname}*</span>}</label>
|
||||
<input type="text" className="form-control" name="lastname" value={props.values?.lastname} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div className="form-group col-md-12">
|
||||
<label htmlFor="name1">Account Name {(props.errors.account_name && props.touched.account_name) && <span className="text-danger">{props.errors.account_name}*</span>}</label>
|
||||
<input type="text" className="form-control" name="account_name" value={props.values?.account_name} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div className="form-group col-md-12">
|
||||
<label htmlFor="phone1">Phone Number {(props.errors.phone && props.touched.phone) && <span className="text-danger">{props.errors.phone}*</span>}</label>
|
||||
<input type="text" className="form-control" name="phone" value={props.values?.phone} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div className="form-group col-md-12">
|
||||
<label htmlFor="email1">Email {(props.errors.email && props.touched.email) && <span className="text-danger">{props.errors.email}*</span>}</label>
|
||||
<input type="text" className="form-control" name="email" readOnly value={props.values?.email} onChange={props.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="add1">Address {(props.errors.full_address && props.touched.full_address) && <span className="text-danger">{props.errors.full_address}*</span>}</label>
|
||||
<input type="text" className="form-control" name="full_address" value={props.values?.full_address} onChange={props.handleChange} />
|
||||
</div>
|
||||
<div style={{textAlign: "right"}}>
|
||||
<button type="submit" className="btn btn-primary">Update Profile
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
|
||||
{/* Vertical Center Modal */}
|
||||
<div ref={modalRef} className="modal fade" id="modal" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||
{(updateProfileMutation.error || updateProfileMutation.isSuccess) && (
|
||||
<div className="col-12">
|
||||
<p className={`p-2 text-center ${updateProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||
{updateProfileMutation.isSuccess ? 'Updated Successfully' : updateProfileMutation.error.message}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" className="btn btn-primary" disabled={updateProfileMutation.isSuccess} onClick={proceed}>{updateProfileMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* END of Vertical Center Modal */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import React, { memo, useRef, useState } from 'react'
|
||||
// import { useSelector } from 'react-redux';
|
||||
import getImage from '../../utils/getImage';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { uploadProfileImg } from '../../services/services';
|
||||
import queryKeys from '../../services/queryKeys';
|
||||
|
||||
const ProfileImage = memo(({intialData}) => {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [selectedImg, setSelectedImg] = useState(null)
|
||||
|
||||
// const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS FOR ACTIVE USER DETAILS
|
||||
const avtarImage = "avtar/merms-user.png";
|
||||
|
||||
// browser profile img
|
||||
const browserImg = useRef(null);
|
||||
const browseProfileImg = () => {
|
||||
browserImg.current.click();
|
||||
};
|
||||
|
||||
const profileImgChangeHandler = (event) => {
|
||||
setSelectedImg(event.target.files[0])
|
||||
}
|
||||
|
||||
const uploadProfileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.img){
|
||||
throw new Error('Please, select an image')
|
||||
}
|
||||
return uploadProfileImg(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res.data.resultCode != '0'){
|
||||
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||
}
|
||||
// const account_name = res?.data?.personal_data?.account_name
|
||||
// dispatch(updateUserDetails({ account_name }));
|
||||
},
|
||||
onSettled: ()=>{
|
||||
setTimeout(() => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||
})
|
||||
uploadProfileMutation.reset()
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
|
||||
const proceedToUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
img: selectedImg
|
||||
}
|
||||
// console.log('reqData', reqData)
|
||||
uploadProfileMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
||||
<div className="page-account-profil pt-5">
|
||||
<div className="profile-img text-center rounded-circle">
|
||||
<div className="pt-5">
|
||||
<div className="bg-img m-auto">
|
||||
<img
|
||||
src={selectedImg ? URL.createObjectURL(selectedImg) : intialData?.personal_data?.picture ? intialData?.personal_data?.picture : getImage(avtarImage)}
|
||||
// src={getImage(avtarImage)}
|
||||
className="img-fluid" alt="user"
|
||||
/>
|
||||
<input
|
||||
ref={browserImg}
|
||||
className='d-none'
|
||||
type='file'
|
||||
accept="image/*"
|
||||
onChange={(e) => profileImgChangeHandler(e)}
|
||||
id='profile-image'
|
||||
/>
|
||||
</div>
|
||||
<div className="profile pt-4">
|
||||
<h4 className="mb-1">{intialData?.personal_data?.lastname} {intialData?.personal_data?.firstname}</h4>
|
||||
<div style={{padding: '10px'}}>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="profile-btn text-center">
|
||||
<div>
|
||||
<button onClick={browseProfileImg} className="btn btn-light text-primary mb-2">Change
|
||||
</button>
|
||||
</div>
|
||||
{selectedImg &&
|
||||
<div>
|
||||
<button onClick={proceedToUpload} disabled={uploadProfileMutation.isSuccess || uploadProfileMutation.isPending} className="btn btn-light text-primary mb-2">
|
||||
{uploadProfileMutation.isPaused ? 'Upload...' : 'Upload New Avatar'}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
{/* success or error message */}
|
||||
{(uploadProfileMutation.isSuccess || uploadProfileMutation.isError) &&
|
||||
<div>
|
||||
<p className={`${uploadProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||
{uploadProfileMutation.isSuccess ? 'Uploaded successfully' : uploadProfileMutation.error.message}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default ProfileImage
|
||||
@@ -1,10 +1,37 @@
|
||||
import React from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import getImage from "../../utils/getImage";
|
||||
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { profileDetails } from "../../services/services";
|
||||
import ProfileForm from "./ProfileForm";
|
||||
import LinksForm from "./LinksForm";
|
||||
import ProfileImage from "./ProfileImage";
|
||||
|
||||
export default function Settings() {
|
||||
const avtarImage = "avtar/merms-user.png";
|
||||
|
||||
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)
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']}/>
|
||||
@@ -12,184 +39,45 @@ export default function Settings() {
|
||||
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
|
||||
<div className="row account-contant">
|
||||
{isFetching ?
|
||||
<>
|
||||
<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="card card-statistics">
|
||||
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
||||
<div className="row no-gutters">
|
||||
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
||||
<div className="page-account-profil pt-5">
|
||||
<div className="profile-img text-center rounded-circle">
|
||||
<div className="pt-5">
|
||||
<div className="bg-img m-auto">
|
||||
{/*<img src="assets/img/avtar/01.jpg" className="img-fluid"*/}
|
||||
{/* alt="users-avatar" />*/}
|
||||
<img src={getImage(avtarImage)}
|
||||
className="img-fluid" alt="user"/>
|
||||
</div>
|
||||
<div className="profile pt-4">
|
||||
<h4 className="mb-1">Alice Williams</h4>
|
||||
<div style={{padding: '10px'}}>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-danger">{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="row account-contant">
|
||||
<div className="col-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
||||
<div className="row no-gutters">
|
||||
<ProfileImage intialData={intialData} />
|
||||
<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">
|
||||
<ProfileForm data={intialData.personal_data} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="profile-btn text-center">
|
||||
<div>
|
||||
<button className="btn btn-light text-primary mb-2">Upload New Avatar
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-xl-4 col-md-6 border-t col-12">
|
||||
<div className="page-account-form">
|
||||
<div className="form-titel border-bottom p-3">
|
||||
<h5 className="mb-0 py-2">Your External Link</h5>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<LinksForm data={intialData.external_links} />
|
||||
</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="form-group col-md-4">*/}
|
||||
{/* <label htmlFor="inputState3">City</label>*/}
|
||||
{/* <select id="inputState3" className="form-control">*/}
|
||||
{/* <option>Choose...</option>*/}
|
||||
{/* <option selected="">London</option>*/}
|
||||
{/* <option>Montreal</option>*/}
|
||||
{/* <option>Delhi</option>*/}
|
||||
{/* <option>Tokyo</option>*/}
|
||||
{/* </select>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="form-group col-md-4">*/}
|
||||
{/* <label htmlFor="inputState4">State</label>*/}
|
||||
{/* <select id="inputState4" className="form-control">*/}
|
||||
{/* <option>Choose...</option>*/}
|
||||
{/* <option selected="">England</option>*/}
|
||||
{/* <option>California</option>*/}
|
||||
{/* <option>Texas</option>*/}
|
||||
{/* <option>Scotland</option>*/}
|
||||
{/* </select>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="form-group col-md-4">*/}
|
||||
{/* <label htmlFor="inputZip">Zip</label>*/}
|
||||
{/* <input type="text" className="form-control" id="inputZip"*/}
|
||||
{/* value="EC1A 1BB" />*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="form-group">*/}
|
||||
{/* <div className="form-check">*/}
|
||||
{/* <input className="form-check-input" type="checkbox"*/}
|
||||
{/* id="gridCheck" />*/}
|
||||
{/* <label className="form-check-label" htmlFor="gridCheck">*/}
|
||||
{/* I agree to receive email notification.*/}
|
||||
{/* </label>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
<div style={{textAlign: "right"}}>
|
||||
<button type="submit" className="btn btn-primary">Update Profile
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xl-4 col-md-6 border-t col-12">
|
||||
<div className="page-account-form">
|
||||
<div className="form-titel border-bottom p-3">
|
||||
<h5 className="mb-0 py-2">Your External Link</h5>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<form>
|
||||
<div className="form-group">
|
||||
<label htmlFor="fb">Facebook URL:</label>
|
||||
<input type="text" className="form-control" id="fb"
|
||||
value="https://www.facebook.com/"/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="tr">Twitter URL:</label>
|
||||
<input type="text" className="form-control" id="tr"
|
||||
value="https://twitter.com/"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="br">Blogger URL:</label>
|
||||
<input type="text" className="form-control" id="br"
|
||||
value="https://www.blogger.com"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="go">Google+ URL:</label>
|
||||
<input type="text" className="form-control" id="go"
|
||||
value="https://plus.google.com/discover"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="li">LinkedIn URL:</label>
|
||||
<input type="text" className="form-control" id="li"
|
||||
value="https://in.linkedin.com/"/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="we">Website URL:</label>
|
||||
<input type="text" className="form-control" id="we"
|
||||
value="https://yourwebsite.com"/>
|
||||
</div>
|
||||
<div style={{textAlign: "right"}}>
|
||||
<button type="submit" className="btn btn-primary">Update Links
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,8 +85,7 @@ export default function Settings() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -57,7 +57,7 @@ export default function Subscription() {
|
||||
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
|
||||
</div>
|
||||
<div className="pt-2" style={{textAlign: 'left'}}>
|
||||
<div style={{fontSize: '12px', fontWeight: 'bolder' , color: "#3E3699" }}>
|
||||
<div style={{fontSize: '12px', fontWeight: 'bolder', color: "#3E3699"}}>
|
||||
Next Payment: {getDateTimeFromDateString(currentSubscription?.next_payment)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import TrafficChart from "./TrafficChart";
|
||||
|
||||
|
||||
export default function Traffic() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Traffic' paths={['Dashboard', 'Traffic']}/>
|
||||
<div className="row">
|
||||
<div className="col-lg-4">
|
||||
<div className="card card-statistics" style={{minHeight: '350px', borderRadius: '10px', backgroundColor: 'aliceblue'}}>
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Site Traffic Monitoring</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-8">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Plot</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="apexchart-wrapper">
|
||||
<TrafficChart />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import { useState } from "react";
|
||||
import ReactApexChart from "react-apexcharts";
|
||||
|
||||
const TrafficChart = () => {
|
||||
const [state, setState] = useState({
|
||||
|
||||
series: [
|
||||
{
|
||||
// name: "High - 2013",
|
||||
name: 'Professional Website',
|
||||
data: [28, 29, 33, 36, 32, 32, 33, 33, 36, 32, 32, 33]
|
||||
},
|
||||
{
|
||||
// name: "Low - 2013",
|
||||
name: 'Personal Website',
|
||||
data: [12, 11, 14, 18, 17, 13, 13, 14, 18, 17, 13, 13]
|
||||
},
|
||||
{
|
||||
// name: "Low - 2013",
|
||||
name: 'Personal Forum',
|
||||
data: [10, 11, 14, 19, 18, 23, 17, 14, 10, 17, 23, 10]
|
||||
},
|
||||
{
|
||||
// name: "High - 2013",
|
||||
name: 'Professional Forum',
|
||||
data: [20, 19, 30, 36, 30, 35, 33, 33, 36, 32, 32, 30]
|
||||
}
|
||||
],
|
||||
options: {
|
||||
chart: {
|
||||
height: 350,
|
||||
type: 'line',
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
color: '#000',
|
||||
top: 18,
|
||||
left: 7,
|
||||
blur: 10,
|
||||
opacity: 0.5
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
colors: ['#77B6EA', '#545454', '#F50898','#213ece'],
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth'
|
||||
},
|
||||
title: {
|
||||
text: 'Recent Sites Traffic',
|
||||
align: 'left'
|
||||
},
|
||||
grid: {
|
||||
borderColor: '#e7e7e7',
|
||||
row: {
|
||||
colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns
|
||||
opacity: 0.5
|
||||
},
|
||||
},
|
||||
markers: {
|
||||
size: 1
|
||||
},
|
||||
xaxis: {
|
||||
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'],
|
||||
title: {
|
||||
text: 'Month'
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: 'Visits'
|
||||
},
|
||||
min: 5,
|
||||
max: 40
|
||||
},
|
||||
legend: {
|
||||
position: 'top',
|
||||
horizontalAlign: 'right',
|
||||
floating: true,
|
||||
offsetY: -25,
|
||||
offsetX: -5
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id="chart">
|
||||
<ReactApexChart options={state.options} series={state.series} type="line" height={450} />
|
||||
</div>
|
||||
<div id="html-dist"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default TrafficChart
|
||||
@@ -2063,6 +2063,8 @@ ul.activity {
|
||||
.img-icon{
|
||||
width:60px;
|
||||
height:60px;
|
||||
min-width:60px;
|
||||
min-height:60px;
|
||||
border-radius:100px;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
function sortArrayByListOrder(data) {
|
||||
// Convert object to array if needed
|
||||
const array = Array.isArray(data)
|
||||
? [...data]
|
||||
: Object.values(data);
|
||||
|
||||
// Sort ascending by list_order
|
||||
array.sort((a, b) => {
|
||||
const orderA = a.list_order ?? 0;
|
||||
const orderB = b.list_order ?? 0;
|
||||
return orderA - orderB;
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
export default sortArrayByListOrder
|
||||
@@ -3,6 +3,7 @@ const siteLinks = {
|
||||
help: '/help',
|
||||
home: '/',
|
||||
dash: '/dash',
|
||||
traffic: '/traffic',
|
||||
start: '/start',
|
||||
profile_complete: '/profile-complete',
|
||||
product: '/product/*',
|
||||
@@ -10,6 +11,7 @@ const siteLinks = {
|
||||
comments: '/comments',
|
||||
reports: '/reports',
|
||||
subscription: '/subscription',
|
||||
my_media: '/my-files',
|
||||
subscription_success:'/subscription-success',
|
||||
subscribe: '/subscribe',
|
||||
onboard: '/subscription',
|
||||
|
||||
@@ -10,6 +10,12 @@ const queryKeys = {
|
||||
myProductConfig: ['myproduct_config'],
|
||||
productTemplateData: ['product_template_data'],
|
||||
subscriptions: ['subscriptions'],
|
||||
profile_data: ['profile_data'],
|
||||
my_files: ['my_files'],
|
||||
topics: ['topics'],
|
||||
payment_report: ['payment_report'],
|
||||
product_report: ['product_report'],
|
||||
system_report: ['system_report'],
|
||||
|
||||
dashboard: ['dashboard'],
|
||||
topBar: ['top-bar'],
|
||||
|
||||
+130
-6
@@ -1,10 +1,9 @@
|
||||
import axios from "axios"
|
||||
|
||||
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
config.headers = {
|
||||
Accept: "application/json",
|
||||
// Accept: "application/json",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
|
||||
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
|
||||
@@ -23,11 +22,20 @@ axios.interceptors.request.use(
|
||||
|
||||
const postAuxEnd = (path, postData, media=false) => {
|
||||
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
|
||||
return axios.post(`${basePath}${path}`, postData).then(res => {
|
||||
let newPostData = {}
|
||||
if(!media){
|
||||
newPostData = {...postData}
|
||||
}else{
|
||||
newPostData = new FormData();
|
||||
for (let data in postData) {
|
||||
newPostData.append(data, postData[data]);
|
||||
}
|
||||
}
|
||||
return axios.post(`${basePath}${path}`, newPostData).then(res => {
|
||||
return res
|
||||
}).catch(err => {
|
||||
// console.log('res', err.response.data)
|
||||
throw new Error(err.response.data.error_message);
|
||||
// throw new Error(err.response.data.error_message);
|
||||
throw new Error(err);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,6 +84,30 @@ export const topBar = (reqData) => {
|
||||
return postAuxEnd(`/panel/account/bar`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PROFILE DATA
|
||||
export const profileDetails = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/profile`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO UPDATE PROFILE
|
||||
export const updateProfile = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/profile-update`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO UPDATE LINKS
|
||||
export const updateLinks = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return null //postAuxEnd(`/panel/account/links-update`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PRODUCT BY ID
|
||||
export const MyProductData = (reqData) => {
|
||||
let postData = {
|
||||
@@ -99,7 +131,7 @@ export const getCalendarEvents = (reqData) => {
|
||||
return postAuxEnd(`/panel/account/calendar`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
|
||||
// FUNCTION TO GET CONTACT DATA
|
||||
export const contactData = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
@@ -107,6 +139,14 @@ export const contactData = (reqData) => {
|
||||
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
|
||||
export const productsURL = (reqData) => {
|
||||
let postData = {
|
||||
@@ -198,6 +238,20 @@ export const getProductTemplateData = (reqData) => {
|
||||
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
||||
}
|
||||
|
||||
export const getProductColorStyles = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/products/color-styles`, postData, false)
|
||||
}
|
||||
|
||||
export const getTemplateConfig = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/myproduct/template-config`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO ACTIVATE TEMPLATE
|
||||
export const activateTemplate = (reqData) => {
|
||||
let postData = {
|
||||
@@ -206,6 +260,14 @@ export const activateTemplate = (reqData) => {
|
||||
return postAuxEnd(`/panel/account/template/activate`, postData, false)
|
||||
}
|
||||
|
||||
export const activateColorStyle = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/colorstyle/activate`, postData, false)
|
||||
}
|
||||
|
||||
|
||||
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
||||
export const completeProfile = (reqData) => {
|
||||
let postData = {
|
||||
@@ -222,6 +284,51 @@ export const getSubscriptions = (reqData) => {
|
||||
return postAuxEnd(`/panel/subscription/products`, postData, false)
|
||||
}
|
||||
|
||||
export const getMediaFileList = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/media-files`, postData, false)
|
||||
}
|
||||
|
||||
export const uploadFile = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/upload/webfiles`, postData, true)
|
||||
}
|
||||
|
||||
export const getReportsTopicsList = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/topics`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PAYMENT REPORTS
|
||||
export const getPaymentReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/payment`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PRODUCT REPORTS
|
||||
export const getProductReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/product`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET SYSTEM REPORTS
|
||||
export const getSystemReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/system`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET COMMON PRACTICE
|
||||
export const getCommonPractice = (reqData) => {
|
||||
let postData = {
|
||||
@@ -230,6 +337,23 @@ export const getCommonPractice = (reqData) => {
|
||||
return postAuxEnd(`/panel/common/practice`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO SET EXTERNAL URL
|
||||
export const setExternalURL = (reqData) => {
|
||||
let postData = {
|
||||
...reqData
|
||||
}
|
||||
return postAuxEnd('/panel/myproduct/external-url', postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO UPLOAD PROFILE IMAGE
|
||||
export const uploadProfileImg = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
throw new Error('Opps')
|
||||
// return postAuxEnd(`/panel/account/profile-update`, postData, true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import MyMedia from "../component/mymedia/MyMedia";
|
||||
|
||||
export default function MyMediaPage() {
|
||||
return (
|
||||
<MyMedia />
|
||||
)
|
||||
}
|
||||
@@ -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