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
|
remote.allowAnyHosts = true
|
||||||
|
|
||||||
// Copy the build directory to the remote server
|
// 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
|
// 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!'
|
echo 'Pipeline completed successfully!'
|
||||||
|
|||||||
20
src/App.jsx
20
src/App.jsx
@ -6,7 +6,7 @@ import {
|
|||||||
Navigate
|
Navigate
|
||||||
} from 'react-router-dom'
|
} from 'react-router-dom'
|
||||||
import { App, ConfigProvider } from 'antd'
|
import { App, ConfigProvider } from 'antd'
|
||||||
import AuthLayout from './components/Auth/AuthLayout.jsx'
|
|
||||||
import ProductionOverview from './components/Dashboard/Production/ProductionOverview'
|
import ProductionOverview from './components/Dashboard/Production/ProductionOverview'
|
||||||
|
|
||||||
import Printers from './components/Dashboard/Production/Printers'
|
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 Dashboard from './components/Dashboard/common/Dashboard'
|
||||||
import PrivateRoute from './components/PrivateRoute'
|
import PrivateRoute from './components/PrivateRoute'
|
||||||
import PublicRoute from './components/PublicRoute.jsx'
|
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import { SocketProvider } from './components/Dashboard/context/SocketContext.js'
|
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 { SpotlightProvider } from './components/Dashboard/context/SpotlightContext.js'
|
||||||
import StockEvents from './components/Dashboard/Inventory/StockEvents.jsx'
|
import StockEvents from './components/Dashboard/Inventory/StockEvents.jsx'
|
||||||
import Settings from './components/Dashboard/Management/Settings'
|
import Settings from './components/Dashboard/Management/Settings'
|
||||||
@ -54,6 +53,7 @@ import {
|
|||||||
ThemeProvider,
|
ThemeProvider,
|
||||||
useThemeContext
|
useThemeContext
|
||||||
} from './components/Dashboard/context/ThemeContext'
|
} from './components/Dashboard/context/ThemeContext'
|
||||||
|
import AppError from './components/App/AppError'
|
||||||
|
|
||||||
const AppContent = () => {
|
const AppContent = () => {
|
||||||
const { themeConfig } = useThemeContext()
|
const { themeConfig } = useThemeContext()
|
||||||
@ -79,11 +79,6 @@ const AppContent = () => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
|
||||||
path='login'
|
|
||||||
element={<PublicRoute component={() => <AuthLayout />} />}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path='/dashboard'
|
path='/dashboard'
|
||||||
element={<PrivateRoute component={() => <Dashboard />} />}
|
element={<PrivateRoute component={() => <Dashboard />} />}
|
||||||
@ -175,6 +170,15 @@ const AppContent = () => {
|
|||||||
/>
|
/>
|
||||||
<Route path='management/settings' element={<Settings />} />
|
<Route path='management/settings' element={<Settings />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route
|
||||||
|
path='*'
|
||||||
|
element={
|
||||||
|
<AppError
|
||||||
|
message='404! Page not found.'
|
||||||
|
showRefresh={false}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
</SpotlightProvider>
|
</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 Particles, { initParticlesEngine } from '@tsparticles/react'
|
||||||
import { loadSlim } from '@tsparticles/slim'
|
import { loadSlim } from '@tsparticles/slim'
|
||||||
|
|
||||||
import './Auth.css'
|
|
||||||
|
|
||||||
const ParticlesComponent = React.memo(({ options, particlesLoaded }) => {
|
const ParticlesComponent = React.memo(({ options, particlesLoaded }) => {
|
||||||
return (
|
return (
|
||||||
<Particles
|
<Particles
|
||||||
@ -17,7 +15,7 @@ const ParticlesComponent = React.memo(({ options, particlesLoaded }) => {
|
|||||||
|
|
||||||
ParticlesComponent.displayName = 'ParticlesComponent'
|
ParticlesComponent.displayName = 'ParticlesComponent'
|
||||||
|
|
||||||
const AuthParticles = () => {
|
const AppParticles = () => {
|
||||||
const [init, setInit] = useState(false)
|
const [init, setInit] = useState(false)
|
||||||
|
|
||||||
// this should be run only once per application lifetime
|
// this should be run only once per application lifetime
|
||||||
@ -120,4 +118,4 @@ ParticlesComponent.propTypes = {
|
|||||||
particlesLoaded: PropTypes.func.isRequired
|
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 { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
|
|
||||||
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
import NewFilamentStock from './FilamentStocks/NewFilamentStock'
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
|
||||||
import NewPartStock from './PartStocks/NewPartStock'
|
import NewPartStock from './PartStocks/NewPartStock'
|
||||||
import IdText from '../common/IdText'
|
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 { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
|
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
ClockCircleOutlined
|
ClockCircleOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../../Auth/AuthContext'
|
import { AuthContext } from '../../context/AuthContext'
|
||||||
import IdText from '../../common/IdText'
|
import IdText from '../../common/IdText'
|
||||||
import TimeDisplay from '../../common/TimeDisplay'
|
import TimeDisplay from '../../common/TimeDisplay'
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import { createStyles } from 'antd-style'
|
|||||||
import { LoadingOutlined, AuditOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, AuditOutlined } from '@ant-design/icons'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import TimeDisplay from '../common/TimeDisplay'
|
import TimeDisplay from '../common/TimeDisplay'
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import NewFilament from './Filaments/NewFilament'
|
import NewFilament from './Filaments/NewFilament'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import FilamentIcon from '../../Icons/FilamentIcon'
|
import FilamentIcon from '../../Icons/FilamentIcon'
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
|
||||||
import NewMaterial from './Materials/NewMaterial'
|
import NewMaterial from './Materials/NewMaterial'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import NewProduct from './Products/NewProduct'
|
import NewProduct from './Products/NewProduct'
|
||||||
import PartIcon from '../../Icons/PartIcon'
|
import PartIcon from '../../Icons/PartIcon'
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import TimeDisplay from '../common/TimeDisplay'
|
import TimeDisplay from '../common/TimeDisplay'
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import {
|
|||||||
InputNumber
|
InputNumber
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
|
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
|
||||||
import { AuthContext } from '../../../Auth/AuthContext'
|
import { AuthContext } from '../../context/AuthContext'
|
||||||
import PartIcon from '../../../Icons/PartIcon'
|
import PartIcon from '../../../Icons/PartIcon'
|
||||||
import { StlViewer } from 'react-stl-viewer'
|
import { StlViewer } from 'react-stl-viewer'
|
||||||
import VendorSelect from '../../common/VendorSelect'
|
import VendorSelect from '../../common/VendorSelect'
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined, ExportOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, ExportOutlined } from '@ant-design/icons'
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import NewVendor from './Vendors/NewVendor'
|
import NewVendor from './Vendors/NewVendor'
|
||||||
import CountryDisplay from '../common/CountryDisplay'
|
import CountryDisplay from '../common/CountryDisplay'
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import NewGCodeFile from './GCodeFiles/NewGCodeFile'
|
import NewGCodeFile from './GCodeFiles/NewGCodeFile'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import {
|
|||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../../Auth/AuthContext'
|
import { AuthContext } from '../../context/AuthContext.js'
|
||||||
|
|
||||||
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext.js'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
import NewPrintJob from './PrintJobs/NewPrintJob'
|
import NewPrintJob from './PrintJobs/NewPrintJob'
|
||||||
import JobState from '../common/JobState'
|
import JobState from '../common/JobState'
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import {
|
|||||||
import { createStyles } from 'antd-style'
|
import { createStyles } from 'antd-style'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import PrinterState from '../common/PrinterState'
|
import PrinterState from '../common/PrinterState'
|
||||||
import NewPrinter from './Printers/NewPrinter'
|
import NewPrinter from './Printers/NewPrinter'
|
||||||
import IdText from '../common/IdText'
|
import IdText from '../common/IdText'
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'
|
|||||||
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
import PrinterPositionPanel from '../../common/PrinterPositionPanel'
|
||||||
import PrinterMovementPanel from '../../common/PrinterMovementPanel'
|
import PrinterMovementPanel from '../../common/PrinterMovementPanel'
|
||||||
import PrinterState from '../../common/PrinterState'
|
import PrinterState from '../../common/PrinterState'
|
||||||
import { AuthContext } from '../../../Auth/AuthContext'
|
import { AuthContext } from '../../context/AuthContext'
|
||||||
import PrinterSubJobsTree from '../../common/PrinterJobsTree'
|
import PrinterSubJobsTree from '../../common/PrinterJobsTree'
|
||||||
import IdText from '../../common/IdText'
|
import IdText from '../../common/IdText'
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
DisconnectOutlined,
|
DisconnectOutlined,
|
||||||
MenuOutlined
|
MenuOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SocketContext } from '../context/SocketContext'
|
import { SocketContext } from '../context/SocketContext'
|
||||||
import { SpotlightContext } from '../context/SpotlightContext'
|
import { SpotlightContext } from '../context/SpotlightContext'
|
||||||
import { useNavigate, useLocation } from 'react-router-dom'
|
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 React, { useEffect, useState, useContext } from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { TreeSelect, message, Tag } from 'antd'
|
|||||||
import React, { useEffect, useState, useContext } from 'react'
|
import React, { useEffect, useState, useContext } from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import PrinterState from './PrinterState'
|
import PrinterState from './PrinterState'
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
|
|
||||||
const PrinterSelect = ({ onChange, disabled, checkable, value = [] }) => {
|
const PrinterSelect = ({ onChange, disabled, checkable, value = [] }) => {
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import React, { createContext, useState, useCallback, useEffect } from 'react'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { message, Modal, notification, Progress, Button, Space } from 'antd'
|
import { message, Modal, notification, Progress, Button, Space } from 'antd'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import ExclamationOctogonIcon from '../Icons/ExclamationOctagonIcon'
|
import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||||
import InfoCircleIcon from '../Icons/InfoCircleIcon'
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
import config from '../../config'
|
import config from '../../../config'
|
||||||
|
import AppError from '../../App/AppError'
|
||||||
|
|
||||||
const AuthContext = createContext()
|
const AuthContext = createContext()
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
const [userProfile, setUserProfile] = useState(null)
|
const [userProfile, setUserProfile] = useState(null)
|
||||||
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
|
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
|
||||||
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
|
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
|
||||||
|
const [authError, setAuthError] = useState(null)
|
||||||
|
|
||||||
const logout = useCallback((redirectUri = '/login') => {
|
const logout = useCallback((redirectUri = '/login') => {
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
@ -40,6 +42,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
// Function to check if the user is logged in
|
// Function to check if the user is logged in
|
||||||
const checkAuthStatus = useCallback(async () => {
|
const checkAuthStatus = useCallback(async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
setAuthError(null)
|
||||||
try {
|
try {
|
||||||
// Make a call to your backend to check auth status
|
// Make a call to your backend to check auth status
|
||||||
const response = await axios.get(`${config.backendUrl}/auth/user`, {
|
const response = await axios.get(`${config.backendUrl}/auth/user`, {
|
||||||
@ -54,11 +57,14 @@ const AuthProvider = ({ children }) => {
|
|||||||
setUserProfile(response.data)
|
setUserProfile(response.data)
|
||||||
} else {
|
} else {
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
|
setAuthError('Failed to authenticate user.')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Auth check failed', error)
|
console.log('Auth check failed', error)
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
setShowUnauthorizedModal(true)
|
setShowUnauthorizedModal(true)
|
||||||
|
} else {
|
||||||
|
setAuthError('Error connecting to authentication service.')
|
||||||
}
|
}
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
} finally {
|
} finally {
|
||||||
@ -179,6 +185,10 @@ const AuthProvider = ({ children }) => {
|
|||||||
checkAuthStatus()
|
checkAuthStatus()
|
||||||
}, [checkAuthStatus])
|
}, [checkAuthStatus])
|
||||||
|
|
||||||
|
if (authError) {
|
||||||
|
return <AppError message={authError} showBack={false} />
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@ -9,7 +9,7 @@ import React, {
|
|||||||
import io from 'socket.io-client'
|
import io from 'socket.io-client'
|
||||||
import { message, notification } from 'antd'
|
import { message, notification } from 'antd'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { AuthContext } from '../../Auth/AuthContext'
|
import { AuthContext } from './AuthContext'
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
|
|
||||||
const SocketContext = createContext()
|
const SocketContext = createContext()
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// PrivateRoute.js
|
// PrivateRoute.js
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
//import { Navigate } from 'react-router-dom'
|
import { AuthContext } from './Dashboard/context/AuthContext'
|
||||||
import { AuthContext } from './Auth/AuthContext'
|
import AuthLoading from './App/AppLoading'
|
||||||
|
|
||||||
const PrivateRoute = ({ component: Component }) => {
|
const PrivateRoute = ({ component: Component }) => {
|
||||||
const { authenticated, loading, showSessionExpiredModal } =
|
const { authenticated, loading, showSessionExpiredModal } =
|
||||||
@ -10,7 +10,7 @@ const PrivateRoute = ({ component: Component }) => {
|
|||||||
|
|
||||||
// Show loading state while auth state is being determined
|
// Show loading state while auth state is being determined
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading...</div>
|
return <AuthLoading />
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to login if not authenticated
|
// Redirect to login if not authenticated
|
||||||
|
|||||||
@ -2,14 +2,15 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { Navigate } from 'react-router-dom'
|
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 PublicRoute = ({ component: Component }) => {
|
||||||
const { authenticated, loading } = useContext(AuthContext)
|
const { authenticated, loading } = useContext(AuthContext)
|
||||||
|
|
||||||
// Show loading state while auth state is being determined
|
// Show loading state while auth state is being determined
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading...</div>
|
return <AuthLoading />
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to login if not authenticated
|
// Redirect to login if not authenticated
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user