diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3083f1f3..2aa8a8fc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ import { Routes, Route } from 'react-router-dom'; +import { ReactElement, useEffect } from 'react'; import Navigation from './Navigation'; import Conversation from './conversation/Conversation'; import About from './About'; @@ -8,29 +9,93 @@ import { useMediaQuery } from './hooks'; import { useState } from 'react'; import Setting from './settings'; import './locale/i18n'; - +import SharedConversation from './conversation/SharedConversation'; +import { useDarkTheme } from './hooks'; inject(); -export default function App() { +function MainLayout({ children }: { children: ReactElement }) { const { isMobile } = useMediaQuery(); const [navOpen, setNavOpen] = useState(!isMobile); return ( -
+ <>
- - } /> - } /> - } /> - } /> - + {children}
-
+ + ); +} + +function Layout({ children }: { children: ReactElement }) { + return ( + <> +
{children}
+ + ); +} +export default function App() { + const [isDarkTheme] = useDarkTheme(); + useEffect(() => { + localStorage.setItem('selectedTheme', isDarkTheme ? 'Dark' : 'Light'); + if (isDarkTheme) { + document + .getElementById('root') + ?.classList.add('dark', 'dark:bg-raisin-black'); + } else { + document.getElementById('root')?.classList.remove('dark'); + } + }, [isDarkTheme]); + return ( + <> + + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + {/* default page */} + + + + } + /> + + ); } diff --git a/frontend/src/conversation/SharedConversation.tsx b/frontend/src/conversation/SharedConversation.tsx new file mode 100644 index 00000000..82e6be62 --- /dev/null +++ b/frontend/src/conversation/SharedConversation.tsx @@ -0,0 +1,146 @@ +import { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; +import { Query } from './conversationModels'; +import ConversationBubble from './ConversationBubble'; +import { Fragment } from 'react'; +const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; +const SharedConversation = () => { + const params = useParams(); + const navigate = useNavigate(); + const { identifier } = params; //identifier is a uuid, not conversationId + const [queries, setQueries] = useState([]); + const [title, setTitle] = useState(''); + const [date, setDate] = useState(''); + + function formatISODate(isoDateStr: string) { + const date = new Date(isoDateStr); + + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'June', + 'July', + 'Aug', + 'Sept', + 'Oct', + 'Nov', + 'Dec', + ]; + + const month = monthNames[date.getMonth()]; + const day = date.getDate(); + const year = date.getFullYear(); + + let hours = date.getHours(); + const minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + + hours = hours % 12; + hours = hours ? hours : 12; + const minutesStr = minutes < 10 ? '0' + minutes : minutes; + const formattedDate = `Published ${month} ${day}, ${year} at ${hours}:${minutesStr} ${ampm}`; + return formattedDate; + } + const fetchQueris = () => { + fetch(`${apiHost}/api/shared_conversation/${identifier}`) + .then((res) => { + if (res.status === 404 || res.status === 400) navigate('/pagenotfound'); + return res.json(); + }) + .then((data) => { + if (data.success) { + setQueries(data.queries); + setTitle(data.title); + setDate(formatISODate(data.timestamp)); + } + }); + }; + + const prepResponseView = (query: Query, index: number) => { + let responseView; + if (query.response) { + responseView = ( + + ); + } else if (query.error) { + responseView = ( + + ); + } + return responseView; + }; + useEffect(() => { + fetchQueris(); + }, []); + return ( +
+
+ {queries.length > 0 && ( +
+
+
+

+ {title} +

+

+ Created with{' '} + + DocsGPT + +

+

+ {date} +

+
+
+ {queries.map((query, index) => { + return ( + + + + {prepResponseView(query, index)} + + ); + })} +
+
+
+ )} +
+ + + This is a chatbot that uses the GPT-3, Faiss and LangChain to answer + questions. + +
+
+
+ ); +}; + +export default SharedConversation; diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 6248b3f8..c8258ad2 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -77,21 +77,23 @@ export function useDarkTheme() { // Set dark mode based on local storage preference if (savedMode === 'Dark') { setIsDarkTheme(true); - document.documentElement.classList.add('dark'); - document.documentElement.classList.add('dark:bg-raisin-black'); + document + .getElementById('root') + ?.classList.add('dark', 'dark:bg-raisin-black'); } else { // If no preference found, set to default (light mode) setIsDarkTheme(false); - document.documentElement.classList.remove('dark'); + document.getElementById('root')?.classList.remove('dark'); } }, []); useEffect(() => { localStorage.setItem('selectedTheme', isDarkTheme ? 'Dark' : 'Light'); if (isDarkTheme) { - document.documentElement.classList.add('dark'); - document.documentElement.classList.add('dark:bg-raisin-black'); + document + .getElementById('root') + ?.classList.add('dark', 'dark:bg-raisin-black'); } else { - document.documentElement.classList.remove('dark'); + document.getElementById('root')?.classList.remove('dark'); } }, [isDarkTheme]); //method to toggle theme diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx index 886901b5..d32c5f90 100644 --- a/frontend/src/modals/ShareConversationModal.tsx +++ b/frontend/src/modals/ShareConversationModal.tsx @@ -57,13 +57,13 @@ export const ShareConversationModal = ({ remain private

- {`${domain}/shared/${ + {`${domain}/share/${ identifier ?? '....' }`} {status === 'fetched' ? (