From d6e59a6a0a1754adccb011c4a08960ae815f3917 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 11 Jul 2024 21:45:47 +0530 Subject: [PATCH] conversation tile: add menu, add share modal --- application/api/user/routes.py | 3 +- frontend/package-lock.json | 10 ++ frontend/src/assets/red-trash.svg | 3 + frontend/src/assets/share.svg | 3 + frontend/src/assets/three-dots.svg | 3 + .../src/conversation/ConversationTile.tsx | 154 ++++++++++++++---- .../src/modals/ShareConversationModal.tsx | 93 +++++++++++ frontend/tailwind.config.cjs | 1 + 8 files changed, 238 insertions(+), 32 deletions(-) create mode 100644 frontend/src/assets/red-trash.svg create mode 100644 frontend/src/assets/share.svg create mode 100644 frontend/src/assets/three-dots.svg create mode 100644 frontend/src/modals/ShareConversationModal.tsx diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 8db821fa..12744f0f 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -498,6 +498,7 @@ def delete_api_key(): #route to share conversation +##isPromptable should be passed through queries @user.route("/api/share",methods=["POST"]) def share_conversation(): try: @@ -526,7 +527,7 @@ def share_conversation(): "$ref":"conversations", "$id":ObjectId(conversation_id) } , - "isPromptable":isPromptable, + "isPromptable":isPromptable, "first_n_queries":current_n_queries, "user":user }) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 83e0a930..2b868da2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,7 @@ "@reduxjs/toolkit": "^1.9.2", "@vercel/analytics": "^0.1.10", "i18next": "^23.11.5", + "i18next-browser-languagedetector": "^8.0.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", @@ -4194,6 +4195,15 @@ "@babel/runtime": "^7.23.2" } }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", + "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", diff --git a/frontend/src/assets/red-trash.svg b/frontend/src/assets/red-trash.svg new file mode 100644 index 00000000..b3331d95 --- /dev/null +++ b/frontend/src/assets/red-trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/share.svg b/frontend/src/assets/share.svg new file mode 100644 index 00000000..4699e16b --- /dev/null +++ b/frontend/src/assets/share.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/three-dots.svg b/frontend/src/assets/three-dots.svg new file mode 100644 index 00000000..6462b942 --- /dev/null +++ b/frontend/src/assets/three-dots.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/conversation/ConversationTile.tsx b/frontend/src/conversation/ConversationTile.tsx index b9d2301d..94731b90 100644 --- a/frontend/src/conversation/ConversationTile.tsx +++ b/frontend/src/conversation/ConversationTile.tsx @@ -5,11 +5,14 @@ import Exit from '../assets/exit.svg'; import Message from '../assets/message.svg'; import MessageDark from '../assets/message-dark.svg'; import { useDarkTheme } from '../hooks'; +import ConfirmationModal from '../modals/ConfirmationModal'; import CheckMark2 from '../assets/checkMark2.svg'; -import Trash from '../assets/trash.svg'; - +import Trash from '../assets/red-trash.svg'; +import Share from '../assets/share.svg'; +import threeDots from '../assets/three-dots.svg'; import { selectConversationId } from '../preferences/preferenceSlice'; - +import { ActiveState } from '../models/misc'; +import { ShareConversationModal } from '../modals/ShareConversationModal'; interface ConversationProps { name: string; id: string; @@ -32,13 +35,18 @@ export default function ConversationTile({ const [isDarkTheme] = useDarkTheme(); const [isEdit, setIsEdit] = useState(false); const [conversationName, setConversationsName] = useState(''); - + const [isOpen, setOpen] = useState(false); + const [isShareModalOpen, setShareModalState] = useState(false); + const [deleteModalState, setDeleteModalState] = + useState('INACTIVE'); + const menuRef = useRef(null); useEffect(() => { setConversationsName(conversation.name); }, [conversation.name]); function handleEditConversation() { setIsEdit(true); + setOpen(false); } function handleSaveConversation(changedConversation: ConversationProps) { @@ -50,6 +58,18 @@ export default function ConversationTile({ } } + const handleClickOutside = (event: MouseEvent) => { + if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + setOpen(false); + } + }; + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); function onClear() { setConversationsName(conversation.name); setIsEdit(false); @@ -79,7 +99,7 @@ export default function ConversationTile({ setConversationsName(e.target.value)} /> @@ -90,36 +110,108 @@ export default function ConversationTile({ )} {conversationId === conversation.id && ( -
- Edit { - event.stopPropagation(); - isEdit - ? handleSaveConversation({ +
+ {isEdit ? ( +
+ Edit { + event.stopPropagation(); + handleSaveConversation({ id: conversationId, name: conversationName, - }) - : handleEditConversation(); - }} - /> - Exit { - event.stopPropagation(); - isEdit ? onClear() : onDeleteConversation(conversation.id); - }} - /> + }); + }} + /> + Exit { + event.stopPropagation(); + onClear(); + }} + /> +
+ ) : ( + + )} + {isOpen && ( +
+ + + +
+ )}
)} + onDeleteConversation(conversation.id)} + submitLabel="Delete" + /> + {isShareModalOpen && conversationId && ( + { + setShareModalState(false); + }} + conversationId={conversationId} + /> + )}
); } diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx new file mode 100644 index 00000000..886901b5 --- /dev/null +++ b/frontend/src/modals/ShareConversationModal.tsx @@ -0,0 +1,93 @@ +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import Spinner from '../assets/spinner.svg'; +import Exit from '../assets/exit.svg'; +const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; + +export const ShareConversationModal = ({ + close, + conversationId, +}: { + close: () => void; + conversationId: string; +}) => { + const [identifier, setIdentifier] = useState(null); + const [isCopied, setIsCopied] = useState(false); + type StatusType = 'loading' | 'idle' | 'fetched' | 'failed'; + const [status, setStatus] = useState('idle'); + const { t } = useTranslation(); + const domain = window.location.origin; + const handleCopyKey = (url: string) => { + navigator.clipboard.writeText(url); + setIsCopied(true); + }; + const shareCoversationPublicly: (isPromptable: boolean) => void = ( + isPromptable = false, + ) => { + setStatus('loading'); + fetch(`${apiHost}/api/share?isPromptable=${isPromptable}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ conversation_id: conversationId }), + }) + .then((res) => { + console.log(res.status); + return res.json(); + }) + .then((data) => { + if (data.success && data.identifier) { + setIdentifier(data.identifier); + setStatus('fetched'); + } else setStatus('failed'); + }) + .catch((err) => setStatus('failed')); + }; + return ( +
+
+ +
+

Create a public page to share

+

+ Source document, personal information and further conversation will + remain private +

+
+ {`${domain}/shared/${ + identifier ?? '....' + }`} + {status === 'fetched' ? ( + + ) : ( + + )} +
+
+
+
+ ); +}; diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index 63f99513..938eacee 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -48,6 +48,7 @@ module.exports = { 'soap':'#D8CCF1', 'independence':'#54546D', 'philippine-yellow':'#FFC700', + 'bright-gray':'#EBEBEB' }, }, },