import { memo, useState, useCallback, useContext } from 'react'; import Cookies from 'js-cookie'; import { useRecoilState } from 'recoil'; import { useParams } from 'react-router-dom'; import { buildTree } from 'librechat-data-provider'; import { CalendarDays, Settings } from 'lucide-react'; import { useGetSharedMessages } from 'librechat-data-provider/react-query'; import { Spinner, Button, OGDialog, ThemeContext, OGDialogTitle, useMediaQuery, OGDialogHeader, OGDialogContent, OGDialogTrigger, } from '@librechat/client'; import { ThemeSelector, LangSelector } from '~/components/Nav/SettingsTabs/General/General'; import { ShareArtifactsContainer } from './ShareArtifacts'; import { useLocalize, useDocumentTitle } from '~/hooks'; import { useGetStartupConfig } from '~/data-provider'; import { ShareContext } from '~/Providers'; import { ShareMessagesProvider } from './ShareMessagesProvider'; import MessagesView from './MessagesView'; import Footer from '../Chat/Footer'; import { cn } from '~/utils'; import store from '~/store'; function SharedView() { const localize = useLocalize(); const { data: config } = useGetStartupConfig(); const { theme, setTheme } = useContext(ThemeContext); const { shareId } = useParams(); const { data, isLoading } = useGetSharedMessages(shareId ?? ''); const dataTree = data && buildTree({ messages: data.messages }); const messagesTree = dataTree?.length === 0 ? null : (dataTree ?? null); const [langcode, setLangcode] = useRecoilState(store.lang); // configure document title let docTitle = ''; if (config?.appTitle != null && data?.title != null) { docTitle = `${data.title} | ${config.appTitle}`; } else { docTitle = data?.title ?? config?.appTitle ?? document.title; } useDocumentTitle(docTitle); const locale = langcode || (typeof navigator !== 'undefined' ? navigator.language || navigator.languages?.[0] || 'en-US' : 'en-US'); const formattedDate = data?.createdAt != null ? new Date(data.createdAt).toLocaleDateString(locale, { month: 'long', day: 'numeric', year: 'numeric', }) : null; const handleThemeChange = useCallback( (value: string) => { setTheme(value); }, [setTheme], ); const handleLangChange = useCallback( (value: string) => { let userLang = value; if (value === 'auto') { userLang = (typeof navigator !== 'undefined' ? navigator.language || navigator.languages?.[0] : null) ?? 'en-US'; } requestAnimationFrame(() => { document.documentElement.lang = userLang; }); setLangcode(userLang); Cookies.set('lang', userLang, { expires: 365 }); }, [setLangcode], ); let content: JSX.Element; if (isLoading) { content = (
); } else if (data && messagesTree && messagesTree.length !== 0) { content = ( <> ); } else { content = (
{localize('com_ui_shared_link_not_found')}
); } const footer = (
); const mainContent = (
{content} {footer}
); const artifactsContainer = data && data.messages ? ( ) : ( mainContent ); return (
{artifactsContainer}
); } interface ShareHeaderProps { title?: string; formattedDate: string | null; theme: string; langcode: string; settingsLabel: string; onThemeChange: (value: string) => void; onLangChange: (value: string) => void; } function ShareHeader({ title, formattedDate, theme, langcode, settingsLabel, onThemeChange, onLangChange, }: ShareHeaderProps) { const [settingsOpen, setSettingsOpen] = useState(false); const isMobile = useMediaQuery('(max-width: 767px)'); const handleDialogOutside = useCallback((event: Event) => { const target = event.target as HTMLElement | null; if (target?.closest('[data-dialog-ignore="true"]')) { event.preventDefault(); } }, []); return (

{title}

{formattedDate && (
)}
{settingsLabel}
); } export default memo(SharedView);