Allow saved time unit redirect past blocker

This commit is contained in:
karilint
2026-05-27 18:47:37 +03:00
parent 699cbb125b
commit a4bf5c050a
3 changed files with 26 additions and 5 deletions
@@ -65,7 +65,10 @@ export const TimeUnitDetails = ({
})
unsavedChanges?.setDirty(false)
notify('Edited item successfully.')
return () => navigate(`/time-unit/${tu_name}`)
return () => {
unsavedChanges?.allowNextNavigation?.()
navigate(`/time-unit/${tu_name}`)
}
} catch (e) {
if (data) {
setEditData(makeEditData(data))
@@ -1,4 +1,4 @@
import { useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from 'react'
import { useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import { UNSAFE_DataRouterContext, useBlocker } from 'react-router-dom'
import { UnsavedChangesDialog } from './UnsavedChangesDialog'
@@ -20,12 +20,13 @@ const unblockedState = {
}
type BlockerState = typeof unblockedState | ReturnType<typeof useBlocker>
type BlockerPredicate = Parameters<typeof useBlocker>[0]
const BlockerBridge = ({
shouldBlock,
onChange,
}: {
shouldBlock: boolean
shouldBlock: BlockerPredicate
onChange: (blocker: ReturnType<typeof useBlocker>) => void
}) => {
const blocker = useBlocker(shouldBlock)
@@ -45,6 +46,7 @@ export const UnsavedChangesProvider = ({
const [isDirty, setDirty] = useState(false)
const [message, setMessage] = useState(defaultMessage)
const [blocker, setBlocker] = useState<BlockerState>(unblockedState)
const allowNextNavigationRef = useRef(false)
const dataRouterContext = useContext(UNSAFE_DataRouterContext)
const isSamePathNavigation = blocker.state === 'blocked' && blocker.location?.pathname === window.location.pathname
@@ -54,6 +56,20 @@ export const UnsavedChangesProvider = ({
setMessage(defaultMessage)
}, [defaultMessage])
const allowNextNavigation = useCallback(() => {
allowNextNavigationRef.current = true
setDirty(false)
}, [])
const shouldBlockNavigation = useCallback(() => {
if (!isDirty) return false
if (allowNextNavigationRef.current) {
allowNextNavigationRef.current = false
return false
}
return true
}, [isDirty])
const handleConfirm = useCallback(() => {
if (blocker.state === 'blocked') {
setDirty(false)
@@ -87,13 +103,14 @@ export const UnsavedChangesProvider = ({
setDirty,
setMessage,
resetMessage,
allowNextNavigation,
}),
[isDirty, message, resetMessage]
[allowNextNavigation, isDirty, message, resetMessage]
)
return (
<UnsavedChangesContext.Provider value={value}>
{dataRouterContext ? <BlockerBridge shouldBlock={isDirty} onChange={setBlocker} /> : null}
{dataRouterContext ? <BlockerBridge shouldBlock={shouldBlockNavigation} onChange={setBlocker} /> : null}
{children}
<UnsavedChangesDialog
open={showDialog}
@@ -6,6 +6,7 @@ export type UnsavedChangesContextValue = {
setDirty: (dirty: boolean) => void
setMessage: (message: string) => void
resetMessage: () => void
allowNextNavigation?: () => void
}
export const UnsavedChangesContext = createContext<UnsavedChangesContextValue | null>(null)