-
-
Notifications
You must be signed in to change notification settings - Fork 380
Add blocker to prevent changes being lost #197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Add blocker to prevent changes being lost #197
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we leave the ThemeProvider as the top parent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
components/entry/entry-form.tsx
Outdated
} from "@dnd-kit/modifiers"; | ||
import { CSS } from "@dnd-kit/utilities"; | ||
import { ChevronLeft, GripVertical, Loader, Plus, Trash2 } from "lucide-react"; | ||
import { Blocker } from "../navigation-block"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolute path please. I would only use a relative path in a self contained module (e.g. field).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
|
||
return ( | ||
<Form {...form}> | ||
{isDirty && <Blocker />} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the conditional on <Blocker />
. When would <Bocker />
be falsy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When there are no changes to save, we don't need to block navigation away? This is what this is doing.
'use client'; | ||
import { startTransition } from 'react'; | ||
import NextLink from 'next/link'; | ||
import { useRouter } from 'next/navigation'; | ||
import { useIsBlocked } from './navigation-block'; | ||
|
||
/** | ||
* A custom Link component that wraps Next.js's next/link component. | ||
*/ | ||
export function Link({ | ||
href, | ||
children, | ||
replace, | ||
...rest | ||
}: Parameters<typeof NextLink>[0]) { | ||
const router = useRouter(); | ||
const isBlocked = useIsBlocked(); | ||
|
||
return ( | ||
<NextLink | ||
href={href} | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
|
||
// Cancel navigation | ||
if (isBlocked && !window.confirm('Do you really want to leave?')) { | ||
return; | ||
} | ||
|
||
startTransition(() => { | ||
const url = href.toString(); | ||
if (replace) { | ||
router.replace(url); | ||
} else { | ||
router.push(url); | ||
} | ||
}); | ||
}} | ||
{...rest} | ||
> | ||
{children} | ||
</NextLink> | ||
); | ||
} No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this coming from and where is it used? I don't see it imported in your other commits..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
components/providers.tsx
Outdated
</TooltipProvider> | ||
</UserProvider> | ||
</ThemeProvider> | ||
<NavigationBlockerProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not leave the ThemeProvider as the top parent? Can't remember it clearly, but pretty sure ThemeProvider had to be top parent (you can check the shadcn/ui documentation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
// components/navigation-block.tsx | ||
'use client'; | ||
|
||
import { | ||
Dispatch, | ||
SetStateAction, | ||
createContext, | ||
useContext, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
|
||
const NavigationBlockerContext = createContext< | ||
[isBlocked: boolean, setBlocked: Dispatch<SetStateAction<boolean>>] | ||
>([false, () => { }]); | ||
|
||
export function NavigationBlockerProvider({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
// [isBlocked, setBlocked] | ||
const state = useState(false); | ||
return ( | ||
<NavigationBlockerContext.Provider value={state}> | ||
{children} | ||
</NavigationBlockerContext.Provider> | ||
); | ||
} | ||
|
||
export function useIsBlocked() { | ||
const [isBlocked] = useContext(NavigationBlockerContext); | ||
return isBlocked; | ||
} | ||
|
||
export function Blocker() { | ||
const [isBlocked, setBlocked] = useContext(NavigationBlockerContext); | ||
useEffect(() => { | ||
setBlocked(() => { | ||
return true; | ||
}); | ||
return () => { | ||
setBlocked(() => { | ||
return false; | ||
}); | ||
}; | ||
}, [isBlocked, setBlocked]); | ||
return null; | ||
} | ||
|
||
export function BlockBrowserNavigation() { | ||
const isBlocked = useIsBlocked(); | ||
useEffect(() => { | ||
console.log({ isBlocked }); | ||
if (isBlocked) { | ||
const showModal = (event: BeforeUnloadEvent) => { | ||
event.preventDefault(); | ||
}; | ||
|
||
window.addEventListener('beforeunload', showModal); | ||
return () => { | ||
window.removeEventListener('beforeunload', showModal); | ||
}; | ||
} | ||
}, [isBlocked]); | ||
|
||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where did you get this solution from? Can you explain me what it does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vercel/next.js#41934 (comment) - explains it there
Can you test against the latest version? |
No description provided.