mirror of https://github.com/buster-so/buster.git
78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
'use client';
|
|
|
|
import { BusterRoutesWithArgsRoute, createBusterRoute } from '@/routes/busterRoutes';
|
|
import { pathNameToRoute } from '@/routes/helpers';
|
|
import { useMemoizedFn, usePrevious } from '@/hooks';
|
|
import { useRouter, usePathname, useSelectedLayoutSegment, useParams } from 'next/navigation';
|
|
import React, { PropsWithChildren } from 'react';
|
|
import { createContext, useContextSelector } from 'use-context-selector';
|
|
|
|
export const useAppLayout = () => {
|
|
const { push } = useRouter();
|
|
const pathname = usePathname();
|
|
const params = useParams();
|
|
const currentRoute = pathNameToRoute(pathname, params);
|
|
const [openInviteModal, setOpenInviteModal] = React.useState(false);
|
|
|
|
const onToggleInviteModal = useMemoizedFn((v?: boolean) => {
|
|
setOpenInviteModal(v ?? !openInviteModal);
|
|
});
|
|
|
|
const onChangePage = useMemoizedFn(
|
|
(params: BusterRoutesWithArgsRoute | string): Promise<void> => {
|
|
return new Promise((resolve) => {
|
|
const targetPath = typeof params === 'string' ? params : createBusterRoute(params);
|
|
const currentPath = window.location.pathname;
|
|
|
|
// If we're already on the target path, resolve immediately
|
|
if (currentPath === targetPath) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
// Set up an effect to watch for pathname changes
|
|
const checkPathChange = (waitTime: number = 25, iteration: number = 0) => {
|
|
if (window.location.pathname !== currentPath) {
|
|
resolve();
|
|
} else if (iteration >= 10) {
|
|
// Resolve after 10 attempts to prevent infinite loops
|
|
resolve();
|
|
} else {
|
|
// Check again in a short while if the path hasn't changed yet
|
|
const newWaitTime = waitTime * 1.25;
|
|
setTimeout(() => checkPathChange(newWaitTime, iteration + 1), newWaitTime);
|
|
}
|
|
};
|
|
|
|
// Start the navigation
|
|
push(targetPath);
|
|
|
|
// Start checking for path changes
|
|
checkPathChange();
|
|
});
|
|
}
|
|
);
|
|
|
|
return {
|
|
currentRoute,
|
|
onToggleInviteModal,
|
|
openInviteModal,
|
|
onChangePage
|
|
};
|
|
};
|
|
|
|
const AppLayoutContext = createContext<ReturnType<typeof useAppLayout>>(
|
|
{} as ReturnType<typeof useAppLayout>
|
|
);
|
|
|
|
export const AppLayoutProvider = React.memo<PropsWithChildren>(({ children }) => {
|
|
const value = useAppLayout();
|
|
|
|
return <AppLayoutContext.Provider value={value}>{children}</AppLayoutContext.Provider>;
|
|
});
|
|
AppLayoutProvider.displayName = 'AppLayoutProvider';
|
|
|
|
export const useAppLayoutContextSelector = <T,>(
|
|
selector: (state: ReturnType<typeof useAppLayout>) => T
|
|
) => useContextSelector(AppLayoutContext, selector);
|