Added better app loading and error handling
This commit is contained in:
parent
2ccf770525
commit
60f62df55a
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@ -39,10 +39,10 @@ node {
|
||||
remote.allowAnyHosts = true
|
||||
|
||||
// Copy the build directory to the remote server
|
||||
sshPut remote: remote, from: 'build/*', into: '/srv/farmcontrol-server/'
|
||||
sshPut remote: remote, from: 'build/*', into: '/srv/farmcontrol-ui/'
|
||||
|
||||
// Restart the service using sudo
|
||||
sshCommand remote: remote, command: 'sudo /bin/systemctl restart farmcontrol-server.service'
|
||||
sshCommand remote: remote, command: 'sudo /bin/systemctl restart nginx.service'
|
||||
}
|
||||
|
||||
echo 'Pipeline completed successfully!'
|
||||
|
||||
20
src/App.jsx
20
src/App.jsx
@ -6,7 +6,7 @@ import {
|
||||
Navigate
|
||||
} from 'react-router-dom'
|
||||
import { App, ConfigProvider } from 'antd'
|
||||
import AuthLayout from './components/Auth/AuthLayout.jsx'
|
||||
|
||||
import ProductionOverview from './components/Dashboard/Production/ProductionOverview'
|
||||
|
||||
import Printers from './components/Dashboard/Production/Printers'
|
||||
@ -43,10 +43,9 @@ import StockAuditInfo from './components/Dashboard/Inventory/StockAudits/StockAu
|
||||
|
||||
import Dashboard from './components/Dashboard/common/Dashboard'
|
||||
import PrivateRoute from './components/PrivateRoute'
|
||||
import PublicRoute from './components/PublicRoute.jsx'
|
||||
import './App.css'
|
||||
import { SocketProvider } from './components/Dashboard/context/SocketContext.js'
|
||||
import { AuthProvider } from './components/Auth/AuthContext.js'
|
||||
import { AuthProvider } from './components/Dashboard/context/AuthContext.js'
|
||||
import { SpotlightProvider } from './components/Dashboard/context/SpotlightContext.js'
|
||||
import StockEvents from './components/Dashboard/Inventory/StockEvents.jsx'
|
||||
import Settings from './components/Dashboard/Management/Settings'
|
||||
@ -54,6 +53,7 @@ import {
|
||||
ThemeProvider,
|
||||
useThemeContext
|
||||
} from './components/Dashboard/context/ThemeContext'
|
||||
import AppError from './components/App/AppError'
|
||||
|
||||
const AppContent = () => {
|
||||
const { themeConfig } = useThemeContext()
|
||||
@ -79,11 +79,6 @@ const AppContent = () => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='login'
|
||||
element={<PublicRoute component={() => <AuthLayout />} />}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path='/dashboard'
|
||||
element={<PrivateRoute component={() => <Dashboard />} />}
|
||||
@ -175,6 +170,15 @@ const AppContent = () => {
|
||||
/>
|
||||
<Route path='management/settings' element={<Settings />} />
|
||||
</Route>
|
||||
<Route
|
||||
path='*'
|
||||
element={
|
||||
<AppError
|
||||
message='404! Page not found.'
|
||||
showRefresh={false}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Router>
|
||||
</SpotlightProvider>
|
||||
|
||||
65
src/components/App/AppError.jsx
Normal file
65
src/components/App/AppError.jsx
Normal file
@ -0,0 +1,65 @@
|
||||
import React from 'react'
|
||||
import { Flex, Card, Alert, Button } from 'antd'
|
||||
import AuthParticles from './AppParticles'
|
||||
import FarmControlLogo from '../Logos/FarmControlLogo'
|
||||
import ExclamationOctagonIcon from '../Icons/ExclamationOctagonIcon'
|
||||
import PropTypes from 'prop-types'
|
||||
import ArrowLeftIcon from '../Icons/ArrowLeftIcon'
|
||||
import ReloadIcon from '../Icons/ReloadIcon'
|
||||
|
||||
const AppError = ({
|
||||
message = 'Error Message',
|
||||
showBack = true,
|
||||
showRefresh = true
|
||||
}) => {
|
||||
const handleBack = () => {
|
||||
window.history.back()
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthParticles />
|
||||
<Flex
|
||||
align='center'
|
||||
justify='center'
|
||||
vertical
|
||||
style={{ height: '100vh' }}
|
||||
gap={'large'}
|
||||
>
|
||||
<Card>
|
||||
<Flex vertical align='center'>
|
||||
<FarmControlLogo style={{ fontSize: '350px', height: '31px' }} />
|
||||
</Flex>
|
||||
</Card>
|
||||
<Alert
|
||||
message={message}
|
||||
icon={<ExclamationOctagonIcon />}
|
||||
type={'error'}
|
||||
showIcon
|
||||
/>
|
||||
{(showBack || showRefresh) && (
|
||||
<Flex gap='middle'>
|
||||
{showBack && (
|
||||
<Button icon={<ArrowLeftIcon />} onClick={handleBack} />
|
||||
)}
|
||||
{showRefresh && (
|
||||
<Button icon={<ReloadIcon />} onClick={handleRefresh} />
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AppError.propTypes = {
|
||||
message: PropTypes.string,
|
||||
showBack: PropTypes.bool,
|
||||
showRefresh: PropTypes.bool
|
||||
}
|
||||
|
||||
export default AppError
|
||||
33
src/components/App/AppLoading.jsx
Normal file
33
src/components/App/AppLoading.jsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from 'react'
|
||||
import { Flex, Card, Alert } from 'antd'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
import AuthParticles from './AppParticles'
|
||||
import FarmControlLogo from '../Logos/FarmControlLogo'
|
||||
|
||||
const AppLoading = () => {
|
||||
return (
|
||||
<>
|
||||
<AuthParticles />
|
||||
<Flex
|
||||
align='center'
|
||||
justify='center'
|
||||
vertical
|
||||
style={{ height: '100vh' }}
|
||||
gap={'large'}
|
||||
>
|
||||
<Card>
|
||||
<Flex vertical align='center'>
|
||||
<FarmControlLogo style={{ fontSize: '350px', height: '31px' }} />
|
||||
</Flex>
|
||||
</Card>
|
||||
<Alert
|
||||
message='Loading Farm Control please wait...'
|
||||
icon={<LoadingOutlined />}
|
||||
showIcon
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AppLoading
|
||||
@ -3,8 +3,6 @@ import React, { useState, useEffect, useMemo, useCallback } from 'react'
|
||||
import Particles, { initParticlesEngine } from '@tsparticles/react'
|
||||
import { loadSlim } from '@tsparticles/slim'
|
||||
|
||||
import './Auth.css'
|
||||
|
||||
const ParticlesComponent = React.memo(({ options, particlesLoaded }) => {
|
||||
return (
|
||||
<Particles
|
||||
@ -17,7 +15,7 @@ const ParticlesComponent = React.memo(({ options, particlesLoaded }) => {
|
||||
|
||||
ParticlesComponent.displayName = 'ParticlesComponent'
|
||||
|
||||
const AuthParticles = () => {
|
||||
const AppParticles = () => {
|
||||
const [init, setInit] = useState(false)
|
||||
|
||||
// this should be run only once per application lifetime
|
||||
@ -120,4 +118,4 @@ ParticlesComponent.propTypes = {
|
||||
particlesLoaded: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default AuthParticles
|
||||
export default AppParticles
|
||||
@ -1,29 +0,0 @@
|
||||
/* AuthPage.css */
|
||||
.auth-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-image: url('../../../public/wallpaper.webp');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.auth-form > h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.auth-form {
|
||||
width: 300px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.auth-form-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ant-spin-blur {
|
||||
filter: blur(2.5px);
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useContext } from 'react'
|
||||
import { Spin, Flex, Card } from 'antd'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import AuthParticles from './AuthParticles'
|
||||
import './Auth.css'
|
||||
|
||||
const AuthLayout = ({ children }) => {
|
||||
const { loading } = useContext(AuthContext)
|
||||
return (
|
||||
<>
|
||||
<AuthParticles />
|
||||
<Flex
|
||||
horizontal='true'
|
||||
align='center'
|
||||
justify='center'
|
||||
style={{ paddingTop: '35px' }}
|
||||
>
|
||||
<Card style={{ maxWidth: 350 }}>
|
||||
<Spin
|
||||
spinning={loading}
|
||||
indicator={<LoadingOutlined spin />}
|
||||
size='large'
|
||||
>
|
||||
{children}
|
||||
</Spin>
|
||||
</Card>
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AuthLayout.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export default AuthLayout
|
||||
@ -1,52 +0,0 @@
|
||||
import React, { useContext } from 'react'
|
||||
//import { useNavigate } from 'react-router-dom'
|
||||
import { Form, Button, Divider, Typography, Flex } from 'antd'
|
||||
import { UserAddOutlined } from '@ant-design/icons'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import AuthLayout from './AuthLayout'
|
||||
|
||||
import './Auth.css'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
const LoginUser = () => {
|
||||
//const [error] = useState('')
|
||||
//const navigate = useNavigate()
|
||||
const { loginWithSSO } = useContext(AuthContext)
|
||||
const handleLogin = async () => {
|
||||
loginWithSSO('/dashboard/production/overview')
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Flex vertical='true' align='center' style={{ marginBottom: 25 }}>
|
||||
<img
|
||||
src='/logo512@2x.png'
|
||||
style={{ width: '100px' }}
|
||||
alt='Farm Control Logo'
|
||||
></img>
|
||||
<h1 style={{ marginTop: 10, marginBottom: 10 }}>Farm Control</h1>
|
||||
<Text style={{ textAlign: 'center' }}>Please sign in below.</Text>
|
||||
</Flex>
|
||||
<Form name='loginForm' className='login-form' onFinish={handleLogin}>
|
||||
<Form.Item>
|
||||
<Button
|
||||
className='auth-form-button'
|
||||
type='primary'
|
||||
style={{ width: '250px' }}
|
||||
htmlType='submit'
|
||||
>
|
||||
Login with auth.tombutcher.work
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
<Divider plain></Divider>
|
||||
<Button className='auth-form-button' icon={<UserAddOutlined />}>
|
||||
Register
|
||||
</Button>
|
||||
</AuthLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginUser
|
||||
@ -1,56 +0,0 @@
|
||||
import React, { useState, useContext } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Button, Typography, Flex } from 'antd'
|
||||
import { LockOutlined } from '@ant-design/icons'
|
||||
import { AuthContext } from './AuthContext'
|
||||
|
||||
import PassKeysIcon from '../Icons/PassKeysIcon' // Adjust the path if necessary
|
||||
|
||||
import './Auth.css'
|
||||
import AuthLayout from './AuthLayout'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
const RegisterPasskey = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const navigate = useNavigate()
|
||||
const { registerPasskey } = useContext(AuthContext)
|
||||
const [init, setInit] = useState(false)
|
||||
|
||||
const handleRegisterPasskey = async (e) => {
|
||||
const result = await registerPasskey(email, password)
|
||||
if (result.successful === true) {
|
||||
setTimeout(() => {
|
||||
navigate('/dashboard/overview')
|
||||
}, 500)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Flex vertical='true' align='center' style={{ marginBottom: 25 }}>
|
||||
<PassKeysIcon style={{ fontSize: '64px' }} />
|
||||
<h1 style={{ marginTop: 10, marginBottom: 10 }}>Register a Passkey</h1>
|
||||
<Text style={{ textAlign: 'center' }}>
|
||||
Please setup a passkey in order to continue. The passkey may use
|
||||
another device for encryption.
|
||||
</Text>
|
||||
</Flex>
|
||||
<Button
|
||||
type='primary'
|
||||
className='auth-form-button'
|
||||
icon={<LockOutlined />}
|
||||
onClick={() => {
|
||||
handleRegisterPasskey()
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</AuthLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default RegisterPasskey
|
||||
@ -16,7 +16,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
|
||||
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
|
||||
import NewPartStock from './PartStocks/NewPartStock'
|
||||
import IdText from '../common/IdText'
|
||||
|
||||
@ -6,7 +6,7 @@ import { Table, Button, Flex, Space, message, Dropdown, Typography } from 'antd'
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
|
||||
import IdText from '../common/IdText'
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
ClockCircleOutlined
|
||||
} from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../../Auth/AuthContext'
|
||||
import { AuthContext } from '../../context/AuthContext'
|
||||
import IdText from '../../common/IdText'
|
||||
import TimeDisplay from '../../common/TimeDisplay'
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined, AuditOutlined } from '@ant-design/icons'
|
||||
import moment from 'moment'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import IdText from '../common/IdText'
|
||||
import TimeDisplay from '../common/TimeDisplay'
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import NewFilament from './Filaments/NewFilament'
|
||||
import IdText from '../common/IdText'
|
||||
import FilamentIcon from '../../Icons/FilamentIcon'
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
|
||||
import NewMaterial from './Materials/NewMaterial'
|
||||
import IdText from '../common/IdText'
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import IdText from '../common/IdText'
|
||||
import NewProduct from './Products/NewProduct'
|
||||
import PartIcon from '../../Icons/PartIcon'
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
|
||||
import IdText from '../common/IdText'
|
||||
import TimeDisplay from '../common/TimeDisplay'
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
InputNumber
|
||||
} from 'antd'
|
||||
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
|
||||
import { AuthContext } from '../../../Auth/AuthContext'
|
||||
import { AuthContext } from '../../context/AuthContext'
|
||||
import PartIcon from '../../../Icons/PartIcon'
|
||||
import { StlViewer } from 'react-stl-viewer'
|
||||
import VendorSelect from '../../common/VendorSelect'
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
} from 'antd'
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined, ExportOutlined } from '@ant-design/icons'
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import IdText from '../common/IdText'
|
||||
import NewVendor from './Vendors/NewVendor'
|
||||
import CountryDisplay from '../common/CountryDisplay'
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import NewGCodeFile from './GCodeFiles/NewGCodeFile'
|
||||
import IdText from '../common/IdText'
|
||||
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
||||
|
||||
@ -23,7 +23,7 @@ import {
|
||||
} from 'antd'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../../Auth/AuthContext'
|
||||
import { AuthContext } from '../../context/AuthContext.js'
|
||||
|
||||
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext.js'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import NewPrintJob from './PrintJobs/NewPrintJob'
|
||||
import JobState from '../common/JobState'
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
import { createStyles } from 'antd-style'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import PrinterState from '../common/PrinterState'
|
||||
import NewPrinter from './Printers/NewPrinter'
|
||||
import IdText from '../common/IdText'
|
||||
|
||||
@ -27,7 +27,7 @@ import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
||||
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
||||
import PrinterMovementPanel from '../../common/PrinterMovementPanel'
|
||||
import PrinterState from '../../common/PrinterState'
|
||||
import { AuthContext } from '../../../Auth/AuthContext'
|
||||
import { AuthContext } from '../../context/AuthContext'
|
||||
import PrinterSubJobsTree from '../../common/PrinterJobsTree'
|
||||
import IdText from '../../common/IdText'
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
DisconnectOutlined,
|
||||
MenuOutlined
|
||||
} from '@ant-design/icons'
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { SocketContext } from '../context/SocketContext'
|
||||
import { SpotlightContext } from '../context/SpotlightContext'
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
|
||||
@ -4,7 +4,7 @@ import { TreeSelect, Badge, Flex, message, Typography } from 'antd'
|
||||
import React, { useEffect, useState, useContext } from 'react'
|
||||
import axios from 'axios'
|
||||
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
|
||||
import config from '../../../config'
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { TreeSelect, message, Tag } from 'antd'
|
||||
import React, { useEffect, useState, useContext } from 'react'
|
||||
import axios from 'axios'
|
||||
import PrinterState from './PrinterState'
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import config from '../../../config'
|
||||
|
||||
const PrinterSelect = ({ onChange, disabled, checkable, value = [] }) => {
|
||||
|
||||
@ -3,9 +3,10 @@ import React, { createContext, useState, useCallback, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import { message, Modal, notification, Progress, Button, Space } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import ExclamationOctogonIcon from '../Icons/ExclamationOctagonIcon'
|
||||
import InfoCircleIcon from '../Icons/InfoCircleIcon'
|
||||
import config from '../../config'
|
||||
import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||
import config from '../../../config'
|
||||
import AppError from '../../App/AppError'
|
||||
|
||||
const AuthContext = createContext()
|
||||
|
||||
@ -20,6 +21,7 @@ const AuthProvider = ({ children }) => {
|
||||
const [userProfile, setUserProfile] = useState(null)
|
||||
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
|
||||
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
|
||||
const [authError, setAuthError] = useState(null)
|
||||
|
||||
const logout = useCallback((redirectUri = '/login') => {
|
||||
setAuthenticated(false)
|
||||
@ -40,6 +42,7 @@ const AuthProvider = ({ children }) => {
|
||||
// Function to check if the user is logged in
|
||||
const checkAuthStatus = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setAuthError(null)
|
||||
try {
|
||||
// Make a call to your backend to check auth status
|
||||
const response = await axios.get(`${config.backendUrl}/auth/user`, {
|
||||
@ -54,11 +57,14 @@ const AuthProvider = ({ children }) => {
|
||||
setUserProfile(response.data)
|
||||
} else {
|
||||
setAuthenticated(false)
|
||||
setAuthError('Failed to authenticate user.')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Auth check failed', error)
|
||||
if (error.response?.status === 401) {
|
||||
setShowUnauthorizedModal(true)
|
||||
} else {
|
||||
setAuthError('Error connecting to authentication service.')
|
||||
}
|
||||
setAuthenticated(false)
|
||||
} finally {
|
||||
@ -179,6 +185,10 @@ const AuthProvider = ({ children }) => {
|
||||
checkAuthStatus()
|
||||
}, [checkAuthStatus])
|
||||
|
||||
if (authError) {
|
||||
return <AppError message={authError} showBack={false} />
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
@ -9,7 +9,7 @@ import React, {
|
||||
import io from 'socket.io-client'
|
||||
import { message, notification } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import { AuthContext } from '../../Auth/AuthContext'
|
||||
import { AuthContext } from './AuthContext'
|
||||
import config from '../../../config'
|
||||
|
||||
const SocketContext = createContext()
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// PrivateRoute.js
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useContext } from 'react'
|
||||
//import { Navigate } from 'react-router-dom'
|
||||
import { AuthContext } from './Auth/AuthContext'
|
||||
import { AuthContext } from './Dashboard/context/AuthContext'
|
||||
import AuthLoading from './App/AppLoading'
|
||||
|
||||
const PrivateRoute = ({ component: Component }) => {
|
||||
const { authenticated, loading, showSessionExpiredModal } =
|
||||
@ -10,7 +10,7 @@ const PrivateRoute = ({ component: Component }) => {
|
||||
|
||||
// Show loading state while auth state is being determined
|
||||
if (loading) {
|
||||
return <div>Loading...</div>
|
||||
return <AuthLoading />
|
||||
}
|
||||
|
||||
// Redirect to login if not authenticated
|
||||
|
||||
@ -2,14 +2,15 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useContext } from 'react'
|
||||
import { Navigate } from 'react-router-dom'
|
||||
import { AuthContext } from './Auth/AuthContext'
|
||||
import { AuthContext } from './Dashboard/context/AuthContext'
|
||||
import AuthLoading from './App/AppLoading'
|
||||
|
||||
const PublicRoute = ({ component: Component }) => {
|
||||
const { authenticated, loading } = useContext(AuthContext)
|
||||
|
||||
// Show loading state while auth state is being determined
|
||||
if (loading) {
|
||||
return <div>Loading...</div>
|
||||
return <AuthLoading />
|
||||
}
|
||||
|
||||
// Redirect to login if not authenticated
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user