Merge branch 'master-bootstrap' of MERMS/MermsPanelReactJS into master

This commit is contained in:
2024-12-27 23:51:45 +00:00
committed by Gogs
53 changed files with 2544 additions and 647 deletions
+4 -1
View File
@@ -1,7 +1,10 @@
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com"
REACT_APP_MAIN_API="https://dev-api.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
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
+4 -1
View File
@@ -1,6 +1,9 @@
SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com"
REACT_APP_MAIN_API="https://dev-api.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com"
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
+3
View File
@@ -3,3 +3,6 @@ REACT_APP_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"
# Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000
+11 -1
View File
@@ -4,19 +4,29 @@
"private": true,
"dependencies": {
"@popperjs/core": "^2.11.8",
"@reduxjs/toolkit": "^2.4.0",
"@tanstack/react-query": "^5.62.3",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"apexcharts": "^4.1.0",
"axios": "^1.7.9",
"bootstrap": "^5.3.3",
"dayjs": "^1.11.13",
"formik": "^2.4.6",
"react": "^18.3.1",
"react-apexcharts": "^1.7.0",
"react-big-calendar": "^1.17.0",
"react-dom": "^18.3.1",
"react-icons": "^5.4.0",
"react-redux": "^9.1.2",
"react-router-dom": "^7.0.2",
"react-scripts": "5.0.1",
"redux": "^5.0.1",
"sass": "^1.82.0",
"web-vitals": "^2.1.4"
"socket.io-client": "^4.8.1",
"web-vitals": "^2.1.4",
"yup": "^1.6.0"
},
"scripts": {
"start": "react-scripts start -e .env.development",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

+9 -36
View File
@@ -1,38 +1,11 @@
.App {
text-align: center;
.custom-bg {
background-image: url('./assets/bg/bg_1.jpg') !important;
background-size: cover;
background-repeat: no-repeat;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.signup-bg {
background-image: url('./assets/bg/signup_bg.jpg') !important;
background-size: 100%;
background-repeat: no-repeat;
}
+16 -39
View File
@@ -1,47 +1,24 @@
import { Routes, Route } from 'react-router-dom';
// import './App.css';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import AppRouters from './AppRouters';
import UserExist from './component/authorization/UserExist';
import AuthLayout from './component/auth/AuthLayout';
import LoginPage from './views/LoginPage';
import siteLinks from './links/siteLinks';
import SignupPage from './views/SignupPage';
import ForgetpwdPage from './views/ForgetpwdPage';
import HomePage from './views/HomePage';
import ReportsPage from './views/ReportsPage'
import CommentsPage from './views/CommentsPage'
import ContactsPage from './views/ContactsPage'
import UserPage from './views/UserPage'
import CalendarPage from './views/CalendarPage'
import SettingsPage from './views/SettingsPage'
import './App.css';
function App() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 3,
// refetchOnMount: false,
staleTime: 3000
},
},
})
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.error} element={<ForgetpwdPage />} />
</Route>
{/* protected routes */}
<Route element={<UserExist />}>
<Route path={siteLinks.dash} element={<HomePage />} />
<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>
</Routes>
</div>
<QueryClientProvider client={queryClient}>
<AppRouters />
</QueryClientProvider>
);
}
+53
View File
@@ -0,0 +1,53 @@
import { Routes, Route } from 'react-router-dom';
import UserExist from './component/authorization/UserExist';
import AuthLayout from './component/auth/AuthLayout';
import siteLinks from './links/siteLinks';
import LoginPage from './views/LoginPage';
import SignupPage from './views/SignupPage';
import ForgetpwdPage from './views/ForgetpwdPage';
import HomePage from './views/HomePage';
import ReportsPage from './views/ReportsPage'
import CommentsPage from './views/CommentsPage'
import ContactsPage from './views/ContactsPage'
import UserPage from './views/UserPage'
import CalendarPage from './views/CalendarPage'
import SettingsPage from './views/SettingsPage'
import ProductPage from './views/ProductPage'
import SocketIOContextProvider from './component/context/SocketIOContext';
import CSignupPage from './views/CSignupPage';
function AppRouters() {
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.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.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

+174
View File
@@ -0,0 +1,174 @@
import React, { useEffect, useState } from 'react'
import { Form, Formik } from "formik";
import * as Yup from "yup";
// import LoginImg from '../../assets/bg/login.svg'
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
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"),
password: Yup.string().required("Password is required"),
confirmpassword: Yup.string().required("Confirm Password is required").oneOf([Yup.ref('password')], 'Passwords must match')
// lastname: Yup.string().required("Lastname is required"),
// isChecked: Yup.bool().oneOf([true], "Please accept the terms & policy"), // use bool instead of boolean
})
const initialValues = {
email: '',
password: '',
confirmpassword: '',
// lastname: '',
// isChecked: false,
};
export default function CSignup() {
const {jwt} = useParams()
const navigate = useNavigate()
const mutation = useMutation({
mutationFn: (fields) => {
return signUpUser(fields)
},
onSuccess: (res) => {
console.log('res', res)
}
})
const CSignUp = (values) => {
// helpers.resetForm()
// console.log('values', values, helpers)
// mutation.mutate(values)
console.log('values', values)
}
useEffect(()=>{
if(!jwt){
return navigate(siteLinks.login, {replace: true})
}
})
return (
<div className="app">
<div className="app-wrap">
<div className="app-contant">
<div className="bg-white custom-bg">
<div className="container-fluid p-0">
<div className="row no-gutters justify-content-center">
<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">MERMS Panel</h1>
<p>Welcome, Enter your password.</p>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={CSignUp}
>
{(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> */}
<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.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>
{/* <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...' : 'Continue'}</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 text-center">
<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">
{/* <p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p> */}
<p>Ready our Privacy Statement</p>
</div>
</div>
</Form>
);
}}
</Formik>
</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>
)
}
+78 -30
View File
@@ -1,23 +1,43 @@
import React, { useEffect, useState } from 'react'
import LoginImg from '../../assets/bg/login.svg'
import { Form, Formik } from "formik";
import * as Yup from "yup";
// import LoginImg from '../../assets/bg/login.svg'
import MainLoaderBS from '../loaders/MainLoaderBS'
import { Link, useNavigate } from 'react-router-dom'
import { Link } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import { useMutation } from '@tanstack/react-query'
import { recoverPWD } from '../../services/services';
const validationSchema = Yup.object().shape({
username: 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"),
})
const initialValues = {
username: ''
};
export default function Forgetpwd2() {
const [loading, setLoading] = useState(true)
const mutation = useMutation({
mutationFn: (fields) => {
return recoverPWD(fields)
},
// onSuccess: (res) => {
// console.log('res', res)
// }
})
const navigate = useNavigate()
useEffect(()=>{
const timer = setTimeout(()=>{
setLoading(false)
},1000)
return () => clearTimeout(timer)
},[])
const recoverPWDSubmit = (values) => {
mutation.mutate(values)
}
return (
<div className="app">
@@ -31,29 +51,57 @@ export default function Forgetpwd2() {
<div className="login p-50">
<h1 className="mb-2">Recover Password</h1>
<p>Please enter your email.</p>
<form className="mt-3 mt-sm-5">
<div className="row">
<div className="col-12">
<div className="form-group">
<label className="control-label">Email*</label>
<input type="text" className="form-control" placeholder="Email" />
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={recoverPWDSubmit}
>
{(props) => {
return (
<Form className='mt-2 mt-sm-5'>
<div className="row">
{!mutation.isSuccess ?
<>
<div className="col-12">
<div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Email*</label>
<input type="email" name='username' className="form-control" placeholder="Email" value={props.values.username} onChange={props.handleChange} />
</div>
</div>
{mutation.error &&
<>
<div className="col-12 mt-3">
<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...' : 'Send'}</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 password reset.</h4>
<Link to={siteLinks.login} className='p-2 text-primary' style={{color: '#6FCAEF'}}>Home</Link>
</div>
</div>
</div>
<div className="col-12 mt-3">
<button type='button' onClick={()=>{navigate(siteLinks.dash)}} className="btn btn-primary text-uppercase">Send</button>
</div>
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</div>
</form>
}
<div className="col-12 mt-3">
<p>Go <Link to={siteLinks.home}> Back</Link></p>
</div>
</div>
</Form>
);
}}
</Formik>
</div>
</div>
</div>
<div className="col-sm-6 col-xxl-9 col-lg-7 bg-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>
+93 -20
View File
@@ -1,23 +1,66 @@
import React, { useEffect, useState } from 'react'
import LoginImg from '../../assets/bg/login.svg'
import React, { useState } from 'react'
import { useMutation } from '@tanstack/react-query'
import { useDispatch } from 'react-redux'
// import LoginImg from '../../assets/bg/login.svg'
import MainLoaderBS from '../loaders/MainLoaderBS'
import { Link, useNavigate } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
import { loginUser } from '../../services/services'
import { updateUserDetails } from '../../store/UserDetails'
import GoogleDownload from '../../assets/img/download/andriod.jpg'
import IOSDownload from '../../assets/img/download/apple.jpg'
export default function Login() {
const [loading, setLoading] = useState(true)
const dispatch = useDispatch()
const navigate = useNavigate()
useEffect(()=>{
const timer = setTimeout(()=>{
setLoading(false)
},1000)
const [fields, setFields] = useState({
username: localStorage.getItem('username') || '',
password: '',
remember: localStorage.getItem('username') ? true : false
})
return () => clearTimeout(timer)
},[])
const handleChange = ({target:{name, value}}) => {
if(name == 'remember'){
return setFields(prev => ({...prev, remember:!prev.remember}))
}
setFields(prev => ({...prev, [name]:value}))
}
const login = useMutation({
mutationFn: (fields) => {
if(!fields.username || !fields.password){
throw new Error('Please provide all fields marked *')
}
rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE
return loginUser(fields)
},
onError: (error) => {
console.log(error)
},
onSuccess: (res) => {
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 rememberMe = (checked) => {
if(checked){
localStorage.setItem('username', fields.username)
}else{
localStorage.removeItem('username')
}
}
return (
<div className="app">
@@ -35,42 +78,72 @@ export default function Login() {
<div className="row">
<div className="col-12">
<div className="form-group">
<label className="control-label">User Name*</label>
<input type="text" className="form-control" placeholder="Username" />
<label className="control-label text-black fw-bold">User Name*</label>
<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">Password*</label>
<input type="password" className="form-control" placeholder="Password" />
<label className="control-label text-black fw-bold">Password*</label>
<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" />
<label className="form-check-label" htmlFor="gridCheck">
<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>
</div>
<Link to={siteLinks.forgetpwd} className="ml-auto">Forgot Password ?</Link>
</div>
</div>
<div className="col-12 mt-3">
<button type='button' onClick={()=>{navigate(siteLinks.dash)}} className="btn btn-primary text-uppercase">Sign In</button>
{login.error &&
<>
<div className="col-12">
<p className='text-danger'>{login.error.message}</p>
</div>
</>
}
<div className="col-12 mt-3 text-end">
<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>Don't have an account ?<Link to={siteLinks.signup}> Sign Up</Link></p>
</div>
</div>
</form>
<div className="row" style={{marginTop: '20px'}}>
<div className="col-6">
<div className="app-store-icons-wrap text-center">
<a className="icon google"
href='#'
// href="https://play.google.com/store/apps/details?id=com.mermsemr.providers" target="_blank"
>
<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='#'
// href="https://play.google.com/store/apps/details?id=com.mermsemr.providers" target="_blank"
>
<img src={GoogleDownload} className='w-100 h-auto' alt='IOS Download' />
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-sm-6 col-xxl-9 col-lg-7 bg-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>
+132 -67
View File
@@ -1,23 +1,56 @@
import React, { useEffect, useState } from 'react'
import LoginImg from '../../assets/bg/login.svg'
import React, { useState } from 'react'
import { Form, Formik } from "formik";
import * as Yup from "yup";
import MainLoaderBS from '../loaders/MainLoaderBS'
import { Link, useNavigate } from 'react-router-dom'
// import LoginImg from '../../assets/bg/login.svg'
import { Link } from 'react-router-dom'
import siteLinks from '../../links/siteLinks'
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"),
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 = {
email: '',
firstname: '',
lastname: '',
isChecked: false,
// username: '',
// password: ''
};
export default function Signup2() {
const [loading, setLoading] = useState(true)
const mutation = useMutation({
mutationFn: (fields) => {
return signUpUser(fields)
},
onSuccess: (res) => {
console.log('res', res)
}
})
const navigate = useNavigate()
useEffect(()=>{
const timer = setTimeout(()=>{
setLoading(false)
},1000)
return () => clearTimeout(timer)
},[])
const signUp = (values) => {
// helpers.resetForm()
// console.log('values', values, helpers)
mutation.mutate(values)
}
return (
<div className="app">
@@ -26,66 +59,98 @@ export default function Signup2() {
<div className="bg-white">
<div className="container-fluid p-0">
<div className="row no-gutters">
<div class="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1">
<div class="d-flex align-items-center h-100-vh">
<div class="register p-5">
<h1 class="mb-2">MERMS Panel</h1>
<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>
<form class="mt-2 mt-sm-5">
<div class="row">
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label">First Name*</label>
<input type="text" class="form-control" placeholder="First Name" />
<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>
<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>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label">Last Name*</label>
<input type="text" class="form-control" placeholder="Last Name" />
</div>
</div>
<div class="col-12">
<div class="form-group">
<label class="control-label">Email*</label>
<input type="email" class="form-control" placeholder="Email" />
</div>
</div>
<div class="col-12">
<div class="form-group">
<label class="control-label">Username*</label>
<input type="text" class="form-control" placeholder="Username" />
</div>
</div>
<div class="col-12">
<div class="form-group">
<label class="control-label">Password*</label>
<input type="password" class="form-control" placeholder="Password" />
</div>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gridCheck" />
<label class="form-check-label" for="gridCheck">
I accept terms & policy
</label>
</div>
</div>
<div class="col-12 mt-3">
<button type='button' onClick={()=>navigate(siteLinks.dash)} class="btn btn-primary text-uppercase">Sign up</button>
</div>
<div class="col-12 mt-3">
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
</div>
</div>
</form>
</Form>
);
}}
</Formik>
</div>
</div>
</div>
<div className="col-sm-6 col-xxl-9 col-lg-7 bg-gradient o-hidden order-1 order-sm-2">
<div className="signup-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
{/* <img className="img-fluid" src={LoginImg} alt="" /> */}
</div>
</div>
</div>
+89 -5
View File
@@ -1,19 +1,103 @@
import React, { useEffect, useState } from 'react'
import { Outlet } from 'react-router-dom'
import { useDispatch, useSelector } from "react-redux";
import { Outlet, useNavigate } from 'react-router-dom'
import { updateUserDetails } from "../../store/UserDetails";
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';
export default function UserExist() {
const [loading, setLoading] = useState(true)
const {joinRoom} = SocketContextValues() // Destructures values from socket context
const navigate = useNavigate()
const [loading, setLoading] = useState(true)
const dispatch = useDispatch()
const [lastActivityTime, setLastActivityTime] = useState(Date.now()); // HOLDS THE INITIAL TIME USER LOGS IN
const { userDetails: { lastname }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = lastname ? true : false; // variable to determine if user is logged in
// console.log('loggedIn', loggedIn)
// Function to log the user out
const logoutUser = () => {
localStorage.clear()
navigate(siteLinks.login)
window.location.reload()
};
// Function to reset the activity time
const resetTimer = () => {
debounceFunction(setLastActivityTime(Date.now()), 1000)
};
useEffect(()=>{
const timer = setTimeout(()=>{
setLoading(false)
},1000)
if(Date.now() - Number(lastActivityTime) >= Number(process.env.REACT_APP_TIMEOUT)){
logoutUser()
}
}, Number(process.env.REACT_APP_TIMEOUT))
// Listen for activity events
const events = ['mousemove', 'keydown', 'click', 'scroll', 'touchstart'];
// Adding event listeners
events.forEach(event => {
window.addEventListener(event, resetTimer);
});
return () => {
clearTimeout(timer)
events.forEach(event => {
window.removeEventListener(event, resetTimer);
})
}
},[lastActivityTime])
useEffect(()=>{
accountDashboard().then(res => {
const {dash_data} = res?.data
setLoading(false)
dispatch(updateUserDetails({ ...dash_data }));
}).catch(err => {
navigate(siteLinks.login)
setLoading(false)
})
},[])
return () => clearTimeout(timer)
// 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')){
joinRoom(localStorage.getItem('room'));
joinRoom("merms_global_events"); // global room for all
}
},[])
return (
+100 -2
View File
@@ -1,14 +1,112 @@
import React from "react";
import React, { useCallback, useState } from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import EventCalendar from "./EventCalendar";
export default function Calendar(){
const [draggedEvent, setDraggedEvent] = useState('undroppable')
const handleDragStart = useCallback((event) => setDraggedEvent(event), [])
// const dummyEvents = [
// {id: '1', title: 'Family Vacation', color: 'fc-event-primary', start: new Date('2024-12-18'), end: new Date('2024-12-18'), isAllDay: false, resource: ''},
// {id: '2', title: 'Meeting In Office', color: 'fc-event-warning', start: new Date('2024-12-19'), end: new Date('2024-12-19'), isAllDay: false, resource: ''},
// {id: '3', title: 'Client Call', color: 'fc-event-danger', start: new Date('2024-12-20'), end: new Date('2024-12-20'), isAllDay: false, resource: ''},
// {id: '4', title: 'Interview', color: 'fc-event-success', start: new Date('2024-12-21'), end: new Date('2024-12-21'), isAllDay: false, resource: ''}
// ]
const dummyEvents = [
{id: '1', title: 'Family Vacation', color: 'fc-event-primary', isAllDay: false},
{id: '2', title: 'Meeting In Office', color: 'fc-event-warning', isAllDay: false},
{id: '3', title: 'Client Call', color: 'fc-event-danger', isAllDay: false},
{id: '4', title: 'Interview', color: 'fc-event-success', isAllDay: false}
]
return(
<>
<BreadcrumbComBS title='Calendar' paths={['Dashboard', 'Calendar']} />
<div className="row">
<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>
<div className="col-lg-12">
<div className="card card-statistics">
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">Event Calendar</h4>
</div>
</div>
<div className="card-body">
<div className="row">
<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>
{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>
))}
<div className="form-check">
<input className="form-check-input" type="checkbox" value=""
id="defaultCheck1" />
<label className="form-check-label" htmlFor="defaultCheck1">
Remove After Drop
</label>
</div>
</div>
</div>
<div className="col-xl-9">
<div className="event-calendar">
<EventCalendar draggedEvent={draggedEvent} setDraggedEvent={setDraggedEvent} />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Event Modal */}
<div className="modal fade" id="eventModal" tabIndex="-1" role="dialog">
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="verticalCenterTitle">Add New Event</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">
<form>
<div className="form-group">
<label>Event Name</label>
<input type="email" className="form-control" id="eventname" />
</div>
<div className="form-group">
<label>Choose Event Color</label>
<select className="form-control">
<option>Primary</option>
<option>Warning</option>
<option>Success</option>
<option>Danger</option>
</select>
</div>
</form>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-success">Save changes</button>
</div>
</div>
</div>
</div>
</>
)
+130
View File
@@ -0,0 +1,130 @@
import React, { useCallback, useState } from 'react'
import { Calendar, dayjsLocalizer } from 'react-big-calendar'
import dayjs from 'dayjs'
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop'
const localizer = dayjsLocalizer(dayjs)
const DnDCalendar = withDragAndDrop(Calendar)
export default function EventCalendar({draggedEvent, setDraggedEvent}) {
const myEventsList = []
const [myEvents, setMyEvents] = useState(myEventsList)
const moveEvent = useCallback(
({ event, start, end, isAllDay: droppedOnAllDaySlot = false }) => {
// const { isAllDay } = event
// if (!allDay && droppedOnAllDaySlot) {
// event.allDay = true
// }
// if (allDay && !droppedOnAllDaySlot) {
// event.allDay = false;
// }
setMyEvents((prev) => {
const existing = prev.find((ev) => ev.id === event.id) ?? {}
const filtered = prev.filter((ev) => ev.id !== event.id)
return [...filtered, { ...existing, start, end, allDay: event.allDay }]
})
},
[setMyEvents]
)
const [displayDragItemInCell, setDisplayDragItemInCell] = useState(true)
const dragFromOutsideItem = useCallback(() => draggedEvent === 'undroppable' ? null : draggedEvent, [draggedEvent])
const customOnDragOverFromOutside = useCallback(
(dragEvent) => {
// check for undroppable is specific to this example
// and not part of API. This just demonstrates that
// onDragOver can optionally be passed to conditionally
// allow draggable items to be dropped on cal, based on
// whether event.preventDefault is called
if (draggedEvent !== 'undroppable') {
console.log('preventDefault')
dragEvent.preventDefault()
}
},
[draggedEvent]
)
const eventPropGetter = useCallback(
(event) => ({
...(event.isDraggable
? { className: 'isDraggable' }
: { className: 'nonDraggable' }),
}),
[]
)
const newEvent = useCallback(
(event) => {
setMyEvents((prev) => {
const idList = prev.map((item) => item.id)
const newId = Math.max(...idList) + 1
// return [...prev, { ...event, id: newId }]
return [...prev, { ...event}]
})
},
[setMyEvents]
)
const onDropFromOutside = useCallback(
({ start, end, allDay: isAllDay }) => {
if (draggedEvent === 'undroppable') {
setDraggedEvent(null)
return
}
const { title, id } = draggedEvent
const event = {
title: title,
start,
end,
isAllDay,
id
}
setDraggedEvent(null)
newEvent(event)
},
[draggedEvent, setDraggedEvent, newEvent]
)
const resizeEvent = useCallback(
({ event, start, end }) => {
setMyEvents((prev) => {
const existing = prev.find((ev) => ev.id === event.id) ?? {}
const filtered = prev.filter((ev) => ev.id !== event.id)
return [...filtered, { ...existing, start, end }]
})
},
[setMyEvents]
)
return (
<div className='w-100'>
<DnDCalendar
dragFromOutsideItem={
displayDragItemInCell ? dragFromOutsideItem : null
}
eventPropGetter={eventPropGetter}
// draggableAccessor="isDraggable"
localizer={localizer}
events={myEvents}
startAccessor="start"
endAccessor="end"
style={{ height: 500 }}
// onEventResize={resizeEvent}
resizable
onEventDrop={moveEvent}
onDropFromOutside={onDropFromOutside}
// onDragOverFromOutside={customOnDragOverFromOutside}
/>
</div>
)
}
+359 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Comments(){
@@ -8,7 +8,364 @@ export default function Comments(){
<>
<BreadcrumbComBS title='Comments' paths={['Dashboard', 'Comments']} />
<div className="row">
<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
<div className="col-12">
<div className="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>
<ul className="pl-0 mt-5">
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-circle-o text-danger pr-4"></i>
</span>
<span>
<span>Personal</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-circle-o pr-4 text-warning"></i>
</span>
<span>
<span>Work</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-plus pr-4"></i>
</span>
<span>
<span>Add Category</span>
</span>
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-8 col-xxl-4 border-md-t">
<div className="mail-content border-right border-n h-100">
<div className="mail-search border-bottom">
<div className="row align-items-center mx-0">
<div className="col-12">
<div className="form-group pt-3">
<input type="text" className="form-control" id="search" placeholder="Search.." />
<i className="fa fa-search"></i>
</div>
</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>
<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="d-md-flex px-5 py-4">*/}
{/* <div className="flex-fill align-items-center">*/}
{/* <div className="d-flex">*/}
{/* <i className="ti ti-clip pr-3 font-22"></i>*/}
{/* <p className="pr-3 font-weight-bold">Wireframe</p>*/}
{/* <p>(220.MB)</p>*/}
{/* </div>*/}
{/* </div>*/}
{/* <div className="flex-fill text-left text-md-right"><a href="javascript:void(0)" className="text-primary"><i className="ti ti-download pr-2"></i><span>Download</span></a></div>*/}
{/*</div>*/}
<div className="bg-light mail-f px-4 py-3">
<div className="py-2 bg-white px-4 py-3 d-flex justify-content-between">
<p>Click here to <a href="#editer" data-toggle="collapse" className="text-primary px-1">Reply</a>or<a href="#forward" data-toggle="collapse" className="text-primary px-1">Forward</a></p>
<a href="javascript:void(0)" className="text-primary"><i className="fa fa-microphone"></i></a>
</div>
<div className="collapse" id="editer">
<div className="form-group">
<textarea className="form-control mt-3" id="exampleFormControlTextarea1" rows="3" placeholder="Type here..."></textarea>
</div>
</div>
<div className="collapse" id="forward">
<div className="form-group">
<input className="form-control mt-3" id="exampleFormControl" placeholder="Email Address" />
</div>
</div>
<div className="d-flex align-items-center justify-content-between py-2">
<div>
<ul className="nav">
<li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-clip font-20"></i></a></li>
<li className="nav-item pr-3"><a href="javascript:void(0)"><i className="ti ti-face-smile font-20"></i></a></li>
<li className="nav-item"><a href="javascript:void(0)"><i className="ti ti-gallery font-20"></i></a></li>
</ul>
</div>
<div>
<a href="javascript:void(0)" className="btn btn-primary"><span>Send</span> <i className="fa fa-paper-plane"></i></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
+350 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage";
export default function Contacts(){
@@ -8,7 +8,355 @@ export default function Contacts(){
<>
<BreadcrumbComBS title='Contacts' paths={['Dashboard', 'Contacts']} />
<div className="row">
<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
<div className="col-12">
<div className="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>
<ul className="pl-0 mt-5">
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-circle-o text-danger pr-4"></i>
</span>
<span>
<span>Personal</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-circle-o pr-4 text-warning"></i>
</span>
<span>
<span>Work</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="javascript:void(0)">
<span className="nav align-items-center">
<span>
<i className="fa fa-plus pr-4"></i>
</span>
<span>
<span>Add Category</span>
</span>
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-8 col-xxl-4 border-md-t">
<div className="mail-content border-right border-n h-100">
<div className="mail-search border-bottom">
<div className="row align-items-center mx-0">
<div className="col-12">
{/*<div className="form-group pt-3">*/}
{/* <input type="text" className="form-control" id="search" placeholder="Search.." />*/}
{/* <i className="fa fa-search"></i>*/}
{/*</div>*/}
</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>
</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>
</>
)
+80
View File
@@ -0,0 +1,80 @@
import { useQueryClient } from "@tanstack/react-query";
import React, { createContext, useContext, useEffect, useState } from "react";
import { Outlet } from "react-router-dom";
import { io } from "socket.io-client";
import queryKeys from "../../services/queryKeys";
import { socketEmitEvents, socketOnEvents } from "./socketEvents";
// import io from "socket.io-client";
// import { tableReload } from "../../store/TableReloads";
// import { useDispatch, useSelector } from "react-redux";
let SocketIOContext = createContext({})
export default function SocketIOContextProvider({children}) {
const queryClient = useQueryClient()
// const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS IF USER UID, to determine if user is active
// const dispatch = useDispatch()
const socket = io.connect(process.env.REACT_APP_SOCKET_URL);
// // Messages States
// const [message, setMessage] = useState("");
const [socketMsgReceived, setSocketMsgReceived] = useState("");
const joinRoom = (room) => {
if (room !== "") {
return socket.emit("join_room", room);
}
return
};
const sendMessage = (eventType, message, room) => {
if(message && room){
socket.emit(eventType, { message, room });
}
};
useEffect(() => {
socket.on(socketOnEvents.receive_message, (data) => {
// setSocketMsgReceived(data.message);
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
console.log('DATA', data)
queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction],
// type: 'active',
// exact: true,
})
});
// client-side
socket.on("connect", () => {
console.log(socket.id);
});
socket.on("disconnect", () => {
console.log(socket.id);
});
}, [socket]);
let values = {
socket,
sendMessage,
socketMsgReceived,
setSocketMsgReceived,
joinRoom,
}
return (
<SocketIOContext.Provider value={values}>
<Outlet />
</SocketIOContext.Provider>
)
}
export const SocketContextValues = () => {
return useContext(SocketIOContext)
}
+9
View File
@@ -0,0 +1,9 @@
export const socketEmitEvents = {
send_message: 'send_message'
}
export const socketOnEvents = {
receive_message: 'receive_message'
}
+40 -404
View File
@@ -1,9 +1,19 @@
import React from "react";
import React, { useEffect } from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import RecentActions from "./RecentActions";
import Products from "./Products";
import TopBar from "./TopBar";
import ProductsURL from "./ProductsURL";
import { SocketContextValues } from "../context/SocketIOContext";
export default function HomeSections(){
const {sendMessage} = SocketContextValues() // Destructures values from socket context
// useEffect(()=>{
// sendMessage('Hello socket', '2020aklksod')
// },[])
return <>
{/* <div className="row">
<div className="col-md-12 m-b-30">
@@ -29,424 +39,50 @@ export default function HomeSections(){
</div> */}
<BreadcrumbComBS title='Home' paths={['Dashboard', 'Home']} />
<div className="row">
<div 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">$65,456</h3>
<small className="d-block">Last 6 months</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">Revenue</h5>
<strong className="text-danger 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>
<div 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 ecommerce-contant-text m-b-0 h-100">
<div className="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">52%</h3>
<small className="d-block">Past 12 hours</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">Conversion Rate</h5>
<strong className="text-primary m-t-5"><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> 5.35%</strong>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo1" className="chart-fit"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div 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="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">605</h3>
<small className="d-block">Last 90 days</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">Transactions</h5>
<strong className="text-orange m-t-5"><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> 4.65%</strong>
</div>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo2" className="chart-fit"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div 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">5,687</h3>
<small className="d-block">Last 3 months</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">Purchases</h5>
<strong className="text-success m-t-5"><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> 9.89%</strong>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo4" className="chart-fit"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<TopBar />
</div>
<div className="row">
<div className="col-xxl-6 m-b-30">
<div className="card card-statistics h-100 mb-0">
<div className="card-header">
<h4 className="card-title">My Products</h4>
</div>
<div className="card-body pb-0">
<div className="row m-b-20">
<div className="col-xxs-6 col-xl-4 col-xxl-4 mb-2 mb-xxl-0">
<div className="d-flex align-items-center">
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className="fa fa-cart-plus text-primary"></i>
</div>
<div className="report-details">
<p>Annual Sales</p>
<h3>15,236</h3>
</div>
</div>
</div>
<div className="col-xxs-6 col-md-4 col-xxl-4 mb-2 mb-xxl-0">
<div className="d-flex align-items-center">
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className="fa fa-dollar text-primary"></i>
</div>
<div className="report-details">
<p>Annual Revenue</p>
<h3>$40,516</h3>
</div>
</div>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommerce5" className="chart-fit"></div>
</div>
</div>
</div>
<Products />
</div>
<div className="col-xxl-6 m-b-30">
<div className="card card-statistics h-100 mb-0">
<div className="card-header d-sm-flex justify-content-between align-items-center py-3">
<div className="card-heading mb-3 mb-sm-0">
<h4 className="card-title">Recent Actions</h4>
</div>
<div className="dropdown">
{/*<input type="text" className="form-control form-control-sm" placeholder="Search Invoice"/>*/}
</div>
</div>
<div className="card-body scrollbar scroll_dark" style={{maxHeight: '420px'}}>
<div className="d-xxs-flex align-items-center">
<div className="total-sales">
<p>Last Update</p>
<h1>10-10-2021 10 AM</h1>
</div>
<div className="mb-3 mb-sm-0 ml-auto">
{/*<button className="btn btn-primary btn-xs">View All Invoices</button>*/}
</div>
</div>
<div className="d-none d-sm-flex progress m-t-20 m-b-0" style={{height: '5px'}}>
<div className="progress-bar bg-primary" role="progressbar" style={{width: '25%'}}
aria-valuenow="15" aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-warning" role="progressbar" style={{width: '25%'}}
aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-info" role="progressbar" style={{width: '25%'}} aria-valuenow="20"
aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-success" role="progressbar" style={{width: '25%'}}
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div className="row no-gutters">
<div className="col-6 col-xxs-3 ">
<p>Overdue</p>
<h4>$1596</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Outstanding</p>
<h4>$2586</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Open</p>
<h4>$5678</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Paid</p>
<h4>$2458</h4>
</div>
</div>
<div className="table-responsive m-t-20">
<table id="datatable-buttons" className="table">
<thead>
<tr>
<th>No.</th>
<th>Name</th>
<th>Date</th>
<th>Total</th>
<th>Status</th>
</tr>
</thead>
<tbody className="text-muted">
<tr>
<td>1</td>
<td>Smith Drake</td>
<td>27/3/2014</td>
<td>$1,00,000</td>
<td>
<label className="badge mb-0 badge-primary-inverse"> Overdue</label>
</td>
</tr>
<tr>
<td>2</td>
<td>Martha Doe</td>
<td>28/3/2015</td>
<td>$70,000</td>
<td>
<label className="badge mb-0 badge-warning-inverse
"> Outstanding</label>
</td>
</tr>
<tr>
<td>3</td>
<td>Fenish Paul</td>
<td>24/3/2015</td>
<td>$60,000</td>
<td>
<label className="badge mb-0 badge-info-inverse
"> Open</label>
</td>
</tr>
<tr>
<td>4</td>
<td>Albom Mitch</td>
<td>29/3/2016</td>
<td>$60,000</td>
<td>
<label className="badge mb-0 badge-success-inverse
"> Paid</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<RecentActions />
</div>
</div>
<div className="row">
<div className="col-xxl-8 m-b-30">
<div className="card card-statistics h-100 mb-0">
<div className="card-header d-flex align-items-center justify-content-between">
<div className="card-heading">
<h4 className="card-title">Top selling products</h4>
</div>
<div className="dropdown">
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
</div>
</div>
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
<div className="datatable-wrapper table-responsive">
<table id="datatable" className="table table-borderless table-striped">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Price</th>
<th>In stock</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Cold Shoulder Bling Dress</td>
<td>$65.342</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '80%'}}
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-success-inverse">Active</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<tr>
<td>2</td>
<td>PlayStation 4 Pro 1TB Console</td>
<td>$47.655</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '36%'}} aria-valuenow="36" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-success-inverse">Active</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<tr>
<td>3</td>
<td>Extra Fine Wool Jumpers</td>
<td>$56.479</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '60%'}} aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-danger-inverse">Canceled</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<tr>
<td>4</td>
<td>Long Sleeve Bow Top</td>
<td>$04.786</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '50%'}}
aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-success-inverse">Active</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<tr>
<td>5</td>
<td>Shine Stripe Long Sleeve Ruffle</td>
<td>$23.456</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '75%'}}
aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-success-inverse">Active</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<tr>
<td>6</td>
<td>Long Sleeve Micro Thermal Shirt</td>
<td>$65.598</td>
<td>
<div className="progress my-3" style={{height: '3px'}}>
<div className="progress-bar" role="progressbar" style={{width: '90%'}}
aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td><span className="badge badge-info-inverse">info</span></td>
<td><a className="mr-3" href=""><i className="fe fe-edit"></i></a><a
href=""><i className="fe fe-trash-2"></i></a></td>
</tr>
<ProductsURL />
</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>
</div>
</div>
</div>
<div className="col-xxl-4 m-b-30">
<div className="card card-statistics h-100 mb-0">
<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">Lifetime sales</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>
<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>
{/*<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 className="col-lg-8">
<div className="morris-wrapper">
<div id="morrisecommerce1" style={{height: '260px'}}></div>
</div>
</div>
<div className="col-lg-4 mt-4">
<div className="mb-3">
<h3 className="mb-0">680</h3>
<p className="mb-0 text-info">Total sales</p>
</div>
<div className="mb-3">
<h3 className="mb-0">800</h3>
<p className="mb-0 text-primary">Open campaign</p>
</div>
<div className="mb-3">
<h3 className="mb-0">500</h3>
<p className="mb-0">Daily sales</p>
</div>
</div>
.
</div>
</div>
</div>
+75
View File
@@ -0,0 +1,75 @@
import { useQuery } from '@tanstack/react-query'
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';
export default function Products() {
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product,
queryFn: () => productData()
})
const products = data?.data?.products_data?.products
return (
<>
<div className="card card-statistics h-100 mb-0 panel_round_c1">
<div className="card-header">
<h4 className="card-title">My Products</h4>
</div>
<div className="card-body pb-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 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 ">
<Link to={productPath(product?.uid)} >
<div className="d-flex align-items-center extraProductCard">
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className="fa fa-cart-plus text-primary"></i>
</div>
<div className="report-details">
<p>{product?.status}</p>
<h4>{product?.description}</h4>
</div>
</div>
</Link>
</div>
))}
{/*<div style={{backgroundColor: 'green'}} className="col-xxs-6 col-md-4 col-xxl-6 mb-2 mb-xxl-0">*/}
{/* <div className="d-flex align-items-center">*/}
{/* <div className="icon-container img-icon m-r-20 bg-light-gray rounded">*/}
{/* <i className="fa fa-dollar text-primary"></i>*/}
{/* </div>*/}
{/* <div className="report-details">*/}
{/* <p>Annual Revenue</p>*/}
{/* <h3>$40,516</h3>*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
</div>
}
<div className="apexchart-wrapper">
<div id="ecommerce5" className="chart-fit"></div>
</div>
</div>
</div>
</>
)
}
+86
View File
@@ -0,0 +1,86 @@
import React from 'react'
import { productsURL } from '../../services/services'
import { useQuery } from '@tanstack/react-query'
import queryKeys from '../../services/queryKeys'
export default function ProductsURL() {
const {data:data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product_url,
queryFn: () => productsURL()
})
const urlData = data?.data?.url_data?.url
return (
<>
<div className="col-xxl-8 m-b-30">
<div className="card card-statistics h-100 mb-0">
<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 className="dropdown">
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
</div>
</div>
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
<div className="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>Description</th>
<th style={{width: '100px'}}>Status</th>
<th style={{width: '40px'}}>Action</th>
</tr>
</thead>
<tbody>
{urlData && urlData.map((item, index) => {
let statusColor = item?.status == 'Active' ? 'badge-success-inverse' : item?.status == 'Updating' ? 'badge-success-inverse' : item?.status == 'Refreshing' ? 'badge-danger-inverse' : 'badge-info-inverse'
return (
<tr key={index}>
<td>{Number(item?.no) + Number(index)}</td>
<td>{item?.description} - <a href={item?.url} target='_blank'>{item?.url}</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>
</div>
</div>
</div>
</>
)
}
+113
View File
@@ -0,0 +1,113 @@
import React from 'react'
import { useQuery } from "@tanstack/react-query";
import { recentActions } from "../../services/services";
import queryKeys from "../../services/queryKeys";
export default function RecentActions() {
const {data:dataAction, isFetching, isError, error} = useQuery({
queryKey: queryKeys.recentAction,
queryFn: () => recentActions()
})
const actionData = dataAction?.data?.action_data
return (
<>
<div className="card card-statistics h-100 mb-0 panel_round_c2" style={{minHeight: '460px'}}>
<div className="card-header">
<div className="card-heading">
<h4 className="card-title">Recent Actions</h4>
</div>
{/* <div className="dropdown">
<input type="text" className="form-control form-control-sm" placeholder="Search Invoice"/>
</div> */}
</div>
<div className="card-body scrollbar scroll_dark" style={{maxHeight: '450px'}}>
{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="d-xxs-flex align-items-center">
<div className="total-sales">
<p>Last Update</p>
<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>*/}
</div>
</div>
<div className="d-none d-sm-flex progress m-t-20 m-b-0" style={{height: '5px'}}>
<div className="progress-bar bg-primary" role="progressbar" style={{width: '25%'}}
aria-valuenow="15" aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-warning" role="progressbar" style={{width: '25%'}}
aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-info" role="progressbar" style={{width: '25%'}} aria-valuenow="20"
aria-valuemin="0" aria-valuemax="100"></div>
<div className="progress-bar bg-success" role="progressbar" style={{width: '25%'}}
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div className="row no-gutters">
<div className="col-6 col-xxs-3 ">
<p>Initial</p>
<h4>{actionData?.initial}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Processing</p>
<h4>{actionData?.processing}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Verifying</p>
<h4>{actionData?.verifying}</h4>
</div>
<div className="col-6 col-xxs-3 ">
<p>Completed</p>
<h4>{actionData?.completed}</h4>
</div>
</div>
<div className="table-responsive m-t-20">
<table id="datatable-buttons" className="table">
<thead>
<tr>
<th style={{width: '30px'}}>#.</th>
<th>Description</th>
<th style={{width: '100px'}}>Date</th>
<th style={{width: '100px'}}>Status</th>
</tr>
</thead>
<tbody className="text-muted">
{actionData && actionData?.actions.map((action, index) => {
let bgColor = action?.status == 'completed' ? 'badge-success-inverse' : action?.status == 'verifying' ? 'badge-info-inverse' : action?.status == 'processing' ? 'badge-warning-inverse' : 'badge-primary-inverse'
return (
<tr key={index}>
<td>{action?.no}</td>
<td>{action?.description}</td>
<td>{action?.date}</td>
<td>
<label className={`badge mb-0 ${bgColor}`}>{action?.status}</label>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
</>
}
</div>
</div>
</>
)
}
+67
View File
@@ -0,0 +1,67 @@
import { useQuery } from '@tanstack/react-query'
import React from 'react'
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('TOP', 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>
)
})}
</>
}
</>
)
}
+49 -22
View File
@@ -1,46 +1,74 @@
import React from "react";
import getImage from "../../../utils/getImage";
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); // CHECKS IF USER Details are avaliable, to determine if user is active
const toggleSidebar = (e) => {
e.preventDefault()
document.body.classList.toggle('sidebar-toggled')
}
const removeSidebar = (e) => {
e.preventDefault()
document.body.classList.remove('sidebar-toggled')
}
// const toggleSidebarMini = (e) => {
// e.preventDefault()
// }
const navigate = useNavigate()
const logout = () => {
localStorage.clear()
navigate(siteLinks.login, {replace: true})
window.location.reload()
}
return (
<header className="app-header top-bar">
<nav className="navbar navbar-expand-md">
<div className="navbar-header d-flex align-items-center">
<a href="#" className="mobile-toggle"><i className="ti ti-align-right"></i></a>
<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-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 className="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
<button onClick={removeSidebar} className="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<i className="ti ti-align-left"></i>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<div className="navigation d-flex">
<div className="navigation d-flex align-items-center">
<ul className="navbar-nav nav-left">
<li className="nav-item">
<h4 className="text-info pt-1">{userDetails?.account_name}</h4>
{/* <li className="nav-item">
<a href="#" className="nav-link sidebar-toggle">
<i className="ti ti-align-right"></i>
</a>
</li>
</li> */}
<li className="nav-item full-screen d-none d-lg-block" id="btnFullscreen">
{/* <li className="nav-item full-screen d-none d-lg-block" id="btnFullscreen">
<a href="#" className="nav-link expand">
<i className="icon-size-fullscreen"></i>
</a>
</li>
</li> */}
</ul>
{/* ul className="navbar-nav nav-right ml-auto dropdown" */}
<ul className="navbar-nav nav-right ml-auto">
{/* <li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="navbarDropdown2" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<a href="#" className="nav-link dropdown-toggle" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<i className="ti ti-email"></i>
</a>
<div className="dropdown-menu extended animated fadeIn" aria-labelledby="navbarDropdown">
<div className="dropdown-menu extended animated fadeIn" aria-labelledby="dropdownMenuLink">
<ul>
<li className="dropdown-header bg-gradient p-4 text-white text-left">Messages
<label className="label label-info label-round">6</label>
@@ -134,16 +162,16 @@ export default function UserHeader(){
</li>
</ul>
</div>
</li>
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="navbarDropdown3" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
</li> */}
{/* <li className="nav-item dropdown">
<a href="#" className="nav-link dropdown-toggle" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<i className="fe fe-bell"></i>
<span className="notify">
<span className="blink"></span>
<span className="dot"></span>
</span>
</a>
<div className="dropdown-menu extended animated fadeIn" aria-labelledby="navbarDropdown">
<div className="dropdown-menu extended animated fadeIn" aria-labelledby="dropdownMenuLink">
<ul>
<li className="dropdown-header bg-gradient p-4 text-white text-left">Notifications
<a href="#" className="float-right btn btn-square btn-inverse-light btn-xs m-0">
@@ -234,8 +262,8 @@ export default function UserHeader(){
</li>
</ul>
</div>
</li>
<li className="nav-item">
</li> */}
{/* <li className="nav-item">
<a className="nav-link search" href="#">
<i className="ti ti-search"></i>
</a>
@@ -254,8 +282,7 @@ export default function UserHeader(){
</div>
</div>
</li> */}
<li className="nav-item user-profile dropdown">
<li className="nav-item user-profile">
<a href="#" className="nav-link dropdown-toggle" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<img src={getImage('avtar/02.jpg')} alt="avtar-img" />
<span className="bg-success user-status"></span>
@@ -264,10 +291,10 @@ export default function UserHeader(){
<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">Alice Williams</h4>
<small className="text-white">Henry@example.com</small>
<h5 className="text-white mb-0">{userDetails?.firstname} {userDetails?.lastname}</h5>
<small className="text-white">{userDetails.email}</small>
</div>
<a href="#" className="text-white font-20 tooltip-wrapper" data-toggle="tooltip"
<a href="#" onClick={logout} className="text-white font-20 tooltip-wrapper" data-toggle="tooltip"
data-placement="top" title="" data-original-title="Logout"> <i
className="zmdi zmdi-power"></i></a>
</div>
+10 -2
View File
@@ -1,10 +1,18 @@
import React from 'react'
import { Link, useLocation } from 'react-router-dom'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import siteLinks from '../../../links/siteLinks'
import { IoIosArrowDown } from 'react-icons/io'
export default function UserMenu() {
const {pathname} = useLocation()
const navigate = useNavigate()
const logout = () => {
localStorage.clear()
navigate(siteLinks.login, {replace: true})
window.location.reload()
}
return (
<>
<div className="sidebar-nav scrollbar scroll_dark">
@@ -48,7 +56,7 @@ export default function UserMenu() {
<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={siteLinks.login}> Log Out</Link>
<Link className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0" to='' onClick={logout}> Log Out</Link>
</li>
</ul>
</div>
+54
View File
@@ -0,0 +1,54 @@
import React from "react";
import { useQuery } from '@tanstack/react-query'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
// import getImage from "../../utils/getImage";
import ProductStart from "./ProductStart";
import { useLocation } from 'react-router-dom';
import {MyProductData, productData} from "../../services/services";
import queryKeys from "../../services/queryKeys";
export default function ProductFactory(){
const location = useLocation();
const pathname = location.pathname;
// Split the pathname by '/' and get the last element
const lastPart = pathname.split('/').pop();
console.log(lastPart)
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product,
queryFn: () => MyProductData(lastPart)
})
const myproduct_data = data?.data?.myproduct_data
const product_name = myproduct_data?.product_name;
return(
<>
<BreadcrumbComBS title={product_name} paths={['Dashboard', 'Product']} />
<div className="row">
{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>
<ProductStart productData={myproduct_data} />
</div>
}
</div>
</>
)
}
+91
View File
@@ -0,0 +1,91 @@
import React, { useRef } from "react";
import getImage from "../../utils/getImage";
import { Modal } from "bootstrap";
export default function ProductStart(props){
console.log(props)
const productBanner = "product/"+props.productData.banner;
const productTitle = props.productData.title;
const productDescription = props.productData.description;
const promotion_text = props.productData.promotion_text;
const modalRef = useRef()
const hideModal = () => {
// modalRef.current.hide()
// document.body.classList.remove('modal-open')
// const modal = new Modal(document.querySelector('.modal'))
// modal.hide()
}
return (
<>
<div className="row">
<div className="col-md-9">
<div className="card card-statistics ">
<img className="card-img-top" src={getImage(productBanner)} alt="Card image cap" />
<div className="card-body">
<h4 className="card-title">{productTitle}</h4>
<p className="card-text">{productDescription}</p>
</div>
</div>
</div>
<div className="col-md-3">
<div className="card card-statistics mb-30 panel_round_c3">
{/*<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">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 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">Start Product</button>
</div>
</div>
</div>
</div>
{/* Vertical Center Modal */}
<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" id="verticalCenterTitle">Modal title</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">
<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
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,
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 sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean
lacinia bibendum nulla sed consectetur.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-success" onClick={hideModal}>Save changes</button>
</div>
</div>
</div>
</div>
{/* END of Vertical Center Modal */}
</>
)
}
+15 -10
View File
@@ -324,19 +324,19 @@
@include mobile-landscape {
margin:0 !important;
justify-content: space-between;
justify-content: end;
padding:0 30px;
width: 100%;;
}
@include mobile-portrait-sm {
margin:0 !important;
justify-content: space-between;
justify-content: end;
padding:0 30px;
width: 100%;;
}
@include mobile-portrait-xs {
margin:0 !important;
justify-content: space-between;
justify-content: end;
padding:0 30px;
width: 100%;;
}
@@ -588,13 +588,18 @@
left: 0px;
}
}
.show {
.dropdown-menu{
margin-top: 0;
visibility: visible;
opacity: 1;
}
}
.show + .dropdown-menu{
margin-top: 0;
visibility: visible;
opacity: 1;
}
// .show {
// .dropdown-menu{
// margin-top: 0;
// visibility: visible;
// opacity: 1;
// }
// }
}
.nav-item.dropdown, .nav-item.dropup {
@include mobile-landscape {
+63
View File
@@ -84,5 +84,68 @@
@import "pages/coming-soon";
// THIS IMPORTS ARE FOR THE CALENDAR PACKAGE - PLEASE DO NOT REMOVE
$today-highlight-bg: #fcf8e3;
// $btn-color: #fff;
$btn-bg: #8e54e9;
$btn-border: #8e54e9;
$event-padding: 10px;
@import 'react-big-calendar/lib/sass/styles';
@import 'react-big-calendar/lib/addons/dragAndDrop/styles'; // if using DnD
.extraProductCard{
background-color: aliceblue;
border-radius: 5px;
margin: 2px;
}
.subscribe-box{
width: 100%;
padding: 10px;
text-align: center;
}
.panel_round_c1{
background-color: #e6f5f4;
border-radius: 10px;
}
.panel_round_c2{
background-color: #e3dfef;
border-radius: 10px;
}
.panel_round_c3{
background-color: #fcfaf1;
border-radius: 10px;
}
/* CALENDER STYLE HERE */
// .rbc-today{
// background-color: '#fcf8e3' !important;
// }
.rbc-toolbar button {
background: #eceef3;
border: none;
color: #a6a9b7 !important;
text-transform: capitalize;
box-shadow: none!important;
text-shadow: none!important;
border-radius: 3px!important;
margin: 0 3px!important;
padding: 6px 12px!important;
height: auto!important;
}
.rbc-toolbar-label{
color: black !important;
font-size: 1.5rem;
font-weight: 700;
}
// .rbc-month-view{
// border: .5px solid #e8edf1!important;
// }
.rbc-toolbar button.rbc-active, .rbc-toolbar button:active, .rbc-toolbar button:hover{
color: #fff!important;
}
/* END OF CALENDER STYLE */
+7 -2
View File
@@ -1,8 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
// import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import store from './store/store'
import App from './App';
//import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap.min.js'
@@ -14,7 +17,9 @@ const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
</React.StrictMode>
);
+3 -1
View File
@@ -2,6 +2,7 @@ const siteLinks = {
error: '*',
home: '/',
dash: '/dash',
product: '/product/*',
contacts: '/contacts',
comments: '/comments',
reports: '/reports',
@@ -10,7 +11,8 @@ const siteLinks = {
settings: '/settings',
login: '/auth/login',
signup: '/auth/signup',
forgetpwd: '/auth/forgetpwd'
forgetpwd: '/auth/forgetpwd',
csignup: '/csignup/:jwt'
}
export default siteLinks
+9
View File
@@ -0,0 +1,9 @@
const queryKeys = {
dashboard: ['dashboard'],
topBar: ['top-bar'],
recentAction: ['recent-action'],
product: ['product-data'],
product_url: ['product_url']
}
export default queryKeys
+99
View File
@@ -0,0 +1,99 @@
import axios from "axios"
axios.interceptors.request.use(
config => {
config.headers = {
// Accept: "application/json",
"Access-Control-Allow-Origin": "*",
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
// "Content-Type": "application/json;charset=UTF-8",
'Authorization': `Bearer ${localStorage.getItem('token')}`
};
// config.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`;
// config.baseURL = process.env.REACT_APP_MAIN_API
return config;
},
error => {
return Promise.reject(error);
}
);
const postAuxEnd = (path, postData, media=false) => {
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
return axios.post(`${basePath}${path}`, postData).then(res => {
return res
}).catch(err => {
throw new Error(err.response.data.message);
})
}
const getAuxEnd = (path, reqData= null) => {
const basePath = process.env.REACT_APP_MAIN_API
return axios.get(`${basePath}${path}`,{ params: reqData }).then(res => {
return res
// localStorage.clear();
// window.location.href = `/login?sessionExpired=true`;
}).catch(err => {
throw new Error(err);
// throw new Error(err.response.data.message);
// return err
})
}
// FUNCTION TO LOGIN USER IN
export const loginUser = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/auth/login', postData, false)
}
// FUNCTION TO REGISTER USER
export const signUpUser = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/auth/register', postData, false)
}
// FUNCTION TO RESET USER PASSWORD
export const recoverPWD = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/auth/reset', postData, false)
}
// FUNCTION TO GET DASHBOARD DATA
export const accountDashboard = () => {
return getAuxEnd(`/panel/account/dash`)
}
// FUNCTION TO GET DASHBOARD TOP BAR SECTION
export const topBar = () => {
return getAuxEnd(`/panel/account/bar`)
}
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION
export const recentActions = () => {
return getAuxEnd(`/panel/account/actions`)
}
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
export const productData = () => {
return getAuxEnd(`/panel/account/products`)
}
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION
export const productsURL = () => {
return getAuxEnd(`/panel/account/products/url`)
}
export const MyProductData = (productID) => {
const reqData = { product_id : productID}
//console.log(reqData)
return getAuxEnd(`/panel/myproduct/dash`,reqData)
}
+20
View File
@@ -0,0 +1,20 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
userDetails: {},
};
export const userSlice = createSlice({
name: "userDetails",
initialState,
reducers: {
updateUserDetails: (state, action) => {
state.userDetails = { ...action.payload };
},
},
});
// Action creators are generated for each case reducer function
export const { updateUserDetails } = userSlice.actions;
export default userSlice.reducer;
+10
View File
@@ -0,0 +1,10 @@
import { configureStore } from "@reduxjs/toolkit";
import userDetailReducer from "./UserDetails";
export default configureStore({
reducer: {
userDetails: userDetailReducer,
},
});
+15
View File
@@ -0,0 +1,15 @@
function debounceFunction(func, delay) {
let timer;
return function(...args) {
// Clear the previous timer if the function is called before the delay
clearTimeout(timer);
// Set a new timer to execute the function after the specified delay
timer = setTimeout(() => {
func(...args);
}, delay);
};
}
export default debounceFunction
+9
View File
@@ -0,0 +1,9 @@
let productPath = (product_uid) => {
if (!product_uid) {
return "/product/"; // require(`../assets/img/logo.png`);
} else {
return "/product/"+ product_uid; // require(`../assets/img/${location}`);
}
};
export default productPath
+8
View File
@@ -0,0 +1,8 @@
import React from 'react'
import CSignup from '../component/auth/CSignup'
export default function CSignupPage() {
return (
<CSignup />
)
}
+7
View File
@@ -0,0 +1,7 @@
import React from 'react'
import ProductFactory from '../component/product/ProductFactory'
export default function ProductPage() {
return (
<ProductFactory />
)
}