Extract useGoogleAuth from app.tsx

This commit is contained in:
Przemek Więch
2026-06-11 17:31:52 +02:00
parent 843e0f528c
commit ef2653b51f
3 changed files with 23 additions and 5 deletions

View File

@@ -100,7 +100,7 @@ We will gradually eliminate React state variables in `src/app.tsx` and derive th
* [x] **Step 3.4:** Extract `config` state. Parse display settings on render using `argsToConfig` helper. Remove state. In `ViewPage`, run `updateChartWithConfig(config, data)` synchronously during the render pass (e.g. in the `useMemo` that derives query parameters/config) to update the in-memory chart data before it is rendered by the `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred. * [x] **Step 3.4:** Extract `config` state. Parse display settings on render using `argsToConfig` helper. Remove state. In `ViewPage`, run `updateChartWithConfig(config, data)` synchronously during the render pass (e.g. in the `useMemo` that derives query parameters/config) to update the in-memory chart data before it is rendered by the `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred.
#### Phase 4: Structural Page Nesting #### Phase 4: Structural Page Nesting
* [ ] **Step 4.1:** Create `src/hooks/use_google_auth.ts` to manage Google Drive authentication token updates. Remove `hasGoogleToken` state from `src/app.tsx`. * [x] **Step 4.1:** Create `src/hooks/use_google_auth.ts` to manage Google Drive authentication token updates. Remove `hasGoogleToken` state from `src/app.tsx`.
* [ ] **Step 4.2:** Create `src/pages/view_page.tsx` containing layout rendering (`renderMainArea`), asynchronous data loaders, view state management, `revokeObjectUrls` cleanups, and `<GoogleAuthModal>` error fallback state and rendering. * [ ] **Step 4.2:** Create `src/pages/view_page.tsx` containing layout rendering (`renderMainArea`), asynchronous data loaders, view state management, `revokeObjectUrls` cleanups, and `<GoogleAuthModal>` error fallback state and rendering.
* [ ] **Step 4.3:** Create `src/pages/intro_page.tsx` rendering the landing screen and its own local header. * [ ] **Step 4.3:** Create `src/pages/intro_page.tsx` rendering the landing screen and its own local header.
* [ ] **Step 4.4:** Refactor `src/app.tsx` to serve as a pure routing switch routing to `<IntroPage />` or `<ViewPage />`. In `App`, handle Google Drive redirection synchronously during the render pass by returning a `<Navigate replace />` element (preventing render flashing), and ensure the redirection parser checks both the router `location.search` and the external `window.location.search` to handle HashRouter query structure robustly. Once external parameters (like `state` or `authcode`) are detected, they must be stripped from `window.location.search` using `window.history.replaceState` to prevent redirection loops on page refresh. Remove all layout state logic from the root file, including moving the `useWebMcpBridge` hook invocation into `<ViewPage />`. Run final verification scripts (`npm run check:all`). * [ ] **Step 4.4:** Refactor `src/app.tsx` to serve as a pure routing switch routing to `<IntroPage />` or `<ViewPage />`. In `App`, handle Google Drive redirection synchronously during the render pass by returning a `<Navigate replace />` element (preventing render flashing), and ensure the redirection parser checks both the router `location.search` and the external `window.location.search` to handle HashRouter query structure robustly. Once external parameters (like `state` or `authcode`) are detected, they must be stripped from `window.location.search` using `window.history.replaceState` to prevent redirection loops on page refresh. Remove all layout state logic from the root file, including moving the `useWebMcpBridge` hook invocation into `<ViewPage />`. Run final verification scripts (`npm run check:all`).

View File

@@ -43,6 +43,7 @@ import {
WikiTreeSourceSpec, WikiTreeSourceSpec,
} from './datasource/wikitree'; } from './datasource/wikitree';
import {DonatsoChart} from './donatso-chart'; import {DonatsoChart} from './donatso-chart';
import {useGoogleAuth} from './hooks/use_google_auth';
import {useWebMcpBridge} from './hooks/use_webmcp_bridge'; import {useWebMcpBridge} from './hooks/use_webmcp_bridge';
import {Intro} from './intro'; import {Intro} from './intro';
import {GoogleAuthModal} from './menu/google_auth_modal'; import {GoogleAuthModal} from './menu/google_auth_modal';
@@ -90,10 +91,8 @@ export function App() {
const [showAuthModal, setShowAuthModal] = useState(false); const [showAuthModal, setShowAuthModal] = useState(false);
/** Stores the file ID that failed to load from Google Drive due to authorization errors. */ /** Stores the file ID that failed to load from Google Drive due to authorization errors. */
const [failedFileId, setFailedFileId] = useState<string>(); const [failedFileId, setFailedFileId] = useState<string>();
/** Tracks whether the user has a valid cached Google Drive OAuth access token. */ /** Tracks whether the user has a valid cached Google Drive OAuth access token and provides a state setter. */
const [hasGoogleToken, setHasGoogleToken] = useState( const {hasGoogleToken, setHasGoogleToken} = useGoogleAuth();
() => !!googleDriveService.getAccessToken(),
);
const intl = useIntl(); const intl = useIntl();
const navigate = useNavigate(); const navigate = useNavigate();

View File

@@ -0,0 +1,19 @@
import {useState} from 'react';
import {googleDriveService} from '../datasource/google_drive_service';
/**
* Custom React hook to manage and track the state of Google Drive OAuth2 credentials.
*/
export function useGoogleAuth() {
/** Tracks whether the user has a valid cached Google Drive OAuth access token. */
const [hasGoogleToken, setHasGoogleToken] = useState(
() => !!googleDriveService.getAccessToken(),
);
return {
/** Tracks whether the user has a valid cached Google Drive OAuth access token. */
hasGoogleToken,
/** Function to update the token presence state in React. */
setHasGoogleToken,
};
}