Skip to content

Commit 9c2c303

Browse files
committed
refactor(ui): migrate unsaved-page blocker to react-router useBlocker API
1 parent 5a82f0f commit 9c2c303

5 files changed

Lines changed: 154 additions & 162 deletions

File tree

ui/dashboard/src/app/index.tsx

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { memo, useCallback, useEffect, useState } from 'react';
22
import { I18nextProvider } from 'react-i18next';
33
import {
4-
BrowserRouter,
4+
createBrowserRouter,
5+
Outlet,
56
Route,
7+
RouterProvider,
68
Routes,
7-
useParams,
9+
useLocation,
810
useNavigate,
9-
useLocation
11+
useParams
1012
} from 'react-router';
1113
import { QueryClientProvider } from '@tanstack/react-query';
1214
import {
@@ -97,46 +99,12 @@ export const AppLoading = () => (
9799
</div>
98100
);
99101

100-
function App() {
101-
return (
102-
<I18nextProvider i18n={i18n}>
103-
<QueryClientProvider client={queryClient}>
104-
<ConfirmProvider>
105-
<BrowserRouter>
106-
<AuthProvider>
107-
<Routes>
108-
<Route
109-
path={PAGE_PATH_AUTH_CALLBACK}
110-
element={<AuthCallbackPage />}
111-
/>
112-
<Route
113-
path={PAGE_PATH_AUTH_DEMO_CALLBACK}
114-
element={<AuthDemoCallbackPage />}
115-
/>
116-
<Route
117-
path={PAGE_PATH_AUTH_SIGNIN}
118-
element={<SignInEmailPage />}
119-
/>
120-
<Route
121-
path={PAGE_PATH_DEMO_SITE}
122-
element={<AccessDemoPage />}
123-
/>
124-
<Route
125-
path={`${PAGE_PATH_DEMO_SITE}/new`}
126-
element={<CreateDemoPage />}
127-
/>
128-
<Route path={`${PAGE_PATH_ROOT}*`} element={<Root />} />
129-
</Routes>
130-
</AuthProvider>
131-
</BrowserRouter>
132-
</ConfirmProvider>
133-
{/* {process.env.NODE_ENV === 'development' && (
134-
<ReactQueryDevtools initialIsOpen={false} />
135-
)} */}
136-
</QueryClientProvider>
137-
</I18nextProvider>
138-
);
139-
}
102+
// All routes live inside AuthShell so every page can access AuthProvider context
103+
const AuthShell = () => (
104+
<AuthProvider>
105+
<Outlet />
106+
</AuthProvider>
107+
);
140108

141109
export const Root = memo(() => {
142110
const authToken = getTokenStorage();
@@ -146,7 +114,7 @@ export const Root = memo(() => {
146114

147115
const handleChangePageKey = useCallback(() => {
148116
setPageKey(uuid());
149-
}, [setPageKey]);
117+
}, []);
150118

151119
if (isInitialLoading) {
152120
return <AppLoading />;
@@ -300,11 +268,37 @@ export const EnvironmentRoot = memo(
300268
<Route path={`${PAGE_PATH_AUDIT_LOGS}/*`} element={<AuditLogsPage />} />
301269
<Route path={`${PAGE_PATH_DEBUGGER}/*`} element={<DebuggerPage />} />
302270
<Route path={`${PAGE_PATH_INSIGHTS}/*`} element={<InsightsPage />} />
303-
304271
<Route path="*" element={<NotFoundPage />} />
305272
</Routes>
306273
);
307274
}
308275
);
309276

277+
// Router is defined after all components to avoid "used before declaration" errors
278+
const router = createBrowserRouter([
279+
{
280+
element: <AuthShell />,
281+
children: [
282+
{ path: PAGE_PATH_AUTH_CALLBACK, element: <AuthCallbackPage /> },
283+
{ path: PAGE_PATH_AUTH_DEMO_CALLBACK, element: <AuthDemoCallbackPage /> },
284+
{ path: PAGE_PATH_AUTH_SIGNIN, element: <SignInEmailPage /> },
285+
{ path: PAGE_PATH_DEMO_SITE, element: <AccessDemoPage /> },
286+
{ path: `${PAGE_PATH_DEMO_SITE}/new`, element: <CreateDemoPage /> },
287+
{ path: `${PAGE_PATH_ROOT}*`, element: <Root /> }
288+
]
289+
}
290+
]);
291+
292+
function App() {
293+
return (
294+
<I18nextProvider i18n={i18n}>
295+
<QueryClientProvider client={queryClient}>
296+
<ConfirmProvider>
297+
<RouterProvider router={router} />
298+
</ConfirmProvider>
299+
</QueryClientProvider>
300+
</I18nextProvider>
301+
);
302+
}
303+
310304
export default App;

ui/dashboard/src/components/navigation/my-projects.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { ENVIRONMENT_WITH_EMPTY_ID } from 'constants/app';
1313
import { PAGE_PATH_FEATURES } from 'constants/routing';
1414
import { useToast } from 'hooks';
15-
import { allowNavigation, useConfirm } from 'hooks/use-unsaved-leave-page';
15+
import { useConfirm } from 'hooks/use-unsaved-leave-page';
1616
import { useTranslation } from 'i18n';
1717
import {
1818
clearCurrentEnvIdStorage,
@@ -38,7 +38,12 @@ const MyProjects = () => {
3838
const navigate = useNavigate();
3939
const { consoleAccount, logout } = useAuth();
4040
const { errorNotify } = useToast();
41-
const { isShow: showConfirm, confirm, setIsShow } = useConfirm();
41+
const {
42+
isShow: showConfirm,
43+
confirm,
44+
setIsShow,
45+
allowNavigation
46+
} = useConfirm();
4247
const [isShowProjectsList, setIsShowProjectsList] = useState(false);
4348
const [searchValue, setSearchValue] = useState('');
4449
const [projects, setProjects] = useState<Project[]>();

ui/dashboard/src/components/navigation/switch-organization.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { switchOrganization } from '@api/auth';
44
import { useAuth } from 'auth';
55
import { PAGE_PATH_ROOT } from 'constants/routing';
66
import { useToast } from 'hooks';
7-
import { allowNavigation, useConfirm } from 'hooks/use-unsaved-leave-page';
7+
import { useConfirm } from 'hooks/use-unsaved-leave-page';
88
import { useTranslation } from 'i18n';
99
import { clearCurrentEnvIdStorage } from 'storage/environment';
1010
import {
@@ -67,7 +67,13 @@ const SwitchOrganization = ({
6767
const { t } = useTranslation(['common', 'form']);
6868
const { myOrganizations, onMeFetcher } = useAuth();
6969
const { errorNotify } = useToast();
70-
const { isShow: showConfirm, setIsShow, confirm, options } = useConfirm();
70+
const {
71+
isShow: showConfirm,
72+
setIsShow,
73+
confirm,
74+
options,
75+
allowNavigation
76+
} = useConfirm();
7177
const organizationId = getOrgIdStorage();
7278
const [searchValue, setSearchValue] = useState('');
7379
const [currentOrganization, setCurrentOrganization] = useState(

0 commit comments

Comments
 (0)