Skip to content

Commit

Permalink
Merge pull request #74 from aws-samples/feature/clear-conversation
Browse files Browse the repository at this point in the history
Add clear all conversations
  • Loading branch information
wadabee authored Oct 26, 2023
2 parents 86d1263 + 4965d2d commit 6b7da65
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 14 deletions.
44 changes: 44 additions & 0 deletions frontend/src/components/DialogConfirmClearConversations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { BaseProps } from '../@types/common';
import Button from './Button';
import ModalDialog from './ModalDialog';
import { Trans, useTranslation } from 'react-i18next';

type Props = BaseProps & {
isOpen: boolean;
onDelete: () => void;
onClose: () => void;
};

const DialogConfirmClearConversations: React.FC<Props> = (props) => {
const { t } = useTranslation();
return (
<ModalDialog {...props} title={t('clearDialog.title')}>
<div>
<Trans
i18nKey="clearDialog.content"
components={{
Bold: <span className="font-bold" />,
}}
/>
</div>

<div className="mt-4 flex justify-end gap-2">
<Button
onClick={props.onClose}
className="bg-transparent p-2 text-aws-font-color">
{t('button.cancel')}
</Button>
<Button
onClick={() => {
props.onDelete();
}}
className="bg-red-500 p-2 text-aws-font-color-white">
{t('button.deleteAll')}
</Button>
</div>
</ModalDialog>
);
};

export default DialogConfirmClearConversations;
38 changes: 36 additions & 2 deletions frontend/src/components/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import Button from './Button';
import { PiList, PiSignOut, PiTranslate } from 'react-icons/pi';
import { PiList, PiSignOut, PiTranslate, PiTrash } from 'react-icons/pi';
import { useTranslation } from 'react-i18next';
import DialogSelectLanguage from './DialogSelectLanguage';
import { BaseProps } from '../@types/common';
import DialogConfirmClearConversations from './DialogConfirmClearConversations';
import useConversation from '../hooks/useConversation';
import { useNavigate } from 'react-router-dom';

type Props = BaseProps & {
onSignOut: () => void;
Expand All @@ -15,6 +18,10 @@ const Menu: React.FC<Props> = (props) => {

const [isOpen, setIsOpen] = useState(false);
const [isOpenLangage, setIsOpenLangage] = useState(false);
const [isOpenClearConversation, setIsOpenClearConversation] = useState(false);

const { clearConversations: clear } = useConversation();
const navigate = useNavigate();

const buttonRef = useRef<HTMLButtonElement>(null);
const menuRef = useRef<HTMLDivElement>(null);
Expand All @@ -40,6 +47,17 @@ const Menu: React.FC<Props> = (props) => {
};
}, [menuRef]);

