jvcgpt / src /app.tsx
Greums's picture
dont use parent location
7cfb454
raw
history blame
6.91 kB
import {JSX} from "preact";
import {useState, useEffect, useCallback} from "preact/hooks";
import "./styles.scss";
import style from "./style.module.scss";
import {Container} from "./components/container";
import {loadTopics, saveTopics} from "./utils/topics";
import {Topic} from "./utils/topics";
import {Topics} from "./components/topics";
import {Topic as TopicComponent} from "./components/topic";
import {Route, routes, RouteSetter} from "./utils/route";
import {Settings} from "./components/settings";
import {Layout} from "./components/layout";
import {fetchSettings, resetSettings, saveSettings} from "./utils/settings";
import {generateTopic, generatePosts} from "./utils/oobabooga";
import {tokenizeTopic} from "./utils/model";
export function App(): JSX.Element {
const [route, _setRoute] = useState<Route>(routes.home);
const [page, setPage] = useState<number>(0);
const [topicId, setTopicId] = useState<Topic["id"] | null>(null);
// null when loading
const [topics, setTopics] = useState<Topic[]>(loadTopics);
const [latestGeneratedTopicId, setLatestGeneratedTopicId] = useState<string|null>(null);
const [pendingGeneration, setPendingGeneration] = useState<boolean>(false);
useEffect(() => {
console.log("save !")
saveTopics(topics);
}, [topics]);
const _generateTopic = async (postsCount: number) => {
setPendingGeneration(true);
const topic = await generateTopic(settings, postsCount);
setLatestGeneratedTopicId(topic.id);
setTopics(topics => [...topics, topic]);
setPendingGeneration(false);
}
const addPosts = async (topicId: string, postsCount: number) => {
setPendingGeneration(true);
const posts = await generatePosts(settings, postsCount, topics.find(t => t.id === topicId));
const newTopics = [...topics]; // Clone topics to avoid bugs
const foundIndex = newTopics.findIndex(t => t.id === topicId);
newTopics[foundIndex].posts = newTopics[foundIndex].posts.concat(posts);
setTopics(newTopics)
setPendingGeneration(false);
}
// useEffect(() => {
// setTopics(loadTopics());
// }, []);
const [settings, setSettings] = useState(fetchSettings)
useEffect(() => {
saveSettings(settings);
}, [settings]);
const resetApp = () => {
resetSettings();
setSettings(fetchSettings);
setTopics([]);
}
const updateRoute = useCallback(() => {
const url = new URL(window.location.href);
const route = url.searchParams.get("route");
if (route && route in routes) {
_setRoute(route as keyof typeof routes);
}
const page = url.searchParams.get("page");
if (page) {
setPage(parseInt(page));
}
const id = url.searchParams.get("id");
if (id) {
setTopicId(id);
}
}, []);
// Init page from url
useEffect(() => {
updateRoute()
}, []);
// Listen for URl change
useEffect(() => {
function listener() {
updateRoute()
}
window.addEventListener('popstate', listener);
return () => {
window.removeEventListener('popstate', listener)
}
}, []);
// Update URL params on route change
const setRoute: RouteSetter = useCallback((route: Route, page?: number, id?: string) => {
const url = new URL(window.location.href);
url.searchParams.set("route", route);
_setRoute(route);
if (page !== undefined) {
url.searchParams.set("page", String(page));
setPage(page);
} else {
url.searchParams.delete("page");
setPage(0);
}
if (id !== undefined) {
url.searchParams.set("id", id);
setTopicId(id);
} else {
url.searchParams.delete("id");
setTopicId(null);
}
const newUrl = url.toString();
// Avoid to push the same URL mutiple time
if (newUrl !== window.location.href) {
window.history.pushState({}, "", newUrl);
}
}, []);
let routeComponent: JSX.Element = undefined;
let breadcrumbs: string = undefined;
let title: string = undefined;
switch (route) {
case routes.home:
routeComponent = <Topics
topics={topics}
setRoute={setRoute}
settings={settings}
setSettings={setSettings}
generateTopic={_generateTopic}
pendingGeneration={pendingGeneration}
latestGeneratedTopicId={latestGeneratedTopicId}
/>
breadcrumbs = "accueil"
title = "Liste des sujets"
break;
case routes.topic:
if (topicId === null) {
routeComponent = <div>Impossible d'afficher le sujet</div>
breadcrumbs = "accueil"
title = "Sujet"
} else {
if (topics === null) {
routeComponent = <div>Chargement...</div>
breadcrumbs = `accueil / sujet`
title = `Chargement...`
} else {
const topic = topics.find(t => t.id === topicId);
routeComponent = <TopicComponent
topic={topic}
settings={settings}
setSettings={setSettings}
addPosts={addPosts}
pendingGeneration={pendingGeneration}
/>
breadcrumbs = `accueil / ${topic.title}`
title = `Sujet : ${topic.title}`
}
}
break;
case routes.settings:
routeComponent = <Settings settings={settings} setSettings={setSettings} resetApp={resetApp}/>
breadcrumbs = "accueil / paramètres"
title = "Paramètres"
break;
}
return (
<>
<header className={style.header}>
<Container>
<h1 className={style.logo}>
<a href="#" onClick={e => {
e.preventDefault();
setRoute(routes.home);
}}>
JVCGPT
</a>
</h1>
</Container>
</header>
<main>
<Container>
<Layout
breadcrumbs={breadcrumbs}
title={title}
setRoute={setRoute}
>
{routeComponent}
</Layout>
</Container>
</main>
</>
);
}