chore: udpate react, downshift and routing
This commit is contained in:
parent
61285c9037
commit
d9e570990c
30 changed files with 4131 additions and 2813 deletions
6580
package-lock.json
generated
6580
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -18,7 +18,7 @@
|
|||
"d3": "^6.2.0",
|
||||
"date-fns": "^2.26.0",
|
||||
"date-fns-tz": "^1.1.6",
|
||||
"downshift": "3.3.4",
|
||||
"downshift": "9.0.9",
|
||||
"file-saver": "2.0.2",
|
||||
"formik": "2.2.0",
|
||||
"jss-plugin-extend": "^10.0.0",
|
||||
|
|
@ -28,17 +28,18 @@
|
|||
"pretty-ms": "^2.1.0",
|
||||
"qrcode.react": "4.2.0",
|
||||
"ramda": "^0.26.1",
|
||||
"react": "17.0.2",
|
||||
"react": "18.3.1",
|
||||
"react-copy-to-clipboard": "^5.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-dom": "18.3.1",
|
||||
"react-dropzone": "^11.4.2",
|
||||
"react-number-format": "^4.4.1",
|
||||
"react-otp-input": "3.1.1",
|
||||
"react-router-dom": "5.1.2",
|
||||
"react-virtualized": "^9.21.2",
|
||||
"ua-parser-js": "1.0.40",
|
||||
"uuid": "11.1.0",
|
||||
"yup": "1.6.1"
|
||||
"wouter": "^3.7.0",
|
||||
"yup": "1.6.1",
|
||||
"zustand": "^4.5.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import CssBaseline from '@mui/material/CssBaseline'
|
||||
import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles'
|
||||
import React, { useState } from 'react'
|
||||
import { BrowserRouter as Router } from 'react-router-dom'
|
||||
import { Router } from 'wouter'
|
||||
import ApolloProvider from './utils/apollo'
|
||||
|
||||
import AppContext from './AppContext'
|
||||
|
|
@ -9,10 +9,12 @@ import theme from './styling/theme'
|
|||
|
||||
import Main from './Main'
|
||||
import './styling/global/global.css'
|
||||
import useLocationWithConfirmation from './routing/useLocationWithConfirmation.js'
|
||||
|
||||
const App = () => {
|
||||
const [wizardTested, setWizardTested] = useState(false)
|
||||
const [userData, setUserData] = useState(null)
|
||||
const [isDirtyForm, setDirtyForm] = useState(false)
|
||||
|
||||
const setRole = role => {
|
||||
if (userData && role && userData.role !== role) {
|
||||
|
|
@ -22,8 +24,16 @@ const App = () => {
|
|||
|
||||
return (
|
||||
<AppContext.Provider
|
||||
value={{ wizardTested, setWizardTested, userData, setUserData, setRole }}>
|
||||
<Router>
|
||||
value={{
|
||||
wizardTested,
|
||||
setWizardTested,
|
||||
userData,
|
||||
setUserData,
|
||||
setRole,
|
||||
isDirtyForm,
|
||||
setDirtyForm,
|
||||
}}>
|
||||
<Router hook={useLocationWithConfirmation}>
|
||||
<ApolloProvider>
|
||||
<StyledEngineProvider enableCssLayer>
|
||||
<ThemeProvider theme={theme}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useHistory, useLocation } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import React, { useContext, useState } from 'react'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import Slide from '@mui/material/Slide'
|
||||
|
|
@ -27,8 +27,7 @@ const GET_USER_DATA = gql`
|
|||
`
|
||||
|
||||
const Main = () => {
|
||||
const location = useLocation()
|
||||
const history = useHistory()
|
||||
const [location, navigate] = useLocation()
|
||||
const { wizardTested, userData, setUserData } = useContext(AppContext)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
|
|
@ -41,16 +40,14 @@ const Main = () => {
|
|||
},
|
||||
})
|
||||
|
||||
const route = location.pathname
|
||||
const sidebar = hasSidebar(location)
|
||||
const parent = sidebar ? getParent(location) : {}
|
||||
|
||||
const sidebar = hasSidebar(route)
|
||||
const parent = sidebar ? getParent(route) : {}
|
||||
const is404 = location === '/404'
|
||||
|
||||
const is404 = location.pathname === '/404'
|
||||
const isSelected = it => location === it.route
|
||||
|
||||
const isSelected = it => location.pathname === it.route
|
||||
|
||||
const onClick = it => history.push(it.route)
|
||||
const onClick = it => navigate(it.route)
|
||||
|
||||
const contentClassName = sidebar ? 'flex-1 ml-12 pt-4' : 'w-[1200px]'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,19 @@
|
|||
import { useFormikContext } from 'formik'
|
||||
import React, { useEffect } from 'react'
|
||||
import { Prompt } from 'react-router-dom'
|
||||
|
||||
const PROMPT_DEFAULT_MESSAGE =
|
||||
'You have unsaved changes on this page. Are you sure you want to leave?'
|
||||
import useDirtyHandler from '../routing/dirtyHandler.js'
|
||||
|
||||
const PromptWhenDirty = ({ message = PROMPT_DEFAULT_MESSAGE }) => {
|
||||
const PromptWhenDirty = () => {
|
||||
const setIsDirty = useDirtyHandler(state => state.setIsDirty)
|
||||
const formik = useFormikContext()
|
||||
|
||||
const hasChanges = formik.dirty && formik.submitCount === 0
|
||||
|
||||
useEffect(() => {
|
||||
if (hasChanges) {
|
||||
window.onbeforeunload = confirmExit
|
||||
} else {
|
||||
window.onbeforeunload = undefined
|
||||
}
|
||||
setIsDirty(hasChanges)
|
||||
}, [hasChanges])
|
||||
|
||||
const confirmExit = () => {
|
||||
return PROMPT_DEFAULT_MESSAGE
|
||||
}
|
||||
|
||||
return <Prompt when={hasChanges} message={message} />
|
||||
return <></>
|
||||
}
|
||||
|
||||
export default PromptWhenDirty
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Popper from '@mui/material/Popper'
|
|||
import classnames from 'classnames'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo, useState, useEffect, useRef } from 'react'
|
||||
import { NavLink, useHistory } from 'react-router-dom'
|
||||
import { Link as WLink, useRoute, useLocation } from 'wouter'
|
||||
import ActionButton from '../buttons/ActionButton'
|
||||
import { H4 } from '../typography'
|
||||
import AddIconReverse from '../../styling/icons/button/add/white.svg?react'
|
||||
|
|
@ -23,6 +23,32 @@ const HAS_UNREAD = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const Link = ({
|
||||
setActive,
|
||||
isParent,
|
||||
className,
|
||||
activeClassName,
|
||||
item,
|
||||
...props
|
||||
}) => {
|
||||
const [location] = useLocation()
|
||||
const [isActive] = useRoute(props.to)
|
||||
if (isActive) setActive(item)
|
||||
|
||||
const isParentActive = isParent && location.startsWith(props.to)
|
||||
|
||||
const classNames = classnames({
|
||||
[className]: true,
|
||||
[activeClassName]: isActive || isParentActive,
|
||||
})
|
||||
|
||||
return (
|
||||
<WLink {...props} asChild>
|
||||
<a className={classNames}>{props.children}</a>
|
||||
</WLink>
|
||||
)
|
||||
}
|
||||
|
||||
const Subheader = ({ item, user }) => {
|
||||
const [prev, setPrev] = useState(null)
|
||||
|
||||
|
|
@ -35,17 +61,15 @@ const Subheader = ({ item, user }) => {
|
|||
if (!R.includes(user.role, it.allowedRoles)) return <></>
|
||||
return (
|
||||
<li key={idx} className={styles.subheaderLi}>
|
||||
<NavLink
|
||||
to={{ pathname: it.route, state: { prev } }}
|
||||
<Link
|
||||
to={it.route}
|
||||
state={{ prev }}
|
||||
className={styles.subheaderLink}
|
||||
activeClassName={styles.activeSubheaderLink}
|
||||
isActive={match => {
|
||||
if (!match) return false
|
||||
setPrev(it.route)
|
||||
return true
|
||||
}}>
|
||||
item={it.route}
|
||||
setActive={setPrev}>
|
||||
{it.label}
|
||||
</NavLink>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
|
@ -68,7 +92,7 @@ const Header = memo(({ tree, user }) => {
|
|||
const { data, refetch, startPolling, stopPolling } = useQuery(HAS_UNREAD)
|
||||
const notifCenterButtonRef = useRef()
|
||||
const popperRef = useRef()
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.hasUnreadNotifications) return setHasUnread(true)
|
||||
|
|
@ -83,7 +107,7 @@ const Header = memo(({ tree, user }) => {
|
|||
|
||||
const onPaired = machine => {
|
||||
setOpen(false)
|
||||
history.push('/maintenance/machine-status', { id: machine.deviceId })
|
||||
navigate('/maintenance/machine-status', { state: { id: machine.deviceId } })
|
||||
}
|
||||
|
||||
// these inline styles prevent scroll bubbling: when the user reaches the bottom of the notifications list and keeps scrolling,
|
||||
|
|
@ -114,7 +138,7 @@ const Header = memo(({ tree, user }) => {
|
|||
<div
|
||||
onClick={() => {
|
||||
setActive(false)
|
||||
history.push('/dashboard')
|
||||
navigate('/dashboard')
|
||||
}}
|
||||
className={classnames(styles.logo, styles.logoLink)}>
|
||||
<Logo />
|
||||
|
|
@ -125,15 +149,13 @@ const Header = memo(({ tree, user }) => {
|
|||
{tree.map((it, idx) => {
|
||||
if (!R.includes(user.role, it.allowedRoles)) return <></>
|
||||
return (
|
||||
<NavLink
|
||||
<Link
|
||||
isParent
|
||||
key={idx}
|
||||
to={it.route || it.children[0].route}
|
||||
isActive={match => {
|
||||
if (!match) return false
|
||||
setActive(it)
|
||||
return true
|
||||
}}
|
||||
className={classnames(styles.link)}
|
||||
setActive={setActive}
|
||||
item={it}
|
||||
className={styles.link}
|
||||
activeClassName={styles.activeLink}>
|
||||
<li className={styles.li}>
|
||||
<span
|
||||
|
|
@ -142,7 +164,7 @@ const Header = memo(({ tree, user }) => {
|
|||
{it.label}
|
||||
</span>
|
||||
</li>
|
||||
</NavLink>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
)
|
||||
const container = document.getElementById('root')
|
||||
const root = createRoot(container)
|
||||
root.render(<App />)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useMutation, useLazyQuery, gql } from '@apollo/client'
|
||||
import { Form, Formik } from 'formik'
|
||||
import React, { useContext, useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { TL1, P } from '../../components/typography'
|
||||
|
||||
import AppContext from '../../AppContext'
|
||||
|
|
@ -37,7 +37,7 @@ const GET_USER_DATA = gql`
|
|||
`
|
||||
|
||||
const Input2FAState = ({ state, dispatch }) => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const { setUserData } = useContext(AppContext)
|
||||
|
||||
const [invalidToken, setInvalidToken] = useState(false)
|
||||
|
|
@ -45,7 +45,7 @@ const Input2FAState = ({ state, dispatch }) => {
|
|||
const [getUserData, { error: queryError }] = useLazyQuery(GET_USER_DATA, {
|
||||
onCompleted: ({ userData }) => {
|
||||
setUserData(userData)
|
||||
history.push('/')
|
||||
navigate('/')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useMutation, useLazyQuery, gql } from '@apollo/client'
|
|||
import { startAssertion } from '@simplewebauthn/browser'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import React, { useState, useContext } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { H2, Label2, P } from '../../components/typography'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ const InputFIDOState = ({ state, strategy }) => {
|
|||
}
|
||||
`
|
||||
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const { setUserData } = useContext(AppContext)
|
||||
|
||||
const [localClientField, setLocalClientField] = useState('')
|
||||
|
|
@ -125,7 +125,7 @@ const InputFIDOState = ({ state, strategy }) => {
|
|||
const [getUserData, { error: queryError }] = useLazyQuery(GET_USER_DATA, {
|
||||
onCompleted: ({ userData }) => {
|
||||
setUserData(userData)
|
||||
history.push('/')
|
||||
navigate('/')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useMutation, useLazyQuery, gql } from '@apollo/client'
|
|||
import { startAssertion } from '@simplewebauthn/browser'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import React, { useContext } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { Label3, P } from '../../components/typography'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ const getErrorMsg = (formikErrors, formikTouched, mutationError) => {
|
|||
}
|
||||
|
||||
const LoginState = ({ dispatch, strategy }) => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const { setUserData } = useContext(AppContext)
|
||||
|
||||
const [login, { error: loginMutationError }] = useMutation(LOGIN)
|
||||
|
|
@ -125,7 +125,7 @@ const LoginState = ({ dispatch, strategy }) => {
|
|||
{
|
||||
onCompleted: ({ userData }) => {
|
||||
setUserData(userData)
|
||||
history.push('/')
|
||||
navigate('/')
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Grid from '@mui/material/Grid'
|
|||
import Paper from '@mui/material/Paper'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import React, { useReducer } from 'react'
|
||||
import { useLocation, useHistory } from 'react-router-dom'
|
||||
import { useLocation, useSearchParams } from 'wouter'
|
||||
import { H2, Label3, P } from '../../components/typography'
|
||||
import Logo from '../../styling/icons/menu/logo.svg?react'
|
||||
import * as Yup from 'yup'
|
||||
|
|
@ -12,8 +12,6 @@ import { Button } from '../../components/buttons'
|
|||
import { SecretInput } from '../../components/inputs/formik'
|
||||
import classes from './Authentication.module.css'
|
||||
|
||||
const QueryParams = () => new URLSearchParams(useLocation().search)
|
||||
|
||||
const VALIDATE_REGISTER_LINK = gql`
|
||||
query validateRegisterLink($token: String!) {
|
||||
validateRegisterLink(token: $token) {
|
||||
|
|
@ -84,8 +82,9 @@ const getErrorMsg = (
|
|||
}
|
||||
|
||||
const Register = () => {
|
||||
const history = useHistory()
|
||||
const token = QueryParams().get('t')
|
||||
const [, navigate] = useLocation()
|
||||
const [searchParams] = useSearchParams()
|
||||
const token = searchParams.get('t')
|
||||
|
||||
const [state, dispatch] = useReducer(reducer, initialState)
|
||||
|
||||
|
|
@ -118,7 +117,7 @@ const Register = () => {
|
|||
|
||||
const [register, { error: mutationError }] = useMutation(REGISTER, {
|
||||
onCompleted: ({ register: success }) => {
|
||||
if (success) history.push('/wizard', { fromAuthRegister: true })
|
||||
if (success) navigate('/')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Paper from '@mui/material/Paper'
|
|||
import { Form, Formik } from 'formik'
|
||||
import { QRCodeSVG as QRCode } from 'qrcode.react'
|
||||
import React, { useReducer, useState } from 'react'
|
||||
import { useLocation, useHistory } from 'react-router-dom'
|
||||
import { useLocation, useSearchParams } from 'wouter'
|
||||
import { H2, Label2, Label3, P } from '../../components/typography'
|
||||
import Logo from '../../styling/icons/menu/logo.svg?react'
|
||||
|
||||
|
|
@ -43,9 +43,9 @@ const reducer = (state, action) => {
|
|||
}
|
||||
|
||||
const Reset2FA = () => {
|
||||
const history = useHistory()
|
||||
const QueryParams = () => new URLSearchParams(useLocation().search)
|
||||
const token = QueryParams().get('t')
|
||||
const [, navigate] = useLocation()
|
||||
const [searchParams] = useSearchParams()
|
||||
const token = searchParams.get('t')
|
||||
|
||||
const [isShowing, setShowing] = useState(false)
|
||||
const [invalidToken, setInvalidToken] = useState(false)
|
||||
|
|
@ -85,7 +85,7 @@ const Reset2FA = () => {
|
|||
|
||||
const [reset2FA, { error: mutationError }] = useMutation(RESET_2FA, {
|
||||
onCompleted: ({ reset2FA: success }) => {
|
||||
success ? history.push('/') : setInvalidToken(true)
|
||||
success ? navigate('/') : setInvalidToken(true)
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Grid from '@mui/material/Grid'
|
|||
import Paper from '@mui/material/Paper'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import React, { useState } from 'react'
|
||||
import { useLocation, useHistory } from 'react-router-dom'
|
||||
import { useLocation, useSearchParams } from 'wouter'
|
||||
import { H2, Label3, P } from '../../components/typography'
|
||||
import Logo from '../../styling/icons/menu/logo.svg?react'
|
||||
import * as Yup from 'yup'
|
||||
|
|
@ -57,9 +57,9 @@ const getErrorMsg = (formikErrors, formikTouched, mutationError) => {
|
|||
}
|
||||
|
||||
const ResetPassword = () => {
|
||||
const history = useHistory()
|
||||
const QueryParams = () => new URLSearchParams(useLocation().search)
|
||||
const token = QueryParams().get('t')
|
||||
const [, navigate] = useLocation()
|
||||
const [searchParams] = useSearchParams()
|
||||
const token = searchParams.get('t')
|
||||
const [userID, setUserID] = useState(null)
|
||||
const [isLoading, setLoading] = useState(true)
|
||||
const [wasSuccessful, setSuccess] = useState(false)
|
||||
|
|
@ -83,7 +83,7 @@ const ResetPassword = () => {
|
|||
|
||||
const [resetPassword, { error }] = useMutation(RESET_PASSWORD, {
|
||||
onCompleted: ({ resetPassword: success }) => {
|
||||
if (success) history.push('/')
|
||||
if (success) navigate('/')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useMutation, useQuery, useLazyQuery, gql } from '@apollo/client'
|
|||
import { Form, Formik } from 'formik'
|
||||
import { QRCodeSVG as QRCode } from 'qrcode.react'
|
||||
import React, { useContext, useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { Label3, P } from '../../components/typography'
|
||||
|
||||
import AppContext from '../../AppContext'
|
||||
|
|
@ -48,7 +48,7 @@ const GET_USER_DATA = gql`
|
|||
`
|
||||
|
||||
const Setup2FAState = ({ state }) => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const { setUserData } = useContext(AppContext)
|
||||
|
||||
const [secret, setSecret] = useState(null)
|
||||
|
|
@ -85,7 +85,7 @@ const Setup2FAState = ({ state }) => {
|
|||
const [getUserData] = useLazyQuery(GET_USER_DATA, {
|
||||
onCompleted: ({ userData }) => {
|
||||
setUserData(userData)
|
||||
history.push('/')
|
||||
navigate('/')
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Switch from '@mui/material/Switch'
|
|||
import NavigateNextIcon from '@mui/icons-material/NavigateNext'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo, useState } from 'react'
|
||||
import { useHistory, useParams } from 'react-router-dom'
|
||||
import { useLocation, useParams } from 'wouter'
|
||||
import { Label1, Label2 } from '../../components/typography'
|
||||
import AuthorizeReversedIcon from '../../styling/icons/button/authorize/white.svg?react'
|
||||
import AuthorizeIcon from '../../styling/icons/button/authorize/zodiac.svg?react'
|
||||
|
|
@ -284,7 +284,7 @@ const CHECK_AGAINST_SANCTIONS = gql`
|
|||
`
|
||||
|
||||
const CustomerProfile = memo(() => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
|
||||
const [showCompliance, setShowCompliance] = useState(false)
|
||||
const [wizard, setWizard] = useState(false)
|
||||
|
|
@ -515,7 +515,7 @@ const CustomerProfile = memo(() => {
|
|||
<Label1
|
||||
noMargin
|
||||
className="cursor-pointer text-comet"
|
||||
onClick={() => history.push('/compliance/customers')}>
|
||||
onClick={() => navigate('/compliance/customers')}>
|
||||
Customers
|
||||
</Label1>
|
||||
<Label2 noMargin className="cursor-pointer text-comet">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useQuery, useMutation, gql } from '@apollo/client'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import SearchBox from '../../components/SearchBox'
|
||||
import SearchFilter from '../../components/SearchFilter'
|
||||
import TitleSection from '../../components/layout/TitleSection'
|
||||
|
|
@ -95,10 +95,10 @@ const getFiltersObj = filters =>
|
|||
R.reduce((s, f) => ({ ...s, [f.type]: f.value }), {}, filters)
|
||||
|
||||
const Customers = () => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
|
||||
const handleCustomerClicked = customer =>
|
||||
history.push(`/compliance/customer/${customer.id}`)
|
||||
navigate(`/compliance/customer/${customer.id}`)
|
||||
|
||||
const [filteredCustomers, setFilteredCustomers] = useState([])
|
||||
const [variables, setVariables] = useState({})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import List from '@mui/material/List'
|
|||
import ListItem from '@mui/material/ListItem'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { P } from '../../../components/typography/index'
|
||||
import Wrench from '../../../styling/icons/action/wrench/zodiac.svg?react'
|
||||
import CashBoxEmpty from '../../../styling/icons/cassettes/cashbox-empty.svg?react'
|
||||
|
|
@ -23,7 +23,7 @@ const links = {
|
|||
}
|
||||
|
||||
const AlertsTable = ({ numToRender, alerts, machines }) => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const alertsToRender = R.slice(0, numToRender, alerts)
|
||||
|
||||
const alertMessage = alert => {
|
||||
|
|
@ -45,7 +45,7 @@ const AlertsTable = ({ numToRender, alerts, machines }) => {
|
|||
<P className="my-2">{alertMessage(alert)}</P>
|
||||
<AlertLinkIcon
|
||||
className="ml-auto cursor-pointer"
|
||||
onClick={() => history.push(links[alert.type] || '/dashboard')}
|
||||
onClick={() => navigate(links[alert.type] || '/dashboard')}
|
||||
/>
|
||||
</ListItem>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useQuery, gql } from '@apollo/client'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import TitleSection from '../../components/layout/TitleSection'
|
||||
import { H1, Info2, TL2, Label1 } from '../../components/typography'
|
||||
import TxInIcon from '../../styling/icons/direction/cash-in.svg?react'
|
||||
|
|
@ -26,14 +26,14 @@ const GET_DATA = gql`
|
|||
`
|
||||
|
||||
const Dashboard = () => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const { data, loading } = useQuery(GET_DATA)
|
||||
|
||||
const onPaired = machine => {
|
||||
setOpen(false)
|
||||
history.push('/maintenance/machine-status', { id: machine.deviceId })
|
||||
navigate('/maintenance/machine-status', { state: { id: machine.deviceId } })
|
||||
}
|
||||
|
||||
return !loading ? (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import TableHead from '@mui/material/TableHead'
|
|||
import TableRow from '@mui/material/TableRow'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { Status } from '../../../components/Status'
|
||||
import { Label2, TL2 } from '../../../components/typography'
|
||||
import TxOutIcon from '../../../styling/icons/direction/cash-out.svg?react'
|
||||
|
|
@ -39,7 +39,7 @@ const HeaderCell = styled(TableCell)({
|
|||
})
|
||||
|
||||
const MachinesTable = ({ machines = [], numToRender }) => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
|
||||
const { data } = useQuery(GET_CONFIG)
|
||||
const fillingPercentageSettings = fromNamespace(
|
||||
|
|
@ -65,8 +65,10 @@ const MachinesTable = ({ machines = [], numToRender }) => {
|
|||
}
|
||||
|
||||
const redirect = ({ name, deviceId }) => {
|
||||
return history.push(`/machines/${deviceId}`, {
|
||||
return navigate(`/machines/${deviceId}`, {
|
||||
state: {
|
||||
selectedMachine: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Breadcrumbs from '@mui/material/Breadcrumbs'
|
|||
import NavigateNextIcon from '@mui/icons-material/NavigateNext'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState } from 'react'
|
||||
import { Link, useLocation, useHistory } from 'react-router-dom'
|
||||
import { Link, useLocation } from 'wouter'
|
||||
import { TL1, TL2, Label3 } from '../../components/typography'
|
||||
|
||||
import Cassettes from './MachineComponents/Cassettes'
|
||||
|
|
@ -61,17 +61,13 @@ const GET_INFO = gql`
|
|||
const getMachineID = path => path.slice(path.lastIndexOf('/') + 1)
|
||||
|
||||
const MachineRoute = () => {
|
||||
const location = useLocation()
|
||||
const history = useHistory()
|
||||
|
||||
const id = getMachineID(location.pathname)
|
||||
|
||||
const [location, navigate] = useLocation()
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const id = getMachineID(location)
|
||||
const { data, refetch } = useQuery(GET_INFO, {
|
||||
onCompleted: data => {
|
||||
if (data.machine === null)
|
||||
return history.push('/maintenance/machine-status')
|
||||
if (data.machine === null) return navigate('/maintenance/machine-status')
|
||||
|
||||
setLoading(false)
|
||||
},
|
||||
|
|
@ -85,7 +81,7 @@ const MachineRoute = () => {
|
|||
})
|
||||
|
||||
const reload = () => {
|
||||
return history.push(location.pathname)
|
||||
return navigate(location)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useQuery, gql } from '@apollo/client'
|
|||
import { formatDistance } from 'date-fns'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
import { useHistory, useLocation } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { MainStatus } from '../../components/Status'
|
||||
import Title from '../../components/Title'
|
||||
import DataTable from '../../components/tables/DataTable'
|
||||
|
|
@ -55,9 +55,8 @@ const GET_DATA = gql`
|
|||
`
|
||||
|
||||
const MachineStatus = () => {
|
||||
const history = useHistory()
|
||||
const { state } = useLocation()
|
||||
const addedMachineId = state?.id
|
||||
const [, navigate] = useLocation()
|
||||
const addedMachineId = history.state?.id
|
||||
const {
|
||||
data: machinesResponse,
|
||||
refetch,
|
||||
|
|
@ -77,7 +76,7 @@ const MachineStatus = () => {
|
|||
{m.name}
|
||||
<div
|
||||
onClick={() => {
|
||||
history.push(`/machines/${m.deviceId}`)
|
||||
navigate(`/machines/${m.deviceId}`)
|
||||
}}>
|
||||
<MachineRedirectIcon />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { toUnit, formatCryptoAddress } from '@lamassu/coins/lightUtils'
|
|||
import BigNumber from 'bignumber.js'
|
||||
import * as R from 'ramda'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import LogsDowloaderPopover from '../../components/LogsDownloaderPopper'
|
||||
import SearchBox from '../../components/SearchBox'
|
||||
import SearchFilter from '../../components/SearchFilter'
|
||||
|
|
@ -134,7 +134,7 @@ const getFiltersObj = filters =>
|
|||
R.reduce((s, f) => ({ ...s, [f.type]: f.value }), {}, filters)
|
||||
|
||||
const Transactions = () => {
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
|
||||
const [filters, setFilters] = useState([])
|
||||
const { data: filtersResponse, loading: filtersLoading } = useQuery(
|
||||
|
|
@ -160,7 +160,7 @@ const Transactions = () => {
|
|||
const timezone = R.path(['config', 'locale_timezone'], configResponse)
|
||||
|
||||
const redirect = customerId => {
|
||||
return history.push(`/compliance/customer/${customerId}`)
|
||||
return navigate(`/compliance/customer/${customerId}`)
|
||||
}
|
||||
|
||||
const elements = [
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Dialog from '@mui/material/Dialog'
|
|||
import DialogContent from '@mui/material/DialogContent'
|
||||
import classnames from 'classnames'
|
||||
import React, { useState, useContext } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
import { getWizardStep, STEPS } from './helper'
|
||||
|
||||
import AppContext from '../../AppContext'
|
||||
|
|
@ -23,7 +23,7 @@ const GET_DATA = gql`
|
|||
|
||||
const Wizard = () => {
|
||||
const { data, loading } = useQuery(GET_DATA)
|
||||
const history = useHistory()
|
||||
const [, navigate] = useLocation()
|
||||
const { setWizardTested } = useContext(AppContext)
|
||||
|
||||
const [step, setStep] = useState(0)
|
||||
|
|
@ -52,7 +52,7 @@ const Wizard = () => {
|
|||
if (step >= STEPS.length - 1) {
|
||||
setOpen(false)
|
||||
setWizardTested(true)
|
||||
history.push('/')
|
||||
navigate('/')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { Route, Redirect } from 'react-router-dom'
|
||||
import { Route, Redirect } from 'wouter'
|
||||
|
||||
import AppContext from '../AppContext'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,17 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { Route, Redirect } from 'react-router-dom'
|
||||
import { Route, Redirect } from 'wouter'
|
||||
|
||||
import AppContext from '../AppContext'
|
||||
|
||||
import { isLoggedIn } from './utils'
|
||||
|
||||
const PublicRoute = ({ component: Component, restricted, ...rest }) => {
|
||||
const PublicRoute = ({ restricted, ...rest }) => {
|
||||
const { userData } = useContext(AppContext)
|
||||
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
render={props =>
|
||||
isLoggedIn(userData) && restricted ? (
|
||||
return isLoggedIn(userData) && restricted ? (
|
||||
<Redirect to="/" />
|
||||
) : (
|
||||
<Component {...props} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Route {...rest} />
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
8
packages/admin-ui/src/routing/dirtyHandler.js
Normal file
8
packages/admin-ui/src/routing/dirtyHandler.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { create } from 'zustand'
|
||||
|
||||
const useDirtyHandler = create(set => ({
|
||||
isDirty: false,
|
||||
setIsDirty: it => set({ isDirty: it }),
|
||||
}))
|
||||
|
||||
export default useDirtyHandler
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
import { Redirect } from 'wouter'
|
||||
import Funding from '../pages/Funding/Funding.jsx'
|
||||
import IndividualDiscounts from '../pages/LoyaltyPanel/IndividualDiscounts'
|
||||
import PromoCodes from '../pages/LoyaltyPanel/PromoCodes'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import Fade from '@mui/material/Fade'
|
|||
import Slide from '@mui/material/Slide'
|
||||
import * as R from 'ramda'
|
||||
import React, { useContext } from 'react'
|
||||
import { matchPath, Redirect, Switch, useLocation } from 'react-router-dom'
|
||||
import { Redirect, Switch, useLocation } from 'wouter'
|
||||
import Login from '../pages/Authentication/Login'
|
||||
import Register from '../pages/Authentication/Register'
|
||||
import Reset2FA from '../pages/Authentication/Reset2FA'
|
||||
|
|
@ -50,7 +50,7 @@ const getParent = route =>
|
|||
)(flattened)
|
||||
|
||||
const Routes = () => {
|
||||
const location = useLocation()
|
||||
const [location] = useLocation()
|
||||
const { userData } = useContext(AppContext)
|
||||
|
||||
const getFilteredRoutes = () => {
|
||||
|
|
@ -63,14 +63,14 @@ const Routes = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const Transition = location.state ? Slide : Fade
|
||||
const Transition = history.state ? Slide : Fade
|
||||
|
||||
const transitionProps =
|
||||
Transition === Slide
|
||||
? {
|
||||
direction:
|
||||
R.findIndex(R.propEq('route', location.state.prev))(leafRoutes) >
|
||||
R.findIndex(R.propEq('route', location.pathname))(leafRoutes)
|
||||
R.findIndex(R.propEq('route', history.state.prev))(leafRoutes) >
|
||||
R.findIndex(R.propEq('route', location))(leafRoutes)
|
||||
? 'right'
|
||||
: 'left',
|
||||
}
|
||||
|
|
@ -79,9 +79,9 @@ const Routes = () => {
|
|||
return (
|
||||
<Switch>
|
||||
<PrivateRoute exact path="/">
|
||||
<Redirect to={{ pathname: '/dashboard' }} />
|
||||
<Redirect to="/dashboard" />
|
||||
</PrivateRoute>
|
||||
<PrivateRoute path={'/dashboard'}>
|
||||
<PrivateRoute path="/dashboard">
|
||||
<Transition
|
||||
className={wrapperClasses}
|
||||
{...transitionProps}
|
||||
|
|
@ -93,7 +93,9 @@ const Routes = () => {
|
|||
</div>
|
||||
</Transition>
|
||||
</PrivateRoute>
|
||||
<PrivateRoute path="/machines" component={Machines} />
|
||||
<PrivateRoute path="/machines">
|
||||
<Machines />
|
||||
</PrivateRoute>
|
||||
<PublicRoute path="/register" component={Register} />
|
||||
<PublicRoute path="/resetpassword" component={ResetPassword} />
|
||||
<PublicRoute path="/reset2fa" component={Reset2FA} />
|
||||
|
|
@ -103,20 +105,18 @@ const Routes = () => {
|
|||
<Transition
|
||||
className={wrapperClasses}
|
||||
{...transitionProps}
|
||||
in={!!matchPath(location.pathname, { path: route })}
|
||||
in={location === route}
|
||||
mountOnEnter
|
||||
unmountOnExit>
|
||||
<div className={wrapperClasses}>
|
||||
<PrivateRoute path={route} key={key}>
|
||||
<Page name={key} />
|
||||
</PrivateRoute>
|
||||
</div>
|
||||
</Transition>
|
||||
</PrivateRoute>
|
||||
))}
|
||||
<PublicRoute path="/404" />
|
||||
<PublicRoute path="*">
|
||||
<Redirect to={{ pathname: '/404' }} />
|
||||
<Redirect to="/404" />
|
||||
</PublicRoute>
|
||||
</Switch>
|
||||
)
|
||||
|
|
|
|||
34
packages/admin-ui/src/routing/useLocationWithConfirmation.js
Normal file
34
packages/admin-ui/src/routing/useLocationWithConfirmation.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import useDirtyHandler from './dirtyHandler.js'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useBrowserLocation } from 'wouter/use-browser-location'
|
||||
|
||||
const PROMPT_DEFAULT_MESSAGE =
|
||||
'You have unsaved changes on this page. Are you sure you want to leave?'
|
||||
|
||||
const useLocationWithConfirmation = () => {
|
||||
const setIsDirty = useDirtyHandler(state => state.setIsDirty)
|
||||
const isDirtyRef = useRef(useDirtyHandler.getState().isDirty)
|
||||
useEffect(
|
||||
() =>
|
||||
useDirtyHandler.subscribe(state => (isDirtyRef.current = state.isDirty)),
|
||||
[],
|
||||
)
|
||||
const [location, setLocation] = useBrowserLocation()
|
||||
|
||||
return [
|
||||
location,
|
||||
newLocation => {
|
||||
let perfomNavigation = true
|
||||
if (isDirtyRef.current) {
|
||||
perfomNavigation = window.confirm(PROMPT_DEFAULT_MESSAGE)
|
||||
}
|
||||
|
||||
if (perfomNavigation) {
|
||||
setLocation(newLocation)
|
||||
setIsDirty(false)
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export default useLocationWithConfirmation
|
||||
|
|
@ -7,7 +7,7 @@ import {
|
|||
import { onError } from '@apollo/client/link/error'
|
||||
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs'
|
||||
import React, { useContext } from 'react'
|
||||
import { useHistory, useLocation } from 'react-router-dom'
|
||||
import { useLocation } from 'wouter'
|
||||
|
||||
import AppContext from '../AppContext'
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ const uploadLink = createUploadLink({
|
|||
uri: `/graphql`,
|
||||
})
|
||||
|
||||
const getClient = (history, location, getUserData, setUserData, setRole) =>
|
||||
const getClient = (navigate, location, getUserData, setUserData, setRole) =>
|
||||
new ApolloClient({
|
||||
link: ApolloLink.from([
|
||||
onError(({ graphQLErrors, networkError }) => {
|
||||
|
|
@ -24,7 +24,7 @@ const getClient = (history, location, getUserData, setUserData, setRole) =>
|
|||
graphQLErrors.forEach(({ message, locations, path, extensions }) => {
|
||||
if (extensions?.code === 'UNAUTHENTICATED') {
|
||||
setUserData(null)
|
||||
if (location.pathname !== '/login') history.push('/login')
|
||||
if (location !== '/login') navigate('/login')
|
||||
}
|
||||
console.log(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
|
||||
|
|
@ -66,11 +66,10 @@ const getClient = (history, location, getUserData, setUserData, setRole) =>
|
|||
})
|
||||
|
||||
const Provider = ({ children }) => {
|
||||
const history = useHistory()
|
||||
const location = useLocation()
|
||||
const [location, navigate] = useLocation()
|
||||
const { userData, setUserData, setRole } = useContext(AppContext)
|
||||
const client = getClient(
|
||||
history,
|
||||
navigate,
|
||||
location,
|
||||
() => userData,
|
||||
setUserData,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue