From caf654eda2b1dcc9e9e6ed409fd45a605cfd0c4b Mon Sep 17 00:00:00 2001 From: Douglas Daniel Date: Tue, 7 Jan 2025 19:47:02 -0600 Subject: [PATCH] feat(ai chat): Delete Conversation Confirmation Dialog --- components/ai_chat/core/browser/constants.cc | 2 + .../components/conversations_list/index.tsx | 2 +- .../delete_conversation_modal/index.tsx | 76 +++++++++++++++++++ .../style.module.scss | 39 ++++++++++ .../components/feature_button_menu/index.tsx | 2 +- .../resources/page/components/main/index.tsx | 2 + .../resources/page/state/ai_chat_context.tsx | 8 ++ .../page/stories/components_panel.tsx | 4 + components/resources/ai_chat_ui_strings.grdp | 6 ++ 9 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 components/ai_chat/resources/page/components/delete_conversation_modal/index.tsx create mode 100644 components/ai_chat/resources/page/components/delete_conversation_modal/style.module.scss diff --git a/components/ai_chat/core/browser/constants.cc b/components/ai_chat/core/browser/constants.cc index a3ebc23a9050..b3e0dc353579 100644 --- a/components/ai_chat/core/browser/constants.cc +++ b/components/ai_chat/core/browser/constants.cc @@ -100,6 +100,8 @@ base::span GetLocalizedStrings() { {"feedbackPremiumNote", IDS_CHAT_UI_FEEDBACK_PREMIUM_NOTE}, {"submitButtonLabel", IDS_CHAT_UI_SUBMIT_BUTTON_LABEL}, {"cancelButtonLabel", IDS_CHAT_UI_CANCEL_BUTTON_LABEL}, + {"deleteButtonLabel", IDS_CHAT_UI_DELETE_BUTTON_LABEL}, + {"deleteConversationWarning", IDS_CHAT_UI_DELETE_CONVERSATION_WARNING}, {"saveButtonLabel", IDS_CHAT_UI_SAVE_BUTTON_LABEL}, {"editedLabel", IDS_CHAT_UI_EDITED_LABEL}, {"editButtonLabel", IDS_CHAT_UI_EDIT_BUTTON_LABEL}, diff --git a/components/ai_chat/resources/page/components/conversations_list/index.tsx b/components/ai_chat/resources/page/components/conversations_list/index.tsx index 10c489996c88..8a0d17e6981b 100644 --- a/components/ai_chat/resources/page/components/conversations_list/index.tsx +++ b/components/ai_chat/resources/page/components/conversations_list/index.tsx @@ -79,7 +79,7 @@ function ConversationItem(props: ConversationItemProps) { const handleDelete: EventListener = (e) => { e.preventDefault() - aiChatContext.service?.deleteConversation(uuid) + aiChatContext.setDeletingConversationId(uuid) } const isEditing = aiChatContext.editingConversationId === uuid diff --git a/components/ai_chat/resources/page/components/delete_conversation_modal/index.tsx b/components/ai_chat/resources/page/components/delete_conversation_modal/index.tsx new file mode 100644 index 000000000000..f5e75c09c545 --- /dev/null +++ b/components/ai_chat/resources/page/components/delete_conversation_modal/index.tsx @@ -0,0 +1,76 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import Button from '@brave/leo/react/button' +import Dialog from '@brave/leo/react/dialog' + +// Utils +import { getLocale } from '$web-common/locale' + +// Hooks +import { useAIChat } from '../../state/ai_chat_context' + +// Styles +import styles from './style.module.scss' + +export default function DeleteConversationModal() { + // Context + const aiChatContext = useAIChat() + + // Computed + const title = aiChatContext.visibleConversations.find( + (conversation) => + conversation.uuid === aiChatContext.deletingConversationId + )?.title || getLocale('conversationListUntitled') + + return ( + aiChatContext.setDeletingConversationId(null)} + className={styles.deleteConversationDialog} + > +
+ {getLocale('menuDeleteConversation')} +
+
+
{title}
+ {getLocale('deleteConversationWarning')} +
+
+
+ + +
+
+
+ ) +} diff --git a/components/ai_chat/resources/page/components/delete_conversation_modal/style.module.scss b/components/ai_chat/resources/page/components/delete_conversation_modal/style.module.scss new file mode 100644 index 000000000000..e0ff322438ca --- /dev/null +++ b/components/ai_chat/resources/page/components/delete_conversation_modal/style.module.scss @@ -0,0 +1,39 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// you can obtain one at https://mozilla.org/MPL/2.0/. + +.conversationNameWrapper { + display: flex; + align-items: flex-start; + justify-content: flex-start; + width: 100%; + padding: var(--leo-spacing-l); + border-radius: var(--leo-radius-m); + border: 1px solid var(--leo-color-divider-subtle); + font: var(--leo-font-heading-h4); + color: var(--leo-color-text-secondary); +} + +.deleteConversationDialogTitle { + font: var(--leo-font-heading-h3); +} + +.deleteConversationDialog { + --leo-dialog-padding: 24px; +} + +.deleteConversationBody { + display: flex; + flex-direction: column; + gap: var(--leo-spacing-xl); +} + +.deleteConversationActionsRow { + justify-content: flex-end; +} + +.buttonsWrapper { + display: flex; + gap: var(--leo-spacing-m); +} diff --git a/components/ai_chat/resources/page/components/feature_button_menu/index.tsx b/components/ai_chat/resources/page/components/feature_button_menu/index.tsx index aca51b741e31..105c7078ce93 100644 --- a/components/ai_chat/resources/page/components/feature_button_menu/index.tsx +++ b/components/ai_chat/resources/page/components/feature_button_menu/index.tsx @@ -124,7 +124,7 @@ export default function FeatureMenu(props: Props) { - aiChatContext.service?.deleteConversation(conversationContext.conversationUuid!)}> + aiChatContext.setDeletingConversationId(conversationContext.conversationUuid!)}>
+ ) } 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 05404df1965e..3e1bad93e856 100644 --- a/components/ai_chat/resources/page/state/ai_chat_context.tsx +++ b/components/ai_chat/resources/page/state/ai_chat_context.tsx @@ -32,6 +32,8 @@ type AIChatContextInternal = AIChatContextProps & { editingConversationId: string | null setEditingConversationId: (uuid: string | null) => void, + deletingConversationId: string | null + setDeletingConversationId: (uuid: string | null) => void showSidebar: boolean, toggleSidebar: () => void @@ -52,6 +54,8 @@ const defaultContext: AIChatContext = { editingConversationId: null, setEditingConversationId: () => { }, + deletingConversationId: null, + setDeletingConversationId: () => { }, showSidebar: false, toggleSidebar: () => { }, @@ -71,6 +75,8 @@ export function AIChatContextProvider(props: React.PropsWithChildren(null) + const [deletingConversationId, setDeletingConversationId] = + React.useState(null) const isSmall = useIsSmall() const [showSidebar, setShowSidebar] = React.useState(isSmall) @@ -87,6 +93,8 @@ export function AIChatContextProvider(props: React.PropsWithChildren setShowSidebar(s => !s), conversationEntriesComponent: props.conversationEntriesComponent diff --git a/components/ai_chat/resources/page/stories/components_panel.tsx b/components/ai_chat/resources/page/stories/components_panel.tsx index d4fe9cad58f3..8abd56c925a4 100644 --- a/components/ai_chat/resources/page/stories/components_panel.tsx +++ b/components/ai_chat/resources/page/stories/components_panel.tsx @@ -406,6 +406,7 @@ type CustomArgs = { inputText: string hasConversation: boolean editingConversationId: string | null + deletingConversationId: string | null visibleConversationListCount: number hasSuggestedQuestions: boolean hasSiteInfo: boolean @@ -436,6 +437,7 @@ const args: CustomArgs = { hasSuggestedQuestions: true, hasSiteInfo: true, editingConversationId: null, + deletingConversationId: null, isFeedbackFormVisible: false, isStorageNoticeDismissed: false, canShowPremiumPrompt: false, @@ -532,6 +534,7 @@ function StoryContext(props: React.PropsWithChildren<{args: CustomArgs, setArgs: conversationEntriesComponent: StorybookConversationEntries, initialized: options.args.initialized, editingConversationId: options.args.editingConversationId, + deletingConversationId: options.args.deletingConversationId, visibleConversations, isStoragePrefEnabled: options.args.isStoragePrefEnabled, hasAcceptedAgreement: options.args.hasAcceptedAgreement, @@ -552,6 +555,7 @@ function StoryContext(props: React.PropsWithChildren<{args: CustomArgs, setArgs: dismissPremiumPrompt: () => {}, userRefreshPremiumSession: () => {}, setEditingConversationId: (id: string | null) => setArgs({ editingConversationId: id }), + setDeletingConversationId: (id: string | null) => setArgs({ deletingConversationId: id }), showSidebar: showSidebar, toggleSidebar: () => setShowSidebar(s => !s) } diff --git a/components/resources/ai_chat_ui_strings.grdp b/components/resources/ai_chat_ui_strings.grdp index d13198a1bd12..b7fcd33b9242 100644 --- a/components/resources/ai_chat_ui_strings.grdp +++ b/components/resources/ai_chat_ui_strings.grdp @@ -213,6 +213,12 @@ Cancel + + Delete + + + Are you sure you want to delete this conversation? This action cannot be undone. + Save