better prevent navigation logic

This commit is contained in:
Nate Kelley 2025-04-01 15:31:21 -06:00
parent f915e4caea
commit d9bc8d4741
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
6 changed files with 71 additions and 19 deletions

View File

@ -24,7 +24,6 @@ const SplitterContent: React.FC<{
isSaving: boolean; isSaving: boolean;
open: boolean; open: boolean;
}> = React.memo(({ onReset, onSave, isSaving, open }) => { }> = React.memo(({ onReset, onSave, isSaving, open }) => {
console.log(open);
return ( return (
<React.Fragment> <React.Fragment>
<div className="flex w-full items-center space-x-2.5"> <div className="flex w-full items-center space-x-2.5">

View File

@ -122,7 +122,7 @@ export const SidebarPrimary = React.memo(() => {
const isAdmin = useUserConfigContextSelector((x) => x.isAdmin); const isAdmin = useUserConfigContextSelector((x) => x.isAdmin);
const isUserRegistered = useUserConfigContextSelector((x) => x.isUserRegistered); const isUserRegistered = useUserConfigContextSelector((x) => x.isUserRegistered);
const { data: favorites } = useGetUserFavorites(); const { data: favorites } = useGetUserFavorites();
const currentRoute = useAppLayoutContextSelector((x) => x.currentRoute); const currentParentRoute = useAppLayoutContextSelector((x) => x.currentParentRoute);
const onToggleInviteModal = useInviteModalStore((s) => s.onToggleInviteModal); const onToggleInviteModal = useInviteModalStore((s) => s.onToggleInviteModal);
const [openSupportModal, setOpenSupportModal] = useState(false); const [openSupportModal, setOpenSupportModal] = useState(false);
const { mutateAsync: updateUserFavorites } = useUpdateUserFavorites(); const { mutateAsync: updateUserFavorites } = useUpdateUserFavorites();
@ -150,7 +150,7 @@ export const SidebarPrimary = React.memo(() => {
items.push(tryGroup(onToggleInviteModal, () => setOpenSupportModal(true))); items.push(tryGroup(onToggleInviteModal, () => setOpenSupportModal(true)));
return items; return items;
}, [isAdmin, isUserRegistered, favorites, currentRoute, onFavoritesReorder]); }, [isAdmin, isUserRegistered, favorites, currentParentRoute, onFavoritesReorder]);
const onCloseSupportModal = useMemoizedFn(() => setOpenSupportModal(false)); const onCloseSupportModal = useMemoizedFn(() => setOpenSupportModal(false));
@ -165,7 +165,7 @@ export const SidebarPrimary = React.memo(() => {
<Sidebar <Sidebar
content={sidebarItems} content={sidebarItems}
header={HeaderMemoized} header={HeaderMemoized}
activeItem={currentRoute} activeItem={currentParentRoute}
footer={FooterMemoized} footer={FooterMemoized}
/> />

View File

@ -44,8 +44,10 @@ export const PreventNavigation: React.FC<PreventNavigationProps> = React.memo(
* @param e The triggered event. * @param e The triggered event.
*/ */
const handleClick = useMemoizedFn((event: MouseEvent) => { const handleClick = useMemoizedFn((event: MouseEvent) => {
let originalTarget = event.target as HTMLElement;
let target = event.target as HTMLElement; let target = event.target as HTMLElement;
let href: string | null = null; let href: string | null = null;
let originalEvent = event;
// Traverse up the DOM tree looking for an anchor tag with href // Traverse up the DOM tree looking for an anchor tag with href
while (target && !href) { while (target && !href) {
@ -60,11 +62,53 @@ export const PreventNavigation: React.FC<PreventNavigationProps> = React.memo(
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
console.log(target); // Store both the target and the original event details
confirmationFn.current = () => { confirmationFn.current = () => {
target.click(); // Remove all click listeners temporarily
// if (href) router.push(href); document.querySelectorAll('a').forEach((link) => {
link.removeEventListener('click', handleClick);
});
// Get all click event handlers on the original target
const clickHandlers = originalTarget.onclick;
// Temporarily remove our prevention
if (clickHandlers) {
originalTarget.onclick = null;
}
// Create a new click event
const newEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window,
detail: originalEvent.detail,
screenX: originalEvent.screenX,
screenY: originalEvent.screenY,
clientX: originalEvent.clientX,
clientY: originalEvent.clientY,
ctrlKey: originalEvent.ctrlKey,
altKey: originalEvent.altKey,
shiftKey: originalEvent.shiftKey,
metaKey: originalEvent.metaKey,
button: originalEvent.button,
buttons: originalEvent.buttons
});
// Dispatch the event directly on the original target
originalTarget.dispatchEvent(newEvent);
// Restore click handlers
if (clickHandlers) {
originalTarget.onclick = clickHandlers;
}
// Re-attach our listeners after a short delay
setTimeout(() => {
document.querySelectorAll('a').forEach((link) => {
link.addEventListener('click', handleClick);
});
}, 0);
}; };
setLeavingPage(true); setLeavingPage(true);
@ -79,7 +123,6 @@ export const PreventNavigation: React.FC<PreventNavigationProps> = React.memo(
window.history.pushState(null, document.title, window.location.href); window.history.pushState(null, document.title, window.location.href);
confirmationFn.current = () => { confirmationFn.current = () => {
console.warn('TODO - make sure we can navigate back to the correct page');
router.back(); router.back();
}; };

View File

@ -131,7 +131,6 @@ export const AppSegmented: AppSegmentedComponent = React.memo(
const [isPending, startTransition] = useTransition(); const [isPending, startTransition] = useTransition();
const handleTabClick = useMemoizedFn((value: string) => { const handleTabClick = useMemoizedFn((value: string) => {
console.log('handleTabClick called with:', value);
const item = options.find((item) => item.value === value); const item = options.find((item) => item.value === value);
if (item && !item.disabled && value !== selectedValue) { if (item && !item.disabled && value !== selectedValue) {
setSelectedValue(item.value); setSelectedValue(item.value);
@ -174,6 +173,7 @@ export const AppSegmented: AppSegmentedComponent = React.memo(
<Tabs.Root <Tabs.Root
ref={rootRef} ref={rootRef}
value={selectedValue as string} value={selectedValue as string}
// onValueChange={handleTabClick}
className={cn(segmentedVariants({ block, type }), heightVariants({ size }), className)}> className={cn(segmentedVariants({ block, type }), heightVariants({ size }), className)}>
{isMeasured && ( {isMeasured && (
<motion.div <motion.div
@ -231,6 +231,18 @@ function SegmentedTriggerComponent<T extends string = string>(props: SegmentedTr
const LinkDiv = link ? Link : 'div'; const LinkDiv = link ? Link : 'div';
const handleClick = async (e: React.MouseEvent) => {
if (link) {
e.preventDefault();
handleTabClick(value);
// Wait for a short duration to allow the animation to complete
await new Promise((resolve) => setTimeout(resolve, 1));
router.push(link);
} else {
handleTabClick(value);
}
};
useMount(() => { useMount(() => {
if (link) { if (link) {
router.prefetch(link); router.prefetch(link);
@ -239,13 +251,12 @@ function SegmentedTriggerComponent<T extends string = string>(props: SegmentedTr
return ( return (
<Tooltip title={tooltip || ''} sideOffset={10} delayDuration={150}> <Tooltip title={tooltip || ''} sideOffset={10} delayDuration={150}>
<LinkDiv href={link || ''}> <LinkDiv href={link || ''} onClick={handleClick}>
<Tabs.Trigger <Tabs.Trigger
key={value} key={value}
value={value} value={value}
disabled={disabled} disabled={disabled}
asChild asChild
onClick={() => handleTabClick(value)}
ref={(el) => { ref={(el) => {
if (el) tabRefs.current.set(value, el); if (el) tabRefs.current.set(value, el);
}} }}

View File

@ -13,7 +13,6 @@ export const MetricContainerHeaderSegment: React.FC<FileContainerSegmentProps> =
const metricId = useChatLayoutContextSelector((x) => x.metricId) || ''; const metricId = useChatLayoutContextSelector((x) => x.metricId) || '';
const onChange = useMemoizedFn((fileView: SegmentedItem<FileView>) => { const onChange = useMemoizedFn((fileView: SegmentedItem<FileView>) => {
console.log(fileView);
onSetFileView({ fileView: fileView.value }); onSetFileView({ fileView: fileView.value });
}); });

View File

@ -20,11 +20,7 @@ export const pathNameToRoute = (pathName: string, params: any): BusterRoutes =>
[BusterRoutes.APP_DATASETS_ID_PERMISSIONS_OVERVIEW]: BusterRoutes.APP_DATASETS, [BusterRoutes.APP_DATASETS_ID_PERMISSIONS_OVERVIEW]: BusterRoutes.APP_DATASETS,
[BusterRoutes.APP_DATASETS_ID_OVERVIEW]: BusterRoutes.APP_DATASETS, [BusterRoutes.APP_DATASETS_ID_OVERVIEW]: BusterRoutes.APP_DATASETS,
[BusterRoutes.APP_DATASETS_ID_EDITOR]: BusterRoutes.APP_DATASETS, [BusterRoutes.APP_DATASETS_ID_EDITOR]: BusterRoutes.APP_DATASETS,
[BusterRoutes.APP_TERMS_ID]: BusterRoutes.APP_TERMS, [BusterRoutes.APP_TERMS_ID]: BusterRoutes.APP_TERMS
[BusterRoutes.APP_CHAT_ID_METRIC_ID_CHART]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_METRIC_ID_FILE]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_METRIC_ID_RESULTS]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_DASHBOARD_ID_FILE]: BusterRoutes.APP_CHAT
}; };
if (route && paramRoutesToParent[route as string]) { if (route && paramRoutesToParent[route as string]) {
@ -67,7 +63,11 @@ export const pathNameToParentRoute = (pathName: string, params: any): BusterRout
[BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_USERS]: BusterRoutes.SETTINGS_PERMISSION_GROUPS, [BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_USERS]: BusterRoutes.SETTINGS_PERMISSION_GROUPS,
[BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASET_GROUPS]: [BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASET_GROUPS]:
BusterRoutes.SETTINGS_PERMISSION_GROUPS, BusterRoutes.SETTINGS_PERMISSION_GROUPS,
[BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASETS]: BusterRoutes.SETTINGS_PERMISSION_GROUPS [BusterRoutes.SETTINGS_PERMISSION_GROUPS_ID_DATASETS]: BusterRoutes.SETTINGS_PERMISSION_GROUPS,
[BusterRoutes.APP_CHAT_ID_METRIC_ID_CHART]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_METRIC_ID_FILE]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_METRIC_ID_RESULTS]: BusterRoutes.APP_CHAT,
[BusterRoutes.APP_CHAT_ID_DASHBOARD_ID_FILE]: BusterRoutes.APP_CHAT
}; };
if (route && paramRoutesToParent[route as string]) { if (route && paramRoutesToParent[route as string]) {