Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a57173e25e |
@@ -97,7 +97,6 @@ axiosInstance.interceptors.response.use(
|
|||||||
if (error.response.status === 401 && isRefreshCall) {
|
if (error.response.status === 401 && isRefreshCall) {
|
||||||
await clearTokens();
|
await clearTokens();
|
||||||
applyAccessToken(null);
|
applyAccessToken(null);
|
||||||
// Hash-safe on Capacitor (#24); plain path on web BrowserRouter.
|
|
||||||
redirectToAppPath("/signin/");
|
redirectToAppPath("/signin/");
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import AppRouter from './llm-fe/platform/AppRouter';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import { AuthProvider } from './llm-fe/contexts/AuthContext';
|
import { AuthProvider } from './llm-fe/contexts/AuthContext';
|
||||||
import { AccountProvider } from './llm-fe/contexts/AccountContext';
|
import { AccountProvider } from './llm-fe/contexts/AccountContext';
|
||||||
import { WebSocketProvider } from './llm-fe/contexts/WebSocketContext';
|
import { WebSocketProvider } from './llm-fe/contexts/WebSocketContext';
|
||||||
@@ -16,7 +16,7 @@ const root = ReactDOM.createRoot(
|
|||||||
);
|
);
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<AppRouter>
|
<BrowserRouter>
|
||||||
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm7x7m52m03kbddswbswrt17y"></script>
|
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm7x7m52m03kbddswbswrt17y"></script>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<AccountProvider>
|
<AccountProvider>
|
||||||
@@ -33,6 +33,6 @@ root.render(
|
|||||||
</WebSocketProvider>
|
</WebSocketProvider>
|
||||||
</AccountProvider>
|
</AccountProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</AppRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import { Route, Routes } from 'react-router-dom';
|
|
||||||
import AppRouter from './AppRouter';
|
|
||||||
import { getAppRouter, isNativePlatform } from './nativePlatform';
|
|
||||||
|
|
||||||
describe('AppRouter / getAppRouter (#24)', () => {
|
|
||||||
const originalCapacitor = window.Capacitor;
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
if (originalCapacitor === undefined) {
|
|
||||||
delete window.Capacitor;
|
|
||||||
} else {
|
|
||||||
window.Capacitor = originalCapacitor;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses BrowserRouter on web', () => {
|
|
||||||
delete window.Capacitor;
|
|
||||||
expect(isNativePlatform()).toBe(false);
|
|
||||||
const Router = getAppRouter();
|
|
||||||
expect(Router.name).toBe('BrowserRouter');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses HashRouter on native Capacitor', () => {
|
|
||||||
window.Capacitor = { isNativePlatform: () => true };
|
|
||||||
expect(isNativePlatform()).toBe(true);
|
|
||||||
const Router = getAppRouter();
|
|
||||||
expect(Router.name).toBe('HashRouter');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders nested routes under HashRouter without blank screen', () => {
|
|
||||||
window.Capacitor = { isNativePlatform: () => true };
|
|
||||||
window.location.hash = '#/account/';
|
|
||||||
|
|
||||||
render(
|
|
||||||
<AppRouter>
|
|
||||||
<Routes>
|
|
||||||
<Route path="/account/" element={<div>Account Page</div>} />
|
|
||||||
<Route path="/" element={<div>Home</div>} />
|
|
||||||
</Routes>
|
|
||||||
</AppRouter>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Account Page')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders nested routes under BrowserRouter on web', () => {
|
|
||||||
delete window.Capacitor;
|
|
||||||
window.history.pushState({}, '', '/account/');
|
|
||||||
|
|
||||||
render(
|
|
||||||
<AppRouter>
|
|
||||||
<Routes>
|
|
||||||
<Route path="/account/" element={<div>Account Page</div>} />
|
|
||||||
<Route path="/" element={<div>Home</div>} />
|
|
||||||
</Routes>
|
|
||||||
</AppRouter>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Account Page')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import React, { ReactNode } from 'react';
|
|
||||||
import { getAppRouter } from './nativePlatform';
|
|
||||||
|
|
||||||
type AppRouterProps = {
|
|
||||||
children: ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Single place that chooses BrowserRouter (web) vs HashRouter (Capacitor).
|
|
||||||
* Avoids sprinkling Capacitor.isNativePlatform() through the route tree (#24).
|
|
||||||
*/
|
|
||||||
const AppRouter = ({ children }: AppRouterProps): JSX.Element => {
|
|
||||||
const Router = getAppRouter();
|
|
||||||
return <Router>{children}</Router>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AppRouter;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Capacitor / WebView platform helpers (#24 / #22).
|
* Capacitor / WebView platform helpers.
|
||||||
* Prefer window.Capacitor so unit tests and web builds need no Capacitor package.
|
* Prefer window.Capacitor so unit tests and web builds need no Capacitor package.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -50,16 +50,3 @@ export function redirectToAppPath(path) {
|
|||||||
}
|
}
|
||||||
window.location.href = appHref(path);
|
window.location.href = appHref(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Router class for the current runtime.
|
|
||||||
* HashRouter on Capacitor so nested routes reload without a server rewrite.
|
|
||||||
* BrowserRouter on web (nginx already rewrites to index.html).
|
|
||||||
*
|
|
||||||
* @returns {typeof import('react-router-dom').HashRouter | typeof import('react-router-dom').BrowserRouter}
|
|
||||||
*/
|
|
||||||
export function getAppRouter() {
|
|
||||||
// Lazy require keeps this module usable from axios (no React import cycle in tests).
|
|
||||||
const { BrowserRouter, HashRouter } = require("react-router-dom");
|
|
||||||
return isNativePlatform() ? HashRouter : BrowserRouter;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user