diff --git a/package.json b/package.json
index 7b5db2c..f9c3b41 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"antd-style": "^3.7.1",
"axios": "^1.11.0",
"country-list": "^2.3.0",
+ "cross-env": "^10.0.0",
"dayjs": "^1.11.13",
"dotenv": "^17.2.1",
"eslint": "^9.33.0",
@@ -69,12 +70,12 @@
"main": "build/electron.js",
"description": "3D Printer ERP and Control Software.",
"scripts": {
- "dev": "vite",
- "electron": "set ELECTRON_START_URL=http://0.0.0.0:3000 && NODE_ENV=development && electron .",
+ "dev": "cross-env NODE_ENV=development vite",
+ "electron": "cross-env ELECTRON_START_URL=http://0.0.0.0:3000 && cross-env NODE_ENV=development && electron .",
"start": "serve -s build",
"build": "vite build",
- "dev:electron": "concurrently \"vite --no-open\" \"set ELECTRON_START_URL=http://localhost:3000 && set NODE_ENV=development && electron public/electron.js\"",
- "build:electron": "npm run build && electron-builder"
+ "dev:electron": "concurrently \"cross-env NODE_ENV=development vite --no-open\" \"cross-env ELECTRON_START_URL=http://localhost:3000 cross-env NODE_ENV=development electron public/electron.js\"",
+ "build:electron": "vite build && electron-builder"
},
"eslintConfig": {
"extends": [
diff --git a/src/components/App/AppError.jsx b/src/components/App/AppError.jsx
index 62a7fe0..f47dc40 100644
--- a/src/components/App/AppError.jsx
+++ b/src/components/App/AppError.jsx
@@ -5,12 +5,16 @@ import ExclamationOctagonIcon from '../Icons/ExclamationOctagonIcon'
import PropTypes from 'prop-types'
import ArrowLeftIcon from '../Icons/ArrowLeftIcon'
import ReloadIcon from '../Icons/ReloadIcon'
+import { useNavigate } from 'react-router-dom'
+import VendorIcon from '../Icons/VendorIcon'
const AppError = ({
message = 'Error Message',
showBack = true,
- showRefresh = true
+ showRefresh = true,
+ showHome = true
}) => {
+ const navigate = useNavigate()
const handleBack = () => {
window.history.back()
}
@@ -19,6 +23,10 @@ const AppError = ({
window.location.reload()
}
+ const handleHome = () => {
+ navigate('/production/overview')
+ }
+
return (
<>
@@ -40,7 +48,7 @@ const AppError = ({
type={'error'}
showIcon
/>
- {(showBack || showRefresh) && (
+ {(showBack || showRefresh || showHome) && (
{showBack && (
)}
+ {showHome && (
+ } onClick={handleHome} size='large' />
+ )}
)}
@@ -66,7 +77,8 @@ const AppError = ({
AppError.propTypes = {
message: PropTypes.string,
showBack: PropTypes.bool,
- showRefresh: PropTypes.bool
+ showRefresh: PropTypes.bool,
+ showHome: PropTypes.bool
}
export default AppError
diff --git a/src/components/Dashboard/context/AuthContext.jsx b/src/components/Dashboard/context/AuthContext.jsx
index 41f0ed7..1c6858b 100644
--- a/src/components/Dashboard/context/AuthContext.jsx
+++ b/src/components/Dashboard/context/AuthContext.jsx
@@ -21,7 +21,6 @@ import PropTypes from 'prop-types'
import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import config from '../../../config'
-import AppError from '../../App/AppError'
import loglevel from 'loglevel'
import { ElectronContext } from './ElectronContext'
import { useLocation, useNavigate } from 'react-router-dom'
@@ -30,7 +29,7 @@ logger.setLevel(config.logLevel)
const AuthContext = createContext()
-const Title = Typography
+const { Text } = Typography
const AuthProvider = ({ children }) => {
const [messageApi, contextHolder] = message.useMessage()
@@ -46,6 +45,7 @@ const AuthProvider = ({ children }) => {
const [userProfile, setUserProfile] = useState(null)
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
+ const [showAuthErrorModal, setShowAuthErrorModal] = useState(false)
const [authError, setAuthError] = useState(null)
const { openExternalUrl, isElectron } = useContext(ElectronContext)
const location = useLocation()
@@ -148,13 +148,19 @@ const AuthProvider = ({ children }) => {
} else {
setAuthenticated(false)
setAuthError('Failed to authenticate user.')
+ setShowAuthErrorModal(true)
}
} catch (error) {
logger.debug('Auth check failed', error)
if (error.response?.status === 401) {
setShowUnauthorizedModal(true)
} else {
- setAuthError('Error connecting to authentication service.')
+ const errorMessage =
+ error?.response?.data?.error ||
+ 'Error connecting to authentication service.'
+ const fullStop = errorMessage.endsWith('.')
+ setAuthError(`${errorMessage}${!fullStop && '.'}`)
+ setShowAuthErrorModal(true)
}
setAuthenticated(false)
} finally {
@@ -186,6 +192,7 @@ const AuthProvider = ({ children }) => {
} else {
setAuthenticated(false)
setAuthError('Failed to authenticate user.')
+ setShowAuthErrorModal(true)
}
} catch (error) {
logger.debug('Auth check failed', error)
@@ -193,6 +200,7 @@ const AuthProvider = ({ children }) => {
setShowUnauthorizedModal(true)
} else {
setAuthError('Error connecting to authentication service.')
+ setShowAuthErrorModal(true)
}
setAuthenticated(false)
} finally {
@@ -342,10 +350,6 @@ const AuthProvider = ({ children }) => {
retreivedTokenFromSession
])
- if (authError) {
- return
- }
-
return (
<>
{contextHolder}
@@ -371,7 +375,7 @@ const AuthProvider = ({ children }) => {
Session Expired
}
- open={showSessionExpiredModal}
+ open={showSessionExpiredModal && !loading && !showAuthErrorModal}
onOk={handleSessionExpiredModalOk}
okText='Log In'
style={{ maxWidth: 430 }}
@@ -388,7 +392,7 @@ const AuthProvider = ({ children }) => {
]}
>
- Your session has expired. Please log in again to continue.
+ Your session has expired. Please log in again to continue.
{
Please log in to continue
}
- open={showUnauthorizedModal}
+ open={showUnauthorizedModal && !loading && !showAuthErrorModal}
onOk={() => {
setShowUnauthorizedModal(false)
loginWithSSO()
@@ -419,8 +423,10 @@ const AuthProvider = ({ children }) => {
]}
>
- You need to be logged in to access FarmControl. Please log in with
- tombutcher.work to continue.
+
+ You need to be logged in to access FarmControl. Please log in with
+ tombutcher.work to continue.
+
{
>
-
- Loading, please wait...
-
+ Loading, please wait...
+
+
+ Authentication Error
+
+ }
+ open={showAuthErrorModal && !loading}
+ style={{ maxWidth: 430 }}
+ closable={false}
+ centered
+ maskClosable={false}
+ footer={[
+
+ ]}
+ >
+ {authError}
+
>
)
}
diff --git a/yarn.lock b/yarn.lock
index 55acfbb..c3a5639 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1295,6 +1295,11 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
+"@epic-web/invariant@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@epic-web/invariant/-/invariant-1.0.0.tgz#1073e5dee6dd540410784990eb73e4acd25c9813"
+ integrity sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==
+
"@esbuild/aix-ppc64@0.25.9":
version "0.25.9"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9"
@@ -4030,6 +4035,14 @@ crelt@^1.0.5, crelt@^1.0.6:
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
+cross-env@^10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-10.0.0.tgz#ba25823cfa1ed6af293dcded8796fa16cd162456"
+ integrity sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==
+ dependencies:
+ "@epic-web/invariant" "^1.0.0"
+ cross-spawn "^7.0.6"
+
cross-spawn-windows-exe@^1.1.0, cross-spawn-windows-exe@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz#46253b0f497676e766faf4a7061004618b5ac5ec"