From 268ed1a5008db2edcde657df4fc7d557facd8599 Mon Sep 17 00:00:00 2001 From: Jay Harris Date: Thu, 17 Oct 2024 10:41:41 +1300 Subject: [PATCH] Nicer routing --- components/ai_chat/resources/page/chat_ui.tsx | 2 +- .../page/components/header/index.tsx | 2 +- .../index.tsx => routes.tsx} | 4 ---- .../resources/page/state/ai_chat_context.tsx | 17 +++++++++++++++ .../page/state/conversation_context.tsx | 2 +- components/common/navigation/Context.tsx | 21 +++++++++++-------- 6 files changed, 32 insertions(+), 16 deletions(-) rename components/ai_chat/resources/page/{components/navigation_context/index.tsx => routes.tsx} (85%) diff --git a/components/ai_chat/resources/page/chat_ui.tsx b/components/ai_chat/resources/page/chat_ui.tsx index 0b9852e2131..ad4ebdefab8 100644 --- a/components/ai_chat/resources/page/chat_ui.tsx +++ b/components/ai_chat/resources/page/chat_ui.tsx @@ -21,7 +21,7 @@ import { } from './state/conversation_context' import FullScreen from './components/full_screen' import { NavigationContext } from '$web-common/navigation/Context' -import { Routes } from './components/navigation_context' +import { Routes } from './routes' setIconBasePath('chrome-untrusted://resources/brave-icons') diff --git a/components/ai_chat/resources/page/components/header/index.tsx b/components/ai_chat/resources/page/components/header/index.tsx index c8a20ebdd16..35c85789459 100644 --- a/components/ai_chat/resources/page/components/header/index.tsx +++ b/components/ai_chat/resources/page/components/header/index.tsx @@ -13,7 +13,7 @@ import { useAIChat } from '../../state/ai_chat_context' import { useConversation } from '../../state/conversation_context' import { getLocale } from '$web-common/locale' import useIsConversationVisible from '../../hooks/useIsConversationVisible' -import { useSelectedConversation } from '../navigation_context' +import { useSelectedConversation } from '../../routes' const Logo = ({ isPremium }: { isPremium: boolean }) =>
diff --git a/components/ai_chat/resources/page/components/navigation_context/index.tsx b/components/ai_chat/resources/page/routes.tsx similarity index 85% rename from components/ai_chat/resources/page/components/navigation_context/index.tsx rename to components/ai_chat/resources/page/routes.tsx index 0b70616e48a..c2b803b7b01 100644 --- a/components/ai_chat/resources/page/components/navigation_context/index.tsx +++ b/components/ai_chat/resources/page/routes.tsx @@ -10,10 +10,6 @@ export function useSelectedConversation() { return useParams().chatId } -export function selectConversation(conversationId: string | null) { - window.location.href = conversationId ? `/${conversationId}` : "/" -} - const routes = [ '/', '/{chatId}' diff --git a/components/ai_chat/resources/page/state/ai_chat_context.tsx b/components/ai_chat/resources/page/state/ai_chat_context.tsx index c6f3ebad714..e94a99a2919 100644 --- a/components/ai_chat/resources/page/state/ai_chat_context.tsx +++ b/components/ai_chat/resources/page/state/ai_chat_context.tsx @@ -6,6 +6,7 @@ import * as React from 'react' import getAPI, * as mojom from '../api' import { loadTimeData } from '$web-common/loadTimeData' +import { useNavigation } from '$web-common/navigation/Context' export interface AIChatContext { visibleConversations: mojom.Conversation[] @@ -124,6 +125,22 @@ export function AIChatContextProvider(props: React.PropsWithChildren) { }) }, []) + const { addRoute, removeRoute, params } = useNavigation() + + // Handle the case where a non-existent chat has been selected by going home. + React.useEffect(() => { + const checkExistsHandler = (params: { chatId: string }) => { + if (params.chatId && !context.visibleConversations.find(c => c.uuid === params.chatId)) { + location.href = '/' + } + } + + addRoute('/{chatId}', checkExistsHandler) + return () => { + removeRoute('/{chatId}', checkExistsHandler) + } + }, [context.visibleConversations, params.chatId]) + const { Service, UIHandler } = getAPI() const store: AIChatContext = { diff --git a/components/ai_chat/resources/page/state/conversation_context.tsx b/components/ai_chat/resources/page/state/conversation_context.tsx index 4ad43e629fe..b32f8668f2f 100644 --- a/components/ai_chat/resources/page/state/conversation_context.tsx +++ b/components/ai_chat/resources/page/state/conversation_context.tsx @@ -11,7 +11,7 @@ import * as API from '../api/' import { useAIChat } from './ai_chat_context' import { isLeoModel } from '../model_utils' import { loadTimeData } from '$web-common/loadTimeData' -import { useSelectedConversation } from '../components/navigation_context' +import { useSelectedConversation } from '../routes' import useIsConversationVisible from '../hooks/useIsConversationVisible' const MAX_INPUT_CHAR = 2000 diff --git a/components/common/navigation/Context.tsx b/components/common/navigation/Context.tsx index 14d2257c9b5..2e7b8c99ec3 100644 --- a/components/common/navigation/Context.tsx +++ b/components/common/navigation/Context.tsx @@ -33,8 +33,8 @@ const findMatchingRoute = (url: string, routes: Routes) => { const pathParts = path.split('/') - for (const [path, handler] of routes.entries()) { - const routeParts = path.split('/') + for (const [route, callbacks] of routes.entries()) { + const routeParts = route.split('/') if (routeParts.length !== pathParts.length) continue @@ -56,12 +56,12 @@ const findMatchingRoute = (url: string, routes: Routes) => { } if (isMatch) { - return [handler, params] as const + return [route, callbacks, params] as const } } // Couldn't find a handler - return [null, {}] as const + return [null, [], {}] as const } export function useParams() { @@ -79,7 +79,7 @@ export function NavigationContext(props: React.PropsWithChildren) { useEffect(() => { const handler = (e: NavigateEvent) => { - const [handler, params] = findMatchingRoute(e.destination.url, routes.current) + const [, callbacks, params] = findMatchingRoute(e.destination.url, routes.current) if (!handler) { setParams({}) @@ -89,7 +89,7 @@ export function NavigationContext(props: React.PropsWithChildren) { setParams(params) e.intercept({ handler: async () => { - for (const callback of handler) { + for (const callback of callbacks) { callback?.(params) } } @@ -108,8 +108,11 @@ export function NavigationContext(props: React.PropsWithChildren) { } routes.current.get(route)!.push(callback) - - setParams(findMatchingRoute(location.href, routes.current)[1]) + const [matchingRoute, _, params] = findMatchingRoute(location.href, routes.current) + if (matchingRoute === route) { + setParams(params) + callback?.(params) + } }, []) const removeRoute = React.useCallback((route: string, callback?: (params: NavigationParams) => void) => { @@ -123,7 +126,7 @@ export function NavigationContext(props: React.PropsWithChildren) { routes.current.delete(route) } - setParams(findMatchingRoute(location.href, routes.current)[1]) + setParams(findMatchingRoute(location.href, routes.current)[2]) }, []) return