163 lines
6.5 KiB
TypeScript
163 lines
6.5 KiB
TypeScript
import React, { useEffect, useState, useRef, useCallback } from 'react';
|
|
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
|
import { ThemeProvider } from '@mui/material/styles';
|
|
|
|
import { backstoryTheme } from '../BackstoryTheme';
|
|
|
|
import { SeverityType } from '../Components/Snack';
|
|
import { Query } from '../Components/ChatQuery';
|
|
import { ConversationHandle } from './Components/Conversation';
|
|
import { UserProvider } from './Components/UserContext';
|
|
import { BetaPage } from './Pages/BetaPage';
|
|
import { UserRoute } from './routes/UserRoute';
|
|
import { BackstoryLayout } from './Components/BackstoryLayout';
|
|
|
|
import './BackstoryApp.css';
|
|
import '@fontsource/roboto/300.css';
|
|
import '@fontsource/roboto/400.css';
|
|
import '@fontsource/roboto/500.css';
|
|
import '@fontsource/roboto/700.css';
|
|
|
|
import { connectionBase } from '../Global';
|
|
|
|
// Cookie handling functions
|
|
const getCookie = (name: string) => {
|
|
const value = `; ${document.cookie}`;
|
|
const parts = value.split(`; ${name}=`);
|
|
if (parts.length === 2) return parts.pop()?.split(';').shift();
|
|
return null;
|
|
};
|
|
|
|
const setCookie = (name: string, value: string, days = 7) => {
|
|
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Strict`;
|
|
};
|
|
|
|
const BackstoryApp = () => {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const snackRef = useRef<any>(null);
|
|
const chatRef = useRef<ConversationHandle>(null);
|
|
const [sessionId, setSessionId] = useState<string | undefined>(undefined);
|
|
const setSnack = useCallback((message: string, severity?: SeverityType) => {
|
|
snackRef.current?.setSnack(message, severity);
|
|
}, [snackRef]);
|
|
const submitQuery = (query: Query) => {
|
|
console.log(`handleSubmitChatQuery:`, query, chatRef.current ? ' sending' : 'no handler');
|
|
chatRef.current?.submitQuery(query);
|
|
navigate('/chat');
|
|
};
|
|
const [page, setPage] = useState<string>("");
|
|
const [storeInCookie, setStoreInCookie] = useState(true);
|
|
|
|
// Extract session ID from URL query parameter or cookie
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const urlSessionId = urlParams.get('id');
|
|
const cookieSessionId = getCookie('session_id');
|
|
|
|
// Fetch or join session on mount
|
|
useEffect(() => {
|
|
const fetchSession = async () => {
|
|
try {
|
|
let response;
|
|
let newSessionId;
|
|
let action = ""
|
|
if (urlSessionId) {
|
|
// Attempt to join session from URL
|
|
response = await fetch(`${connectionBase}/api/join-session/${urlSessionId}`, {
|
|
credentials: 'include',
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Session not found');
|
|
}
|
|
newSessionId = (await response.json()).id;
|
|
action = "Joined";
|
|
} else if (cookieSessionId) {
|
|
// Attempt to join session from cookie
|
|
response = await fetch(`${connectionBase}/api/join-session/${cookieSessionId}`, {
|
|
credentials: 'include',
|
|
});
|
|
if (!response.ok) {
|
|
// Cookie session invalid, create new session
|
|
response = await fetch(`${connectionBase}/api/create-session`, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Failed to create session');
|
|
}
|
|
action = "Created new";
|
|
} else {
|
|
action = "Joined";
|
|
}
|
|
newSessionId = (await response.json()).id;
|
|
} else {
|
|
// Create a new session
|
|
response = await fetch(`${connectionBase}/api/create-session`, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Failed to create session');
|
|
}
|
|
action = "Created new";
|
|
newSessionId = (await response.json()).id;
|
|
}
|
|
setSessionId(newSessionId);
|
|
setSnack(`${action} session ${newSessionId}`);
|
|
|
|
// Store in cookie if user opts in
|
|
if (storeInCookie) {
|
|
setCookie('session_id', newSessionId);
|
|
}
|
|
// Update URL without reloading
|
|
if (!storeInCookie) {
|
|
// Update only the 'id' query parameter, preserving the current path
|
|
navigate(`${location.pathname}?id=${newSessionId}`, { replace: true });
|
|
} else {
|
|
// Clear all query parameters, preserve the current path
|
|
navigate(location.pathname, { replace: true });
|
|
}
|
|
} catch (err) {
|
|
setSnack("" + err);
|
|
}
|
|
};
|
|
fetchSession();
|
|
}, [cookieSessionId, setSnack, storeInCookie, urlSessionId]);
|
|
|
|
useEffect(() => {
|
|
const currentRoute = location.pathname.split("/")[1] ? `/${location.pathname.split("/")[1]}` : "/";
|
|
setPage(currentRoute);
|
|
}, [location.pathname]);
|
|
|
|
// Render appropriate routes based on user type
|
|
return (
|
|
<ThemeProvider theme={backstoryTheme}>
|
|
<UserProvider sessionId={sessionId} setSnack={setSnack}>
|
|
<Routes>
|
|
<Route path="/u/:username" element={<UserRoute sessionId={sessionId} setSnack={setSnack} />} />
|
|
{/* Static/shared routes */}
|
|
<Route
|
|
path="/*"
|
|
element={
|
|
<BackstoryLayout
|
|
sessionId={sessionId}
|
|
setSnack={setSnack}
|
|
page={page}
|
|
chatRef={chatRef}
|
|
snackRef={snackRef}
|
|
submitQuery={submitQuery}
|
|
/>
|
|
}
|
|
/>
|
|
</Routes>
|
|
</UserProvider>
|
|
|
|
</ThemeProvider>
|
|
);
|
|
|
|
};
|
|
|
|
export {
|
|
BackstoryApp
|
|
}; |