Compare commits

..

25 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
18 changed files with 507 additions and 181 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
@@ -9,3 +9,30 @@
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>
+36 -15
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,6 +70,12 @@ 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">
@@ -71,7 +85,7 @@ export default function Login() {
<div className="row no-gutters justify-content-center"> <div className="row no-gutters justify-content-center">
<div className="col-11 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="mt-5 d-flex"> <div className="mt-5 d-flex">
<div className="bg-white register p-5"> <div className="bg-white register px-5 pt-5 pb-3">
<h1 className="mb-2">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,6 +146,13 @@ 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>
@@ -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 />
}
</>
)
}
+38 -27
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)){
@@ -64,35 +91,19 @@ export default function UserExist() {
},[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')){
joinRoom(localStorage.getItem('room')); joinRoom(localStorage.getItem('room'));
+21 -6
View File
@@ -85,6 +85,7 @@ export default function Calendar(){
{category.map((item, index) => { {category.map((item, index) => {
let color = item?.cid == '1' ? 'fc-event-success' : item?.cid == '2' ? 'fc-event-danger' : item?.cid == '3' ? 'fc-event-warning' : 'fc-event-primary' let color = item?.cid == '1' ? 'fc-event-success' : item?.cid == '2' ? 'fc-event-danger' : item?.cid == '3' ? 'fc-event-warning' : 'fc-event-primary'
let circleColor = item?.cid == '1' ? 'text-success' : item?.cid == '2' ? 'text-danger' : item?.cid == '3' ? 'text-warning' : 'text-primary'
return ( return (
// <div key={index} className={`fc-event ${color}`} data-color={`${color}`} // <div key={index} className={`fc-event ${color}`} data-color={`${color}`}
// // draggable={false} // // draggable={false}
@@ -94,12 +95,26 @@ export default function Calendar(){
// > // >
// <span>{item.description}</span> // <span>{item.description}</span>
// </div> // </div>
<div key={index} className={`form-check ${color}`}>
<input className="form-check-input" type="radio" value={item.cid} // <div key={index} className={`form-check ${color}`}>
id={item.cid} name='category' checked={item.cid == activeCategory} onChange={() => handleActiveCategory(item.cid)} /> // <input className="form-check-input" type="radio" value={item.cid}
<label className={`w-100 form-check-label`} htmlFor={item.cid}> // id={item.cid} name='category' checked={item.cid == activeCategory} onChange={() => handleActiveCategory(item.cid)} />
{item.description} // <label className={`w-100 form-check-label`} htmlFor={item.cid}>
</label> // {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>
) )
} }
+65 -29
View File
@@ -14,18 +14,34 @@ export default function Contacts(){
queryFn: () => contactData() queryFn: () => contactData()
}) })
const contactsData = contacts?.data?.calendar_data?.contacts 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 [activeContactUID, setActiveContactUID] = useState(null)
const [activeDetail, setActiveDetail] = useState(null) const [activeDetail, setActiveDetail] = useState(null)
const [filteredContactData, setFiltererdContactData] = useState(null)
const changeActiveUID = (uid) => { const changeActiveUID = (uid) => {
setActiveContactUID(uid) setActiveContactUID(uid)
let detail = contactsData.filter(item => item.uid == uid) let detail = contactsData.filter(item => item.uid == uid)
setActiveDetail(detail) 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']} />
@@ -53,16 +69,16 @@ export default function Contacts(){
<div className="col-md-4 col-xxl-2 col-md-4"> <div className="col-md-4 col-xxl-2 col-md-4">
<div className="mail-sidebar"> <div className="mail-sidebar">
<div className="row justify-content-center"> <div className="row justify-content-center">
<div className="col-12"> <div className="d-none 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"><i className="fa fa-plus pl-2"></i></a> <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="col-12">
<div className="px-4 py-4"> <div className="px-4 py-4">
<ul className="pl-0"> <ul className="pl-0">
<li className="py-2"> <li className="py-2">
<a href="javascript:void(0)"> <a href="#">
<span className="nav align-items-center"> <span className="nav align-items-center">
<span> <span>
<i className="fa fa-envelope-o text-primary pr-4"></i> <i className="fa fa-envelope-o text-primary pr-4"></i>
@@ -71,13 +87,13 @@ export default function Contacts(){
<span>Inbox</span> <span>Inbox</span>
</span> </span>
<span className="nav-item ml-auto text-right"> <span className="nav-item ml-auto text-right">
<span className="badge badge-pill badge-primary float-right">0+</span> <span className="badge badge-pill badge-primary float-right">{contactsData?.length}</span>
</span> </span>
</span> </span>
</a> </a>
</li> </li>
<li className="py-2"> <li className="py-2">
<a href="javascript:void(0)"> <a href="#">
<span className="nav align-items-center"> <span className="nav align-items-center">
<span> <span>
<i className="fa fa-paper-plane-o pr-4"></i> <i className="fa fa-paper-plane-o pr-4"></i>
@@ -90,21 +106,36 @@ export default function Contacts(){
</li> </li>
</ul> </ul>
<ul className="pl-0 mt-5"> <ul className="pl-0 mt-5">
<li className="py-2"> <li className="py-2" onClick={()=>changeActiveCategoryUID('0')} style={{cursor: 'pointer'}}>
<a href="javascript:void(0)"> <div>
<span className="nav align-items-center"> <span className="nav align-items-center">
<span> <span>
<i className="fa fa-circle-o text-danger pr-4"></i> <i className={`fa fa-circle-o pr-4 ${activeCategoryUID == '0' ? 'text-primary' : 'text-warning'}`}></i>
</span> </span>
<span> <span>
<span>Personal</span> <span>All</span>
</span> </span>
</span> </span>
</a> </div>
</li> </li>
<li className="py-2"> {contactsCategory && contactsCategory.map(item => (
<a href="javascript:void(0)"> <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 className="nav align-items-center">
<span> <span>
<i className="fa fa-circle-o pr-4 text-warning"></i> <i className="fa fa-circle-o pr-4 text-warning"></i>
@@ -116,7 +147,7 @@ export default function Contacts(){
</a> </a>
</li> </li>
<li className="py-2"> <li className="py-2">
<a href="javascript:void(0)"> <a href="#">
<span className="nav align-items-center"> <span className="nav align-items-center">
<span> <span>
<i className="fa fa-plus pr-4"></i> <i className="fa fa-plus pr-4"></i>
@@ -126,7 +157,7 @@ export default function Contacts(){
</span> </span>
</span> </span>
</a> </a>
</li> </li> */}
</ul> </ul>
</div> </div>
</div> </div>
@@ -146,7 +177,7 @@ export default function Contacts(){
</div> </div>
</div> </div>
<div className="mail-msg scrollbar scroll_dark"> <div className="mail-msg scrollbar scroll_dark">
{contactsData && contactsData.map((contact, index)=> { {contactsData && (filteredContactData || contactsData).map((contact, index)=> {
const isActive = (contact.uid == activeContactUID) || (!activeContactUID && index == 0) const isActive = (contact.uid == activeContactUID) || (!activeContactUID && index == 0)
return ( return (
<div key={contact.uid} onClick={()=>changeActiveUID(contact.uid)} className={`mail-msg-item ${isActive && 'bg-light'}`}> <div key={contact.uid} onClick={()=>changeActiveUID(contact.uid)} className={`mail-msg-item ${isActive && 'bg-light'}`}>
@@ -161,11 +192,16 @@ export default function Contacts(){
<div className="mail-msg-item-titel justify-content-between"> <div className="mail-msg-item-titel justify-content-between">
<p>{contact.sender}</p> <p>{contact.sender}</p>
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */} {/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
<p className="d-none d-xl-block"><span>{getCustomTime(contact.added)}</span></p> <p className="d-none d-xl-block"><span>{new Date(contact.added).toDateString()}</span></p>
</div> </div>
<h5 className="mb-0 my-2">{contact.title}</h5> <h5 className="mb-0 my-2">{contact.title}</h5>
<p>{contact.message.length < 150 ? contact.message : contact.message.substring(0,151) + '...' }</p> <p>{contact.message.length < 100 ? contact.message : contact.message.substring(0,101) + ' ...' }</p>
<p className="d-xl-none"><span>{getCustomTime(contact.added)}</span></p> <p className="d-xl-none">
<span>
{new Date(contact.added).toDateString()}
{/* {getCustomTime(contact.added)} */}
</span>
</p>
</div> </div>
</div> </div>
</a> </a>
@@ -184,7 +220,7 @@ export default function Contacts(){
</div> </div>
<div> <div>
<h4 className="mb-0">{activeContactUID ? activeDetail[0].sender : contactsData[0].sender}</h4> <h4 className="mb-0">{activeContactUID ? activeDetail[0].sender : contactsData[0].sender}</h4>
<p>{activeContactUID ? getCustomTime(activeDetail[0].added) : getCustomTime(contactsData[0].added)}</p> <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="mt-4 d-flex justify-content-between">
@@ -212,7 +248,7 @@ export default function Contacts(){
<div className="bg-light mail-f px-4 py-3"> <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"> <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> <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> <a href="#" className="text-primary"><i className="fa fa-microphone"></i></a>
</div> </div>
<div className="collapse" id="editer"> <div className="collapse" id="editer">
<div className="form-group"> <div className="form-group">
+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>
)
})}
</>
}
</>
)
}
+2
View File
@@ -1,4 +1,6 @@
const queryKeys = { const queryKeys = {
user_details: ['user_details'],
dashboard: ['dashboard'], dashboard: ['dashboard'],
topBar: ['top-bar'], topBar: ['top-bar'],
recentAction: ['recent-action'], recentAction: ['recent-action'],
+96 -39
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,49 +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
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 CALENDAR EVENTS // FUNCTION TO GET CALENDAR EVENTS
export const getCalendarEvents = () => { export const getCalendarEvents = (reqData) => {
return getAuxEnd(`/panel/account/calendar`) let postData = {
} ...reqData,
token: localStorage.getItem('token'), // USER TOKEN
// FUNCTION TO GET DASHBOARD RECENT ACTIONS SECTION uid: localStorage.getItem('uid') // USER UID
export const recentActions = () => { }
return getAuxEnd(`/panel/account/actions`) return postAuxEnd(`/panel/account/calendar`, postData, false)
} }
// FUNCTION TO GET MY PRODUCT PROVISION DATA // FUNCTION TO GET MY PRODUCT PROVISION DATA
export const productProvision = (reqData) => { export const productProvision = (reqData) => {
const postData = { ...reqData } let postData = {
return getAuxEnd(`/panel/myproduct/provision`, postData) ...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 DATA SECTION uid: localStorage.getItem('uid') // USER UID
export const contactData = () => { }
return getAuxEnd(`/panel/contacts`) return postAuxEnd(`/panel/contacts`, postData, false)
} // return getAuxEnd(`/panel/contacts`)
// FUNCTION TO GET DASHBOARD PRODUCT URL DATA SECTION
export const productsURL = () => {
return getAuxEnd(`/panel/account/products/url`)
} }
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)
} }