From a4b373258ac770a2d2541abe051bbc997e322b40 Mon Sep 17 00:00:00 2001 From: Pete Miller Date: Wed, 11 Dec 2024 21:54:24 -0800 Subject: [PATCH] AI Chat storage notice is dismissed after first prompt sending or close button --- .../webui/ai_chat/ai_chat_ui_page_handler.cc | 7 ++++++ .../webui/ai_chat/ai_chat_ui_page_handler.h | 1 + .../ai_chat/core/browser/ai_chat_service.cc | 4 +++ .../ai_chat/core/common/mojom/ai_chat.mojom | 1 + .../notices/notice_conversation_storage.tsx | 25 +------------------ .../resources/page/state/ai_chat_context.tsx | 10 +------- .../page/state/conversation_context.tsx | 6 +++++ .../page/stories/components_panel.tsx | 1 - 8 files changed, 21 insertions(+), 34 deletions(-) diff --git a/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.cc b/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.cc index 9a9585d93109..5b1c23af45df 100644 --- a/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.cc +++ b/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.cc @@ -44,6 +44,9 @@ constexpr char kURLRefreshPremiumSession[] = constexpr char kURLGoPremium[] = "https://account.brave.com/account/?intent=checkout&product=leo"; constexpr char kURLManagePremium[] = "https://account.brave.com/"; +constexpr char kURLLearnMoreAboutStorage[] = + "https://support.brave.com/hc/en-us/articles/" + "32663367857549-How-do-I-use-Chat-History-in-Brave-Leo"; #endif } // namespace @@ -146,6 +149,10 @@ void AIChatUIPageHandler::OpenURL(const GURL& url) { #endif } +void AIChatUIPageHandler::OpenStorageSupportUrl() { + OpenURL(GURL(kURLLearnMoreAboutStorage)); +} + void AIChatUIPageHandler::GoPremium() { #if !BUILDFLAG(IS_ANDROID) OpenURL(GURL(kURLGoPremium)); diff --git a/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.h b/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.h index 81e4f6dfc4ed..a8fa5d418829 100644 --- a/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.h +++ b/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.h @@ -47,6 +47,7 @@ class AIChatUIPageHandler : public mojom::AIChatUIHandler, void OpenAIChatSettings() override; void OpenConversationFullPage(const std::string& conversation_uuid) override; void OpenURL(const GURL& url) override; + void OpenStorageSupportUrl() override; void OpenModelSupportUrl() override; void GoPremium() override; void RefreshPremiumSession() override; diff --git a/components/ai_chat/core/browser/ai_chat_service.cc b/components/ai_chat/core/browser/ai_chat_service.cc index 58a3226d90f6..ee47809581b1 100644 --- a/components/ai_chat/core/browser/ai_chat_service.cc +++ b/components/ai_chat/core/browser/ai_chat_service.cc @@ -121,6 +121,10 @@ AIChatService::AIChatService( prefs::kUserDismissedPremiumPrompt, base::BindRepeating(&AIChatService::OnStateChanged, weak_ptr_factory_.GetWeakPtr())); + pref_change_registrar_.Add( + prefs::kUserDismissedStorageNotice, + base::BindRepeating(&AIChatService::OnStateChanged, + weak_ptr_factory_.GetWeakPtr())); MaybeInitStorage(); } diff --git a/components/ai_chat/core/common/mojom/ai_chat.mojom b/components/ai_chat/core/common/mojom/ai_chat.mojom index b06c21f291c9..ecaa26a9cc3a 100644 --- a/components/ai_chat/core/common/mojom/ai_chat.mojom +++ b/components/ai_chat/core/common/mojom/ai_chat.mojom @@ -360,6 +360,7 @@ interface AIChatUIHandler { OpenConversationFullPage(string conversation_uuid); OpenURL(url.mojom.Url url); + OpenStorageSupportUrl(); OpenModelSupportUrl(); GoPremium(); diff --git a/components/ai_chat/resources/page/components/notices/notice_conversation_storage.tsx b/components/ai_chat/resources/page/components/notices/notice_conversation_storage.tsx index d5b5738d2e91..7a8ab92ed52a 100644 --- a/components/ai_chat/resources/page/components/notices/notice_conversation_storage.tsx +++ b/components/ai_chat/resources/page/components/notices/notice_conversation_storage.tsx @@ -7,7 +7,6 @@ import * as React from 'react' import Button from '@brave/leo/react/button' import Icon from '@brave/leo/react/icon' import { getLocale } from '$web-common/locale' -import VisibilityTimer from '$web-common/visibilityTimer' import { useAIChat } from '../../state/ai_chat_context' import styles from './notices.module.scss' import illustrationUrl from './conversation_storage.svg' @@ -15,31 +14,9 @@ import illustrationUrl from './conversation_storage.svg' export default function NoticeConversationStorage() { const aiChatContext = useAIChat() - const visibilityTimer = React.useRef() - - const noticeElementRef = React.useCallback((el: HTMLDivElement | null) => { - // note: el will be null when we destroy it. - // note: In new versions of React (maybe newer than we're using) you can return a cleanup function instead - // https://react.dev/blog/2024/04/25/react-19#cleanup-functions-for-refs - if (visibilityTimer.current) { - visibilityTimer.current.stopTracking() - } - - if (!el) { - return - } - - visibilityTimer.current = new VisibilityTimer( - aiChatContext.markStorageNoticeViewed, 4000, el - ) - - visibilityTimer.current.startTracking() - }, []) - return (
illustration @@ -51,7 +28,7 @@ export default function NoticeConversationStorage() { aiChatContext.uiHandler?.openModelSupportUrl()} + onClick={() => aiChatContext.uiHandler?.openStorageSupportUrl()} > {getLocale('learnMore')} 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 7547cb421114..05404df1965e 100644 --- a/components/ai_chat/resources/page/state/ai_chat_context.tsx +++ b/components/ai_chat/resources/page/state/ai_chat_context.tsx @@ -24,7 +24,6 @@ type AIChatContextInternal = AIChatContextProps & { managePremium: () => void handleAgreeClick: () => void enableStoragePref: () => void - markStorageNoticeViewed: () => void dismissStorageNotice: () => void dismissPremiumPrompt: () => void userRefreshPremiumSession: () => void @@ -47,7 +46,6 @@ const defaultContext: AIChatContext = { managePremium: () => { }, handleAgreeClick: () => { }, enableStoragePref: () => { }, - markStorageNoticeViewed: () => { }, dismissStorageNotice: () => { }, dismissPremiumPrompt: () => { }, userRefreshPremiumSession: () => { }, @@ -80,13 +78,7 @@ export function AIChatContextProvider(props: React.PropsWithChildren api.uiHandler.goPremium(), managePremium: () => api.uiHandler.managePremium(), - markStorageNoticeViewed: () => api.service.dismissStorageNotice(), - dismissStorageNotice: () => { - api.setPartialState({ - isStorageNoticeDismissed: true - }) - api.service.dismissStorageNotice() - }, + dismissStorageNotice: () => api.service.dismissStorageNotice(), enableStoragePref: () => api.service.enableStoragePref(), dismissPremiumPrompt: () => api.service.dismissPremiumPrompt(), userRefreshPremiumSession: () => api.uiHandler.refreshPremiumSession(), diff --git a/components/ai_chat/resources/page/state/conversation_context.tsx b/components/ai_chat/resources/page/state/conversation_context.tsx index 891fac0f1f6e..bd54c7f3b49f 100644 --- a/components/ai_chat/resources/page/state/conversation_context.tsx +++ b/components/ai_chat/resources/page/state/conversation_context.tsx @@ -405,6 +405,12 @@ export function ConversationContextProvider(props: React.PropsWithChildren) { if (shouldDisableUserInput) return if (handleFilterActivation()) return + if (!aiChatContext.isStorageNoticeDismissed && aiChatContext.hasAcceptedAgreement) { + // Submitting a conversation entry manually, after opt-in, + // means the storage notice can be dismissed. + aiChatContext.dismissStorageNotice() + } + if (context.selectedActionType) { conversationHandler.submitHumanConversationEntryWithAction( context.inputText, diff --git a/components/ai_chat/resources/page/stories/components_panel.tsx b/components/ai_chat/resources/page/stories/components_panel.tsx index a9dc08ab152b..8c8ad71950c7 100644 --- a/components/ai_chat/resources/page/stories/components_panel.tsx +++ b/components/ai_chat/resources/page/stories/components_panel.tsx @@ -511,7 +511,6 @@ const preview: Meta = { managePremium: () => {}, handleAgreeClick: () => {}, enableStoragePref: () => {}, - markStorageNoticeViewed: () => {}, dismissStorageNotice: () => {}, dismissPremiumPrompt: () => {}, userRefreshPremiumSession: () => {},