Compare commits

..

48 Commits

Author SHA1 Message Date
victorAnumudu 9684e7fcfa added token and uid to all endpoints 2025-06-26 17:37:11 +01:00
ameye d4eda11477 Merge branch 'products-endpont' of MERMS/MermsPanelReactJS into master 2025-06-25 19:55:14 +00:00
victorAnumudu 1d31507984 new products endpoint added 2025-06-25 19:31:50 +01:00
ameye a3dbc8cab1 Merge branch 'location-reload' of MERMS/MermsPanelReactJS into master 2025-06-25 13:08:28 +00:00
victorAnumudu 29878e3ddf fix location reload error 2025-06-25 13:06:32 +01:00
CHIEFSOFT\ameye 80a40da9df dev .env 2025-06-24 15:57:41 -04:00
ameye 9f7f1b706b Merge branch 'product-endpoint' of MERMS/MermsPanelReactJS into master 2025-06-24 16:18:58 +00:00
victorAnumudu d878d1d098 made product endpoint a POST request 2025-06-24 17:17:36 +01:00
ameye 3a60d4e12c Merge branch 'new-top-bar' of MERMS/MermsPanelReactJS into master 2025-06-24 15:47:48 +00:00
victorAnumudu c03c70b07e auth layout fix 2025-06-24 16:41:05 +01:00
victorAnumudu 9d158fe1cb added new endpoint for top bar data 2025-06-24 16:38:42 +01:00
CHIEFSOFT\ameye ffd80d9888 New urls 2025-06-23 18:12:51 -04:00
CHIEFSOFT\ameye 384da476a6 Hide real build for now 2025-06-23 16:20:55 -04:00
CHIEFSOFT\ameye 3576e7f702 force all to test 2025-06-23 14:55:27 -04:00
ameye 5ed94fee53 Merge branch 'login-new-endpoint' of MERMS/MermsPanelReactJS into master 2025-06-23 18:36:13 +00:00
victorAnumudu dbf81a4cf5 added the new login endpoint 2025-06-23 19:27:15 +01:00
Olusesan Ameye 0984d78f1e Image registry 2025-04-22 09:25:41 +00:00
victorAnumudu ade91c4ed8 added max input length for login username and password 2025-04-01 17:45:42 +01:00
victor.ebuka 905e783f76 Merge branch 'login-box-radius' of MERMS/MermsPanelReactJS into master 2025-01-27 18:08:15 +00:00
victorAnumudu 08665d51a7 border radius added 2025-01-27 19:05:14 +01:00
victor.ebuka dff0bd72ed Merge branch 'login-links-margin' of MERMS/MermsPanelReactJS into master 2025-01-27 13:58:24 +00:00
victorAnumudu 823ff83f88 added top margin to login links 2025-01-27 14:48:46 +01:00
victor.ebuka 82f0efe6e5 Merge branch 'login-page-links' of MERMS/MermsPanelReactJS into master 2025-01-26 02:07:59 +00:00
victorAnumudu 3eaf99f212 added login links and updated contact page design 2025-01-26 03:06:47 +01:00
victor.ebuka 5d93817555 Merge branch 'contact-page-api' of MERMS/MermsPanelReactJS into master 2025-01-24 20:18:33 +00:00
victorAnumudu 4505a6fbcd contact page api added 2025-01-24 21:15:16 +01:00
victorAnumudu 4367364d4f bug fix 2025-01-24 16:03:50 +01:00
victorAnumudu b2b0bf8af6 label color fixed 2025-01-24 15:08:43 +01:00
victor.ebuka fcde22d4cb Merge branch 'calendar_filtering' of MERMS/MermsPanelReactJS into master 2025-01-24 12:40:05 +00:00
victorAnumudu 56125b427d calendar filtering started 2025-01-24 13:38:47 +01:00
victor.ebuka 16066d030b Merge branch 'scroll-fix' of MERMS/MermsPanelReactJS into master 2025-01-23 20:17:08 +00:00
victorAnumudu b6c79303ae contact scroll bar fixed 2025-01-23 21:13:29 +01:00
victor.ebuka ada406eb3f Merge branch 'promotion-api-query-update' of MERMS/MermsPanelReactJS into master 2025-01-23 17:24:18 +00:00
victorAnumudu 9479be61f1 header link fixed 2025-01-23 18:22:50 +01:00
victorAnumudu 9c8405cf1c Merge master into promotion-api-query-update 2025-01-23 18:18:52 +01:00
victorAnumudu 92ddea329d product subscription uid added 2025-01-23 18:18:00 +01:00
CHIEFSOFT\ameye a79ab63163 Removed waste 2025-01-23 11:20:25 -05:00
victor.ebuka d7fce908cc Merge branch 'calendar-api' of MERMS/MermsPanelReactJS into master 2025-01-21 20:16:54 +00:00
victorAnumudu 1708cb893f started calendar api integration 2025-01-21 21:14:03 +01:00
ameye 7ec139c5ad Merge branch 'auth-page-centralized' of MERMS/MermsPanelReactJS into master 2025-01-20 18:35:46 +00:00
ameye 03d395560a Merge branch 'section-removal' of MERMS/MermsPanelReactJS into master 2025-01-20 18:35:41 +00:00
victorAnumudu fa234a7fae auth page centralized 2025-01-20 18:46:36 +01:00
victorAnumudu b869b76602 removed sections not needed 2025-01-20 17:12:52 +01:00
ameye 6f38611606 Merge branch 'confirm-bug' of MERMS/MermsPanelReactJS into master 2025-01-20 12:07:41 +00:00
victorAnumudu 37774c0aa3 bug commented 2025-01-20 13:02:31 +01:00
victor.ebuka 373956da39 Merge branch 'master-bootstrap' of MERMS/MermsPanelReactJS into master 2025-01-20 05:17:17 +00:00
ameye 397eb7c88b Merge branch 'master-bootstrap' of MERMS/MermsPanelReactJS into master 2024-12-27 23:51:45 +00:00
tokslaw 0f0a674fea Merge branch 'master-bootstrap' of MERMS/MermsPanelReactJS into master 2024-12-06 18:33:29 +00:00
31 changed files with 1008 additions and 675 deletions
+7 -1
View File
@@ -1,10 +1,16 @@
SKIP_PREFLIGHT_CHECK=true SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development" REACT_APP_NODE_ENV="development"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com" REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com" REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com" REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com" REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://dev-www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://dev-www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://dev-www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://dev-www.mermsemr.com/terms'
# Inactivity timeout/logout AT 10MINS # Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000 REACT_APP_TIMEOUT=600000
+7 -1
View File
@@ -1,9 +1,15 @@
SKIP_PREFLIGHT_CHECK=true SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="development" REACT_APP_NODE_ENV="development"
REACT_APP_SOCKET_URL="https://dev-socket.mermsemr.com" REACT_APP_SOCKET_URL="https://devsocket.mermsemr.com"
REACT_APP_MAIN_API="https://devapi.mermsemr.com" REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com" REACT_APP_MEDIA_SERVER="https://dev-media.mermsemr.com"
REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com" REACT_APP_MAIN_SOCKET="https://dev-socket.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://dev-www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://dev-www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://dev-www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://dev-www.mermsemr.com/terms'
# Inactivity timeout/logout AT 10MINS # Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000 REACT_APP_TIMEOUT=600000
+7 -1
View File
@@ -1,8 +1,14 @@
SKIP_PREFLIGHT_CHECK=true SKIP_PREFLIGHT_CHECK=true
REACT_APP_NODE_ENV="production" REACT_APP_NODE_ENV="production"
REACT_APP_SOCKET_URL="https://socket.mermsemr.com" REACT_APP_SOCKET_URL="https://socket.mermsemr.com"
REACT_APP_MAIN_API="https://api.mermsemr.com" REACT_APP_MAIN_API="https://devapi.mermsemr.com"
REACT_APP_MEDIA_SERVER="https://media.mermsemr.com" REACT_APP_MEDIA_SERVER="https://media.mermsemr.com"
# login footer links
REACT_APP_HOME_LINK='https://www.mermsemr.com/'
REACT_APP_ABOUT_LINK='https://www.mermsemr.com/about'
REACT_APP_CONTACTS_LINK='https://www.mermsemr.com/contacts'
REACT_APP_TERMS_LINK='https://www.mermsemr.com/terms'
# Inactivity timeout/logout AT 10MINS # Inactivity timeout/logout AT 10MINS
REACT_APP_TIMEOUT=600000 REACT_APP_TIMEOUT=600000
+1 -1
View File
@@ -1,7 +1,7 @@
version: '3' version: '3'
services: services:
merms-panel: merms-panel:
# image: registry.chiefsoft.net/wrenchboard-users-wrench:latest image: registry.chiefsoft.net/merms-panel-reactjs:latest
build: build:
context: . context: .
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
+2 -1
View File
@@ -33,7 +33,8 @@
}, },
"scripts": { "scripts": {
"start": "react-scripts start -e .env.development", "start": "react-scripts start -e .env.development",
"build": "GENERATE_SOURCEMAP=false react-scripts build -e .env.production", "build": "react-scripts start -e .env.development",
"build_real": "GENERATE_SOURCEMAP=false react-scripts build -e .env.production",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
+27
View File
@@ -8,4 +8,31 @@
background-image: url('./assets/bg/signup_bg.jpg') !important; background-image: url('./assets/bg/signup_bg.jpg') !important;
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;
}
.register{
border-radius: 10px;
}
.login-links{
margin-top: 50px;
display: flex;
flex-direction: row;
justify-content: center;
}
.login-links a {
font-size: 15px;
font-weight: 700;
padding: 0px 20px;
border-right: 2px solid;
cursor: pointer;
}
.login-links a:nth-of-type(1){
padding-left: 0px;
}
.login-links a:last-child{
border: 0px;
} }
+1 -1
View File
@@ -11,7 +11,7 @@ function App() {
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
retry: 3, retry: 3,
// refetchOnMount: false, // refetchOnMount: false,
staleTime: 3000 staleTime: Infinity // can also be a number in millisecond
}, },
}, },
}) })
+23 -20
View File
@@ -2,6 +2,7 @@ import { Routes, Route } from 'react-router-dom';
import UserExist from './component/authorization/UserExist'; import UserExist from './component/authorization/UserExist';
import AuthLayout from './component/auth/AuthLayout'; import AuthLayout from './component/auth/AuthLayout';
import BearerToken from './component/authorization/BearerToken';
import siteLinks from './links/siteLinks'; import siteLinks from './links/siteLinks';
import LoginPage from './views/LoginPage'; import LoginPage from './views/LoginPage';
@@ -22,27 +23,29 @@ function AppRouters() {
return ( return (
<div className=""> <div className="">
<Routes> <Routes>
{/* auth routes wrapper */} <Route element={<BearerToken />}>
<Route element={<AuthLayout />}> {/* auth routes wrapper */}
<Route path={siteLinks.home} element={<LoginPage />} /> <Route element={<AuthLayout />}>
<Route path={siteLinks.login} element={<LoginPage />} /> <Route path={siteLinks.home} element={<LoginPage />} />
<Route path={siteLinks.signup} element={<SignupPage />} /> <Route path={siteLinks.login} element={<LoginPage />} />
<Route path={siteLinks.forgetpwd} element={<ForgetpwdPage />} /> <Route path={siteLinks.signup} element={<SignupPage />} />
<Route path={siteLinks.csignup} element={<CSignupPage />} /> <Route path={siteLinks.forgetpwd} element={<ForgetpwdPage />} />
<Route path={siteLinks.error} element={<LoginPage />} /> <Route path={siteLinks.csignup} element={<CSignupPage />} />
</Route> <Route path={siteLinks.error} element={<LoginPage />} />
</Route>
{/* protected routes */} {/* protected routes */}
<Route element={<SocketIOContextProvider />}> <Route element={<SocketIOContextProvider />}>
<Route element={<UserExist />}> <Route element={<UserExist />}>
<Route path={siteLinks.dash} element={<HomePage />} /> <Route path={siteLinks.dash} element={<HomePage />} />
<Route path={siteLinks.product} element={<ProductPage />} /> <Route path={siteLinks.product} element={<ProductPage />} />
<Route path={siteLinks.reports} element={<ReportsPage />} /> <Route path={siteLinks.reports} element={<ReportsPage />} />
<Route path={siteLinks.comments} element={<CommentsPage />} /> <Route path={siteLinks.comments} element={<CommentsPage />} />
<Route path={siteLinks.contacts} element={<ContactsPage />} /> <Route path={siteLinks.contacts} element={<ContactsPage />} />
<Route path={siteLinks.user} element={<UserPage />} /> <Route path={siteLinks.user} element={<UserPage />} />
<Route path={siteLinks.calendar} element={<CalendarPage />} /> <Route path={siteLinks.calendar} element={<CalendarPage />} />
<Route path={siteLinks.settings} element={<SettingsPage />} /> <Route path={siteLinks.settings} element={<SettingsPage />} />
</Route>
</Route> </Route>
</Route> </Route>
</Routes> </Routes>
+2 -2
View File
@@ -86,10 +86,10 @@ export default function CSignup() {
<div className="app"> <div className="app">
<div className="app-wrap"> <div className="app-wrap">
<div className="app-contant"> <div className="app-contant">
<div className="bg-white custom-bg"> <div className="vh-100 bg-white custom-bg">
<div className="container-fluid p-0"> <div className="container-fluid p-0">
<div className="row no-gutters justify-content-center"> <div className="row no-gutters justify-content-center">
<div className="col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1 h-100-vh"> <div className="col-11 col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1">
<div className="mt-5 d-flex"> <div className="mt-5 d-flex">
<div className="bg-white register p-5"> <div className="bg-white register p-5">
<h1 className="mb-2">MERMS Panel</h1> <h1 className="mb-2">MERMS Panel</h1>
+13 -13
View File
@@ -10,7 +10,7 @@ import { recoverPWD } from '../../services/services';
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
username: Yup.string() username: Yup.string()
.email("Wrong email format") // .email("Wrong email format")
// .matches( // .matches(
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/, // /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
// "Invalid email format" // "Invalid email format"
@@ -43,14 +43,14 @@ export default function Forgetpwd2() {
<div className="app"> <div className="app">
<div className="app-wrap"> <div className="app-wrap">
<div className="app-contant"> <div className="app-contant">
<div className="bg-white"> <div className="vh-100 bg-white custom-bg">
<div className="container-fluid p-0"> <div className="container-fluid p-0">
<div className="row no-gutters"> <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"> <div className="col-11 col-sm-6 col-lg-5 col-xxl-3 align-self-center order-2 order-sm-1h">
<div className="d-flex align-items-center h-100-vh"> <div className="mt-5 d-flex">
<div className="login p-50"> <div className="bg-white register p-5">
<h1 className="mb-2">Recover Password</h1> <h1 className="mb-2">MERMS Panel</h1>
<p>Please enter your email.</p> <p>Please enter your username.</p>
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={validationSchema}
@@ -64,8 +64,8 @@ export default function Forgetpwd2() {
<> <>
<div className="col-12"> <div className="col-12">
<div className="form-group"> <div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Email*</label> <label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Username*</label>
<input type="email" name='username' className="form-control" placeholder="Email" value={props.values.username} onChange={props.handleChange} /> <input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
</div> </div>
</div> </div>
{mutation.error && {mutation.error &&
@@ -98,13 +98,13 @@ export default function Forgetpwd2() {
</div> </div>
</div> </div>
</div> </div>
<div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2"> {/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100"> <div className="row align-items-center h-100">
<div className="col-7 mx-auto "> <div className="col-7 mx-auto ">
{/* <img className="img-fluid" src={LoginImg} alt="" /> */} <img className="img-fluid" src={LoginImg} alt="" />
</div> </div>
</div> </div>
</div> </div> */}
</div> </div>
</div> </div>
</div> </div>
+43 -22
View File
@@ -1,6 +1,6 @@
import React, { useState } from 'react' import React, { useEffect, useState } from 'react'
import { useMutation } from '@tanstack/react-query' import { useMutation } from '@tanstack/react-query'
import { useDispatch } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
// import LoginImg from '../../assets/bg/login.svg' // import LoginImg from '../../assets/bg/login.svg'
@@ -14,14 +14,17 @@ import IOSDownload from '../../assets/img/download/apple.jpg'
export default function Login() { export default function Login() {
const { userDetails: { token, room }} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
let loggedIn = token && room ? true : false; // variable to determine if user is logged in
const dispatch = useDispatch() const dispatch = useDispatch()
const navigate = useNavigate() const navigate = useNavigate()
const [fields, setFields] = useState({ const [fields, setFields] = useState({
username: localStorage.getItem('username') || '', username: '',
password: '', password: '',
remember: localStorage.getItem('username') ? true : false remember: false
}) })
const handleChange = ({target:{name, value}}) => { const handleChange = ({target:{name, value}}) => {
@@ -37,20 +40,25 @@ export default function Login() {
throw new Error('Please provide all fields marked *') throw new Error('Please provide all fields marked *')
} }
rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE
delete fields.remember // REMOVING REMEMBER FROM THE PAYLOAD
return loginUser(fields) return loginUser(fields)
}, },
onError: (error) => { onError: (error) => {
console.log(error) console.log(error)
}, },
onSuccess: (res) => { onSuccess: (res) => {
const {token, room} = res?.data?.data if(res?.data?.error_message){
if(token){ throw({message: res?.data?.error_message})
localStorage.setItem('token', token)
localStorage.setItem('room', room)
// const data = {token}
// dispatch(updateUserDetails({ ...data }));
navigate('/dash') // later add redux to dispatch state
} }
const {token, room, uid} = res?.data
if(!token || !room){
throw({message: 'something went wrong, try again!'})
}
localStorage.setItem('token', token)
localStorage.setItem('room', room)
localStorage.setItem('uid', uid)
dispatch(updateUserDetails({ ...res?.data }));
navigate('/dash') // later add redux to dispatch state
} }
}) })
@@ -62,16 +70,22 @@ export default function Login() {
} }
} }
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS ACTIVE
if(loggedIn){
navigate(siteLinks.dash)
}
},[])
return ( return (
<div className="app"> <div className="app">
<div className="app-wrap"> <div className="app-wrap">
<div className="app-contant"> <div className="app-contant">
<div className="bg-white"> <div className="vh-100 custom-bg">
<div className="container-fluid p-0"> <div className="container-fluid p-0">
<div className="row no-gutters"> <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"> <div className="col-11 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="mt-5 d-flex">
<div className="login p-50"> <div className="bg-white register px-5 pt-5 pb-3">
<h1 className="mb-2">MERMS Panel</h1> <h1 className="mb-2">MERMS Panel</h1>
<p>Welcome back, please login to your account.</p> <p>Welcome back, please login to your account.</p>
<form className="mt-3 mt-sm-5"> <form className="mt-3 mt-sm-5">
@@ -79,19 +93,19 @@ export default function Login() {
<div className="col-12"> <div className="col-12">
<div className="form-group"> <div className="form-group">
<label className="control-label text-black fw-bold">User Name*</label> <label className="control-label text-black fw-bold">User Name*</label>
<input name='username' value={fields.username} onChange={handleChange} type="text" className="form-control" placeholder="Username" /> <input maxLength={55} name='username' value={fields.username} onChange={handleChange} type="text" className="form-control" placeholder="Username" />
</div> </div>
</div> </div>
<div className="col-12"> <div className="col-12">
<div className="form-group"> <div className="form-group">
<label className="control-label text-black fw-bold">Password*</label> <label className="control-label text-black fw-bold">Password*</label>
<input name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" /> <input maxLength={55} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
</div> </div>
</div> </div>
<div className="col-12"> <div className="col-12">
<div className="d-block d-sm-flex align-items-center"> <div className="d-block d-sm-flex align-items-center">
<div className="form-check"> <div className="form-check">
<input className="form-check-input" type="checkbox" id="gridCheck" name='remember' checked={fields.remember} onChange={handleChange} disabled={!fields.username ? true : false} /> <input className="form-check-input" type="checkbox" id="gridCheck" name='remember' checked={fields.remember || false} onChange={handleChange} disabled={!fields.username ? true : false} />
<label className="form-check-label text-black" htmlFor="gridCheck"> <label className="form-check-label text-black" htmlFor="gridCheck">
Remember Me Remember Me
</label> </label>
@@ -132,16 +146,23 @@ export default function Login() {
</div> </div>
</div> </div>
</div> </div>
<div className="login-links">
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
</div>
</div> </div>
</div> </div>
</div> </div>
<div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2"> {/* <div className="custom-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100"> <div className="row align-items-center h-100">
<div className="col-7 mx-auto "> <div className="col-7 mx-auto ">
{/* <img className="img-fluid" src={LoginImg} alt="" /> */} <img className="img-fluid" src={LoginImg} alt="" />
</div> </div>
</div> </div>
</div> </div> */}
</div> </div>
</div> </div>
</div> </div>
+86 -86
View File
@@ -56,104 +56,104 @@ export default function Signup2() {
<div className="app"> <div className="app">
<div className="app-wrap"> <div className="app-wrap">
<div className="app-contant"> <div className="app-contant">
<div className="bg-white"> <div className="vh-100 bg-white custom-bg">
<div className="container-fluid p-0"> <div className="container-fluid p-0">
<div className="row no-gutters"> <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"> <div className="col-11 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="mt-5 d-flex">
<div className="register p-5"> <div className="bg-white register p-5">
<h1 className="mb-2">MERMS Panel</h1> <h1 className="mb-2">MERMS Panel</h1>
<p>Welcome, Please create your account.</p> <p>Welcome, Please create your account.</p>
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={signUp} onSubmit={signUp}
> >
{(props) => { {(props) => {
return ( return (
<Form className='mt-2 mt-sm-5'> <Form className='mt-2 mt-sm-5'>
<div className="row"> <div className="row">
{!mutation.isSuccess ? {!mutation.isSuccess ?
<> <>
<div className="col-12 col-sm-6"> <div className="col-12 col-md-6">
<div className="form-group"> <div className="form-group">
<label className={`text-black fw-bold control-label ${(props.errors.firstname && props.touched.firstname) && 'text-danger'}`}>First Name*</label> <label 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} /> <input type="text" name='firstname' className="form-control" placeholder="First Name" value={props.values.firstname} onChange={props.handleChange} />
</div>
</div> </div>
</div> <div className="col-12 col-md-6">
<div className="col-12 col-sm-6"> <div className="form-group">
<div className="form-group"> <label className={`text-black fw-bold control-label ${(props.errors.lastname && props.touched.lastname) && 'text-danger'}`}>Last Name*</label>
<label 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} />
<input type="text" name='lastname' className="form-control" placeholder="Last Name" value={props.values.lastname} onChange={props.handleChange} /> </div>
</div> </div>
</div>
<div className="col-12">
<div className="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"> <div className="col-12">
<p className='text-danger'>{mutation.error.message}</p> <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> </div>
</>
}
<div className="col-12 mt-3 text-end"> {mutation.error &&
<button type='submit' className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button> <>
</div> <div className="col-12">
</> <p className='text-danger'>{mutation.error.message}</p>
: </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 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>
}
<div className="col-12 mt-3">
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
</div> </div>
}
<div className="col-12 mt-3">
<p>Already have an account ?<Link to={siteLinks.login}> Sign In</Link></p>
</div> </div>
</div> </Form>
</Form> );
); }}
}} </Formik>
</Formik>
</div>
</div>
</div>
<div className="signup-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="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 className="signup-bg col-sm-6 col-xxl-9 col-lg-7 b-gradient o-hidden order-1 order-sm-2">
<div className="row align-items-center h-100">
<div className="col-7 mx-auto ">
<img className="img-fluid" src={LoginImg} alt="" />
</div>
</div>
</div> */}
</div> </div>
</div> </div>
</div> </div>
@@ -0,0 +1,47 @@
import {useEffect} from 'react'
import { useMutation } from '@tanstack/react-query'
import { Outlet } from 'react-router-dom'
import MainLoaderBS from '../loaders/MainLoaderBS'
import { userToken } from '../../services/services'
export default function BearerToken() {
const bearerToken = useMutation({
mutationFn: (fields) => {
return userToken(fields)
},
onError: (error) => {
console.log(error)
// window.location.reload(true)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: 'Something went wrong'})
}
const {access_token, refresh_token} = res?.data?.data
if(access_token){
localStorage.setItem('access_token', access_token)
}else{
throw({message: 'Something went wrong'})
}
}
})
useEffect(()=>{
let reqData = {
"username": "user",
"password": "password"
}
bearerToken.mutate(reqData)
},[])
return (
<>
{bearerToken.isPending ?
<MainLoaderBS />
:
<Outlet />
}
</>
)
}
+40 -29
View File
@@ -1,13 +1,15 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Outlet, useNavigate } from 'react-router-dom' import { Outlet, useNavigate } from 'react-router-dom'
import { useMutation } from '@tanstack/react-query'
import { updateUserDetails } from "../../store/UserDetails"; import { updateUserDetails } from "../../store/UserDetails";
import { userInfo } from '../../services/services'
import MainLoaderBS from '../loaders/MainLoaderBS' import MainLoaderBS from '../loaders/MainLoaderBS'
import Layout from '../layout/Layout' import Layout from '../layout/Layout'
import siteLinks from '../../links/siteLinks' import siteLinks from '../../links/siteLinks'
import debounceFunction from '../../utils/debounceFunction' import debounceFunction from '../../utils/debounceFunction'
import { accountDashboard } from '../../services/services';
import { SocketContextValues } from '../context/SocketIOContext'; import { SocketContextValues } from '../context/SocketIOContext';
@@ -23,9 +25,9 @@ export default function UserExist() {
const [lastActivityTime, setLastActivityTime] = useState(Date.now()); // HOLDS THE INITIAL TIME USER LOGS IN 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 const { userDetails: { token, room }} = 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 let loggedIn = token && room ? true : false; // variable to determine if user is logged in
// console.log('loggedIn', loggedIn) // console.log('loggedIn', loggedIn)
// Function to log the user out // Function to log the user out
@@ -40,6 +42,31 @@ export default function UserExist() {
debounceFunction(setLastActivityTime(Date.now()), 1000) debounceFunction(setLastActivityTime(Date.now()), 1000)
}; };
const getUser = useMutation({
mutationFn: (fields) => {
return userInfo(fields)
},
onError: (error) => {
navigate(siteLinks.login)
setLoading(false)
},
onSuccess: (res) => {
const {token, room, uid} = res?.data
if(!token || !room){
navigate(siteLinks.login)
setLoading(false)
return
}
localStorage.setItem('token', token)
localStorage.setItem('room', room)
localStorage.setItem('uid', uid)
dispatch(updateUserDetails({ ...res?.data }));
setLoading(false)
}
})
useEffect(()=>{ useEffect(()=>{
const timer = setTimeout(()=>{ const timer = setTimeout(()=>{
if(Date.now() - Number(lastActivityTime) >= Number(process.env.REACT_APP_TIMEOUT)){ if(Date.now() - Number(lastActivityTime) >= Number(process.env.REACT_APP_TIMEOUT)){
@@ -61,37 +88,21 @@ export default function UserExist() {
window.removeEventListener(event, resetTimer); window.removeEventListener(event, resetTimer);
}) })
} }
},[lastActivityTime]) },[lastActivityTime])
useEffect(()=>{ useEffect(()=>{
accountDashboard().then(res => { let token = localStorage.getItem('token') // USER TOKEN
const {dash_data} = res?.data let uid = localStorage.getItem('uid') // USER UID
if(token && loggedIn){
setLoading(false) setLoading(false)
dispatch(updateUserDetails({ ...dash_data })); }else if(token && uid && !loggedIn){
}).catch(err => { const reqData = {token, uid}
getUser.mutate(reqData)
}else{
navigate(siteLinks.login) navigate(siteLinks.login)
setLoading(false) setLoading(false)
}) }
},[]) },[])
// useEffect(()=>{
// let token = localStorage.getItem('token')
// const timer = setTimeout(()=>{
// if(token && loggedIn){
// setLoading(false)
// }else if(token && !loggedIn){
// const data = {token}
// dispatch(updateUserDetails({ ...data }));
// setLoading(false)
// // dispatch(updateUserDetails({ ...res.data }));
// }else{
// navigate('auth/login')
// }
// },1000)
// return () => clearTimeout(timer)
// },[])
useEffect(()=>{ useEffect(()=>{
if(localStorage.getItem('room')){ if(localStorage.getItem('room')){
+90 -33
View File
@@ -1,8 +1,13 @@
import React, { useCallback, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { useQuery } from '@tanstack/react-query'
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS"; import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import EventCalendar from "./EventCalendar"; import EventCalendar from "./EventCalendar";
import ExternalDraggable from "./ExternalDraggable"; import ExternalDraggable from "./ExternalDraggable";
import { getCalendarEvents } from '../../services/services'
import queryKeys from '../../services/queryKeys'
export default function Calendar(){ export default function Calendar(){
@@ -11,14 +16,16 @@ export default function Calendar(){
// setDraggedEvent(event) // setDraggedEvent(event)
// } // }
const events = [ const {data, isFetching, isError, error} = useQuery({
{id: '1111', title: 'Family Vacation', color: 'fc-event-primary', start: new Date('2025-01-18')}, queryKey: queryKeys.calendar_events,
{id: '2222', title: 'Meeting In Office', color: 'fc-event-warning', start: new Date('2025-01-19')}, queryFn: () => getCalendarEvents()
{id: '3333', title: 'Client Call', color: 'fc-event-danger', start: new Date('2025-01-22')}, })
{id: '4444', title: 'Interview', color: 'fc-event-success', start: new Date('2025-01-1')}
]
const [dummyEvents, setDummyEvents] = useState(events) const receievedEvents = data?.data?.bar_data
const category = receievedEvents?.category //EVENT CATEGORIES FROM API
const eventList = receievedEvents?.list //EVENT LIST FROM API
const [activeCategory, setActiveCategory] = useState('1')
const [removeAfterDrop, setRemoveAfterDrop] = useState(false) const [removeAfterDrop, setRemoveAfterDrop] = useState(false)
@@ -33,11 +40,14 @@ export default function Calendar(){
const handleAddNewEvent = () => { const handleAddNewEvent = () => {
if(newEvent.title && newEvent.color){ if(newEvent.title && newEvent.color){
const eventToAdd = {...newEvent} const eventToAdd = {...newEvent}
setDummyEvents(prev => ([...prev, eventToAdd])) // setDefaultCategory(prev => ([...prev, eventToAdd]))
setNewEvent({title: '', color: ''}) setNewEvent({title: '', color: ''})
} }
} }
const handleActiveCategory = (id) => {
setActiveCategory(id)
}
return( return(
<> <>
@@ -52,40 +62,87 @@ export default function Calendar(){
</div> </div>
<div className="card-body"> <div className="card-body">
<div className="row"> <div className="row">
<div className="col-xl-3"> {isFetching ?
<div id="external-events"> <>
<button className="btn btn-primary btn-block" data-bs-toggle="modal" data-bs-target="#eventModal"> <div className="col-12">
<p className='text-mute'>Loading...</p>
</div>
</>
: isError ?
<div className="col-12">
<p className='text-danger'>{error.message}</p>
</div>
:
<>
<div className="col-xl-3">
{/* <button className="btn btn-primary btn-block" data-bs-toggle="modal" data-bs-target="#eventModal">
Add New Event Add New Event
</button> </button>
<p className="mt-3"> <p className="mt-3">
Drag and drop your event or click in the calendar. Drag and drop your event or click in the calendar.
</p> </p> */}
{/* {dummyEvents.map((item, index) => (
<div key={index} className={`fc-event ${item.color}`} data-color={`${item.color}`} {category.map((item, index) => {
draggable="true" let color = item?.cid == '1' ? 'fc-event-success' : item?.cid == '2' ? 'fc-event-danger' : item?.cid == '3' ? 'fc-event-warning' : 'fc-event-primary'
onDragStart={() => let circleColor = item?.cid == '1' ? 'text-success' : item?.cid == '2' ? 'text-danger' : item?.cid == '3' ? 'text-warning' : 'text-primary'
handleDragStart({...item}) return (
} // <div key={index} className={`fc-event ${color}`} data-color={`${color}`}
> // // draggable={false}
<span></span> {item.title} // // onDragStart={() =>
</div> // // handleDragStart({...item})
))} */} // // }
<ExternalDraggable dummyEvents={dummyEvents} /> // >
<div className="form-check"> // <span>{item.description}</span>
// </div>
// <div key={index} className={`form-check ${color}`}>
// <input className="form-check-input" type="radio" value={item.cid}
// id={item.cid} name='category' checked={item.cid == activeCategory} onChange={() => handleActiveCategory(item.cid)} />
// <label className={`w-100 form-check-label`} htmlFor={item.cid}>
// {item.description}
// </label>
// </div>
<div key={index} className={`form-check ${color}`} onClick={() => handleActiveCategory(item.cid)} style={{cursor: 'pointer'}}>
<div>
<span className="nav align-items-center">
<span>
<i className={`fa fa-circle-o pr-4 ${item.cid == activeCategory ? circleColor : 'text-light'}`}></i>
</span>
<span>
<span>{item?.description}</span>
</span>
</span>
</div>
</div>
)
}
)}
{/* <div id="external-events">
<ExternalDraggable category={category} />
</div> */}
{/* <div className="form-check">
<input className="form-check-input" type="checkbox" value={removeAfterDrop} <input className="form-check-input" type="checkbox" value={removeAfterDrop}
id="defaultCheck1" onChange={() => setRemoveAfterDrop(prev => !prev)} /> id="defaultCheck1" onChange={() => setRemoveAfterDrop(prev => !prev)} />
<label className="form-check-label" htmlFor="defaultCheck1"> <label className="form-check-label" htmlFor="defaultCheck1">
Remove After Drop Remove After Drop
</label> </label>
</div> */}
</div>
<div className="col-xl-9">
<div className="event-calendar">
<EventCalendar
removeAfterDrop={removeAfterDrop}
eventList={eventList}
activeCategory={activeCategory}
/>
</div> </div>
</div> </div>
</div> </>
<div className="col-xl-9"> }
<div className="event-calendar">
{/* <EventCalendar draggedEvent={draggedEvent} setDraggedEvent={setDraggedEvent} /> */}
<EventCalendar removeAfterDrop={removeAfterDrop} setDummyEvents={setDummyEvents} />
</div>
</div>
</div> </div>
</div> </div>
+27 -19
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { formatDate } from '@fullcalendar/core'; import { formatDate } from '@fullcalendar/core';
import FullCalendar from '@fullcalendar/react'; import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid'; import dayGridPlugin from '@fullcalendar/daygrid';
@@ -6,9 +6,9 @@ import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction'; import interactionPlugin from '@fullcalendar/interaction';
import { INITIAL_EVENTS, createEventId } from './event-utils'; import { INITIAL_EVENTS, createEventId } from './event-utils';
export default function EventCalendar({draggedEvent, setDraggedEvent, removeAfterDrop, setDummyEvents}) { export default function EventCalendar({removeAfterDrop, eventList, activeCategory}) {
const [weekendsVisible, setWeekendsVisible] = useState(true); const [weekendsVisible, setWeekendsVisible] = useState(true);
const [currentEvents, setCurrentEvents] = useState(INITIAL_EVENTS); const [currentEvents, setCurrentEvents] = useState([]);
function handleWeekendsToggle() { function handleWeekendsToggle() {
setWeekendsVisible(!weekendsVisible); setWeekendsVisible(!weekendsVisible);
@@ -51,9 +51,9 @@ export default function EventCalendar({draggedEvent, setDraggedEvent, removeAfte
...event ...event
} }
setCurrentEvents(prev => ([...prev, newEvent])) setCurrentEvents(prev => ([...prev, newEvent]))
if(removeAfterDrop){ // if(removeAfterDrop){
setDummyEvents(prev => prev.filter(item => item.title != newEvent.title)) // setDummyEvents(prev => prev.filter(item => item.title != newEvent.title))
} // }
} }
} }
@@ -64,27 +64,34 @@ export default function EventCalendar({draggedEvent, setDraggedEvent, removeAfte
} }
function handleEventClick(clickInfo) { // function handleEventClick(clickInfo) {
if ( // if (
confirm( // confirm(
`Are you sure you want to delete the event '${clickInfo.event.title}'` // `Are you sure you want to delete the event '${clickInfo.event.title}'`
) // )
) { // ) {
clickInfo.event.remove(); // clickInfo.event.remove();
} // }
} // }
function handleEvents(events) { function handleEvents(events) {
// setCurrentEvents(events); // setCurrentEvents(events);
} }
useEffect(()=>{
// let newEventList = eventList?.map(item => ({...item, start: new Date(item?.start)}))
let newEventList = eventList?.filter(item => (Number(item.category) == Number(activeCategory)))?.map(item => ({...item, start: new Date(item?.start)}))
console.log('newEventList', newEventList)
setCurrentEvents(newEventList)
},[activeCategory])
return ( return (
<div className="demo-app"> <div className="demo-app">
<div className="demo-app-main"> <div className="demo-app-main">
<FullCalendar <FullCalendar
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]} plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
headerToolbar={{ headerToolbar={{
left: 'prev next today', left: 'prev,next,today',
center: 'title', center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay', right: 'dayGridMonth,timeGridWeek,timeGridDay',
}} }}
@@ -96,17 +103,18 @@ export default function EventCalendar({draggedEvent, setDraggedEvent, removeAfte
weekends={weekendsVisible} weekends={weekendsVisible}
// initialEvents={INITIAL_EVENTS} // alternatively, use the `events` setting to fetch from a feed // initialEvents={INITIAL_EVENTS} // alternatively, use the `events` setting to fetch from a feed
events={currentEvents} events={currentEvents}
select={handleDateSelect}
eventContent={renderEventContent} // custom render function eventContent={renderEventContent} // custom render function
eventClick={handleEventClick}
eventsSet={handleEvents} // called after events are initialized/added/changed/removed eventsSet={handleEvents} // called after events are initialized/added/changed/removed
// select={handleDateSelect}
// eventClick={handleEventClick}
/* you can update a remote database when these fire: /* you can update a remote database when these fire:
eventAdd={function(){}} eventAdd={function(){}}
eventChange={function(){}} eventChange={function(){}}
eventRemove={function(){}} eventRemove={function(){}}
*/ */
eventRemove={removeEvent} // eventBackgroundColor='purple'
// eventRemove={removeEvent}
droppable= {true} // this allows things to be dropped onto the calendar droppable= {true} // this allows things to be dropped onto the calendar
drop={onDrop} drop={onDrop}
/> />
+17 -6
View File
@@ -1,9 +1,16 @@
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { Draggable } from "@fullcalendar/interaction"; import { Draggable } from "@fullcalendar/interaction";
const ExternalDraggable = ({dummyEvents}) => { const ExternalDraggable = ({category}) => {
const eventContainerRef = useRef(null); const eventContainerRef = useRef(null);
const events = [
{id: '1111', title: 'Family Vacation', color: 'fc-event-primary', start: new Date('2025-01-18')},
{id: '2222', title: 'Meeting In Office', color: 'fc-event-warning', start: new Date('2025-01-19')},
{id: '3333', title: 'Client Call', color: 'fc-event-danger', start: new Date('2025-01-22')},
{id: '4444', title: 'Interview', color: 'fc-event-success', start: new Date('2025-01-1')}
]
useEffect(() => { useEffect(() => {
// Make the external events draggable // Make the external events draggable
const draggable = new Draggable(eventContainerRef.current, { const draggable = new Draggable(eventContainerRef.current, {
@@ -21,11 +28,15 @@ const ExternalDraggable = ({dummyEvents}) => {
return ( return (
<div ref={eventContainerRef} className="external-events"> <div ref={eventContainerRef} className="external-events">
{dummyEvents.map((item, index) => ( {category && category.map((item, index) => {
<div key={index} className={`fc-event ${item.color}`} data-color={`${item.color}`} > let color = index % 4 === 0 ? 'fc-event-success' : index % 3 === 0 ? 'fc-event-danger' : index % 2 === 0 ? 'fc-event-warning' : 'fc-event-primary'
{item.title} return (
</div> <div key={item?.cid || index} className={`fc-event ${color}`} data-color={`${color}`} >
))} {item.description}
</div>
)
}
)}
</div> </div>
); );
}; };
+13 -13
View File
@@ -2,19 +2,19 @@ let eventGuid = 0;
let todayStr = new Date().toISOString().replace(/T.*$/, ''); // YYYY-MM-DD of today let todayStr = new Date().toISOString().replace(/T.*$/, ''); // YYYY-MM-DD of today
export const INITIAL_EVENTS = [ export const INITIAL_EVENTS = [
// { {
// id: createEventId(), id: createEventId(),
// title: 'All-day event', title: 'All-day event',
// start: new Date('2025-01-19'), start: new Date('2025-01-19'),
// end: new Date('2025-01-20'), end: new Date('2025-01-20'),
// // color: 'blue' // color: 'blue'
// }, },
// { {
// id: createEventId(), id: createEventId(),
// title: 'Timed event', title: 'Timed event',
// start: todayStr + 'T12:00:00', start: todayStr + 'T12:00:00',
// // color: 'red' // color: 'red'
// }, },
]; ];
export function createEventId() { export function createEventId() {
+1 -1
View File
@@ -18,7 +18,7 @@ export default function Comments(){
<div className="row justify-content-center"> <div className="row justify-content-center">
<div className="col-12"> <div className="col-12">
<div className="text-center mail-sidebar-title px-4"> <div className="text-center mail-sidebar-title px-4">
<a href="javascript:void(0)" className="btn btn-primary btn-block py-3 font-weight-bold font-18">className= <i className="fa fa-plus pl-2"></i></a> <a href="javascript:void(0)" className="btn btn-primary btn-block py-3 font-weight-bold font-18"><i className="fa fa-plus pl-2"></i></a>
</div> </div>
</div> </div>
<div className="col-12"> <div className="col-12">
+251 -329
View File
@@ -1,354 +1,276 @@
import React from "react"; "use client"
import React, { useEffect, useState } from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS"; import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage"; import getImage from "../../utils/getImage";
import { useQuery } from "@tanstack/react-query";
import { contactData } from "../../services/services";
import queryKeys from "../../services/queryKeys";
import getCustomTime from "../../utils/getCustomTime";
export default function Contacts(){ export default function Contacts(){
const {data:contacts, isFetching, isError, error} = useQuery({
queryKey: queryKeys.contacts,
queryFn: () => contactData()
})
const contactsData = contacts?.data?.calendar_data?.contacts // LIST OF CONTACTS
const contactsCategory = contacts?.data?.calendar_data?.category // LIST OF CATEGORY
const [activeCategoryUID, setActiveCategoryUID] = useState('0') // HOLDS VALUE OF THE ACTIVE CATEGORY
const [activeContactUID, setActiveContactUID] = useState(null)
const [activeDetail, setActiveDetail] = useState(null)
const [filteredContactData, setFiltererdContactData] = useState(null)
const changeActiveUID = (uid) => {
setActiveContactUID(uid)
let detail = contactsData.filter(item => item.uid == uid)
setActiveDetail(detail)
}
const changeActiveCategoryUID = (id) => {
let filteredConData = []
setActiveCategoryUID(id)
if(id == '0'){
filteredConData = contactsData
}else{
filteredConData = contactsData.filter(item => item.category == id)
}
setFiltererdContactData(filteredConData)
changeActiveUID(filteredConData[0]?.uid)
}
return( return(
<> <>
<BreadcrumbComBS title='Contacts' paths={['Dashboard', 'Contacts']} /> <BreadcrumbComBS title='Contacts' paths={['Dashboard', 'Contacts']} />
<div className="row"> {isFetching ?
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/} <>
<div className="col-12"> <div className="row">
<div className="card card-statistics mail-contant"> <div className="col-12">
<div className="card-body p-0"> <p className='text-mute'>Loading...</p>
<div className="row no-gutters"> </div>
<div className="col-md-4 col-xxl-2 col-md-4"> </div>
<div className="mail-sidebar"> </>
<div className="row justify-content-center"> : isError ?
<div className="col-12"> <div className="row">
<div className="text-center mail-sidebar-title px-4"> <div className="col-12">
<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> <p className='text-danger'>{error.message}</p>
</div>
</div>
:
<div className="row">
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
<div className="col-12">
<div className="card card-statistics mail-contant">
<div className="card-body p-0">
<div className="row no-gutters">
<div className="col-md-4 col-xxl-2 col-md-4">
<div className="mail-sidebar">
<div className="row justify-content-center">
<div className="d-none col-12">
<div className="text-center mail-sidebar-title px-4">
<a href="#" className="btn btn-primary btn-block py-3 font-weight-bold font-18"><i className="fa fa-plus pl-2"></i></a>
</div>
</div> </div>
</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="col-12">
{/*<div className="form-group pt-3">*/} <div className="px-4 py-4">
{/* <input type="text" className="form-control" id="search" placeholder="Search.." />*/} <ul className="pl-0">
{/* <i className="fa fa-search"></i>*/} <li className="py-2">
{/*</div>*/} <a href="#">
<span className="nav align-items-center">
<span>
<i className="fa fa-envelope-o text-primary pr-4"></i>
</span>
<span>
<span>Inbox</span>
</span>
<span className="nav-item ml-auto text-right">
<span className="badge badge-pill badge-primary float-right">{contactsData?.length}</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="#">
<span className="nav align-items-center">
<span>
<i className="fa fa-paper-plane-o pr-4"></i>
</span>
<span>
<span>Replied Mail</span>
</span>
</span>
</a>
</li>
</ul>
<ul className="pl-0 mt-5">
<li className="py-2" onClick={()=>changeActiveCategoryUID('0')} style={{cursor: 'pointer'}}>
<div>
<span className="nav align-items-center">
<span>
<i className={`fa fa-circle-o pr-4 ${activeCategoryUID == '0' ? 'text-primary' : 'text-warning'}`}></i>
</span>
<span>
<span>All</span>
</span>
</span>
</div>
</li>
{contactsCategory && contactsCategory.map(item => (
<li key={item?.product_id} className="py-2" onClick={()=>changeActiveCategoryUID(item?.product_id)} style={{cursor: 'pointer'}}>
<div>
<span className="nav align-items-center">
<span>
<i className={`fa fa-circle-o pr-4 ${activeCategoryUID == item?.product_id ? 'text-primary' : 'text-warning'}`}></i>
</span>
<span>
<span>{item?.title}</span>
</span>
</span>
</div>
</li>
))}
{/* <li className="py-2">
<a href="#">
<span className="nav align-items-center">
<span>
<i className="fa fa-circle-o pr-4 text-warning"></i>
</span>
<span>
<span>Work</span>
</span>
</span>
</a>
</li>
<li className="py-2">
<a href="#">
<span className="nav align-items-center">
<span>
<i className="fa fa-plus pr-4"></i>
</span>
<span>
<span>Add Category</span>
</span>
</span>
</a>
</li> */}
</ul>
</div>
</div> </div>
</div> </div>
</div> </div>
<div className="mail-msg scrollbar scroll_dark"> </div>
<div className="mail-msg-item"> <div className="col-md-8 col-xxl-4 border-md-t">
<a href="javascript:void(0)"> <div className="mail-content border-right border-n h-100">
<div className="media align-items-center"> <div className="mail-search border-bottom">
<div className="mr-3"> <div className="row align-items-center mx-0">
<div className="bg-img"> <div className="col-12">
<img src={getImage("avtar/01.jpg")} className="img-fluid" alt="user" /> {/*<div className="form-group pt-3">*/}
</div> {/* <input type="text" className="form-control" id="search" placeholder="Search.." />*/}
</div> {/* <i className="fa fa-search"></i>*/}
<div className="w-100"> {/*</div>*/}
<div className="mail-msg-item-titel justify-content-between">
<p>Martin smith</p>
<p className="d-none d-xl-block">06:59 <span> PM </span></p>
</div>
<h5 className="mb-0 my-2">Saas Designer</h5>
<p>Since there is not an "all the above" category, I'll take the opportunity to enthusiastically congratulate you on the very high quality.</p>
<p className="d-xl-none">06:59 <span> PM </span></p>
</div>
</div> </div>
</a> </div>
</div> </div>
<div className="mail-msg-item"> <div className="mail-msg scrollbar scroll_dark">
<a href="javascript:void(0)"> {contactsData && (filteredContactData || contactsData).map((contact, index)=> {
<div className="media align-items-center"> const isActive = (contact.uid == activeContactUID) || (!activeContactUID && index == 0)
<div className="mr-3"> return (
<div className="bg-img"> <div key={contact.uid} onClick={()=>changeActiveUID(contact.uid)} className={`mail-msg-item ${isActive && 'bg-light'}`}>
<img src={getImage("avtar/02.jpg")} className="img-fluid" alt="user" /> <a href="#">
</div> <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>{contact.sender}</p>
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
<p className="d-none d-xl-block"><span>{new Date(contact.added).toDateString()}</span></p>
</div>
<h5 className="mb-0 my-2">{contact.title}</h5>
<p>{contact.message.length < 100 ? contact.message : contact.message.substring(0,101) + ' ...' }</p>
<p className="d-xl-none">
<span>
{new Date(contact.added).toDateString()}
{/* {getCustomTime(contact.added)} */}
</span>
</p>
</div>
</div>
</a>
</div> </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> </div>
</div> <div className="col-xxl-6 border-t border-xxl-t">
<div className="col-xxl-6 border-t border-xxl-t">
<div className="mail-chat py-5 px-5">
<div className="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="mail-chat py-5 px-5">
<div className="py-2 bg-white px-4 py-3 d-flex justify-content-between"> <div className="media align-items-center">
<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> <div className="bg-img mr-3">
<a href="javascript:void(0)" className="text-primary"><i className="fa fa-microphone"></i></a> <img src={getImage("avtar/03.jpg")} className="img-fluid" alt="user" />
</div> </div>
<div className="collapse" id="editer"> <div>
<div className="form-group"> <h4 className="mb-0">{activeContactUID ? activeDetail[0].sender : contactsData[0].sender}</h4>
<textarea className="form-control mt-3" id="exampleFormControlTextarea1" rows="3" placeholder="Type here..."></textarea> <p>{activeContactUID ? new Date(activeDetail[0].added).toDateString() : new Date(contactsData[0].added).toDateString()}</p>
</div>
</div> </div>
</div> <div className="mt-4 d-flex justify-content-between">
<div className="collapse" id="forward"> <div>
<div className="form-group"> <h3>{activeContactUID ? activeDetail[0].title : contactsData[0].title}</h3>
<input className="form-control mt-3" id="exampleFormControl" placeholder="Email Address" /> </div>
</div> <div className="d-flex">
</div> {/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
<div className="d-flex align-items-center justify-content-between py-2"> {/*<a href="javascript:void(0)"><i className="fa fa-print font-22"></i></a>*/}
<div> </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>
<div> <div>
{/*<a href="javascript:void(0)" className="btn btn-primary"><span>Send</span> <i className="fa fa-paper-plane"></i></a>*/} <p>{activeContactUID ? activeDetail[0].message : contactsData[0].message}</p>
{/* <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="#" 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>
@@ -357,7 +279,7 @@ export default function Contacts(){
</div> </div>
</div> </div>
</div> </div>
</div> }
</> </>
) )
} }
+30 -25
View File
@@ -1,29 +1,34 @@
import { useQuery } from '@tanstack/react-query' import React, {useEffect} from 'react'
import React from 'react' import { useMutation } from '@tanstack/react-query'
import { productData } from '../../services/services' import { productsData } from '../../services/services'
import queryKeys from '../../services/queryKeys'
import productPath from "../../utils/productpath"; import productPath from "../../utils/productpath";
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
export default function Products() {
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.product, export default function Products() {
queryFn: () => productData() const getProductsData = useMutation({
mutationFn: (reqData) => {
return productsData(reqData)
},
onError: (error) => {
console.log(error)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: 'Something went wrong'})
}
}
}) })
/*
{ useEffect(()=>{
"banner": "p1.jpg", let reqData = {
"description": "Your personal professional web presence", token: localStorage.getItem('token'), // USER TOKEN
"id": 1, uid: localStorage.getItem('uid') // USER UID
"name": "Personal Website", }
"product_id": "A000001", getProductsData.mutate(reqData)
"product_uid": "e92282b4-3ee1-4026-92ac-12cfd214b43a", },[])
"status": 5,
"status_text": "Activate Now" const products = getProductsData?.data?.data?.products_data // PRODUCTS DATA
},
*/
//const products = data?.data?.products_list?.products
const products = data?.data?.products_list
return ( return (
<> <>
@@ -32,7 +37,7 @@ export default function Products() {
<h4 className="card-title">My Products</h4> <h4 className="card-title">My Products</h4>
</div> </div>
<div className="card-body pb-0"> <div className="card-body pb-0">
{isFetching ? {getProductsData?.isPending ?
<> <>
<div className="row"> <div className="row">
<div className="col-12"> <div className="col-12">
@@ -40,10 +45,10 @@ export default function Products() {
</div> </div>
</div> </div>
</> </>
: isError ? : getProductsData?.isPending ?
<div className="row"> <div className="row">
<div className="col-12"> <div className="col-12">
<p className='text-danger'>{error.message}</p> <p className='text-danger'>{getProductsData?.error?.message}</p>
</div> </div>
</div> </div>
: :
+28 -12
View File
@@ -1,20 +1,36 @@
import { useQuery } from '@tanstack/react-query' import React, {useEffect} from 'react'
import React from 'react' import { useMutation } from '@tanstack/react-query'
import { topBar } from '../../services/services' import { topBar } from '../../services/services'
import queryKeys from '../../services/queryKeys'
export default function TopBar() { export default function TopBar() {
const {data, isFetching, isError, error} = useQuery({ const topBarData = useMutation({
queryKey: queryKeys.topBar, mutationFn: (reqData) => {
queryFn: () => topBar() return topBar(reqData)
}) },
onError: (error) => {
console.log(error)
},
onSuccess: (res) => {
if(res?.data?.resultCode != '0'){
throw({message: 'Something went wrong'})
}
}
})
const topData = data?.data?.bar_data?.top_bar useEffect(()=>{
let reqData = {
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
topBarData.mutate(reqData)
},[])
const data = topBarData?.data?.data?.top_bar // top bar data
return ( return (
<> <>
{isFetching ? {topBarData.isPending ?
<> <>
<div className="col-12"> <div className="col-12">
<div className="card p-4"> <div className="card p-4">
@@ -22,15 +38,15 @@ export default function TopBar() {
</div> </div>
</div> </div>
</> </>
: isError ? : topBarData.error ?
<div className="col-12"> <div className="col-12">
<div className="card p-4"> <div className="card p-4">
<p className='text-danger'>{error.message}</p> <p className='text-danger'>{topBarData.error.message}</p>
</div> </div>
</div> </div>
: :
<> <>
{topData && topData?.map((item, index)=>{ {data && data?.map((item, index)=>{
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success' let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
return ( return (
<div key={item.id + index} className="col-sm-6 col-xxl-3"> <div key={item.id + index} className="col-sm-6 col-xxl-3">
+67
View File
@@ -0,0 +1,67 @@
import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { topBar } from '../../services/services'
import queryKeys from '../../services/queryKeys'
export default function TopBar() {
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.topBar,
queryFn: () => topBar()
})
const topData = data?.data?.bar_data?.top_bar
console.log('topData', topData)
return (
<>
{isFetching ?
<>
<div className="col-12">
<div className="card p-4">
<p className='text-mute'>Loading...</p>
</div>
</div>
</>
: isError ?
<div className="col-12">
<div className="card p-4">
<p className='text-danger'>{error.message}</p>
</div>
</div>
:
<>
{topData && topData?.map((item, index)=>{
let textColor = item?.description == 'Contacts' ? 'text-danger' : item?.description == 'Site Traffic' ? 'text-primary' : item?.description == 'Appointments' ? 'text-orange' : 'text-success'
return (
<div key={item.id + index} className="col-sm-6 col-xxl-3">
<div className="card card-statistics ecommerce-contant overflow-h">
<div className="card-body p-0">
<div className="d-flex m-b-0 ecommerce-contant-text h-100">
<div className="w-100">
<div className="row p-3">
<div className="col">
<h3 className="mb-0">{item?.value || 0}</h3>
<small className="d-block">{item?.data_span}</small>
</div>
<div className="col text-right">
<h5 className="text-muted mb-0">{item?.description}</h5>
<strong className={`${textColor} m-t-5`}><i
className="zmdi zmdi-long-arrow-up font-weight-bold"></i> N/A</strong>
</div>
</div>
<div className="apexchart-wrapper">
<div id="ecommercedemo3" className="chart-fit"></div>
</div>
</div>
</div>
</div>
</div>
</div>
)
})}
</>
}
</>
)
}
+24 -22
View File
@@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import getImage from "../../../utils/getImage"; import getImage from "../../../utils/getImage";
import { useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import siteLinks from "../../../links/siteLinks"; import siteLinks from "../../../links/siteLinks";
@@ -83,31 +83,33 @@ export default function UserHeader(){
</div> </div>
</div> </div>
<div className="p-4"> <div className="p-4">
<a className="dropdown-item d-flex nav-link" href="#"> <Link className="dropdown-item d-flex nav-link" to={siteLinks.user}>
<i className="fa fa-user pr-2 text-success"></i> Profile</a> <i className="fa fa-user pr-2 text-success"></i> Users</Link>
<a className="dropdown-item d-flex nav-link" href="#"> <Link className="dropdown-item d-flex nav-link" to={siteLinks.contacts}>
<i className="fa fa-envelope pr-2 text-primary"></i> Inbox <i className="fa fa-envelope pr-2 text-primary"></i> Contacts
<span className="badge badge-primary ml-auto">6</span> <span className="badge badge-primary ml-auto">6</span>
</a> </Link>
<a className="dropdown-item d-flex nav-link" href="#"> <Link className="dropdown-item d-flex nav-link" to={siteLinks.settings}>
<i className=" ti ti-settings pr-2 text-info"></i> Settings <i className=" ti ti-settings pr-2 text-info"></i> Settings
</a> </Link>
<a className="dropdown-item d-flex nav-link" href="#"> <a className="dropdown-item d-flex nav-link" href="#">
<i className="fa fa-compass pr-2 text-warning"></i> Need help?</a> <i className="fa fa-compass pr-2 text-warning"></i> Need help?</a>
<div className="row mt-2">
<div className="col"> {/*<div className="row mt-2">*/}
<a className="bg-light p-3 text-center d-block" href="#"> {/* <div className="col">*/}
<i className="fe fe-mail font-20 text-primary"></i> {/* <a className="bg-light p-3 text-center d-block" href="#">*/}
<span className="d-block font-13 mt-2">My messages</span> {/* <i className="fe fe-mail font-20 text-primary"></i>*/}
</a> {/* <span className="d-block font-13 mt-2">My messages</span>*/}
</div> {/* </a>*/}
<div className="col"> {/* </div>*/}
<a className="bg-light p-3 text-center d-block" href="#"> {/* <div className="col">*/}
<i className="fe fe-plus font-20 text-primary"></i> {/* <a className="bg-light p-3 text-center d-block" href="#">*/}
<span className="d-block font-13 mt-2">Compose new</span> {/* <i className="fe fe-plus font-20 text-primary"></i>*/}
</a> {/* <span className="d-block font-13 mt-2">Compose new</span>*/}
</div> {/* </a>*/}
</div> {/* </div>*/}
{/*</div>*/}
</div> </div>
</div> </div>
</li> </li>
+7 -1
View File
@@ -12,11 +12,17 @@ export default function ProductProvision(props){
const productTitle = props?.productData?.title; const productTitle = props?.productData?.title;
const productDescription = props?.productData?.description; const productDescription = props?.productData?.description;
const productID = props?.productData?.product_id const productID = props?.productData?.product_id
const productUID = props?.productData?.product_uid
const productSubUID = props?.productData?.product_subscription_uid const productSubUID = props?.productData?.product_subscription_uid
const reqData = {
product_id : productID,
product_subscription_uid: productSubUID
}
const {data:provision, isFetching, isError, error} = useQuery({ const {data:provision, isFetching, isError, error} = useQuery({
queryKey: queryKeys.myproduct_provision, queryKey: queryKeys.myproduct_provision,
queryFn: () => productProvision(productID) queryFn: () => productProvision(reqData)
}) })
const provisionData = provision?.data?.provision const provisionData = provision?.data?.provision
+14 -1
View File
@@ -31,13 +31,14 @@
.fc-event { .fc-event {
border-radius: 2px; border-radius: 2px;
border: none; border: none;
cursor: move; // cursor: move;
font-size: 13px; font-size: 13px;
margin: 5px 0px; margin: 5px 0px;
padding: 10px 10px 10px 40px; padding: 10px 10px 10px 40px;
text-align: left; text-align: left;
position:relative; position:relative;
&:before { &:before {
display: none;
content:''; content:'';
position:absolute; position:absolute;
width:15px; width:15px;
@@ -49,6 +50,9 @@
&-primary { &-primary {
@include hex-rgba($primary, 0.2); @include hex-rgba($primary, 0.2);
color:$primary; color:$primary;
& label {
color:$primary;
}
&:before { &:before {
@include hex-rgba($primary, 0.8); @include hex-rgba($primary, 0.8);
} }
@@ -59,6 +63,9 @@
&-warning { &-warning {
@include hex-rgba($warning, 0.2); @include hex-rgba($warning, 0.2);
color:$warning; color:$warning;
& label {
color:$warning;
}
&:before { &:before {
@include hex-rgba($warning, 0.8); @include hex-rgba($warning, 0.8);
} }
@@ -69,6 +76,9 @@
&-danger { &-danger {
@include hex-rgba($danger, 0.2); @include hex-rgba($danger, 0.2);
color:$danger; color:$danger;
& label {
color:$danger;
}
&:before { &:before {
@include hex-rgba($danger, 0.8); @include hex-rgba($danger, 0.8);
} }
@@ -79,6 +89,9 @@
&-success { &-success {
@include hex-rgba($success, 0.2); @include hex-rgba($success, 0.2);
color:$success; color:$success;
& label {
color:$success;
}
&:before { &:before {
@include hex-rgba($success, 0.8); @include hex-rgba($success, 0.8);
} }
+1 -1
View File
@@ -41,7 +41,7 @@
} }
.mail-msg{ .mail-msg{
max-height: 747px; max-height: 747px;
overflow: hidden; overflow-y: auto;
outline: none; outline: none;
@include laptop { @include laptop {
max-height: 450px; max-height: 450px;
+16 -2
View File
@@ -138,14 +138,28 @@ $event-padding: 10px;
.fc-today-button.fc-button, .fc-today-button.fc-button,
.fc-timeGridWeek-button.fc-button-active, .fc-timeGridDay-button.fc-button-active, .fc-dayGridMonth-button.fc-button-active{ .fc-timeGridWeek-button.fc-button-active, .fc-timeGridDay-button.fc-button-active, .fc-dayGridMonth-button.fc-button-active{
color: #fff!important; color: #fff !important;
border: none; border: none;
background-color: #8E54E9!important; background-color: #8E54E9 !important;
text-transform: capitalize !important; text-transform: capitalize !important;
} }
.fc-h-event,
.fc-event.fc-event-draggable.fc-event-start.fc-event-end.fc-daygrid-event, .fc-event.fc-event-draggable.fc-event-start.fc-event-end.fc-daygrid-event,
.fc-event.fc-event-draggable.fc-event-start.fc-event-end.fc-daygrid-event{ .fc-event.fc-event-draggable.fc-event-start.fc-event-end.fc-daygrid-event{
padding: 10px 2px !important; padding: 10px 2px !important;
background-color: #3788d8 !important;
color: white;
} }
.fc-theme-standard .fc-popover{
overflow-y: auto !important;
// height: calc(100% - 50px);
}
.fc .fc-more-popover .fc-popover-body {
overflow-y: auto;
height: 100px !important;
}
/* END OF CALENDER STYLE */ /* END OF CALENDER STYLE */
+5 -1
View File
@@ -1,10 +1,14 @@
const queryKeys = { const queryKeys = {
user_details: ['user_details'],
dashboard: ['dashboard'], dashboard: ['dashboard'],
topBar: ['top-bar'], topBar: ['top-bar'],
recentAction: ['recent-action'], recentAction: ['recent-action'],
product: ['product-data'], product: ['product-data'],
product_url: ['product_url'], product_url: ['product_url'],
myproduct_provision: ['myproduct_provision'] myproduct_provision: ['myproduct_provision'],
calendar_events: ['calendar_events'],
contacts: ['contacts']
} }
export default queryKeys export default queryKeys
+98 -31
View File
@@ -4,12 +4,13 @@ import axios from "axios"
axios.interceptors.request.use( axios.interceptors.request.use(
config => { config => {
config.headers = { config.headers = {
// Accept: "application/json", Accept: "application/json",
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin", // "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token", // "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
// "Content-Type": "application/json;charset=UTF-8", // "Content-Type": "application/json;charset=UTF-8",
'Authorization': `Bearer ${localStorage.getItem('token')}` 'Authorization': (localStorage && localStorage.getItem('access_token')) ? `Bearer ${localStorage.getItem('access_token')}` : '',
// 'uuid': 'dummy'
}; };
// config.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`; // config.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`;
// config.baseURL = process.env.REACT_APP_MAIN_API // config.baseURL = process.env.REACT_APP_MAIN_API
@@ -25,7 +26,7 @@ const postAuxEnd = (path, postData, media=false) => {
return axios.post(`${basePath}${path}`, postData).then(res => { return axios.post(`${basePath}${path}`, postData).then(res => {
return res return res
}).catch(err => { }).catch(err => {
throw new Error(err.response.data.message); throw new Error(err.response.data.msg);
}) })
} }
@@ -42,12 +43,70 @@ const getAuxEnd = (path, reqData= null) => {
}) })
} }
// FUNCTION TO AUTHORIZE USER IN
export const userToken = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/Authorize', postData, false)
}
// FUNCTION TO LOGIN USER IN // FUNCTION TO LOGIN USER IN
export const loginUser = (reqData) => { export const loginUser = (reqData) => {
let postData = { let postData = {
...reqData ...reqData
} }
return postAuxEnd('/panel/auth/login', postData, false) return postAuxEnd('/panel/Login', postData, false)
}
// FUNCTION TO GET USER INFO DATA
export const userInfo = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/account', postData, false)
}
// FUNCTION TO GET DASHBOARD TOP BAR SECTION
export const topBar = (reqData) => {
let postData = {
...reqData,
}
return postAuxEnd(`/panel/account/bar`, postData, false)
}
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION
export const recentActions = (reqData) => {
let postData = {
...reqData,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
//return getAuxEnd(`/panel/account/actions`)
return postAuxEnd(`/panel/account/actions`, postData, false)
}
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
export const productsData = (reqData) => {
let postData = {
...reqData,
}
return postAuxEnd(`/panel/account/products`, postData, false)
}
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION
export const productsURL = (reqData) => {
let postData = {
...reqData,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
return postAuxEnd(`/panel/account/products/url`, postData, false)
// return getAuxEnd(`/panel/account/products/url`)
} }
// FUNCTION TO REGISTER USER // FUNCTION TO REGISTER USER
@@ -77,9 +136,11 @@ export const completeRegistration = (reqData) => {
// FUNCTION TO SUBSCRIBE // FUNCTION TO SUBSCRIBE
export const subscribe = (reqData) => { export const subscribe = (reqData) => {
let postData = { let postData = {
...reqData ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
} }
return postAuxEnd('/panel/myproduct/subscription', postData, false) return postAuxEnd(`/panel/myproduct/subscription`, postData, false)
} }
@@ -91,39 +152,45 @@ export const recoverPWD = (reqData) => {
return postAuxEnd('/panel/auth/reset', postData, false) return postAuxEnd('/panel/auth/reset', postData, false)
} }
// FUNCTION TO GET DASHBOARD DATA // FUNCTION TO GET CALENDAR EVENTS
export const accountDashboard = () => { export const getCalendarEvents = (reqData) => {
return getAuxEnd(`/panel/account/dash`) let postData = {
} ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
// FUNCTION TO GET DASHBOARD TOP BAR SECTION uid: localStorage.getItem('uid') // USER UID
export const topBar = () => { }
return getAuxEnd(`/panel/account/bar`) return postAuxEnd(`/panel/account/calendar`, postData, false)
}
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION
export const recentActions = () => {
return getAuxEnd(`/panel/account/actions`)
} }
// FUNCTION TO GET MY PRODUCT PROVISION DATA // FUNCTION TO GET MY PRODUCT PROVISION DATA
export const productProvision = (productID) => { export const productProvision = (reqData) => {
const reqData = { product_id : productID} let postData = {
return getAuxEnd(`/panel/myproduct/provision`,reqData) ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
return postAuxEnd(`/panel/myproduct/provision`, postData, false)
// return getAuxEnd(`/panel/myproduct/provision`, postData)
} }
// FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION // FUNCTION TO GET DASHBOARD PRODUCT DATA SECTION
export const productData = () => { export const contactData = (reqData) => {
return getAuxEnd(`/panel/account/products`) let postData = {
} ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION uid: localStorage.getItem('uid') // USER UID
export const productsURL = () => { }
return getAuxEnd(`/panel/account/products/url`) return postAuxEnd(`/panel/contacts`, postData, false)
// return getAuxEnd(`/panel/contacts`)
} }
export const MyProductData = (productID) => { export const MyProductData = (productID) => {
const reqData = { product_id : productID} const reqData = { product_id : productID}
//console.log(reqData) let postData = {
return getAuxEnd(`/panel/myproduct/dash`,reqData) ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID
}
return postAuxEnd(`/panel/myproduct/dash`, postData, false)
// return getAuxEnd(`/panel/myproduct/dash`,reqData)
} }
+13
View File
@@ -0,0 +1,13 @@
function getCustomTime(dateStr) {
let date = new Date(dateStr);
if(isNaN(date)){
return '00:00'
}
const hours = date.getHours()
const minutes = date.getMinutes()
return `${hours}:${minutes} ${hours >= 12 ? 'PM' : 'AM'}`
}
export default getCustomTime