LibreChat/client/src/routes/Root.tsx

94 lines
3.4 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Outlet } from 'react-router-dom';
import type { ContextType } from '~/common';
import {
AgentsMapContext,
AssistantsMapContext,
FileMapContext,
SearchContext,
SetConvoProvider,
} from '~/Providers';
import { useAuthContext, useAssistantsMap, useAgentsMap, useFileMap, useSearch } from '~/hooks';
import TermsAndConditionsModal from '~/components/ui/TermsAndConditionsModal';
import { useUserTermsQuery, useGetStartupConfig } from '~/data-provider';
import { Nav, MobileNav } from '~/components/Nav';
import { Banner } from '~/components/Banners';
import { getTermsMarkdown } from '~/utils';
import { useRecoilValue } from 'recoil';
import store from '~/store';
export default function Root() {
const [showTerms, setShowTerms] = useState(false);
const [bannerHeight, setBannerHeight] = useState(0);
const [navVisible, setNavVisible] = useState(() => {
const savedNavVisible = localStorage.getItem('navVisible');
return savedNavVisible !== null ? JSON.parse(savedNavVisible) : true;
});
const { isAuthenticated, logout } = useAuthContext();
const assistantsMap = useAssistantsMap({ isAuthenticated });
const agentsMap = useAgentsMap({ isAuthenticated });
const fileMap = useFileMap({ isAuthenticated });
const search = useSearch({ isAuthenticated });
const lang = useRecoilValue(store.lang);
const modalContent = getTermsMarkdown(lang);
const { data: config } = useGetStartupConfig();
const { data: termsData } = useUserTermsQuery({
enabled: isAuthenticated && config?.interface?.termsOfService?.modalAcceptance === true,
});
useEffect(() => {
if (termsData) {
setShowTerms(!termsData.termsAccepted);
}
}, [termsData]);
const handleAcceptTerms = () => {
setShowTerms(false);
};
// Pass the desired redirect parameter to logout
const handleDeclineTerms = () => {
setShowTerms(false);
logout('/login?redirect=false');
};
if (!isAuthenticated) {
return null;
}
return (
<SetConvoProvider>
<SearchContext.Provider value={search}>
<FileMapContext.Provider value={fileMap}>
<AssistantsMapContext.Provider value={assistantsMap}>
<AgentsMapContext.Provider value={agentsMap}>
<Banner onHeightChange={setBannerHeight} />
<div className="flex" style={{ height: `calc(100dvh - ${bannerHeight}px)` }}>
<div className="relative z-0 flex h-full w-full overflow-hidden">
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
<div className="relative flex h-full max-w-full flex-1 flex-col overflow-hidden">
<MobileNav setNavVisible={setNavVisible} />
<Outlet context={{ navVisible, setNavVisible } satisfies ContextType} />
</div>
</div>
</div>
</AgentsMapContext.Provider>
{config?.interface?.termsOfService?.modalAcceptance === true && (
<TermsAndConditionsModal
open={showTerms}
onOpenChange={setShowTerms}
onAccept={handleAcceptTerms}
onDecline={handleDeclineTerms}
title={config.interface.termsOfService.modalTitle}
modalContent={modalContent}
/>
)}
</AssistantsMapContext.Provider>
</FileMapContext.Provider>
</SearchContext.Provider>
</SetConvoProvider>
);
}