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