Compare commits

..

1 Commits

Author SHA1 Message Date
victorAnumudu 7b5e338e19 changed forget password label from email to username 2025-01-20 17:52:58 +01:00
133 changed files with 2073 additions and 7147 deletions
+4 -15
View File
@@ -1,21 +1,10 @@
REACT_APP_PANEL_NAME="MERMS Panel DEV"
SKIP_PREFLIGHT_CHECK=true
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development"
NODE_ENV="development"
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://devsocket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://qa-www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://qa-www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://qa-www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com"
# Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000
# show download button
REACT_APP_SHOW_DOWNLOAD=0
+4 -17
View File
@@ -1,22 +1,9 @@
REACT_APP_PANEL_NAME="MERMS Panel DEV"
SKIP_PREFLIGHT_CHECK=true
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development"
NODE_ENV="development"
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MAIN_API_LL="http://localhost:14700"
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://devsocket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://qa-www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://qa-www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://qa-www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com"
# Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000
# show download button
REACT_APP_SHOW_DOWNLOAD=0
+2 -14
View File
@@ -1,20 +1,8 @@
REACT_APP_PANEL_NAME="MERMS Panel"
SKIP_PREFLIGHT_CHECK=true
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="production"
NODE_ENV="production"
REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
REACT_APP_MAIN_API="https://api.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://socket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://www.mermsemr.com/about'
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
# show download button
REACT_APP_SHOW_DOWNLOAD=0
REACT_APP_TIMEOUT=600000
-17
View File
@@ -1,17 +0,0 @@
REACT_APP_PANEL_NAME="MERMS Panel QA"
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development"
NODE_ENV="development"
REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://qa-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://devsocket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://qa-www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://qa-www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://qa-www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
# Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000
+2 -2
View File
@@ -1,7 +1,7 @@
version: '3'
services:
merms-panel:
image: registry.chiefsoft.net/merms-panel-reactjs:latest
# image: registry.chiefsoft.net/wrenchboard-users-wrench:latest
build:
context: .
dockerfile: docker/Dockerfile
@@ -20,7 +20,7 @@ services:
extra_hosts:
- api.mermsemr.com:10.10.33.15
- devapi.mermsemr.com:10.10.33.15
- devsocket.mermsemr.com:10.10.33.15
- dev-socket.mermsemr.com:10.10.33.15
- socket.mermsemr.com:10.10.33.15
- dev-media.mermsemr.com:10.10.33.15
- media.mermsemr.com:10.10.33.15
+3 -3
View File
@@ -126,10 +126,10 @@ RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
# add app
COPY . ./
# start appdpvle
#CMD ["npm","run", "start"]
# start app
# CMD ["npm","run", "start"]
# CMD ["yarn", "start"]
# start app
CMD /bin/sh ./run.sh
CMD /bin/sh ./run.sh
-2
View File
@@ -10,8 +10,6 @@
"@fullcalendar/timegrid": "^6.1.15",
"@popperjs/core": "^2.11.8",
"@reduxjs/toolkit": "^2.4.0",
"@stripe/react-stripe-js": "^3.9.1",
"@stripe/stripe-js": "^7.8.0",
"@tanstack/react-query": "^5.62.3",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
+21 -25
View File
@@ -1,35 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Empowering Healthcare Decision-Making with Artificial Intelligence"
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>MERMS-Panel</title>
</head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Y9QSQFV003"></script>
<script>
</head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Y9QSQFV003"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Y9QSQFV003');
</script>
<body class="light-sidebar">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script> -->
</script>
<body class="light-sidebar">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script> -->
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Executable → Regular
+1 -6
View File
@@ -4,17 +4,12 @@ set -x
export NODE_ENV="${NODE_ENV:-development}"
if [ $NODE_ENV = "development" ]; then
if [ $NODE_ENV == "development" ]; then
# this runs webpack-dev-server with hot reloading
echo "Development build"
npm install --legacy-peer-deps
npm start
# npm run build
elif [ $NODE_ENV = "qa" -o $NODE_ENV = "test" ]; then
echo "QA build"
export NODE_ENV="test"
npm install --legacy-peer-deps
npm start
else
# build the app and serve it via nginx
echo "Production build"
+1 -44
View File
@@ -1,5 +1,5 @@
.custom-bg {
background-image: url('./assets/bg/bg_2.jpg') !important;
background-image: url('./assets/bg/bg_1.jpg') !important;
background-size: cover;
background-repeat: no-repeat;
}
@@ -8,47 +8,4 @@
background-image: url('./assets/bg/signup_bg.jpg') !important;
background-size: cover;
background-repeat: no-repeat;
}
.register{
border-radius: 10px;
}
.border-radius-10 {
border-radius: 10px;
}
.login-links{
margin-top: 50px;
display: flex;
flex-direction: row;
justify-content: center;
}
.login-links a {
font-size: 14px;
padding: 0px 20px;
border-right: 2px solid #6c757d;
cursor: pointer;
}
.login-links a:nth-of-type(1){
padding-left: 0px;
}
.login-links a:last-child{
border: 0px;
}
button{
font-size: 1rem!important;
font-weight: 700!important;
}
.font-600 {
font-weight: 600;
}
.accordion-button, .accordion-button:not(.collapsed) {
background-color: transparent!important;
}
+11 -16
View File
@@ -1,28 +1,23 @@
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import { Provider } from 'react-redux';
import store from './store/store'
import AppRouters from './AppRouters';
import './App.css';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 3,
// refetchOnMount: false,
staleTime: 10*60*1000 // can also be a number in millisecond
},
},
})
function App() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 3,
// refetchOnMount: false,
staleTime: 3000
},
},
})
return (
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<AppRouters />
</Provider>
<AppRouters />
</QueryClientProvider>
);
}
+29 -51
View File
@@ -1,8 +1,7 @@
import {Routes, Route} from 'react-router-dom';
import { Routes, Route } from 'react-router-dom';
import UserExist from './component/authorization/UserExist';
import AuthLayout from './component/auth/AuthLayout';
import BearerToken from './component/authorization/BearerToken';
import siteLinks from './links/siteLinks';
import LoginPage from './views/LoginPage';
@@ -18,58 +17,37 @@ import SettingsPage from './views/SettingsPage'
import ProductPage from './views/ProductPage'
import SocketIOContextProvider from './component/context/SocketIOContext';
import CSignupPage from './views/CSignupPage';
import HelpPage from './views/HelpPage';
import SubscriptionPage from './views/SubscriptionPage';
import OnboardPage from "./views/OnboardPage";
import AccPWDResetPage from './views/AccPWDResetPage';
import ProfileCompletePage from './views/ProfileCompletePage';
import SubscribePage from './views/Subscribe'
import StartPage from "./views/StartPage";
import TrafficPage from "./views/TrafficPage";
import MyMediaPage from './views/MyMediaPage.jsx';
function AppRouters() {
return (
<div className="">
<Routes>
<Route element={<BearerToken/>}>
{/* auth routes wrapper */}
<Route element={<AuthLayout/>}>
<Route path={siteLinks.home} element={<LoginPage/>}/>
<Route path={siteLinks.login} element={<LoginPage/>}/>
<Route path={siteLinks.signup} element={<SignupPage/>}/>
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage/>}/>
<Route path={siteLinks.csignup} element={<CSignupPage/>}/>
<Route path={siteLinks.accreset} element={<AccPWDResetPage/>}/>
<Route path={siteLinks.error} element={<LoginPage/>}/>
</Route>
return (
<div className="">
<Routes>
{/* auth routes wrapper */}
<Route element={<AuthLayout />}>
<Route path={siteLinks.home} element={<LoginPage />} />
<Route path={siteLinks.login} element={<LoginPage />} />
<Route path={siteLinks.signup} element={<SignupPage />} />
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage />} />
<Route path={siteLinks.csignup} element={<CSignupPage />} />
<Route path={siteLinks.error} element={<LoginPage />} />
</Route>
{/* protected routes */}
<Route element={<SocketIOContextProvider/>}>
<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/>}/>
<Route path={siteLinks.subscription} element={<SubscriptionPage/>}/>
<Route path={siteLinks.subscription_success} element={<SubscriptionPage/>}/>
<Route path={siteLinks.onboard} element={<OnboardPage/>}/>
<Route path={siteLinks.calendar} element={<CalendarPage/>}/>
<Route path={siteLinks.settings} element={<SettingsPage/>}/>
<Route path={siteLinks.subscribe} element={<SubscribePage/>}/>
<Route path={siteLinks.help} element={<HelpPage/>}/>
</Route>
</Route>
</Route>
</Routes>
</div>
);
{/* protected routes */}
<Route element={<SocketIOContextProvider />}>
<Route element={<UserExist />}>
<Route path={siteLinks.dash} element={<HomePage />} />
<Route path={siteLinks.product} element={<ProductPage />} />
<Route path={siteLinks.reports} element={<ReportsPage />} />
<Route path={siteLinks.comments} element={<CommentsPage />} />
<Route path={siteLinks.contacts} element={<ContactsPage />} />
<Route path={siteLinks.user} element={<UserPage />} />
<Route path={siteLinks.calendar} element={<CalendarPage />} />
<Route path={siteLinks.settings} element={<SettingsPage />} />
</Route>
</Route>
</Routes>
</div>
);
}
export default AppRouters;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 KiB

-220
View File
@@ -1,220 +0,0 @@
import React, { useEffect, useState } from 'react'
import { Form, Formik } from "formik";
import * as Yup from "yup";
import { useDispatch } from 'react-redux'
import { Link, useNavigate, useParams } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import { useMutation } from '@tanstack/react-query';
import { completePWDReset, verifyResetToken } from '../../services/services';
import { updateUserDetails } from '../../store/UserDetails'
import { IoMdArrowDropdown } from "react-icons/io";
import getImage from '../../utils/getImage';
const validationSchema = Yup.object().shape({
password: Yup.string().required("Password is required"),
confirmpassword: Yup.string().required("Confirm Password is required").oneOf([Yup.ref('password')], 'Passwords must match')
})
const initialValues = {
password: '',
confirmpassword: '',
};
export default function AccPWDReset() {
const {token} = useParams()
const dispatch = useDispatch()
const navigate = useNavigate()
const [user, setUser] = useState(null)
// API to verify email link
const verifyLink = useMutation({
mutationFn: (fields) => {
return verifyResetToken(fields)
},
onSuccess: (res) => {
// console.log('res', res.data)
if(res.data.resultCode != '0' || !res?.data?.pending_uid){
throw({message: res?.data?.resultDescription})
}
// setUser({user:'testaccount', ...res.data})
setUser(res.data)
},
// onError: (err) => {
// console.log('err', err)
// }
})
const resetPWD = useMutation({
mutationFn: (fields) => {
return completePWDReset(fields)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: res?.data?.resultDescription})
}
// const {token, room, uid} = res?.data
// if(!token || !room){
// throw({message: 'something went wrong, try again!'})
// }
// localStorage.setItem('token', token)
// localStorage.setItem('room', room)
// localStorage.setItem('uid', uid)
// dispatch(updateUserDetails({ ...res?.data }));
// navigate('/dash') // later add redux to dispatch state
},
// onError: (err) => {
// console.log('err', err)
// }
})
const handleCompletePWDReset = (values) => {
let reqData = {
reset_token: token,
reset_uid: user?.pending_uid,
new_password: values.password,
}
resetPWD.mutate(reqData)
}
useEffect(()=>{
if(!token){
return navigate(siteLinks.login, {replace: true})
}
verifyLink.mutate({reset_token: token})
}, [])
return (
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="vh-100 bg-white custom-bg">
<div className="container-fluid p-0">
<div className="row no-gutters justify-content-center">
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1" style={{maxWidth: '520px'}}>
<div className="mt-5 d-flex">
<div className="bg-white register p-5">
<h1 className="mb-2">MERMS Panel</h1>
{(verifyLink.isSuccess && !resetPWD.isSuccess) && <p>Complete your password reset</p>}
<div
>
<div className='mt-2'>
<div className="row">
{resetPWD.isSuccess ?
<>
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'>Your password reset is completed</h4>
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</>
:
<>
{verifyLink.isPending ?
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-center align-items-center" style={{height: '200px', backgroundColor: '#F2FAF7'}}>
<div className="col-12 d-flex flex-column justify-content-center align-items-center">
<p className='text-black'>loading...</p>
</div>
</div>
</div>
: verifyLink.isSuccess ?
<div className='col-12'>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleCompletePWDReset}
>
{(props) => {
return (
<Form className='mt-2'>
<div className="row">
<>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label`}>Username: {user?.user}</label>
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.password && props.touched.password) && 'text-danger'}`}>Password*</label>
<input type="password" name='password' className="form-control" placeholder="password" value={props.values.password} onChange={props.handleChange} />
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label`}>Confirm Password* <span className={`${(props.errors.confirmpassword && props.touched.confirmpassword) && 'text-danger'}`}>{(props.errors.confirmpassword && props.touched.confirmpassword) && props.errors.confirmpassword}</span></label>
<input type="password" name='confirmpassword' className="form-control" placeholder="confirmpassword" value={props.values.confirmpassword} onChange={props.handleChange} />
</div>
</div>
{resetPWD.error &&
<>
<div className="col-12">
<p className='text-danger'>{resetPWD.error.message}</p>
</div>
</>
}
<div className="col-12 mt-3 text-end">
<button type='submit' className="btn btn-primary text-uppercase">{resetPWD.isPending ? 'loading...' : 'reset password'}</button>
</div>
</>
</div>
</Form>
);
}}
</Formik>
</div>
: verifyLink.error ?
<>
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#E9D0DD'}}>
<h4 className='p-4 text-black'>Unable to continue password reset. Please start again</h4>
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</>
:
null
}
</>
}
</div>
</div>
</div>
</div>
</div>
</div>
{/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
</div>
</div>
</div> */}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
-42
View File
@@ -1,42 +0,0 @@
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>
)
}
+13 -21
View File
@@ -1,13 +1,11 @@
import React, { useEffect, useState } from 'react'
import { Form, Formik } from "formik";
import * as Yup from "yup";
import { useDispatch } from 'react-redux'
import { Link, useNavigate, useParams } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import { useMutation } from '@tanstack/react-query';
import { completeRegistration, verifyEmail } from '../../services/services';
import { updateUserDetails } from '../../store/UserDetails'
import { IoMdArrowDropdown } from "react-icons/io";
@@ -30,8 +28,6 @@ const validationSchema = Yup.object().shape({
export default function CSignup() {
const {jwt} = useParams()
const dispatch = useDispatch()
const navigate = useNavigate()
@@ -55,19 +51,15 @@ export default function CSignup() {
return completeRegistration(fields)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: res?.data?.resultDescription})
const {token, room} = res?.data?.data
if(token){
localStorage.setItem('token', token)
localStorage.setItem('room', room)
// const data = {token}
// dispatch(updateUserDetails({ ...data }));
navigate('/dash') // later add redux to dispatch state
}
const {token, room, uid} = res?.data
if(!token || !room){
throw({message: 'something went wrong, try again!'})
}
localStorage.setItem('token', token)
localStorage.setItem('room', room)
localStorage.setItem('uid', uid)
dispatch(updateUserDetails({ ...res?.data }));
navigate(siteLinks.start, {replace: true}) // later add redux to dispatch state
},
}
// onError: (err) => {
// console.log('err', err)
// }
@@ -78,7 +70,7 @@ export default function CSignup() {
country : values.country,
username: values.username,
password: values.password,
verify_link: jwt
verify_link: user.verify_link
}
cSignup.mutate(reqData)
}
@@ -94,13 +86,13 @@ export default function CSignup() {
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="vh-100 bg-white custom-bg">
<div className="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="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1 h-100-vh">
<div className="mt-5 d-flex">
<div className="bg-white register p-5">
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
<h1 className="mb-2">MERMS Panel</h1>
{/* <p>Welcome, Enter your password.</p> */}
<div
>
@@ -204,7 +196,7 @@ export default function CSignup() {
}
<div className="col-12 mt-3 text-center">
<Link to={siteLinks.signup} className='text-primary' style={{color: '#6FCAEF'}}>Need help with logging in or signing up?</Link>
<Link to={siteLinks.login} className='text-primary' style={{color: '#6FCAEF'}}>Need help with logging in or signing up?</Link>
</div>
<div className="col-12 mt-3 text-center">
-10
View File
@@ -1,10 +0,0 @@
import React from "react";
export default function ExtFooter() {
return <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>
}
+14 -18
View File
@@ -7,8 +7,6 @@ import { Link } from 'react-router-dom'
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()
@@ -18,8 +16,8 @@ const validationSchema = Yup.object().shape({
// "Invalid email format"
// )
.min(3, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Email is required"),
.max(50, "Maximum 50 characters")
.required("Username is required"),
})
const initialValues = {
@@ -45,14 +43,14 @@ export default function Forgetpwd2() {
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="vh-100 bg-white custom-bg">
<div className="bg-white">
<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-1h" 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>
{!mutation.isSuccess && <p>Please enter your username.</p>}
<div className="row no-gutters">
<div className="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1">
<div className="d-flex align-items-center h-100-vh">
<div className="login p-50">
<h1 className="mb-2">Recover Password</h1>
<p>Please enter your username.</p>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
@@ -66,7 +64,7 @@ export default function Forgetpwd2() {
<>
<div className="col-12">
<div className="form-group">
<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>
<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} />
</div>
</div>
@@ -83,9 +81,8 @@ export default function Forgetpwd2() {
</>
:
<div className='col-12'>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{backgroundColor: '#F2FAF7'}}>
<div className="rounded-2 d-flex flex-column justify-content-between align-items-center" style={{height: '200px', backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'>Check your email to continue password reset.</h4>
<img className='' style={{width: '150px'}} src={getImage('reset-password.png')} alt='reset-icon' />
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
@@ -98,17 +95,16 @@ export default function Forgetpwd2() {
);
}}
</Formik>
<AuthFooter />
</div>
</div>
</div>
{/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
{/* <img className="img-fluid" src={LoginImg} alt="" /> */}
</div>
</div>
</div> */}
</div>
</div>
</div>
</div>
+1 -1
View File
@@ -27,7 +27,7 @@ export default function Login() {
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
<div className='w-full text-left'>
<h1 className="mb-2 text-black text-4xl font-semibold">{process.env.REACT_APP_PANEL_NAME}</h1>
<h1 className="mb-2 text-black text-4xl font-semibold">MERMS Panel</h1>
<p className='text-black-gray text-base'>Welcome back, please login to your account.</p>
</div>
<form className="w-full text-14 text-left text-black-gray">
+44 -45
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { useMutation } from '@tanstack/react-query'
import { useDispatch, useSelector } from 'react-redux'
import { useDispatch } from 'react-redux'
// import LoginImg from '../../assets/bg/login.svg'
@@ -9,21 +9,19 @@ import siteLinks from '../../links/siteLinks'
import { loginUser } from '../../services/services'
import { updateUserDetails } from '../../store/UserDetails'
import AuthFooter from './AuthFooter'
import GoogleDownload from '../../assets/img/download/andriod.jpg'
import IOSDownload from '../../assets/img/download/apple.jpg'
export default function Login() {
const { userDetails: { token, room }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = token && room ? true : false; // variable to determine if user is logged in
const dispatch = useDispatch()
const navigate = useNavigate()
const [fields, setFields] = useState({
username: '',
username: localStorage.getItem('username') || '',
password: '',
remember: false
remember: localStorage.getItem('username') ? true : false
})
const handleChange = ({target:{name, value}}) => {
@@ -39,25 +37,20 @@ export default function Login() {
throw new Error('Please provide all fields marked *')
}
rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE
delete fields.remember // REMOVING REMEMBER FROM THE PAYLOAD
return loginUser(fields)
},
onError: (error) => {
console.log(error)
},
onSuccess: (res) => {
if(res?.data && res?.data?.error_message){
throw({message: res?.data?.error_message})
const {token, room} = res?.data?.data
if(token){
localStorage.setItem('token', token)
localStorage.setItem('room', room)
// const data = {token}
// dispatch(updateUserDetails({ ...data }));
navigate('/dash') // later add redux to dispatch state
}
const {token, room, uid} = res?.data
if(!token || !room){
throw({message: 'Unable to complete your login, Please try again!'})
}
localStorage.setItem('token', token)
localStorage.setItem('room', room)
localStorage.setItem('uid', uid)
dispatch(updateUserDetails({ ...res?.data }));
navigate('/dash') // later add redux to dispatch state
}
})
@@ -69,42 +62,36 @@ export default function Login() {
}
}
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS ACTIVE
if(loggedIn){
navigate(siteLinks.dash)
}
},[])
return (
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="vh-100 custom-bg">
<div className="bg-white">
<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>
<div className="row no-gutters">
<div className="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1">
<div className="d-flex align-items-center h-100-vh">
<div className="login p-50">
<h1 className="mb-2">MERMS Panel</h1>
<p>Welcome back, please login to your account.</p>
<form className="mt-3 mt-sm-5">
<div className="row">
<div className="col-12">
<div className="form-group">
<label className="control-label text-black fw-bold">User Name*</label>
<input maxLength={25} name='username' value={fields.username} onChange={handleChange} type="text" className="form-control" placeholder="Username" />
<input 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={25} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
<input name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
</div>
</div>
<div className="col-12">
<div className="d-block d-sm-flex align-items-center">
<div className="form-check">
<input className="form-check-input" type="checkbox" id="gridCheck" name='remember' checked={fields.remember || false} onChange={handleChange} disabled={!fields.username ? true : false} />
<input className="form-check-input" type="checkbox" id="gridCheck" name='remember' checked={fields.remember} onChange={handleChange} disabled={!fields.username ? true : false} />
<label className="form-check-label text-black" htmlFor="gridCheck">
Remember Me
</label>
@@ -123,26 +110,38 @@ export default function Login() {
<button type='button' onClick={()=>{login.mutate(fields)}} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
</div>
<div className="col-12 mt-3">
<p> <Link to={siteLinks.signup}>
{/*<span style={{fontWeight: 'bolder'}}>Sign Up</span>*/}
<button className="btn btn-warning text-uppercase">
Sign Up
</button>
</Link><span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}> if you don't have an account yet.</span></p>
<p>Don't have an account ?<Link to={siteLinks.signup}> Sign Up</Link></p>
</div>
</div>
</form>
<AuthFooter />
<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-100 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-100 h-auto' alt='IOS Download' />
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
{/* <img className="img-fluid" src={LoginImg} alt="" /> */}
</div>
</div>
</div> */}
</div>
</div>
</div>
</div>
+71 -84
View File
@@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react'
import React, { useEffect, useState } from 'react'
import LoginImg from '../../assets/bg/login.svg'
import MainLoader from '../loaders/MainLoader'
import {Link, useNavigate} from 'react-router-dom'
import { Link, useNavigate } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import Label from '../Label'
import TextInput from '../inputs/TextInput'
@@ -9,102 +9,89 @@ import TextInput from '../inputs/TextInput'
export default function Signup() {
const [loading, setLoading] = useState(true)
const [loading, setLoading] = useState(true)
const navigate = useNavigate()
const navigate = useNavigate()
useEffect(() => {
const timer = setTimeout(() => {
setLoading(false)
}, 1000)
useEffect(()=>{
const timer = setTimeout(()=>{
setLoading(false)
},1000)
return () => clearTimeout(timer)
}, [])
return () => clearTimeout(timer)
},[])
return (
<div className="h-screen bg-white w-full flex justify-center items-center">
<div className="h-full w-full bg-white grid sm:grid-cols-2 lg:grid-cols-5 xl:grid-cols-8">
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
<div className='w-full text-left'>
<h1 className="mb-2 text-black text-4xl font-semibold">{process.env.REACT_APP_PANEL_NAME}</h1>
<p className='text-black-gray text-base'>Welcome, Please create your account.</p>
</div>
<form className="w-full text-14 text-left text-black-gray">
<div className="w-full flex flex-col gap-4 justify-start items-start">
<div className='w-full grid grid-cols-2 gap-8'>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='First Name*'/>
<TextInput type='text' placeholder='Firstname'/>
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='Last Name*'/>
<TextInput type='text' placeholder='Lastname'/>
</div>
return (
<div className="h-screen bg-white w-full flex justify-center items-center">
<div className="h-full w-full bg-white grid sm:grid-cols-2 lg:grid-cols-5 xl:grid-cols-8">
<div className="col-span-1 lg:col-span-2 xl:col-span-2 place-content-center order-2 sm:order-1">
<div className="w-full p-4 px-8 md:p-10 flex flex-col gap-6 items-start justify-start">
<div className='w-full text-left'>
<h1 className="mb-2 text-black text-4xl font-semibold">MERMS Panel</h1>
<p className='text-black-gray text-base'>Welcome, Please create your account.</p>
</div>
<form className="w-full text-14 text-left text-black-gray">
<div className="w-full flex flex-col gap-4 justify-start items-start">
<div className='w-full grid grid-cols-2 gap-8'>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='First Name*' />
<TextInput type='text' placeholder='Firstname' />
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='Email*'/>
<TextInput type='text' placeholder='Email'/>
<Label desc='Last Name*' />
<TextInput type='text' placeholder='Lastname' />
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='User Name*'/>
<TextInput type='text' placeholder='Username'/>
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='Password*'/>
<TextInput type='password' placeholder='Password'/>
</div>
</div>
<div className="w-full text-left">
<div className="flex justify-between items-center">
<div className="flex gap-2">
<input className="form-check-input" type="checkbox" id="gridCheck"/>
<label className="font-semibold form-check-label" htmlFor="gridCheck">
I accept terms & policy of use.
</label>
</div>
</div>
</div>
<div className="w-full mt-3">
<button onClick={() => {
navigate(siteLinks.home)
}} className="bg-primary rounded-sm px-4 py-2 text-white font-medium uppercase">Sign
Up
</button>
</div>
<div className="mt-3">
<hr />
<p className='font-medium'>Already have an account ?
<Link to={siteLinks.login}
className='bg-secondary; hover:text-primary font-bold' style={{paddingRight: '10px'}}>
<button className="btn btn-warning text-uppercase">
Sign In
</button>
</Link>
</p>
</div>
</div>
</form>
</div>
</div>
<div
className="bg-login_gradient h-full col-span-1 lg:col-span-3 xl:col-span-6 place-content-center order-1 sm:order-2">
<div className="w-full">
<div className="w-2/3 mx-auto">
<img className="w-[80%]" src={LoginImg} alt=""/>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='Email*' />
<TextInput type='text' placeholder='Email' />
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='User Name*' />
<TextInput type='text' placeholder='Username' />
</div>
</div>
<div className="w-full">
<div className="w-full flex flex-col gap-2">
<Label desc='Password*' />
<TextInput type='password' placeholder='Password' />
</div>
</div>
<div className="w-full text-left">
<div className="flex justify-between items-center">
<div className="flex gap-2">
<input className="form-check-input" type="checkbox" id="gridCheck" />
<label className="font-semibold form-check-label" htmlFor="gridCheck">
I accept terms & policy
</label>
</div>
</div>
</div>
<div className="w-full mt-3">
<button onClick={()=>{navigate(siteLinks.home)}} className="bg-primary rounded-sm px-4 py-2 text-white font-medium uppercase">Sign Up</button>
</div>
<div className="mt-3">
<p className='font-medium'>Already have an account ?<Link to={siteLinks.login} className=' hover:text-primary'> Sign In</Link></p>
</div>
</div>
</form>
</div>
</div>
<div className="bg-login_gradient h-full col-span-1 lg:col-span-3 xl:col-span-6 place-content-center order-1 sm:order-2">
<div className="w-full">
<div className="w-2/3 mx-auto">
<img className="w-[80%]" src={LoginImg} alt="" />
</div>
</div>
</div>
</div>
)
</div>
)
}
+125 -172
View File
@@ -1,212 +1,165 @@
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 getImage from '../../utils/getImage';
import AuthFooter from './AuthFooter';
import { useMutation } from '@tanstack/react-query';
import { signUpUser } from '../../services/services';
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 signUp = (values) => {
// helpers.resetForm()
// console.log('values', values, helpers)
delete values.isChecked
mutation.mutate(values)
const mutation = useMutation({
mutationFn: (fields) => {
return signUpUser(fields)
},
onSuccess: (res) => {
console.log('res', res)
}
})
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} />
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.password && props.touched.password) && 'text-danger'}`}>Password*</label>
<input type="password" name='password' className="form-control" placeholder="Password" value={props.values.password} onChange={props.handleChange} />
</div>
</div> */}
<div className="col-12">
<div className="form-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>
const signUp = (values) => {
// helpers.resetForm()
// console.log('values', values, helpers)
mutation.mutate(values)
}
{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">
<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>
return (
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="bg-white">
<div className="container-fluid p-0">
<div className="row no-gutters">
<div className="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1">
<div className="d-flex align-items-center h-100-vh">
<div className="register p-5">
<h1 className="mb-2">MERMS Panel</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-sm-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>
</Form>
);
}}
</Formik>
<AuthFooter />
</div>
</div>
<div className="col-12 col-sm-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} />
</div>
</div>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.password && props.touched.password) && 'text-danger'}`}>Password*</label>
<input type="password" name='password' className="form-control" placeholder="Password" value={props.values.password} onChange={props.handleChange} />
</div>
</div> */}
<div className="col-12">
<div className="form-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>
</>
}
<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={{height: '200px', backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'>Check your email to continue.</h4>
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</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>
</div>
{/* <div className="signup-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
</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="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
{/* <img className="img-fluid" src={LoginImg} alt="" /> */}
</div>
</div>
</div> */}
</div>
</div>
</div>
</div>
</div>
</div>
)
</div>
)
}
@@ -1,47 +0,0 @@
import {useEffect} from 'react'
import { useMutation } from '@tanstack/react-query'
import { Outlet } from 'react-router-dom'
import MainLoaderBS from '../loaders/MainLoaderBS'
import { userToken } from '../../services/services'
export default function BearerToken() {
const bearerToken = useMutation({
mutationFn: (fields) => {
return userToken(fields)
},
onError: (error) => {
console.log(error)
// window.location.reload(true)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: 'Something went wrong'})
}
const {access_token, refresh_token} = res?.data?.data
if(access_token){
localStorage.setItem('access_token', access_token)
}else{
throw({message: 'Something went wrong'})
}
}
})
useEffect(()=>{
let reqData = {
"username": "user",
"password": "password"
}
bearerToken.mutate(reqData)
},[])
return (
<>
{bearerToken.isPending ?
<MainLoaderBS />
:
<Outlet />
}
</>
)
}
+29 -40
View File
@@ -1,15 +1,13 @@
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from "react-redux";
import { Outlet, useNavigate } from 'react-router-dom'
import { useMutation } from '@tanstack/react-query'
import { updateUserDetails } from "../../store/UserDetails";
import { userInfo } from '../../services/services'
import MainLoaderBS from '../loaders/MainLoaderBS'
import Layout from '../layout/Layout'
import siteLinks from '../../links/siteLinks'
import debounceFunction from '../../utils/debounceFunction'
import { accountDashboard } from '../../services/services';
import { SocketContextValues } from '../context/SocketIOContext';
@@ -25,9 +23,9 @@ export default function UserExist() {
const [lastActivityTime, setLastActivityTime] = useState(Date.now()); // HOLDS THE INITIAL TIME USER LOGS IN
const { userDetails: { token, room }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
const { userDetails: { lastname }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = token && room ? true : false; // variable to determine if user is logged in
let loggedIn = lastname ? true : false; // variable to determine if user is logged in
// console.log('loggedIn', loggedIn)
// Function to log the user out
@@ -42,31 +40,6 @@ export default function UserExist() {
debounceFunction(setLastActivityTime(Date.now()), 1000)
};
const getUser = useMutation({
mutationFn: (fields) => {
return userInfo(fields)
},
onError: (error) => {
navigate(siteLinks.login)
setLoading(false)
},
onSuccess: (res) => {
const {token, room, uid} = res?.data
if(!token || !room){
navigate(siteLinks.login)
setLoading(false)
return
}
localStorage.setItem('token', token)
localStorage.setItem('room', room)
localStorage.setItem('uid', uid)
dispatch(updateUserDetails({ ...res?.data }));
setLoading(false)
}
})
useEffect(()=>{
const timer = setTimeout(()=>{
if(Date.now() - Number(lastActivityTime) >= Number(process.env.REACT_APP_TIMEOUT)){
@@ -88,21 +61,37 @@ export default function UserExist() {
window.removeEventListener(event, resetTimer);
})
}
},[lastActivityTime])
},[lastActivityTime])
useEffect(()=>{
let token = localStorage.getItem('token') // USER TOKEN
let uid = localStorage.getItem('uid') // USER UID
if(token && loggedIn){
accountDashboard().then(res => {
const {dash_data} = res?.data
setLoading(false)
}else if(token && uid && !loggedIn){
const reqData = {token, uid}
getUser.mutate(reqData)
}else{
dispatch(updateUserDetails({ ...dash_data }));
}).catch(err => {
navigate(siteLinks.login)
setLoading(false)
}
})
},[])
// useEffect(()=>{
// let token = localStorage.getItem('token')
// const timer = setTimeout(()=>{
// if(token && loggedIn){
// setLoading(false)
// }else if(token && !loggedIn){
// const data = {token}
// dispatch(updateUserDetails({ ...data }));
// setLoading(false)
// // dispatch(updateUserDetails({ ...res.data }));
// }else{
// navigate('auth/login')
// }
// },1000)
// return () => clearTimeout(timer)
// },[])
useEffect(()=>{
if(localStorage.getItem('room')){
+34 -122
View File
@@ -1,13 +1,8 @@
import React, { useCallback, useEffect, useState } from "react";
import { useMutation, useQuery } from '@tanstack/react-query'
import React, { useCallback, useState } from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import EventCalendar from "./EventCalendar";
import ExternalDraggable from "./ExternalDraggable";
import { getCalendarEvents } from '../../services/services'
import queryKeys from '../../services/queryKeys'
export default function Calendar(){
@@ -16,47 +11,14 @@ export default function Calendar(){
// setDraggedEvent(event)
// }
// const {data, isFetching, isError, error} = useQuery({
// queryKey: queryKeys.calendar_events,
// queryFn: () => getCalendarEvents()
// })
const events = [
{id: '1111', title: 'Family Vacation', color: 'fc-event-primary', start: new Date('2025-01-18')},
{id: '2222', title: 'Meeting In Office', color: 'fc-event-warning', start: new Date('2025-01-19')},
{id: '3333', title: 'Client Call', color: 'fc-event-danger', start: new Date('2025-01-22')},
{id: '4444', title: 'Interview', color: 'fc-event-success', start: new Date('2025-01-1')}
]
// const calendarEvents = useMutation({
// mutationFn: (reqData) => {
// return getCalendarEvents(reqData)
// },
// onError: (error) => {
// console.log(error)
// },
// onSuccess: (res) => {
// if(res?.data?.resultCode != '0'){
// throw({message: 'Something went wrong'})
// }
// }
// })
// useEffect(()=>{
// let reqData = {
// token: localStorage.getItem('token'), // USER TOKEN
// uid: localStorage.getItem('uid') // USER UID
// }
// calendarEvents.mutate(reqData)
// },[])
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.calendar_events,
queryFn: () => getCalendarEvents(reqData),
staleTime: 0
})
const receievedEvents = data?.data
const category = receievedEvents?.category //EVENT CATEGORIES FROM API
const eventList = receievedEvents?.list //EVENT LIST FROM API
const [activeCategory, setActiveCategory] = useState('1')
const [dummyEvents, setDummyEvents] = useState(events)
const [removeAfterDrop, setRemoveAfterDrop] = useState(false)
@@ -71,14 +33,11 @@ export default function Calendar(){
const handleAddNewEvent = () => {
if(newEvent.title && newEvent.color){
const eventToAdd = {...newEvent}
// setDefaultCategory(prev => ([...prev, eventToAdd]))
setDummyEvents(prev => ([...prev, eventToAdd]))
setNewEvent({title: '', color: ''})
}
}
const handleActiveCategory = (id) => {
setActiveCategory(id)
}
return(
<>
@@ -88,92 +47,45 @@ export default function Calendar(){
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">Events</h4>
<h4 className="card-title">Event Calendar</h4>
</div>
</div>
<div className="card-body">
<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-xl-3">
{/* <button className="btn btn-primary btn-block" data-bs-toggle="modal" data-bs-target="#eventModal">
<div className="col-xl-3">
<div id="external-events">
<button className="btn btn-primary btn-block" data-bs-toggle="modal" data-bs-target="#eventModal">
Add New Event
</button>
<p className="mt-3">
Drag and drop your event or click in the calendar.
</p> */}
{category?.map((item, index) => {
let color = item?.cid == '1' ? 'fc-event-success' : item?.cid == '2' ? 'fc-event-danger' : item?.cid == '3' ? 'fc-event-warning' : 'fc-event-primary'
let circleColor = item?.cid == '1' ? 'text-success' : item?.cid == '2' ? 'text-danger' : item?.cid == '3' ? 'text-warning' : 'text-primary'
return (
// <div key={index} className={`fc-event ${color}`} data-color={`${color}`}
// // draggable={false}
// // onDragStart={() =>
// // handleDragStart({...item})
// // }
// >
// <span>{item.description}</span>
// </div>
// <div key={index} className={`form-check ${color}`}>
// <input className="form-check-input" type="radio" value={item.cid}
// id={item.cid} name='category' checked={item.cid == activeCategory} onChange={() => handleActiveCategory(item.cid)} />
// <label className={`w-100 form-check-label`} htmlFor={item.cid}>
// {item.description}
// </label>
// </div>
<div key={index} className={`form-check ${color}`} onClick={() => handleActiveCategory(item.cid)} style={{cursor: 'pointer'}}>
<div>
<span className="nav align-items-center">
<span>
<i className={`fa fa-circle-o pr-4 ${item.cid == activeCategory ? circleColor : 'text-light'}`}></i>
</span>
<span>
<span>{item?.description}</span>
</span>
</span>
</div>
</div>
)
}
)}
{/* <div id="external-events">
<ExternalDraggable category={category} />
</div> */}
{/* <div className="form-check">
</p>
{/* {dummyEvents.map((item, index) => (
<div key={index} className={`fc-event ${item.color}`} data-color={`${item.color}`}
draggable="true"
onDragStart={() =>
handleDragStart({...item})
}
>
<span></span> {item.title}
</div>
))} */}
<ExternalDraggable dummyEvents={dummyEvents} />
<div className="form-check">
<input className="form-check-input" type="checkbox" value={removeAfterDrop}
id="defaultCheck1" onChange={() => setRemoveAfterDrop(prev => !prev)} />
id="defaultCheck1" onChange={() => setRemoveAfterDrop(prev => !prev)} />
<label className="form-check-label" htmlFor="defaultCheck1">
Remove After Drop
</label>
</div> */}
</div>
<div className="col-xl-9">
<div className="event-calendar">
<EventCalendar
removeAfterDrop={removeAfterDrop}
eventList={eventList}
activeCategory={activeCategory}
/>
</div>
</div>
</>
}
</div>
<div className="col-xl-9">
<div className="event-calendar">
{/* <EventCalendar draggedEvent={draggedEvent} setDraggedEvent={setDraggedEvent} /> */}
<EventCalendar removeAfterDrop={removeAfterDrop} setDummyEvents={setDummyEvents} />
</div>
</div>
</div>
</div>
+10 -18
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useState } from 'react';
import { formatDate } from '@fullcalendar/core';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
@@ -6,9 +6,9 @@ import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import { INITIAL_EVENTS, createEventId } from './event-utils';
export default function EventCalendar({removeAfterDrop, eventList, activeCategory}) {
export default function EventCalendar({draggedEvent, setDraggedEvent, removeAfterDrop, setDummyEvents}) {
const [weekendsVisible, setWeekendsVisible] = useState(true);
const [currentEvents, setCurrentEvents] = useState([]);
const [currentEvents, setCurrentEvents] = useState(INITIAL_EVENTS);
function handleWeekendsToggle() {
setWeekendsVisible(!weekendsVisible);
@@ -51,9 +51,9 @@ export default function EventCalendar({removeAfterDrop, eventList, activeCategor
...event
}
setCurrentEvents(prev => ([...prev, newEvent]))
// if(removeAfterDrop){
// setDummyEvents(prev => prev.filter(item => item.title != newEvent.title))
// }
if(removeAfterDrop){
setDummyEvents(prev => prev.filter(item => item.title != newEvent.title))
}
}
}
@@ -78,20 +78,13 @@ export default function EventCalendar({removeAfterDrop, eventList, activeCategor
// setCurrentEvents(events);
}
useEffect(()=>{
// let newEventList = eventList?.map(item => ({...item, start: new Date(item?.start)}))
let newEventList = eventList?.filter(item => (Number(item.category) == Number(activeCategory)))?.map(item => ({...item, start: new Date(item?.start)}))
// console.log('newEventList', newEventList)
setCurrentEvents(newEventList)
},[activeCategory])
return (
<div className="demo-app">
<div className="demo-app-main">
<FullCalendar
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
headerToolbar={{
left: 'prev,next,today',
left: 'prev next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay',
}}
@@ -103,18 +96,17 @@ export default function EventCalendar({removeAfterDrop, eventList, activeCategor
weekends={weekendsVisible}
// initialEvents={INITIAL_EVENTS} // alternatively, use the `events` setting to fetch from a feed
events={currentEvents}
select={handleDateSelect}
eventContent={renderEventContent} // custom render function
eventsSet={handleEvents} // called after events are initialized/added/changed/removed
// select={handleDateSelect}
// eventClick={handleEventClick}
eventsSet={handleEvents} // called after events are initialized/added/changed/removed
/* you can update a remote database when these fire:
eventAdd={function(){}}
eventChange={function(){}}
eventRemove={function(){}}
*/
// eventBackgroundColor='purple'
// eventRemove={removeEvent}
eventRemove={removeEvent}
droppable= {true} // this allows things to be dropped onto the calendar
drop={onDrop}
/>
+6 -17
View File
@@ -1,16 +1,9 @@
import React, { useEffect, useRef } from "react";
import { Draggable } from "@fullcalendar/interaction";
const ExternalDraggable = ({category}) => {
const ExternalDraggable = ({dummyEvents}) => {
const eventContainerRef = useRef(null);
const events = [
{id: '1111', title: 'Family Vacation', color: 'fc-event-primary', start: new Date('2025-01-18')},
{id: '2222', title: 'Meeting In Office', color: 'fc-event-warning', start: new Date('2025-01-19')},
{id: '3333', title: 'Client Call', color: 'fc-event-danger', start: new Date('2025-01-22')},
{id: '4444', title: 'Interview', color: 'fc-event-success', start: new Date('2025-01-1')}
]
useEffect(() => {
// Make the external events draggable
const draggable = new Draggable(eventContainerRef.current, {
@@ -28,15 +21,11 @@ const ExternalDraggable = ({category}) => {
return (
<div ref={eventContainerRef} className="external-events">
{category && category.map((item, index) => {
let color = index % 4 === 0 ? 'fc-event-success' : index % 3 === 0 ? 'fc-event-danger' : index % 2 === 0 ? 'fc-event-warning' : 'fc-event-primary'
return (
<div key={item?.cid || index} className={`fc-event ${color}`} data-color={`${color}`} >
{item.description}
</div>
)
}
)}
{dummyEvents.map((item, index) => (
<div key={index} className={`fc-event ${item.color}`} data-color={`${item.color}`} >
{item.title}
</div>
))}
</div>
);
};
+13 -13
View File
@@ -2,19 +2,19 @@ let eventGuid = 0;
let todayStr = new Date().toISOString().replace(/T.*$/, ''); // YYYY-MM-DD of today
export const INITIAL_EVENTS = [
{
id: createEventId(),
title: 'All-day event',
start: new Date('2025-01-19'),
end: new Date('2025-01-20'),
// color: 'blue'
},
{
id: createEventId(),
title: 'Timed event',
start: todayStr + 'T12:00:00',
// color: 'red'
},
// {
// id: createEventId(),
// title: 'All-day event',
// start: new Date('2025-01-19'),
// end: new Date('2025-01-20'),
// // color: 'blue'
// },
// {
// id: createEventId(),
// title: 'Timed event',
// start: todayStr + 'T12:00:00',
// // color: 'red'
// },
];
export function createEventId() {
+356 -333
View File
@@ -1,349 +1,372 @@
"use client";
import React, { useEffect, useState } from "react";
import React 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()
// })
export default function Comments(){
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"]} />
{getContactData?.isPending ? (
<>
<div className="row">
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">
<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>
</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>
<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">className= <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+</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>
</span>
<span>
<span>Sent Mail</span>
</span>
</span>
</a>
</li>
<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>
</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>
</li>
{contactsCategory &&
contactsCategory.map((item) => (
<li
key={item?.cid}
className="py-2"
onClick={() =>
changeActiveCategoryUID(`${item?.cid}`)
}
style={{ cursor: "pointer" }}
>
</div>
<div className="col-md-8 col-xxl-4 border-md-t">
<div className="mail-content border-right border-n h-100">
<div className="mail-search border-bottom">
<div className="row align-items-center mx-0">
<div className="col-12">
<div className="form-group pt-3">
<input type="text" className="form-control" id="search" placeholder="Search.." />
<i className="fa fa-search"></i>
</div>
</div>
</div>
</div>
<div 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>
</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/02.jpg")} className="img-fluid" alt="user" />
</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></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>
<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>
<h4 className="mb-0">Dutca Patrick</h4>
<p>30 Min ago</p>
</div>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
<div className="mail-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>
</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="mt-4 d-flex justify-content-between">
<div>
<h3>Landing page Designer...</h3>
</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 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>
</a>
</div>
);
})
:
<p className="text-center">Messages will appear here as soon as they are available for selection</p>
}
</div>
</div>
</div>
{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>
<p className="my-4">hey adminjon...</p>
<p className="mb-2">I truly believe Augustines 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>
<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 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>
</div>
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
</>
)
}
+349 -335
View File
@@ -1,349 +1,363 @@
"use client";
import React, { useEffect, useState } from "react";
import React from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
import { useMutation, useQuery } from "@tanstack/react-query";
import { contactData } from "../../services/services";
import queryKeys from "../../services/queryKeys";
import getCustomTime from "../../utils/getCustomTime";
export default function Contacts() {
// const {data:contacts, isFetching, isError, error} = useQuery({
// queryKey: queryKeys.contacts,
// queryFn: () => contactData()
// })
export default function Contacts(){
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 contactData(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="Contacts" paths={["Dashboard", "Contacts"]} />
{getContactData?.isPending ? (
return(
<>
<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>
</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>
<BreadcrumbComBS title='Contacts' paths={['Dashboard', 'Contacts']} />
<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">className= <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+</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>
</span>
<span>
<span>Replied Mail</span>
</span>
</span>
</a>
</li>
<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>
</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>
</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 className="col-md-8 col-xxl-4 border-md-t">
<div className="mail-content border-right border-n h-100">
<div className="mail-search border-bottom">
<div className="row align-items-center mx-0">
<div className="col-12">
{/*<div className="form-group pt-3">*/}
{/* <input type="text" className="form-control" id="search" placeholder="Search.." />*/}
{/* <i className="fa fa-search"></i>*/}
{/*</div>*/}
</div>
</div>
</div>
<div 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>
</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/02.jpg")} className="img-fluid" alt="user" />
</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></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="assets/img/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="assets/img/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>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
<div className="mail-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 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 Augustines 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="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 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>
{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 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>
</div>
</div>
}
</div>
</div>
</div>
</div>
</div>
)}
</>
);
</>
)
}
+1 -1
View File
@@ -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('SOCKET RECEIVED DATA *** ', data)
console.log('DATA', data)
queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction],
// type: 'active',
-48
View File
@@ -1,48 +0,0 @@
import React from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
export default function HelpCom(){
return(
<>
<BreadcrumbComBS title='Frequesntly Asked Questions' paths={['Dashboard', 'Help']} />
{/*<div className="row">*/}
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
{/*</div>*/}
<div className="row account-contant">
<div className="col-12">
<div className="card card-statistics">
<div className="card-body p-lg-15" style={{backgroundColor:"#f9f9fb"}}>
<p className="mb-4">First, a disclaimer the entire process of writing a blog post often takes more than a couple of hours, even if you can type eighty words as per minute and your writing skills are sharp.</p>
<div className="row">
<div className="accordion" id="accordionExample">
{['a', 'b', 'c', 'd'].map((item, index)=>{
return (
<div className="accordion-item">
<h2 className="accordion-header">
<button className="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target={`#${item}`} aria-expanded="true" aria-controls="collapseOne">
{`Accordion Item ${item} 1`}
</button>
</h2>
<div id={item} className={`accordion-collapse collapse ${index == 0 && 'show'}`} data-bs-parent="#accordionExample">
<div className="accordion-body">
<strong>This is the first items accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. Its also worth noting that just about any HTML can go within the accordion-body, though the transition does limit overflow.
</div>
</div>
</div>
)
})}
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
-88
View File
@@ -1,88 +0,0 @@
import React from 'react'
import { getDashPayments } from '../../services/services'
import { useQuery } from '@tanstack/react-query'
import queryKeys from '../../services/queryKeys'
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString'
import getImage from '../../utils/getImage'
export default function DashPayments() {
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.dash_payments,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
return getDashPayments(reqData)
}
})
const payments = data?.data?.member_payments
// console.log('data', payments)
return (
<>
<div className="col-xxl-4 m-b-30" style={{minHeight: '300px'}}>
<div className="card card-statistics h-100 mb-0 panel_round_c3">
<div className="card-header d-flex justify-content-between">
<div className="card-heading">
<h4 className="card-title">Payments</h4>
</div>
</div>
<div className="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
<div className="datatable-wrapper table-responsive">
{isFetching ?
<>
<div className="col-12">
<div className="p-4">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="col-12">
<div className="p-4">
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<table id="datatable" className="table table-borderless table-striped">
<thead>
<tr>
{/* <th style={{width: '30px'}}>#</th> */}
<th>Date</th>
<th style={{width: '130px'}}>Description</th>
<th style={{width: '80px'}}>Amount</th>
</tr>
</thead>
<tbody>
{payments && payments?.length > 0 ?
payments.map((item, index) => {
return (
<tr key={index}>
{/* <td>{Number(item?.id).toString().padStart(6,'0')}</td> */}
<td>
{getDateTimeFromDateString(item?.added)}
</td>
<td>{item?.option_name}</td>
<td className='text-right'>${item?.amount}</td>
</tr>
)
})
:
<td colSpan={3} className='text-center'>No record found</td>
}
</tbody>
</table>
}
</div>
</div>
</div>
</div>
</>
)
}
+35 -2
View File
@@ -5,7 +5,6 @@ import Products from "./Products";
import TopBar from "./TopBar";
import ProductsURL from "./ProductsURL";
import { SocketContextValues } from "../context/SocketIOContext";
import DashPayments from "./DashPayments";
export default function HomeSections(){
@@ -53,7 +52,41 @@ export default function HomeSections(){
<div className="row">
<ProductsURL />
<DashPayments />
<div className="col-xxl-4 m-b-30" style={{minHeight: '300px'}}>
<div className="card card-statistics h-100 mb-0 panel_round_c3">
<div className="card-header d-flex justify-content-between">
<div className="card-heading">
<h4 className="card-title">Payments</h4>
</div>
{/*<div className="dropdown">*/}
{/* <a className="p-2" href="#!" data-toggle="dropdown" aria-haspopup="true"*/}
{/* aria-expanded="false">*/}
{/* <i className="fe fe-circle"></i>*/}
{/* </a>*/}
{/* <div className="dropdown-menu custom-dropdown dropdown-menu-right p-4">*/}
{/* <h6 className="mb-1">Action</h6>*/}
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-o pr-2"></i>View*/}
{/* reports</a>*/}
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-edit pr-2"></i>Edit reports</a>*/}
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-bar-chart-o pr-2"></i>Statistics</a>*/}
{/* <h6 className="mb-1 mt-3">Export</h6>*/}
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-pdf-o pr-2"></i>Export*/}
{/* to PDF</a>*/}
{/* <a className="dropdown-item" href="#!"><i className="fa-fw fa fa-file-excel-o pr-2"></i>Export*/}
{/* to CSV</a>*/}
{/* </div>*/}
{/*</div>*/}
</div>
<div className="card-body">
{/*<h5>We only started collecting data from February 2019 </h5>*/}
{/*<p>Questions about the Net Earnings number? <a*/}
{/* className="btn btn-square btn-inverse-success btn-xs ml-1" href="#">Click here</a></p>*/}
<div className="row mt-4">
.
</div>
</div>
</div>
</div>
</div>
</>;
+25 -18
View File
@@ -1,22 +1,29 @@
import { useQuery } from '@tanstack/react-query'
import { productsData } from '../../services/services'
import React from 'react'
import { productData } from '../../services/services'
import queryKeys from '../../services/queryKeys'
import productPath from "../../utils/productpath";
import { Link } from 'react-router-dom';
import queryKeys from '../../services/queryKeys'
export default function Products() {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.products,
queryFn: () => productsData(reqData)
queryKey: queryKeys.product,
queryFn: () => productData()
})
const products = data?.data?.products_data // PRODUCTS DATA
/*
{
"banner": "p1.jpg",
"description": "Your personal professional web presence",
"id": 1,
"name": "Personal Website",
"product_id": "A000001",
"product_uid": "e92282b4-3ee1-4026-92ac-12cfd214b43a",
"status": 5,
"status_text": "Activate Now"
},
*/
//const products = data?.data?.products_list?.products
const products = data?.data?.products_list
return (
<>
@@ -36,21 +43,21 @@ export default function Products() {
: isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{error?.message}</p>
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<div className="row m-b-20">
{products && products.map((product, index) => (
<div key={product.uid+index} className={`col-xxs-6 col-xl-4 col-xxl-6 mb-2 mb-xxl-0`}>
<div key={product.uid+index} className="col-xxs-6 col-xl-4 col-xxl-6 mb-2 mb-xxl-0 ">
<Link to={productPath(product?.product_id)} >
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
<div className="d-flex align-items-center extraProductCard">
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className={`fa ${product?.product_icon} text-primary`}></i>
<i className="fa fa-cart-plus text-primary"></i>
</div>
<div className="report-details">
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
<h4><span className='text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
<p>{product?.status_text}</p>
<h4>{product?.name}</h4>
</div>
</div>
</Link>
+19 -25
View File
@@ -2,22 +2,15 @@ import React from 'react'
import { productsURL } from '../../services/services'
import { useQuery } from '@tanstack/react-query'
import queryKeys from '../../services/queryKeys'
import getImage from '../../utils/getImage'
export default function ProductsURL() {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
const {data, isFetching, isError, error} = useQuery({
const {data:data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product_url,
queryFn: () => productsURL(reqData)
queryFn: () => productsURL()
})
const urlData = data?.data?.products_data
// console.log('data', urlData)
const urlData = data?.data?.url_data?.url
return (
<>
@@ -31,7 +24,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="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
<div className="datatable-wrapper table-responsive">
{isFetching ?
<>
@@ -60,28 +53,29 @@ export default function ProductsURL() {
</thead>
<tbody>
{urlData && urlData.map((item, index) => {
let statusColor = item?.status === '1' ? 'badge-success-inverse' : item?.status === '6' ? 'badge-success-inverse' : item?.status == '7' ? 'badge-danger-inverse' : 'badge-info-inverse'
let statusText = item?.status === '1' ? 'Preparing' : item?.status === '6' ? 'Provisioning' : item?.status == '7' ? 'Ready' : 'Started'
let statusColor = item?.status === 'Preparing' ? 'badge-success-inverse' : item?.status === 'Active' ? 'badge-success-inverse' : item?.status == 'Refreshing' ? 'badge-danger-inverse' : 'badge-info-inverse'
let productUrl = '/product/'+ item?.product_id
let externalUrl= item?.url_protocol +"://"+ item?.internal_url;
return (
<tr key={index}>
<td>{Number(item?.id).toString().padStart(6,'0')}</td>
<td>
<a className="mr-3" href={externalUrl} target='_blank'><b>{externalUrl}</b></a> - {item?.description}
</td>
<td>{Number(item?.no) + Number(index)}</td>
<td>{item?.description} - <a href={productUrl} target='_blank'>{item?.url}</a></td>
<td><span className={`badge ${statusColor}`}>{statusText}</span></td>
{/* <td><a className="mr-3" href={productUrl}><i className="fe fe-edit"></i></a></td> */}
<td>
<a className="mr-3" href={productUrl}>
<img src={getImage('arrow-next.png')} alt='next' />
</a>
</td>
<td><span className={`badge ${statusColor}`}>{item?.status}</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a></td>
</tr>
)
})}
</tbody>
<tfoot>
<tr>
<th>#</th>
<th>Name</th>
<th>Price</th>
<th>In stock</th>
<th>Status</th>
<th>Action</th>
</tr>
</tfoot>
</table>
}
</div>
+12 -12
View File
@@ -10,7 +10,7 @@ export default function RecentActions() {
queryFn: () => recentActions()
})
const actionData = dataAction?.data?.recent_actions
const actionData = dataAction?.data?.action_data
return (
<>
@@ -43,7 +43,7 @@ export default function RecentActions() {
<div className="d-xxs-flex align-items-center">
<div className="total-sales">
<p>Last Update</p>
<h3>{dataAction?.data?.last_update}</h3>
<h3>{dataAction?.data?.action_data?.last_update}</h3>
</div>
<div className="mb-3 mb-sm-0 ml-auto">
{/*<button className="btn btn-primary btn-xs">View All Invoices</button>*/}
@@ -62,22 +62,22 @@ export default function RecentActions() {
<div className="row no-gutters">
<div className="col-6 col-xxs-3 ">
<p>Initial</p>
<h4>{dataAction?.data?.initial}</h4>
<h4>{actionData?.initial}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Processing</p>
<h4>{dataAction?.data?.processing}</h4>
<h4>{actionData?.processing}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Verifying</p>
<h4>{dataAction?.data?.verifying}</h4>
<h4>{actionData?.verifying}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Completed</p>
<h4>{dataAction?.data?.completed}</h4>
<h4>{actionData?.completed}</h4>
</div>
</div>
<div className="overflow-y-auto table-responsive m-t-20">
<div className="table-responsive m-t-20">
<table id="datatable-buttons" className="table">
<thead>
<tr>
@@ -89,16 +89,16 @@ export default function RecentActions() {
</tr>
</thead>
<tbody className="text-muted">
{actionData && actionData?.map((action, index) => {
{actionData && actionData?.actions.map((action, index) => {
let bgColor = action?.status == '5' ? 'badge-success-inverse' : action?.status == '3' ? 'badge-info-inverse' : action?.status == '0' ? 'badge-warning-inverse' : 'badge-primary-inverse'
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
return (
<tr key={index}>
<td>{(action?.id).toString().slice(-4)}</td>
<td>{action?.action_label}</td>
<td>{new Date(action?.added).toDateString()}</td>
<td>{action?.no}</td>
<td>{action?.description}</td>
<td>{new Date(action?.date).toDateString()}</td>
<td>
<label className={`badge mb-0 ${bgColor}`}>{action?.status_description}</label>
<label className={`badge mb-0 ${bgColor}`}>{text}</label>
</td>
</tr>
)
+26 -57
View File
@@ -1,41 +1,16 @@
import { useQuery } from '@tanstack/react-query'
import React from 'react'
import { topBar } from '../../services/services'
import queryKeys from '../../services/queryKeys'
import { Link } from 'react-router-dom'
export default function TopBar() {
// const topBarData = useMutation({
// mutationFn: (reqData) => {
// return topBar(reqData)
// },
// onError: (error) => {
// console.log(error)
// },
// onSuccess: (res) => {
// if(res?.data?.resultCode != '0'){
// throw({message: 'Something went wrong'})
// }
// }
// })
// useEffect(()=>{
// let reqData = {
// token: localStorage.getItem('token'), // USER TOKEN
// uid: localStorage.getItem('uid') // USER UID
// }
// topBarData.mutate(reqData)
// },[])
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
const {data:topBarData, isFetching, isError, error} = useQuery({
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.topBar,
queryFn: () => topBar(reqData)
queryFn: () => topBar()
})
const data = topBarData?.data?.top_bar // top bar data
const topData = data?.data?.bar_data?.top_bar
return (
<>
@@ -47,7 +22,7 @@ export default function TopBar() {
</div>
</div>
</>
: isError?
: isError ?
<div className="col-12">
<div className="card p-4">
<p className='text-danger'>{error.message}</p>
@@ -55,39 +30,33 @@ export default function TopBar() {
</div>
:
<>
{data && data?.map((item, index)=>{
{topData && topData?.map((item, index)=>{
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
let dataSpan = ''
if(item?.extra_style){
const data = item.data_span.split(' ')
dataSpan = `${data[0]} ${data[1]}`
}
return (
<div key={item.id + index} className="col-sm-6 col-xxl-3">
<Link to={item?.link}>
<div className={`card card-statistics ecommerce-contant overflow-h ${item?.extra_style} `} style={{borderRadius: '10px'}}>
<div className="card-body p-0">
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
<div className="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">{item?.value || 0}</h3>
<small className="d-block">{item?.extra_style ? dataSpan : item?.data_span}</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">{item?.description}</h5>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo3" className="chart-fit"></div>
</div>
<div key={item.id + index} className="col-sm-6 col-xxl-3">
<div className="card card-statistics ecommerce-contant overflow-h">
<div className="card-body p-0">
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
<div className="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">{item?.value || 0}</h3>
<small className="d-block">{item?.data_span}</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">{item?.description}</h5>
<strong className={`${textColor} m-t-5`}><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> N/A</strong>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo3" className="chart-fit"></div>
</div>
</div>
</div>
</Link>
</div>
</div>
</div>
)
})}
</>
-67
View File
@@ -1,67 +0,0 @@
import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { topBar } from '../../services/services'
import queryKeys from '../../services/queryKeys'
export default function TopBar() {
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.topBar,
queryFn: () => topBar()
})
const topData = data?.data?.bar_data?.top_bar
console.log('topData', topData)
return (
<>
{isFetching ?
<>
<div className="col-12">
<div className="card p-4">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="col-12">
<div className="card p-4">
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<>
{topData && topData?.map((item, index)=>{
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
return (
<div key={item.id + index} className="col-sm-6 col-xxl-3">
<div className="card card-statistics ecommerce-contant overflow-h">
<div className="card-body p-0">
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
<div className="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">{item?.value || 0}</h3>
<small className="d-block">{item?.data_span}</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">{item?.description}</h5>
<strong className={`${textColor} m-t-5`}><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> N/A</strong>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo3" className="chart-fit"></div>
</div>
</div>
</div>
</div>
</div>
</div>
)
})}
</>
}
</>
)
}
+1 -7
View File
@@ -1,22 +1,16 @@
import React from 'react'
import { Outlet, useLocation } from 'react-router-dom';
import UserMenu from "./layoutcom/UserMenu";
import UserHeader from "./layoutcom/UserHeader";
import UserFooter from "./layoutcom/UserFooter";
import siteLinks from '../../links/siteLinks';
import { Outlet } from 'react-router-dom';
export default function Layout() {
const {pathname} = useLocation()
// const isProfileComplete = pathname == siteLinks.profile_complete
return (
<div className="app">
<div className="app-wrap">
<UserHeader />
<div className="app-container">
<aside className="app-navbar">
<UserMenu />
</aside>
@@ -2,16 +2,14 @@ import React from "react";
export default function UserFooter(){
const year = new Date().getFullYear()
return <>
<footer className={`footer`}>
<footer className="footer">
<div className="row">
<div className="col-12 col-sm-6 text-center text-sm-left">
<p>&copy; Copyright {year}. All rights reserved.</p>
<p>&copy; Copyright 2024. All rights reserved.</p>
</div>
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
<p>A division of autoMedSys A.I.</p>
<p>A division of <i className="fa fa-key text-danger mx-1"></i> autoMedSys A.I.</p>
</div>
</div>
</footer>
+33 -49
View File
@@ -1,15 +1,13 @@
import React, { useRef } from "react";
import React from "react";
import getImage from "../../../utils/getImage";
import { Link, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { useSelector } from "react-redux";
import siteLinks from "../../../links/siteLinks";
export default function UserHeader(){
const { userDetails } = useSelector((state) => state?.userDetails); // USER Details
const nav_menu = useRef(null)
const { userDetails } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
const toggleSidebar = (e) => {
e.preventDefault()
@@ -34,19 +32,14 @@ export default function UserHeader(){
window.location.reload()
}
const toggleMenu = (e) => {
// e.preventDefault()
nav_menu.current.classList.toggle('show')
}
return (
<header className="app-header top-bar">
<nav className="navbar navbar-expand-md">
<div className="navbar-header d-flex align-items-center">
<a href="#" onClick={toggleSidebar} className="mobile-toggle"><i className="ti ti-align-right"></i></a>
<a className="navbar-brand" href="/dash">
<img src={getImage('logo-pink.png')} className="img-fluid logo-desktop" alt="logo"/>
<img src={getImage('logo-pink.png')} className="img-fluid logo-mobile" alt="logo"/>
<img src={getImage('logo-light.png')} className="img-fluid logo-desktop" alt="logo"/>
<img src={getImage('logo-icon.png')} className="img-fluid logo-mobile" alt="logo"/>
</a>
</div>
<button onClick={removeSidebar} className="navbar-toggler" type="button" data-bs-toggle="collapse"
@@ -73,21 +66,16 @@ 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={userDetails?.picture ? userDetails?.picture : getImage('profile-pic-circle.png')}
// src={getImage('profile-pic-circle.png')}
alt="avtar-img"
/>
<a href="#" className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown">
<img src={getImage('avtar/02.jpg')} 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="dropdown-menu animated fadeIn">
<div className="bg-gradient px-4 py-3">
<div className="d-flex align-items-center justify-content-between">
<div className="mr-1">
{/* <h4 className="text-white mb-0 font-600">{userDetails?.username}</h4> */}
<p className="text-white font-600">{userDetails.username}</p>
<h5 className="text-white mb-0">{userDetails?.firstname} {userDetails?.lastname}</h5>
<small className="text-white">{userDetails.email}</small>
</div>
<a href="#" onClick={logout} className="text-white font-20 tooltip-wrapper" data-toggle="tooltip"
data-placement="top" title="" data-original-title="Logout"> <i
@@ -95,35 +83,31 @@ export default function UserHeader(){
</div>
</div>
<div className="p-4">
<Link className="dropdown-item d-flex nav-link" to={siteLinks.subscription}>
<i className="fa fa-user pr-2 text-success"></i> Subscription</Link>
<Link className="dropdown-item d-flex nav-link" to={siteLinks.contacts}>
<i className="fa fa-envelope pr-2 text-primary"></i> Contacts
<a className="dropdown-item d-flex nav-link" href="#">
<i className="fa fa-user pr-2 text-success"></i> Profile</a>
<a className="dropdown-item d-flex nav-link" href="#">
<i className="fa fa-envelope pr-2 text-primary"></i> Inbox
<span className="badge badge-primary ml-auto">6</span>
</Link>
<Link className="dropdown-item d-flex nav-link" to={siteLinks.settings}>
</a>
<a className="dropdown-item d-flex nav-link" href="#">
<i className=" ti ti-settings pr-2 text-info"></i> Settings
</Link>
<Link className="dropdown-item d-flex nav-link" to={siteLinks.help}>
<i className="fa fa-compass pr-2 text-warning"></i>
Need help?
</Link>
{/*<div className="row mt-2">*/}
{/* <div className="col">*/}
{/* <a className="bg-light p-3 text-center d-block" href="#">*/}
{/* <i className="fe fe-mail font-20 text-primary"></i>*/}
{/* <span className="d-block font-13 mt-2">My messages</span>*/}
{/* </a>*/}
{/* </div>*/}
{/* <div className="col">*/}
{/* <a className="bg-light p-3 text-center d-block" href="#">*/}
{/* <i className="fe fe-plus font-20 text-primary"></i>*/}
{/* <span className="d-block font-13 mt-2">Compose new</span>*/}
{/* </a>*/}
{/* </div>*/}
{/*</div>*/}
</a>
<a className="dropdown-item d-flex nav-link" href="#">
<i className="fa fa-compass pr-2 text-warning"></i> Need help?</a>
<div className="row mt-2">
<div className="col">
<a className="bg-light p-3 text-center d-block" href="#">
<i className="fe fe-mail font-20 text-primary"></i>
<span className="d-block font-13 mt-2">My messages</span>
</a>
</div>
<div className="col">
<a className="bg-light p-3 text-center d-block" href="#">
<i className="fe fe-plus font-20 text-primary"></i>
<span className="d-block font-13 mt-2">Compose new</span>
</a>
</div>
</div>
</div>
</div>
</li>
+5 -6
View File
@@ -16,11 +16,11 @@ export default function UserMenu() {
return (
<>
<div className="sidebar-nav scrollbar scroll_dark">
<ul className="metismenu h-100" id="sidebarNav">
<ul className="metismenu " id="sidebarNav">
<li className="nav-static-title">Panel</li>
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}>
<Link className="has-arrow" to='#' data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<i className="nav-icon ti ti-home"></i>
<i className="nav-icon ti ti-rocket"></i>
<div className='d-flex gap-2 justify-content-between align-items-center'>
<span className="nav-title">Dashboard</span>
<IoIosArrowDown />
@@ -30,7 +30,7 @@ export default function UserMenu() {
<ul id="collapseOne" className="collapse show" aria-labelledby="headingOne" data-bs-parent="#sidebarNav">
<li className={`${pathname == siteLinks.dash ? 'active' : ''}`}><Link to={siteLinks.dash}>Home</Link></li>
<li className={`${pathname == siteLinks.calendar ? 'active' : ''}`}><Link to={siteLinks.calendar}>Calendar</Link></li>
<li className={`${pathname == siteLinks.contacts ? 'active' : ''}`}><Link to={siteLinks.contacts}>Sites Contacts</Link></li>
<li className={`${pathname == siteLinks.contacts ? 'active' : ''}`}><Link to={siteLinks.contacts}>Contacts</Link></li>
<li className={`${pathname == siteLinks.comments ? 'active' : ''}`}><Link to={siteLinks.comments}>Comments</Link></li>
</ul>
</li>
@@ -48,14 +48,13 @@ 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.user ? 'active' : ''}`}><Link to={siteLinks.user}>Users</Link></li>
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
</ul>
</li>
<li className="sidebar-banner p-4 bg-gradient text-center m-3 mt-auto d-block rounded">
<li className="sidebar-banner p-4 bg-gradient text-center m-3 d-block rounded">
<h5 className="text-white mb-1">MERMS Panel</h5>
<Link className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0" to='' onClick={logout}> Log Out</Link>
</li>
-242
View File
@@ -1,242 +0,0 @@
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>
</>
)
}
-71
View File
@@ -1,71 +0,0 @@
import React from 'react'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Onboard() {
const pricingFields ={
starter: { name: 'Starter', price: 5.99, active: true },
basic: { name: 'Basic', price: 12.99, active: true },
premium: { name: 'Premium', price: 20.00, active: true },
}
return (
<>
<BreadcrumbComBS title='Subscription' paths={['Dashboard', 'Subscription']} />
<div className="row">
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Current Subscription(s)</h5>
<h2 className="text-primary pt-3">Basic</h2>
{/*<p className="text-primary pb-3">/ Monthly</p>*/}
{/*<ul className="py-2">*/}
{/* <li>post jobs</li>*/}
{/* <li>advanced instructors search</li>*/}
{/* <li>invite candidates</li>*/}
{/* <li>post events</li>*/}
{/* <li>cancel any time</li>*/}
{/*</ul>*/}
</div>
</div>
</div>
</div>
<>
{Object.entries(pricingFields)?.map(([key, value]) => (
<div key={key} className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>{value.name}</h5>
<h2 className="text-primary pt-3">${value.price}</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go {value.name}</a></div>
</div>
</div>
</div>
</div>
))}
</>
</div>
</>
)
}
+115 -75
View File
@@ -1,100 +1,140 @@
import React, {useEffect, useMemo, useRef, useState} from "react";
import { useSelector } from "react-redux";
import React from "react";
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";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
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 += ''
}
})
const handleRefresh = () => {
const reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData.product_id,
subscription_uid: productData.subscription_uid
}
refresh.mutate(reqData)
}
let externalUrl= 'https://'+productData?.internal_url
const productSubUID = productData.subscription_uid;
useEffect(() => {
const provision_room = "PROVISION_"+productSubUID;
console.log("JOINING ROOM ON ACTIVE *** ", provision_room);
joinRoom(provision_room); // provision subscription room
}, [])
export default function ProductActive(){
return(
<>
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />
{/*<div className="row">*/}
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
{/*</div>*/}
<div className="row account-contant">
<>
<div className="row tabs-contant">
<div className="col-xxl-6">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading d-flex justify-content-between">
{/*<h4 className="card-title">{externalUrl}</h4>*/}
<h4 style={{color: '#148399', fontWeight: 'bolder'}}>
<a href={externalUrl} target='_blank'>{externalUrl}</a></h4>
<button type="button" onClick={()=>iframe.current.src += ''} className="btn">
<img src={getImage('refresh.png')} style={{width: '30px', height: 'auto'}} alt='refresh page' />
</button>
<div className="col-12">
<div className="card card-statistics">
<div className="card-body p-0">
<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={getImage('widget/01.jpg')} className="img-fluid"
alt="users-avatar" />
</div>
<div className="profile pt-4">
<h4 className="mb-1">Product Short Name</h4>
<p>last Update : 00:00:0000</p>
</div>
</div>
</div>
</div>
</div>
<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">
<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 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 Product Settings</h5>
</div>
<div className="p-4">
<form>
<div className="form-row">
<div className="form-group col-md-12">
<label htmlFor="name1">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div className="col-xxl-6">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title"> Site Settings </h4>
<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>
<button type="submit" className="btn btn-primary">Save & Update</button>
</form>
</div>
</div>
</div>
<div className="card-body" style={{minHeight: '680px'}}>
<Settings productData={productData} />
</div>
</div>
</div>
</div>
</>
</div>
</div>
</>
)
}
+33 -30
View File
@@ -1,36 +1,39 @@
import React, {useState} from "react";
import { useQuery } from '@tanstack/react-query'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
// import getImage from "../../utils/getImage";
import ProductStart from "./ProductStart";
import { useLocation, useNavigate } from 'react-router-dom';
import {MyProductData} from "../../services/services";
import { useLocation } from 'react-router-dom';
import {MyProductData, productData} from "../../services/services";
import queryKeys from "../../services/queryKeys";
import ProductActive from "./ProductActive";
import ProductProvision from "./ProductProvision";
import {productConst} from "../../constants/products";
import queryKeys from "../../services/queryKeys";
import siteLinks from '../../links/siteLinks';
export default function ProductFactory(){
const navigate = useNavigate()
const location = useLocation();
const pathname = location.pathname;
const [productStatus, setProductStatus] = useState(0);
//productConst.PRODUCT_ACTIVE
// Split the pathname by '/' and get the last element
const productID = pathname.split('/').pop();
const lastPart = pathname.split('/').pop();
// console.log(lastPart)
let reqData = {
product_id : productID,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product_page,
queryFn: () => MyProductData(reqData),
staleTime: 0
queryKey: queryKeys.product,
queryFn: () => MyProductData(lastPart)
})
const myproduct_data = data?.data?.myproduct?.myproudct // PRODUCT DETAILS
const myproduct_data = data?.data?.myproduct_data
//setProductStatus(myproduct_data?.status)
const product_name = myproduct_data?.product_name;
const product_status = myproduct_data?.status;
return(
@@ -47,25 +50,25 @@ export default function ProductFactory(){
</>
: isError ?
<div className="row">
<div className="text-center col-12" style={{minHeight: '500px', placeContent: 'center'}}>
<p className='text-danger'>{error?.message}</p>
<button onClick={() => navigate(siteLinks.home)} className='mt-3 btn btn-primary'>Return Home</button>
<div className="col-12">
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<div>
{(product_status <= productConst.PRODUCT_AVAILABLE)?
<ProductStart productData={myproduct_data} />
:<></> }
:
<div>
{(product_status <= productConst.PRODUCT_AVAILABLE)?
<ProductStart productData={myproduct_data} />
:<></> }
{(product_status === productConst.PRODUCT_PROVISIONING)?
<ProductProvision productData={myproduct_data} />
:<></> }
{(product_status === productConst.PRODUCT_PROVISIONING)?
<ProductProvision productData={myproduct_data} />
:<></> }
{(product_status === productConst.PRODUCT_ACTIVE)?
<ProductActive productData={myproduct_data} />
:<></> }
</div>
{(product_status === productConst.PRODUCT_ACTIVE)?
<ProductActive productData={myproduct_data} />
:<></> }
</div>
}
</div>
</>
+70 -81
View File
@@ -1,41 +1,33 @@
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_subscription_uid: productSubUID
}
const {data: provision, isFetching, isError, error} = useQuery({
const {data:provision, isFetching, isError, error} = useQuery({
queryKey: queryKeys.myproduct_provision,
queryFn: () => productProvision(reqData)
queryFn: () => productProvision(productID)
})
const provisionData = provision?.data
const provisionData = provision?.data?.provision
useEffect(() => {
const provision_room = "PROVISION_" + productSubUID;
console.log("JOINING ROOM ON START *** ", provision_room);
joinRoom(provision_room); // provision subscription room
}, [])
useEffect(()=>{
joinRoom(productSubUID); // provision subscription room
},[])
return (
<>
{isFetching ?
{isFetching ?
<>
<div className="row">
<div className="col-12">
@@ -44,87 +36,84 @@ export default function ProductProvision(props) {
</div>
</>
: isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{error.message}</p>
</div>
<div className="row">
<div className="col-12">
<p className='text-danger'>{error.message}</p>
</div>
:
<>
<div className="row">
<div className="col-md-12">
<div className="card card-statistics">
<div className="card-header">
</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 className="row">
<div className="col-md-12">
</div>
<div className="row">
<div className="col-md-12">
</div>
</div>
<div className="row">
<div className="col-lg-6">
</div>
<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>
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">Progress Information</h4>
</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>
</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>
</tr>
</thead>
<tbody>
{provisionData?.activities?.map(item => (
<tr key={item.id}>
<th scope="row">{item.id}</th>
<td>{item.action}</td>
</tr>
))}
</tbody>
</table>
</div>
</tbody>
</table>
</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="" dangerouslySetInnerHTML={{__html: productDescription}}/>
</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">
<p>
{productDescription}
</p>
</div>
</div>
</div>
</div>
</>
}
</>
)
+38 -50
View File
@@ -1,7 +1,6 @@
import React, { useRef, useState } from "react";
import {useNavigate} from 'react-router-dom'
import getImage from "../../utils/getImage";
import { Modal } from "bootstrap";
// import { Modal } from "bootstrap";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { subscribe } from '../../services/services'
import queryKeys from "../../services/queryKeys";
@@ -9,28 +8,24 @@ import queryKeys from "../../services/queryKeys";
export default function ProductStart(props){
const queryClient = useQueryClient()
const navigate = useNavigate()
const [requestStatus, setRequestStatus] = useState({status:false, message: ''})
const product_uid = props?.productData?.product_uid;
const product_id = props?.productData?.product_id;
const productBanner = `product/${props.productData?.banner}`;
const productTitle = props?.productData?.title;
const productDescription = props?.productData?.description;
const promotion_text = props?.productData?.promotion_text;
const product_status = props?.productData?.status;
const saleText = props?.productData?.sale_text;
const productBanner = "product/"+props.productData?.banner;
const productTitle = props.productData?.title;
const productDescription = props.productData?.description;
const promotion_text = props.productData?.promotion_text;
const product_status = props.productData?.status;
const modalRef = useRef()
const modalRef = useRef(null)
const invalidate = () => {
// queryClient.refetchQueries({
// queryKey: [...queryKeys.product],
// // type: 'active',
// // exact: true,
// })
queryClient.invalidateQueries({ queryKey: [...queryKeys.product_url] })
queryClient.invalidateQueries({ queryKey: [...queryKeys.product_page] })
const refetch = () => {
queryClient.refetchQueries({
queryKey: [...queryKeys.product],
// type: 'active',
// exact: true,
})
}
const mutation = useMutation({
@@ -43,12 +38,9 @@ export default function ProductStart(props){
},
onSuccess: (res) => {
setRequestStatus({status:true, message:'successful'})
navigate(`/product/${product_id}`, {replace: true}) //'/product/'+ product_id
dismissModal()
console.log(res)
},
onSettled: () => {
invalidate() // Invalidates selected queries
setTimeout(()=>{
setRequestStatus({status:false, message:''})
},4000)
@@ -59,22 +51,6 @@ export default function ProductStart(props){
mutation.mutate({product_id: product_id})
}
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();
};
return (
<>
<div className="row">
@@ -83,8 +59,7 @@ export default function ProductStart(props){
<img className="card-img-top" src={getImage(productBanner)} alt="Card image cap" />
<div className="card-body">
<h4 className="card-title">{productTitle}</h4>
<div className="card-text" style={{fontSize: '14px'}} dangerouslySetInnerHTML={{__html: productDescription}}/>
{/* <p className="card-text">{productDescription}</p> */}
<p className="card-text">{productDescription}</p>
</div>
</div>
</div>
@@ -97,7 +72,7 @@ export default function ProductStart(props){
</>
<div className="card-body">
<p className="card-text">We are actively working to launch this feature soon and will keep you informed every step of the way. </p>
<p className="card-text">Start with your goals in mind and then work possible. </p>
</div>
<ul className="list-group list-group-flush">
<li className="list-group-item"><h4>Coming soon!!!</h4></li>
@@ -109,15 +84,19 @@ export default function ProductStart(props){
{/*<img className="card-img-top" src={getImage('widget/01.jpg')} alt="Card image cap" />*/}
<div className="card-body">
<h4 className="card-title">Subscription</h4>
<p className="card-text">Launch your <span style={{color: '#148399' , fontWeight: 'bolder'}}>{productTitle}</span> with us for free! Benefit from our dedicated support and customize features that align perfectly with your goals. Experience everything at no cost! </p>
<p className="card-text">Start with your goals in mind and then work possible.ith yand Goals. If the plan doesnt support the vision then change it! </p>
</div>
<ul className="list-group list-group-flush">
<li className="list-group-item"><h4>{promotion_text}</h4></li>
<li className="list-group-item">90 days free and $5.99/Month</li>
<li className="list-group-item">90 days free and 3.95/Month</li>
<li className="list-group-item"></li>
</ul>
{/*<div className="card-body">*/}
{/* <a href="javascript:void(0)" className="card-link">Card link</a>*/}
{/* <a href="javascript:void(0)" className="card-link">Another link</a>*/}
{/*</div>*/}
<div className="subscribe-box">
<button className="btn btn-primary mt-2" data-bs-toggle="modal" data-bs-target="#verticalCenter">Activate Now!</button>
<button className="btn btn-primary mt-2" data-bs-toggle="modal" data-bs-target="#verticalCenter">Start Subscription</button>
</div>
</div>
</>
@@ -126,17 +105,26 @@ export default function ProductStart(props){
</div>
{/* Vertical Center Modal */}
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
<div ref={modalRef} className="modal fade" id="verticalCenter" 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">
<h5 className="modal-title" id="verticalCenterTitle">{productTitle}</h5>
<button onClick={refetch} type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div className="modal-body">
<div style={{fontSize: '18px'}} className="" dangerouslySetInnerHTML={{__html: saleText}}/>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis
in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at
eros. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus
</p>
<p>
sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean lacinia
bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque
nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor
fringilla. Cras mattis consectetur purus sit amet fermentum. Cras justo odio,
</p>
{/* {mutation.error &&
<>
<div className="col-12">
@@ -158,8 +146,8 @@ export default function ProductStart(props){
)}
</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={mutation.isSuccess} onClick={handleSubscribe}>{mutation.isPending ? 'activating...' : 'Start Activation'}</button>
<button onClick={refetch} type="button" className="btn btn-danger" data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-success" disabled={mutation.isSuccess} onClick={handleSubscribe}>{mutation.isPending ? 'loading...' : 'Start'}</button>
</div>
</div>
</div>
-278
View File
@@ -1,278 +0,0 @@
import React from "react";
import getImage from "../../utils/getImage";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
export default function ProductActive(){
return(
<>
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
{/*<div className="row">*/}
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
{/*</div>*/}
<div className="row account-contant">
<>
<div className="row tabs-contant">
<div className="col-xxl-6">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">https://25681.devprov.mermsemr.com/</h4>
</div>
</div>
<div className="card-body">
<iframe style={{borderWidth: '0px;'}} src="https://25681.devprov.mermsemr.com/" width="100%" height="600" title="https://25681.devprov.mermsemr.com"></iframe>
</div>
</div>
</div>
<div className="col-xxl-6">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title"> Site Settings </h4>
</div>
</div>
<div className="card-body">
<div className="tab tab-vertical">
<ul className="nav nav-tabs" role="tablist">
<li className="nav-item">
<a className="nav-link active show" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true">General</a>
</li>
<li className="nav-item">
<a className="nav-link" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true">Home Page</a>
</li>
<li className="nav-item">
<a className="nav-link" id="profile-09-tab" data-toggle="tab" href="#profile-09" role="tab" aria-controls="profile-09" aria-selected="false"> Footer </a>
</li>
<li className="nav-item">
<a className="nav-link" id="portfolio-09-tab" data-toggle="tab" href="#portfolio-09" role="tab" aria-controls="portfolio-09" aria-selected="false">About Page </a>
</li>
<li className="nav-item">
<a className="nav-link" id="contact-09-tab" data-toggle="tab" href="#contact-09" role="tab" aria-controls="contact-09" aria-selected="false"> Contact Page</a>
</li>
<li className="nav-item">
<a className="nav-link" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true">Socials</a>
</li>
<li className="nav-item">
<a className="nav-link" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true">Template</a>
</li>
<li className="nav-item">
<a className="nav-link" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true"> Color Scheme</a>
</li>
</ul>
<div className="tab-content">
<div className="tab-pane fade active show" id="home-09" role="tabpanel" aria-labelledby="home-09-tab">
<div className="page-account-form">
<div className="p-4">
<form>
<div className="form-row">
<div className="form-group col-md-12">
<label htmlFor="name1">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</form>
</div>
</div>
</div>
<div className="tab-pane fade" id="profile-09" role="tabpanel" aria-labelledby="profile-09-tab">
<div className="page-account-form">
<div className="p-4">
<form>
<div className="form-row">
<div className="form-group col-md-12">
<label htmlFor="name1">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</form>
</div>
</div>
</div>
<div className="tab-pane fade" id="portfolio-09" role="tabpanel" aria-labelledby="portfolio-09-tab">
<p>
<div className="page-account-form">
<div className="form-titel border-bottom p-3">
<h5 className="mb-0 py-2">Edit Your Product Settings</h5>
</div>
<div className="p-4">
<form>
<div className="form-row">
<div className="form-group col-md-12">
<label htmlFor="name1">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</form>
</div>
</div>
</p> </div>
<div className="tab-pane fade" id="contact-09" role="tabpanel" aria-labelledby="contact-09-tab">
<p>
<div className="page-account-form">
<div className="form-titel border-bottom p-3">
<h5 className="mb-0 py-2">Edit Your Product Settings</h5>
</div>
<div className="p-4">
<form>
<div className="form-row">
<div className="form-group col-md-12">
<label htmlFor="name1">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</form>
</div>
</div>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
</div>
</>
)
}
@@ -1,179 +0,0 @@
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'}}>&ldquo;{custom_template_name}&rdquo;</span> .</h4>
</div>
</div>
</>
}
return (
<div className="page-account-form">
<div className="p-0">
{isFetching ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{error?.message}</p>
</div>
</div>
:
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
<>
{!color_styles?.length ?
<p>No data Found</p>
:
color_styles.map(color_style => (
<div key={color_style.color_style_uid} className="col-xl-6 col-sm-6">
<div className="card card-statistics">
<div className="card-body" style={{
backgroundColor: `#${color_style.color_code}`,
opacity: '0.85',
borderRadius: '10px'
}}>
<div className="text-center p-2">
{/*<div className="mb-2">*/}
{/* <img src={getImage('file-icon/svg.png')}*/}
{/* alt={template.title}/>*/}
{/*</div>*/}
<h4 className="mb-0">{color_style.title}</h4>
{currentColorUID === color_style.color_style_uid ?
<button className="btn btn-light"
disabled={true}>Active</button>
:
<button
onClick={() => handleSubmit(color_style.color_style_uid)}
className="btn btn-primary">Select</button>
}
</div>
</div>
</div>
</div>
))
}
{/* {Object.entries(data)?.map(([key, value]) => (
<div key={key} className="col-xl-6 col-sm-6">
<div className="card card-statistics">
<div className="card-body">
<div className="text-center p-2">
<div className="mb-2">
<img src={getImage(value.banner)} alt={value.title} />
</div>
<h4 className="mb-0">{value.title}</h4>
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
</div>
</div>
</div>
</div>
))} */}
</>
<div className="col-12">
<>
{handleActivateTemplate.isPending ?
<p className={'text-center '}>loading...</p>
:
handleActivateTemplate.isError ?
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
:
handleActivateTemplate.isSuccess ?
<p className={'text-center text-success'}>Templated activated
successfully</p>
:
null
}
</>
</div>
</div>
}
</div>
</div>
)
}
)
export default ColorStyleConfigure
@@ -1,198 +0,0 @@
import React, {memo, useEffect, useMemo, useState} from 'react'
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {pageSettings} from "../../../services/services";
import SiteTemplateSelector from './SiteTemplateSelector';
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
import {IoMdArrowDropdown} from 'react-icons/io';
import queryKeys from '../../../services/queryKeys';
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder';
import URLConfiguration from "./URLConfiguration";
import ColorStyleConfigure from "./ColorStyleConfigure";
const GeneralTab = memo(({
name = 'Full Name',
data,
tabKey,
isCustom,
productData,
backendValues,
setFieldsChanged
}) => {
const queryClient = useQueryClient()
const [reqStatus, setReqStatus] = useState({error: null, message: ''})
// const computeFieldData = useMemo(()=>{
// const fieldData = {}
// Object.entries(data)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
// fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
// })
// backendValues?.data?.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
// fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
// })
// return fieldData
// },[backendValues.data])
const [fields, setFields] = useState({})
const sortedData = sortObjectByListOrder(data ? data : {}) // SORTED SETTINGSCONFIG
useEffect(() => {
const fieldData = {}
Object.entries(sortedData)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
})
backendValues?.data?.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
})
setFields(fieldData)
}, [backendValues.data])
const handleChange = ({target: {name, value}}) => {
setFields(prev => ({...prev, [name]: value}))
setFieldsChanged(true)
}
const submitSettings = useMutation({
mutationFn: (fields) => {
return pageSettings(fields)
},
onSuccess: (res) => {
if (res?.data?.resultCode != '0') {
return setReqStatus({error: true, message: 'Unable to complete, try again later'})
}
setFieldsChanged(false)
setReqStatus({error: false, message: 'Completed successfully'})
},
onError: (err) => {
setReqStatus({error: true, message: 'Unable to complete, try again later'})
},
onSettled: () => {
queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.settingsData],
})
setTimeout(() => {
setReqStatus({error: null, message: ''})
}, 3000)
},
})
const handleSubmit = () => {
const reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id,
settings: {
...fields
}
}
submitSettings.mutate(reqData)
}
console.log(tabKey);
return (
<>
{backendValues?.isFetching || !backendValues?.data ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: backendValues?.isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{backendValues?.error.message}</p>
</div>
</div>
:
<>
{isCustom === true ?
<>
{(tabKey === 'template_tab') &&
<SiteTemplateSelector name={name} data={sortedData} isCustom={isCustom}
productData={productData}/>}
{(tabKey === 'url_config_tab') &&
<URLConfiguration name={name} data={sortedData} isCustom={isCustom}
productData={productData}/>}
{(tabKey === 'color_scheme_tab') &&
<ColorStyleConfigure name={name} data={sortedData} isCustom={isCustom}
productData={productData}/>}
</>
:
<div className="page-account-form">
<div className="p-0" style={{minHeight: '500px'}}>
<form id='tab_form'>
<div className="form-row">
<>
{Object.entries(sortedData)?.map(([key, value]) => {
let fieldName = key; // value.key.toLowerCase().replaceAll(" ", "_")
let fieldValue = fields[key]; //fields[value.name.toLowerCase().replaceAll(" ", "_")]
return (
<div key={key} className="form-group col-md-12">
<label htmlFor="name1">{value.name}</label>
{value.controls === 'TEXT' ?
<input name={fieldName} type="text"
className="form-control" id={key}
value={fieldValue} onChange={handleChange}/>
: value.controls === 'TEXTAREA' ?
<textarea name={fieldName} rows={5}
style={{resize: 'none'}} type="text"
className="form-control" id={key}
value={fieldValue}
onChange={handleChange}/>
: value.controls === 'SELECT_NO_YES' ?
// <NoYesBooleanDropdown name={fieldName} value={fieldValue} onChange={handleChange} />
<div className='position-relative'>
<select onChange={handleChange}
name={fieldName} value={fieldValue}
className="form-control">
<option value=''>Select</option>
<option value='0'>No</option>
<option value='1'>Yes</option>
</select>
<IoMdArrowDropdown
className='position-absolute w-auto'
style={{
top: '50%',
right: '2px',
transform: 'translateY(-50%)'
}}/>
</div>
:
null
}
</div>
)
}
)}
</>
{reqStatus.message &&
<>
<div className="col-12">
<p className={reqStatus.error ? 'text-danger' : 'text-success'}>{reqStatus.message}</p>
</div>
</>
}
<div className="form-group col-md-12" style={{textAlign: 'right'}}>
<button onClick={handleSubmit} type="button" className="btn btn-primary"
disabled={submitSettings.isPending}>{submitSettings.isPending ? 'Loading...' : 'Update'}</button>
</div>
</div>
</form>
</div>
</div>
}
</>
}
</>
)
}
)
export default GeneralTab
@@ -1,11 +0,0 @@
import React, {memo} from 'react'
export default function NoYesBooleanDropdown(name, value, onChange) {
return (
<select onChange={onChange} name={name} value={value} className="form-control">
<option value=''>Select</option>
<option value='0'>No</option>
<option value='1'>Yes</option>
</select>
)
}
@@ -1,144 +0,0 @@
import React, { memo, useMemo, useState } from 'react'
import GeneralTab from './GeneralTab'
import { getSettingsData, getMyProductConfig } from '../../../services/services';
import queryKeys from '../../../services/queryKeys';
import { useSelector } from 'react-redux';
import { useQuery } from '@tanstack/react-query';
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
import TemplateConfigure from './TemplateConfigure';
const Settings = memo(({productData}) => {
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
const {data:configData, isFetching:configIsFetching, configIsError, error:configError} = useQuery({
queryKey: queryKeys.myProductConfig,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id
}
return getMyProductConfig(reqData)
},
staleTime: 0,
})
const settingsConfig = configData?.data?.settings_items
// console.log('CONFIG DATA...', settingsConfig)
// console.log('configData', configData?.data?.subscription_template)
const [fieldsChanged, setFieldsChanged] = useState(false)
// const [activeTab, setActiveTab] = useState(Object.entries(settingsConfig)[0][1]?.controls)
const [activeTab, setActiveTab] = useState(null)
const handleChangeTab = (value) => {
// if(fieldsChanged){
// const proceed = confirm('Continue without saving changes')
// if(proceed){
// setActiveTab(value)
// setFieldsChanged(false)
// }
// }else{
// setActiveTab(value)
// }
setActiveTab(value)
}
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.settingsData,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id
}
return getSettingsData(reqData)
},
staleTime: 0,
enabled: settingsConfig ? true : false
})
const settingsData = {data: data?.data?.settings, isFetching, isError, error}
// console.log('data', settingsData)
const sortedSettingsConfig = sortObjectByListOrder(settingsConfig ? settingsConfig : {}) // SORTED SETTINGSCONFIG
return (
<>
{configIsFetching ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: configIsError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{configError.message}</p>
</div>
</div>
:
<div className="d-flex">
<ul className="bg-body-secondary flex-column nav" role="tablist" style={{width: '25%', minHeight: '670px', maxHeight: '670px'}}>
<>
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
<li key={key} className="nav-item">
<p className={`text-black nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show bg-primary text-white'}`}
id={key}
// data-bs-toggle="pill"
// data-bs-target={`#${value.controls}`}
type="button"
// role="tab"
// aria-controls={value.controls}
// aria-selected="true"
onClick={()=>handleChangeTab(value.controls)}
>
{value.title}
</p>
</li>
))}
{configData?.data?.subscription_template &&
<li className="mt-auto nav-item">
<p className={`text-black nav-link ${(activeTab == 'config_temp') && 'active show bg-primary text-white'}`}
// data-bs-toggle="pill"
// data-bs-target={`#${value.controls}`}
type="button"
// role="tab"
// aria-controls={value.controls}
// aria-selected="true"
onClick={()=>handleChangeTab('config_temp')}
>
Configure Template
</p>
</li>
}
</>
</ul>
<div className="p-3 tab-content" style={{width: '75%'}}>
<>
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
// id={value.controls} role="tabpanel"
// aria-labelledby={key}
>
<GeneralTab tabKey={key} name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
</div>
))}
<div className={`tab-pane fade ${(activeTab == 'config_temp') && 'active show'}`}
>
<TemplateConfigure productData={productData} />
</div>
</>
</div>
</div>
}
</>
)
}
)
export default Settings
@@ -1,169 +0,0 @@
import React, {memo} from 'react'
import getImage from "../../../utils/getImage";
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
import queryKeys from '../../../services/queryKeys';
import {getProductTemplateData, activateTemplate} from '../../../services/services';
import {Link} from "react-router-dom";
import siteLinks from "../../../links/siteLinks";
const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
const queryClient = useQueryClient()
const {data: templateData, isFetching, isError, error} = useQuery({
queryKey: queryKeys.productTemplateData,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id
}
return getProductTemplateData(reqData)
},
staleTime: 0
})
const templateResponse = templateData?.data
const currentTemUID = templateResponse?.current_template_uid
const templates = templateResponse?.templates
const custom_template_name = templateResponse?.custom_template_name
// console.log('data Template', templateResponse)
console.log("Page data == ", data)
const handleActivateTemplate = useMutation({
mutationFn: (fields) => {
return activateTemplate(fields)
},
onSuccess: (res) => {
if (res?.data?.resultCode != '0') {
throw new Error(res.data.resultDescription)
}
queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.settingsData],
})
},
onSettled: () => {
setTimeout(() => {
handleActivateTemplate.reset()
}, 3000)
}
})
const handleSubmit = (tem_uid) => {
const reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id,
template_uid: tem_uid
}
// console.log(reqData)
handleActivateTemplate.mutate(reqData)
}
if (custom_template_name && custom_template_name != '') {
// This implies we have a custom template , just return here
return <>
<div className='col-12'>
<div
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
style={{backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
<img className='' style={{width: '200px'}}
src={getImage('custom-template.png')}
alt='mail-alert'/>
<h4 className='p-4 text-black'
style={{marginTop: '20px'}}>This product is using a custom template named <span
style={{color: 'darkred'}}>&ldquo;{custom_template_name}&rdquo;</span> .</h4>
</div>
</div>
</>
}
return (
<div className="page-account-form">
<div className="p-0">
{isFetching ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{error?.message}</p>
</div>
</div>
:
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
<>
{!templates?.length ?
<p>No data Found</p>
:
templates.map(template => (
<div key={template.template_uid} className="col-xl-6 col-sm-6">
<div className="card card-statistics">
<div className="card-body">
<div className="text-center p-2">
<div className="mb-2">
<img src={getImage('file-icon/svg.png')}
alt={template.title}/>
</div>
<h4 className="mb-0">{template.title}</h4>
{currentTemUID == template.template_uid ?
<button className="btn btn-light"
disabled={true}>Active</button>
:
<button onClick={() => handleSubmit(template.template_uid)}
className="btn btn-primary">Activate</button>
}
</div>
</div>
</div>
</div>
))
}
{/* {Object.entries(data)?.map(([key, value]) => (
<div key={key} className="col-xl-6 col-sm-6">
<div className="card card-statistics">
<div className="card-body">
<div className="text-center p-2">
<div className="mb-2">
<img src={getImage(value.banner)} alt={value.title} />
</div>
<h4 className="mb-0">{value.title}</h4>
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
</div>
</div>
</div>
</div>
))} */}
</>
<div className="col-12">
<>
{handleActivateTemplate.isPending ?
<p className={'text-center '}>loading...</p>
:
handleActivateTemplate.isError ?
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
:
handleActivateTemplate.isSuccess ?
<p className={'text-center text-success'}>Templated activated
successfully</p>
:
null
}
</>
</div>
</div>
}
</div>
</div>
)
}
)
export default SiteTemplateSelector
@@ -1,185 +0,0 @@
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
@@ -1,141 +0,0 @@
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,128 +0,0 @@
import React, {memo, useState} from 'react'
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { pageSettings } from "../../../services/services";
import SiteTemplateSelector from './SiteTemplateSelector';
import NoYesBooleanDropdown from './NoYesBooleanDropdown';
import { IoMdArrowDropdown } from 'react-icons/io';
import queryKeys from '../../../services/queryKeys';
const GeneralTab = memo(({name='Full Name', data, isCustom, productData, backendValues, setFieldsChanged}) =>{
const queryClient = useQueryClient()
const [reqStatus, setReqStatus] = useState({error: null, message: ''})
const fieldData = {}
Object.entries(data)?.forEach(([key, value]) => { // LOOP TO POPULATE FIELDDATA PROPERTIES WITH DATA OF EACH TAB
fieldData[value?.name?.toLowerCase().replaceAll(" ", "_")] = ''
})
backendValues.forEach(item => { //LOOPING THROUGH USER ALREADY ADDED DATA FROM BACKEND IF ANY AND UPDATING THE FIELDDATA OBJECT
fieldData[item?.setting_key?.toLowerCase().replaceAll(" ", "_")] = item?.setting_value
})
// console.log('fieldData', fieldData)
const [fields, setFields] = useState(fieldData)
const handleChange = ({target:{name, value}}) => {
setFields(prev => ({...prev, [name]:value}))
setFieldsChanged(true)
}
const submitSettings = useMutation({
mutationFn: (fields) => {
return pageSettings(fields)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
return setReqStatus({error: true, message: 'Unable to complete, try again later'})
}
setFieldsChanged(false)
setReqStatus({error: false, message: 'Completed successfully'})
},
onError: (err) => {
setReqStatus({error: true, message: 'Unable to complete, try again later'})
},
onSettled: () => {
queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.settingsData],
})
setTimeout(()=>{
setReqStatus({error: null, message: ''})
},3000)
},
})
const handleSubmit = () => {
const reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id,
settings : {
...fields
}
}
// console.log('formInfo', reqData)
submitSettings.mutate(reqData)
}
if (isCustom === true){
return <SiteTemplateSelector name={name} data={data} isCustom={isCustom} productData={productData} />
}
return (
<div className="page-account-form">
<div className="p-0" style={{ minHeight: '500px'}}>
<form id='tab_form'>
<div className="form-row">
<>
{Object.entries(data)?.map(([key, value]) => {
let fieldName = value.name.toLowerCase().replaceAll(" ", "_")
let fieldValue = fields[value.name.toLowerCase().replaceAll(" ", "_")]
return (
<div key={key} className="form-group col-md-12">
<label htmlFor="name1">{value.name}</label>
{value.controls == 'TEXT' ?
<input name={fieldName} type="text" className="form-control" id={key} value={fieldValue} onChange={handleChange} />
:value.controls == 'TEXTAREA' ?
<textarea name={fieldName} rows={5} style={{resize: 'none'}} type="text" className="form-control" id={key} value={fieldValue} onChange={handleChange} />
: value.controls == 'SELECT_NO_YES' ?
// <NoYesBooleanDropdown name={fieldName} value={fieldValue} onChange={handleChange} />
<div className='position-relative'>
<select onChange={handleChange} name={fieldName} value={fieldValue} className="form-control">
<option value=''>Select</option>
<option value='0'>No</option>
<option value='1'>Yes</option>
</select>
<IoMdArrowDropdown className='position-absolute w-auto' style={{top: '50%', right: '2px', transform: 'translateY(-50%)'}} />
</div>
:
null
}
</div>
)
}
)}
</>
{reqStatus.message &&
<>
<div className="col-12">
<p className={reqStatus.error ? 'text-danger' : 'text-success'}>{reqStatus.message}</p>
</div>
</>
}
<div className="form-group col-md-12" style={{textAlign:'right'}}>
<button onClick={handleSubmit} type="button" className="btn btn-primary" disabled={submitSettings.isPending}>{submitSettings.isPending ? 'Loading...' : 'Update'}</button>
</div>
</div>
</form>
</div>
</div>
)
}
)
export default GeneralTab
@@ -1,179 +0,0 @@
import React, { memo, useMemo, useState } from 'react'
import GeneralTab from './GeneralTab'
import { getSettingsData, getMyProductConfig } from '../../../services/services';
import queryKeys from '../../../services/queryKeys';
import { useSelector } from 'react-redux';
import { useQuery } from '@tanstack/react-query';
const Settings = memo(({productData}) => {
const { userDetails: { uid }} = useSelector((state) => state?.userDetails); // GETS USER UID
const {data:configData, isFetching:configIsFetching, configIsError, error:configError} = useQuery({
queryKey: queryKeys.myProductConfig,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id
}
return getMyProductConfig(reqData)
}
})
const settingsConfig = configData?.data?.settings_items
// console.log('CONFIG DATA...', settingsConfig)
const dataFields ={
site_title: { name: 'Title', controls: 'TEXT', active: true },
site_description: { name: 'Description', controls: 'TEXTAREA', active: true },
site_logo_text: { name: 'Logo Text', controls: 'TEXT', active: true },
site_contact_email: { name: 'Email', controls: 'TEXT', active: true },
site_contact_phone: { name: 'Phone', controls: 'TEXT', active: true },
}
const socialFields ={
facebook: { name: 'Facebook', controls: 'TEXT', active: true },
twitter: { name: 'Twitter', controls: 'TEXT', active: true },
youtube: { name: 'Youtube', controls: 'TEXT', active: true },
}
const homeFields ={
banner_text: { name: 'Banner Text', controls: 'TEXT', active: true },
banner_description: { name: 'Banner Description', controls: 'TEXTAREA', active: true },
}
const footerFields ={
footer_description: { name: 'Footer Description', controls: 'TEXTAREA', active: true },
boolean_footer_show_email: { name: 'Show email in footer', controls: 'SELECT_NO_YES', active: true },
boolean_footer_show_made_by: { name: 'Show made by in footer', controls: 'SELECT_NO_YES', active: true },
boolean_footer_show_socials: { name: 'Show social in footer', controls: 'SELECT_NO_YES', active: true },
}
const aboutFields ={
about_title: { name: 'About Title', controls: 'TEXT', active: true },
about_description: { name: 'About Details', controls: 'TEXTAREA', active: true },
about_extra_1: { name: 'Extra About us', controls: 'TEXTAREA', active: true },
about_extra_2: { name: 'More About us', controls: 'TEXTAREA', active: true },
}
const templateData = {
template_16 : { title: 'Template Name-16', template_id: '02af24fd-2b1a-46ed-af21-87018e726408', banner: 'file-icon/svg.png', active: '' },
template_22 : { title: 'Template Name-22', template_id: '8b296894-42e4-4f2e-abd1-7c2a38d6e07b', banner: 'file-icon/svg.png', active: '' },
template_47 : { title: 'Template Name-47', template_id: 'ef2ffa1c-9272-42cd-9d33-0e614047b4f8', banner: 'file-icon/svg.png', active: '' },
template_25 : { title: 'Template Name-25', template_id: 'b3a7ba31-dc47-4a40-a5cc-fd1ff27d6b78', banner: 'file-icon/svg.png', active: '' },
template_49 : { title: 'Template Name-49', template_id: '60959c69-6672-4f69-a006-eeb7d210e605', banner: 'file-icon/svg.png', active: '' },
template_27 : { title: 'Template Name-27', template_id: 'e4acb98a-c584-45f2-bece-af677dcf0a1f', banner: 'file-icon/svg.png', active: '' },
template_51 : { title: 'Template Name-51', template_id: '975ee42e-3169-4978-92d7-d28e7e2ac014', banner: 'file-icon/svg.png', active: '' },
template_9 : { title: 'Template Name-9', template_id: 'fc8f0738-6500-4775-9895-2047cd275302', banner: 'file-icon/svg.png', active: '' },
}
const contactFields ={
contact_title : { name: 'Contact Title', controls: 'TEXT', active: true },
contact_introduction: { name: 'Extra Introduction', controls: 'TEXTAREA', active: true },
}
const settingsObject = useMemo(()=>{
return {
settings: { title: 'Settings', controls: 'settings', active: 'active show' , custom: false, data: dataFields},
home_tab: { title: 'Home Page', controls: 'home', active: '', custom: false, data: homeFields},
footer_tab: { title: 'Footer', controls: 'footer', active: '', custom: false, data: footerFields },
about_tab: { title: 'About Page', controls: 'about', active: '', custom: false, data: aboutFields },
contact_tab: { title: 'Contact Page', controls: 'contact', active: '', custom: false, data: contactFields },
social_tab: { title: 'Socials', controls: 'social', active: '', custom: false, data: socialFields },
template_tab: { title: 'Template', controls: 'template', active: '', custom: true, data: templateData },
color_scheme_tab: { title: 'Color Scheme', controls: 'color-scheme', active: '', custom: true, data: {} },
};
},[])
const [fieldsChanged, setFieldsChanged] = useState(false)
const [activeTab, setActiveTab] = useState(Object.entries(settingsObject)[0][1]?.controls)
const handleChangeTab = (value) => {
// if(fieldsChanged){
// const proceed = confirm('Continue without saving changes')
// if(proceed){
// setActiveTab(value)
// setFieldsChanged(false)
// }
// }else{
// setActiveTab(value)
// }
setActiveTab(value)
}
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.settingsData,
queryFn: () => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
product_id: productData?.product_id
}
return getSettingsData(reqData)
}
})
const settingsData = data?.data?.settings
// console.log('data', settingsData)
return (
<>
{isFetching ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<div className="tab tab-vertical">
<ul className="nav nav-tabs" role="tablist">
<>
{Object.entries(settingsObject).map(([key, value]) => (
<li key={key} className="nav-item">
<a className={`nav-link ${activeTab == value.controls && 'active show'}`}
id={key}
// data-bs-toggle="pill"
// data-bs-target={`#${value.controls}`}
type="button"
// role="tab"
// aria-controls={value.controls}
// aria-selected="true"
onClick={()=>handleChangeTab(value.controls)}
>
{value.title}
</a>
</li>
))}
</>
</ul>
<div className="tab-content">
<>
{Object.entries(settingsObject).map(([key, value]) => (
<div key={key} className={`tab-pane fade ${activeTab == value.controls && 'active show'}`}
// id={value.controls} role="tabpanel"
// aria-labelledby={key}
>
<GeneralTab name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
</div>
))}
</>
</div>
</div>
}
</>
)
}
)
export default Settings
@@ -1,299 +0,0 @@
import React, {useCallback, useEffect, useMemo, useState} from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
// import { useLocation } from "react-router-dom";
import { Form, Formik } from "formik";
import * as Yup from "yup";
import {useMutation, useQuery} from "@tanstack/react-query";
import getImage from "../../utils/getImage";
import {IoMdArrowDropdown} from "react-icons/io";
import {completeProfile, getCommonPractice} from '../../services/services';
import siteLinks from "../../links/siteLinks";
import {useLocation, useNavigate} from "react-router-dom";
import {updateUserDetails} from "../../store/UserDetails";
import {useDispatch} from "react-redux";
const validationSchema = Yup.object().shape({
practice: Yup.string().required("Required"),
specialization: Yup.string().when('practice', {
is: (value) => typeof value === 'string' && value.trim().length > 0,
then: (schema) => schema.required('Required'),
otherwise: (schema) => schema,
}),
introduction: Yup.string().min(1, "Minimum 1 character").max(50, "Maximum 50 characters"),
url_name: Yup.string().min(6, "Minimum 6 characters").max(16, "Maximum 16 characters").required("Required").matches(
/^[a-zA-Z0-9]+$/, // Regex for alphanumeric characters
'Must contain only alphanumeric characters' // Custom error message
),
})
export default function ProfileCompleteCom() {
const dispatch = useDispatch()
const navigate = useNavigate()
const {state: {redirectLink}} = useLocation()
const [practices, setPractices] = useState([])
const [specialties, setSpecialties] = useState([])
const [initialValues, setInitialValues] = useState({
practice: '',
specialization: '',
introduction: '',
url_name: ''
})
const handleUpdateSpecialties = (e) => {
setInitialValues(prev => ({...prev, specialization: ''}))
const specialtiesArr = practices.filter(item => item.practice == e.target.value)[0]?.specialties
setSpecialties(specialtiesArr)
}
const mutation = useMutation({
mutationFn: (fields) => {
const {practice, specialization, url_name} = fields
if (!practice || !specialization || !url_name) {
throw new Error('Please Select both Practice, Specialization and Enter URL_Name')
}
return completeProfile(fields)
},
onError: () => {
setTimeout(() => {
mutation.reset()
}, 4000)
},
onSuccess: (res) => {
if (res.data.resultCode != '0') {
throw({message: res?.data?.resultDescription})
}
dispatch(updateUserDetails({profile_completed: res?.data?.profile_completed}));
setTimeout(() => {
navigate(redirectLink)
}, 2000)
// console.log('res', res)
}
})
const commonPractices = useMutation({ // FUNCTION TO GET COMMON PRACTICES
mutationFn: (fields) => {
return getCommonPractice(fields)
},
onError: () => {
setPractices([])
},
onSuccess: (res) => {
if (!res?.data) {
return setPractices([])
}
let returnPractices = Object.entries(res?.data).filter(([key, value]) => typeof value == 'object')?.map(item => item[1])
setPractices(returnPractices)
}
})
const handleCompleteProfile = (values) => { // FUNCTION TO COMPLETE PROFILE
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
...values
}
mutation.mutate(reqData)
}
useEffect(() => {
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
commonPractices.mutate(reqData)
}, [])
return <>
<BreadcrumbComBS title='Tell us more about your practice.' paths={['Dashboard', 'Profile']}/>
{commonPractices?.isFetching ?
<>
<div className="row">
<div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: commonPractices?.isError ?
<div className="row">
<div className="col-12">
<p className='text-danger'>{commonPractices?.error?.message}</p>
</div>
</div>
:
<div className="row pt-1">
<div className="col-md-6 m-b-30">
<div className="card card-statistics h-100 mb-0" style={{borderRadius: '10px'}}>
{/* <div className="card-header d-flex align-items-center justify-content-between">
<div className="card-heading">
<h4 className="card-title">My Product URLs</h4>
</div>
</div> */}
{/* <div style={{minHeight: '400px'}}></div> */}
<div className="card-body">
<div className='h-100 row flex-column'>
{/* <div className="row"> */}
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleCompleteProfile}
enableReinitialize={true}
>
{(props) => {
return (
<Form className='mt-2'>
<>
<div className="">
<div className="form-group position-relative">
<label className={`text-black fw-bold control-label`}>Practice : <span className="text-danger">{(props.errors.practice && props.touched.practice) && props.errors.practice}</span></label>
<div className="position-relative">
{/* <select onChange={props.handleChange} name='practice' value={props.values.practice} className="form-control">
<option value=''>Select</option>
{practices.map((practice, index)=>(
<option key={index} value={practice.practice}>{practice.practice}</option>
))}
</select> */}
<select
onChange={(e) => {props.handleChange(e); props.setFieldValue('specialization', ''); handleUpdateSpecialties(e)}}
name='practice'
value={props.values.practice} className="form-control">
<option value=''>Select</option>
{practices.map((practice, index) => (
<option key={index}
value={practice.practice}>{practice.practice}</option>
))}
</select>
<IoMdArrowDropdown className='position-absolute w-auto' style={{
top: '50%',
right: '2px',
transform: 'translateY(-50%)'
}}/>
</div>
</div>
</div>
<div className="">
<div className="form-group">
<label className={`text-black fw-bold control-label`}>Your
Specialization : <span className="text-danger">{(props.errors.specialization && props.touched.specialization) && props.errors.specialization}</span></label>
<div className="position-relative">
<select onChange={props.handleChange} name='specialization'
value={props.values.specialization}
className="form-control">
<option value=''>Select</option>
{specialties.map((specialty, index) => (
<option key={index} value={specialty}>{specialty}</option>
))}
</select>
<IoMdArrowDropdown className='position-absolute w-auto' style={{
top: '50%',
right: '2px',
transform: 'translateY(-50%)'
}}/>
</div>
</div>
</div>
<div className="">
<div className="form-group position-relative">
<label className={`text-black fw-bold control-label`}>Other General Information : <span className="text-danger">{(props.errors.introduction && props.touched.introduction) && props.errors.introduction}</span></label>
<textarea name='introduction' rows={5} style={{resize: 'none'}}
className="form-control" value={props.values.introduction}
onChange={props.handleChange}/>
</div>
</div>
<div className="">
<div className="form-group position-relativ'e">
{/*<label className={`text-black fw-bold control-label`}>What we use this*/}
{/* information for :</label>*/}
<div style={{
fontSize: '14px',
borderRadius: '10px',
backgroundColor: 'aliceblue',
fontWeight: 'bolder',
padding: '15px'
}}>
MERMS A.I. agents use the information supplied to help generate
useful entries for your product settings.
</div>
</div>
</div>
<div className="">
<div className="form-group position-relative">
<label className={`text-black fw-bold control-label`}>URL Name : <span className="text-danger">{(props.errors.url_name && props.touched.url_name) && props.errors.url_name}</span></label>
<div className="position-relative d-flex flex-column flex-xxl-row" style={{gap: '10px'}}>
{/* <select onChange={handlePracticeChange} name='url_name'
value={initialValues.url_name} className="form-control">
<option value=''>Select</option>
{practices.map((practice, index) => (
<option key={index}
value={practice.practice}>{practice.practice}</option>
))}
</select>
<IoMdArrowDropdown className='position-absolute w-auto' style={{
top: '50%',
right: '2px',
transform: 'translateY(-50%)'
}}/> */}
<input
className="form-control"
onChange={props.handleChange} name='url_name'
value={props.values.url_name}
minLength={6}
maxLength={16}
/>
<p className="border-radius-10 p-2 border border-warning"
style={{fontSize: "1.0rem"}}>We use the URL Name to form part of
your default URL when we configure
a new URL for your products. You can always change your product
URL. <br/>
<b>Example : <span style={{color: 'red'}}>url_name</span>.product.mermsemr.com
</b>
</p>
</div>
</div>
</div>
{(mutation.isError || mutation.isSuccess) &&
<>
<div className="">
<p className={`${mutation.isSuccess ? 'text-success' : 'text-danger'}`}>{mutation.isSuccess ? 'Completed successfully, redirecting...' : mutation.error.message}</p>
</div>
</>
}
<div className="mt-auto text-end">
<button type='submit'
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Continue'}</button>
</div>
</>
</Form>
);
}}
</Formik>
{/* </div> */}
</div>
</div>
</div>
</div>
<div className="col-md-6 m-b-30">
<div className="text-center img-block left-column wow fadeInRight">
<img className="img-fluid" src={getImage('tell-us-more.png')} alt="content-image"/>
</div>
</div>
</div>
}
</>;
}
@@ -1,202 +0,0 @@
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>
</>
)
}
@@ -1,205 +0,0 @@
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>
</>
)
}
+4 -82
View File
@@ -1,92 +1,14 @@
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(){
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 (
return(
<>
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']} />
<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>
<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 className="vh-100 col-12 flex align-items-center">Coming Soon</div>
</div>
</>
)
-205
View File
@@ -1,205 +0,0 @@
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>
</>
)
}
-159
View File
@@ -1,159 +0,0 @@
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">&times;</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 */}
</>
)
}
-164
View File
@@ -1,164 +0,0 @@
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">&times;</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 */}
</>
)
}
-117
View File
@@ -1,117 +0,0 @@
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
+274 -67
View File
@@ -1,83 +1,289 @@
import React, { useMemo, useState } from "react";
import React 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 [intialData, setInitialData] = useState({
external_links: {},
personal_data: {},
})
export default function Settings(){
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 (
return(
<>
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']}/>
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']} />
{/*<div className="row">*/}
{/* <div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
{/*</div>*/}
{isFetching ?
<>
<div className="row">
<div className="col-12">
<p className="text-mute">Loading...</p>
</div>
</div>
</>
: isError ?
<div className="row">
<div className="row account-contant">
<div className="col-12">
<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 className="card card-statistics">
<div className="card-body p-0">
<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" />
</div>
<div className="profile pt-4">
<h4 className="mb-1">Alice Williams</h4>
<p>Enthusiast</p>
</div>
</div>
<div className="p-4">
<ProfileForm data={intialData.personal_data} />
</div>
<div className="py-5 profile-counter">
<ul className="nav justify-content-center text-center">
<li className="nav-item border-right px-3">
<div>
<h4 className="mb-0">90</h4>
<p>Post</p>
</div>
</li>
<li className="nav-item border-right px-3">
<div>
<h4 className="mb-0">1.5K</h4>
<p>Messages</p>
</div>
</li>
<li className="nav-item px-3">
<div>
<h4 className="mb-0">4.4K</h4>
<p>Members</p>
</div>
</li>
</ul>
</div>
<div className="profile-btn text-center">
<div>
<button className="btn btn-light text-primary mb-2">Upload New Avatar
</button>
</div>
<div>
<button className="btn btn-danger">Delete</button>
</div>
</div>
</div>
<div 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>
<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">Full Name</label>
<input type="text" className="form-control" id="name1"
value="Alice Williams" />
</div>
<div className="form-group col-md-12">
<label htmlFor="title1">Title</label>
<input type="text" className="form-control" id="title1"
value="Marketing expert" />
</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="col-12">
<label className="mb-1">Birthday</label>
</div>
<div className="form-group col-md-4">
<select id="inputState" className="form-control">
<option>Date</option>
<option>01</option>
<option>02</option>
<option>03</option>
<option>04</option>
<option>05</option>
<option>06</option>
<option>07</option>
<option>08</option>
<option>09</option>
<option>10</option>
<option selected="">11</option>
<option>12</option>
<option>13</option>
<option>14</option>
<option>15</option>
<option>16</option>
<option>17</option>
<option>18</option>
<option>19</option>
<option>20</option>
<option>21</option>
<option>22</option>
<option>23</option>
<option>24</option>
<option>25</option>
<option>26</option>
<option>27</option>
<option>28</option>
<option>29</option>
<option>30</option>
<option>31</option>
</select>
</div>
<div className="form-group col-md-4">
<select id="inputState1" className="form-control">
<option>Month</option>
<option>January</option>
<option>February</option>
<option>March</option>
<option>April</option>
<option selected="">May</option>
<option>June</option>
<option>July</option>
<option>August</option>
<option>September</option>
<option>October</option>
<option>November</option>
<option>December</option>
</select>
</div>
<div className="form-group col-md-4">
<select id="inputState2" className="form-control">
<option>Year</option>
<option>1984</option>
<option>1985</option>
<option>1986</option>
<option>1987</option>
<option>1988</option>
<option>1989</option>
<option>1990</option>
<option>1991</option>
<option>1992</option>
<option>1993</option>
<option selected="">1994</option>
<option>1995</option>
<option>1996</option>
<option>1997</option>
<option>1998</option>
<option>1999</option>
<option>2000</option>
<option>2001</option>
<option>2002</option>
<option>2003</option>
<option>2004</option>
<option>2005</option>
<option>2006</option>
<option>2007</option>
<option>2008</option>
<option>2009</option>
<option>2010</option>
</select>
</div>
</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>
<button type="submit" className="btn btn-primary">Update Information
</button>
</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>
<button type="submit" className="btn btn-primary">Save & Update</button>
</form>
</div>
</div>
</div>
@@ -85,7 +291,8 @@ export default function Settings() {
</div>
</div>
</div>
}
</div>
</>
)
}
-82
View File
@@ -1,82 +0,0 @@
import React from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Start() {
const bgImg = getImage("side-banner.jpg");
return (
<>
<BreadcrumbComBS title='Get Started...' paths={['Dashboard', 'Start']}/>
<div className="row">
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3"
style={{minHeight: '550px', borderRadius: '10px', backgroundImage: `url(${bgImg})`}}>
</div>
</div>
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Start with</h5>
<h2 className="text-primary pt-3"><a href="/product/A000001">Personal Website</a></h2>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="/product/A000001"
className="btn btn-primary btn-round btn-sm">Start</a></div>
</div>
</div>
</div>
</div>
<div className="col-xl-3 col-md-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Start with</h5>
<h2 className="text-primary pt-3"><a href="/product/A000002">Business Website</a></h2>
<ul className="py-2">
<li>post jobs</li>
<li>advanced instructors search</li>
<li>invite candidates</li>
<li>post events</li>
<li>cancel any time</li>
</ul>
<div className="pt-2"><a href="/product/A000001"
className="btn btn-primary btn-round btn-sm">Start</a></div>
</div>
</div>
</div>
</div>
<div className="col-xl-3 col-md-6">
{/*<div className="card card-statistics text-center py-3">*/}
{/*<div className="card-body pricing-content">*/}
{/*<div className="pricing-content-card">*/}
{/* <h5>small</h5>*/}
{/* <h2 className="text-primary pt-3">$80</h2>*/}
{/* <p className="text-primary pb-3">/ Monthly</p>*/}
{/* <ul className="py-2">*/}
{/* <li>post jobs</li>*/}
{/* <li>advanced instructors search</li>*/}
{/* <li>invite candidates</li>*/}
{/* <li>post events</li>*/}
{/* <li>cancel any time</li>*/}
{/* </ul>*/}
{/* <div className="pt-2"><a href="javascript:void(0)" className="btn btn-inverse-secondary btn-round btn-sm">go premium</a></div>*/}
{/*</div>*/}
{/*</div>*/}
{/*</div>*/}
</div>
</div>
</>
)
}
@@ -1,57 +0,0 @@
import React from 'react';
import { loadStripe } from '@stripe/stripe-js';
import { Elements, useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
import {MyProductData, StripeSubscriptionCreate} from '../../services/services';
import {useQuery} from "@tanstack/react-query";
import queryKeys from "../../services/queryKeys";
import { useNavigate } from 'react-router-dom';
//const stripePromise = loadStripe('your_stripe_publishable_key');
const stripePromise = loadStripe('pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT');
const CheckoutForm = ({ priceId, customerId ,option_name }) => {
const stripe = useStripe();
const elements = useElements();
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
if (!stripe || !elements) {
return;
}
let reqData = {
priceId : priceId,
customerId: customerId,
option_name: option_name,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
StripeSubscriptionCreate(reqData).then( (res)=>{
console.log(res);
console.log(res.data.stripe_session);
//navigate(res.data.stripe_session)
window.location.replace(res.data.stripe_session);
});
};
return (
<form onSubmit={handleSubmit}>
<CardElement />
<button type="submit" disabled={!stripe}>
Subscribe
</button>
</form>
);
};
const StripeSubscriptionButton = ({ priceId, customerId ,option_name}) => {
return (
<Elements stripe={stripePromise}>
<CheckoutForm priceId={priceId} customerId={customerId} option_name={option_name} />
</Elements>
);
};
export default StripeSubscriptionButton;
@@ -1,35 +0,0 @@
import React from 'react'
export default function SubcribePaymentOptions({activePaymentType, setActivePaymentType}){
const handleSwitch = ({target:{name, value}}) => {
console.log('SWITCH', name, value)
setActivePaymentType(value)
}
return <>
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">Select Payment Option</h4>
</div>
</div>
<div className="card-body">
<div className="form-check form-check-inline">
<input onChange={handleSwitch} className="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1"
value="previous" checked={activePaymentType == 'previous'} />
<label className="form-check-label" htmlFor="inlineRadio1">Previous Cards</label>
</div>
<div className="form-check form-check-inline">
<input onChange={handleSwitch} className="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2"
value="new" checked={activePaymentType == 'new'} />
<label className="form-check-label" htmlFor="inlineRadio2">Add New card</label>
</div>
</div>
{/*<div className="card card-statistics"> </div>*/}
</>
}
-72
View File
@@ -1,72 +0,0 @@
import React, {useState} from 'react'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import {Link, useLocation} from 'react-router-dom'
import SubscribeNewCard from "./SubscribeNewCard";
import SubscribePreviousCard from "./SubscribePreviousCard";
import SubcribePaymentOptions from "./SubcribePaymentOptions";
import StripeSubscriptionButton from "./StripeSubscriptionButton";
export default function Subscribe() {
const {state: {selectedSubscription,customerId}} = useLocation()
console.log('selectedSubscription', selectedSubscription)
console.log('selectedSubscription.option_name',selectedSubscription.option_name)
console.log('customerId', customerId)
let [activePaymentType, setActivePaymentType] = useState('previous')
return (
<>
<BreadcrumbComBS title='Activate or Update your Subscription' paths={['Dashboard', 'subscribe']}/>
<div className="row">
<div className="col-12 col-lg-6 col-xl-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>Current Subscription(s)</h5>
{/*<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>*/}
<SubcribePaymentOptions activePaymentType={activePaymentType}
setActivePaymentType={setActivePaymentType}/>
{activePaymentType == 'new' ?
<SubscribeNewCard/>
:
<SubscribePreviousCard/>
}
<>
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id} customerId={customerId} option_name={selectedSubscription.option_name} />
</>
</div>
</div>
</div>
</div>
<>
<div key="basic" className="col-12 col-lg-6 col-xl-6">
<div className="card card-statistics text-center py-3">
<div className="card-body pricing-content">
<div className="pricing-content-card">
<h5>{selectedSubscription.display_name}</h5>
<h2 className="text-primary pt-3">${selectedSubscription.monthly}</h2>
<p className="text-primary pb-3">/ Monthly</p>
<ol className="py-2"
style={{fontSize: '16px', fontWeight: 'bold', textAlign: 'left'}}>
{selectedSubscription?.items?.map(item => (
<li key={item.description}>{item.description}</li>
))}
</ol>
{/*<div className="pt-2">*/}
{/* <button className="btn btn-inverse-secondary btn-round btn-sm">Go {subscriptionSelection.display_name}</button>*/}
{/*</div>*/}
</div>
</div>
</div>
</div>
</>
</div>
</>
)
}
@@ -1,28 +0,0 @@
import React from 'react'
export default function SubscribeNewCard(){
return <>
<div className="row">
<div className="col-md-12 col-12 selects-contant">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading" style={{textAlign: 'left'}}>
<h4 className="card-title">Pay with New Card</h4>
</div>
</div>
<div className="card-body">
<div className="form-group mb-0">
</div>
</div>
</div>
</div>
</div>
</>
}

Some files were not shown because too many files have changed in this diff Show More