const clearConversations = useCallback(
() => {
clear().then(() => {
navigate('');
setIsOpenClearConversation(false);
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);

return (
<>
<Button
Expand All @@ -66,6 +84,15 @@ const Menu: React.FC<Props> = (props) => {
<PiTranslate className="mr-2" />
{t('button.language')}
</div>
<div
className="flex w-full cursor-pointer items-center p-2 hover:bg-aws-sea-blue-hover"
onClick={() => {
setIsOpen(false);
setIsOpenClearConversation(true);
}}>
<PiTrash className="mr-2" />
{t('button.clearConversation')}
</div>
<div
className="flex w-full cursor-pointer items-center border-t p-2 hover:bg-aws-sea-blue-hover"
onClick={props.onSignOut}>
Expand All @@ -81,6 +108,13 @@ const Menu: React.FC<Props> = (props) => {
setIsOpenLangage(false);
}}
/>
<DialogConfirmClearConversations
isOpen={isOpenClearConversation}
onClose={() => {
setIsOpenClearConversation(false);
}}
onDelete={clearConversations}
/>
</>
);
};
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/hooks/useConversation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { produce } from "immer";
import useConversationApi from "./useConversationApi";
import { produce } from 'immer';
import useConversationApi from './useConversationApi';

const useConversation = () => {
const conversationApi = useConversationApi();
Expand All @@ -14,7 +14,7 @@ const useConversation = () => {
},
getTitle: (conversationId: string) => {
return (
conversations?.find((c) => c.id === conversationId)?.title ?? "New Chat"
conversations?.find((c) => c.id === conversationId)?.title ?? 'New Chat'
);
},
deleteConversation: (conversationId: string) => {
Expand All @@ -29,6 +29,12 @@ const useConversation = () => {
});
});
},
clearConversations: () => {
return mutate(async () => {
await conversationApi.clearConversations();
return [];
});
},
updateTitle: (conversationId: string, title: string) => {
return mutate(async (current) => {
await conversationApi.updateTitle(conversationId, title);
Expand Down
15 changes: 9 additions & 6 deletions frontend/src/hooks/useConversationApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { MutatorCallback, useSWRConfig } from "swr";
import { MutatorCallback, useSWRConfig } from 'swr';
import {
Conversation,
ConversationMeta,
PostMessageRequest,
PostMessageResponse,
} from "../@types/conversation";
import useHttp from "./useHttp";
} from '../@types/conversation';
import useHttp from './useHttp';

const useConversationApi = () => {
const http = useHttp();
Expand All @@ -19,7 +19,7 @@ const useConversationApi = () => {

return {
getConversations: () => {
return http.get<ConversationMeta[]>("conversations", {
return http.get<ConversationMeta[]>('conversations', {
keepPreviousData: true,
});
},
Expand All @@ -32,13 +32,16 @@ const useConversationApi = () => {
);
},
postMessage: (input: PostMessageRequest) => {
return http.post<PostMessageResponse>("conversation", {
return http.post<PostMessageResponse>('conversation', {
...input,
});
},
deleteConversation: (conversationId: string) => {
return http.delete(`conversation/${conversationId}`);
},
clearConversations: () => {
return http.delete('conversations');
},
updateTitle,
updateTitleWithGeneratedTitle: async (conversationId: string) => {
const res = await http.getOnce<{
Expand All @@ -53,7 +56,7 @@ const useConversationApi = () => {
| MutatorCallback<ConversationMeta[]>,
options?: Parameters<typeof mutate>[2]
) => {
return mutate("conversations", conversations, options);
return mutate('conversations', conversations, options);
},
};
};
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ const translation = {
inputMessage: 'Send a message',
},
deleteDialog: {
title: 'Delete chat?',
title: 'Delete?',
content: 'Are you sure to delete <Bold>{{title}}</Bold>?',
},
clearDialog: {
title: 'Delete ALL?',
content: 'Are you sure to delete ALL conversations?',
},
languageDialog: {
title: 'Switch language',
},
Expand All @@ -17,10 +21,12 @@ const translation = {
resend: 'Resend',
regenerate: 'Regenerate',
delete: 'Delete',
deleteAll: 'Delete All',
ok: 'OK',
cancel: 'Cancel',
menu: 'Menu',
language: 'Language',
clearConversation: 'Delete ALL conversations',
signOut: 'Sign out',
},
error: {
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/i18n/ja/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ const translation: typeof en = {
inputMessage: '入力してください',
},
deleteDialog: {
title: '削除確認',
title: '削除',
content: 'チャット「<Bold>{{title}}</Bold>」を削除しますか?',
},
clearDialog: {
title: '削除',
content: 'すべての会話履歴を削除しますか?',
},
languageDialog: {
title: '言語の切替',
},
Expand All @@ -19,10 +23,12 @@ const translation: typeof en = {
resend: '再送信',
regenerate: '再生成',
delete: '削除',
deleteAll: 'すべて削除',
ok: 'OK',
cancel: 'キャンセル',
menu: 'Menu',
language: '言語の切替',
clearConversation: 'すべての会話をクリア',
signOut: 'サインアウト',
},
error: {
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/i18n/ko/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const translation: typeof en = {
title: '삭제 확인',
content: '채팅 "<Bold>{{title}}</Bold>"을(를) 삭제하시겠습니까?',
},
clearDialog: {
title: '삭제 확인',
content: '모든 대화 기록을 삭제하시겠습니까?',
},
languageDialog: {
title: '언어 변경',
},
Expand All @@ -19,14 +23,16 @@ const translation: typeof en = {
resend: '재전송',
regenerate: '재생성',
delete: '삭제',
deleteAll: '모두 삭제',
ok: '확인',
cancel: '취소',
menu: '메뉴',
language: '언어 변경',
clearConversation: '모든 대화 지우기',
signOut: '로그아웃',
},
error: {
answerResponse: '답변 중에 오류가 발생했습니다.',
answerResponse: '응답 중 오류가 발생했습니다.',
notFoundConversation:
'지정된 채팅이 존재하지 않기 때문에 새로운 채팅 화면을 표시했습니다.',
notFoundPage: '찾고 있는 페이지를 찾을 수 없습니다.',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/i18n/zh/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const translation: typeof en = {
title: '删除确认',
content: '您确定要删除聊天 "<Bold>title</Bold>" 吗?',
},
clearDialog: {
title: '删除确认',
content: '是否删除所有聊天记录?',
},
languageDialog: {
title: '切换语言',
},
Expand All @@ -19,10 +23,12 @@ const translation: typeof en = {
resend: '重新发送',
regenerate: '重新生成',
delete: '删除',
deleteAll: '全部删除',
ok: '确定',
cancel: '取消',
menu: '菜单',
language: '切换语言',
clearConversation: '清除所有对话',
signOut: '退出登录',
},
error: {
Expand Down

0 comments on commit 6b7da65

Please sign in to comment.