Using cross-env and fixed login error handling.

This commit is contained in:
Tom Butcher 2025-08-23 22:04:39 +01:00
parent 894b6af3c8
commit 5f20f81a2c
4 changed files with 78 additions and 22 deletions

View File

@ -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": [

View File

@ -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 (
<>
<AuthParticles />
@ -40,7 +48,7 @@ const AppError = ({
type={'error'}
showIcon
/>
{(showBack || showRefresh) && (
{(showBack || showRefresh || showHome) && (
<Flex gap='middle'>
{showBack && (
<Button
@ -56,6 +64,9 @@ const AppError = ({
size='large'
/>
)}
{showHome && (
<Button icon={<VendorIcon />} onClick={handleHome} size='large' />
)}
</Flex>
)}
</Flex>
@ -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

View File

@ -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 <AppError message={authError} showBack={false} />
}
return (
<>
{contextHolder}
@ -371,7 +375,7 @@ const AuthProvider = ({ children }) => {
Session Expired
</Space>
}
open={showSessionExpiredModal}
open={showSessionExpiredModal && !loading && !showAuthErrorModal}
onOk={handleSessionExpiredModalOk}
okText='Log In'
style={{ maxWidth: 430 }}
@ -388,7 +392,7 @@ const AuthProvider = ({ children }) => {
</Button>
]}
>
Your session has expired. Please log in again to continue.
<Text>Your session has expired. Please log in again to continue.</Text>
</Modal>
<Modal
title={
@ -397,7 +401,7 @@ const AuthProvider = ({ children }) => {
Please log in to continue
</Space>
}
open={showUnauthorizedModal}
open={showUnauthorizedModal && !loading && !showAuthErrorModal}
onOk={() => {
setShowUnauthorizedModal(false)
loginWithSSO()
@ -419,8 +423,10 @@ const AuthProvider = ({ children }) => {
</Button>
]}
>
You need to be logged in to access FarmControl. Please log in with
tombutcher.work to continue.
<Text>
You need to be logged in to access FarmControl. Please log in with
tombutcher.work to continue.
</Text>
</Modal>
<Modal
open={loading}
@ -434,11 +440,35 @@ const AuthProvider = ({ children }) => {
>
<Space size={'middle'}>
<LoadingOutlined />
<Title level={5} style={{ margin: 0 }}>
Loading, please wait...
</Title>
<Text style={{ margin: 0 }}>Loading, please wait...</Text>
</Space>
</Modal>
<Modal
title={
<Space size={'middle'}>
<ExclamationOctogonIcon />
Authentication Error
</Space>
}
open={showAuthErrorModal && !loading}
style={{ maxWidth: 430 }}
closable={false}
centered
maskClosable={false}
footer={[
<Button
key='submit'
onClick={() => {
showAuthErrorModal(false)
loginWithSSO()
}}
>
Retry Login
</Button>
]}
>
<Text>{authError}</Text>
</Modal>
</>
)
}

View File

@ -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"