the-forest/client/src/page/PageWithSidebar.jsx

128 lines
4.4 KiB
JavaScript

import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useParams, useNavigate } from 'react-router-dom';
import { apiUrl, fetchPage, fetchPageAtEdit, postPage, deletePage } from '../apiTools.jsx';
import { useFixLinks } from '../clientStuff.jsx';
import { useLoggedIn } from '../AuthProvider.jsx';
import Sidebar from './Sidebar.jsx';
import CommandEntry from './CommandEntry.jsx';
import './Pages.css';
function PageWithSidebar({ editing }) {
const queryClient = useQueryClient();
const navigate = useNavigate();
const { pagenumber, editid } = useParams();
const loggedIn = useLoggedIn();
const noLoad = useFixLinks();
const [command, setCommand] = useState("");
const fetchQuery = useQuery({ // fetch the currrent values
queryKey: ['page', pagenumber, editid],
queryFn: () => editid ? fetchPageAtEdit(pagenumber, editid) : fetchPage(pagenumber)
})
const postMutation = useMutation({ // for changing the value when we're done with it
mutationFn: ({id, title, description}) => postPage({id, title, description}),
onSettled: async (data, error, variables) => {
// Invalidate and refetch
await queryClient.invalidateQueries({ queryKey: ['page', variables.id, undefined] })
},
});
const deleteMutation = useMutation({ // for changing the value when we're done with it
mutationFn: (id) => deletePage(id),
onSettled: async (data, error, variables) => {
// Invalidate and refetch
await queryClient.invalidateQueries({ queryKey: ['pages'] })
},
});
const readyToShow = !(fetchQuery.error || fetchQuery.isPending);
let {id, title, description, html, time, author} = fetchQuery.data || {};
if (!title) title = "[no title]";
if (!html) html = "[body missing]";
if (!description) description = "[body missing]";
function submitChanges(e) {
const newTitle = document.querySelector('span').innerHTML;
const newText = document.querySelector('pre').innerHTML;
postMutation.mutate({
id: pagenumber,
title: newTitle,
description: newText
});
navigate(`/${pagenumber}`, {replace: true})
}
function submitDelete(e) {
e.preventDefault();
deleteMutation.mutate(pagenumber);
navigate(`/`);
}
return (
<>
<div className="main-column">
<header>
<h1>
<a href="/" {...noLoad}>🌳</a>
{pagenumber}.&nbsp;
<span
contentEditable={editing}
dangerouslySetInnerHTML={{__html: readyToShow ? title : "..." }} />
</h1>
{readyToShow && editid && `saved at ${time} by user #${author}`}
<hr/>
</header>
<section className="page-contents">
{ readyToShow ?
(
editing ?
<pre
contentEditable="true"
dangerouslySetInnerHTML={{__html: description}} />
:
<div
dangerouslySetInnerHTML={{__html: html}}
{...noLoad} />
)
:
"..."
}
</section>
<button
onClick={() => navigate(`/${pagenumber}/history`)}>
History
</button>
{editing && (
<button
disabled={postMutation.isPending}
onClick={submitChanges}>
{postMutation.isPending ? "Updating..." : "Update"}
</button>)}
{!editing && !editid && (
<button
disabled={!loggedIn}
onClick={() => navigate(`/${pagenumber}/edit`)}>
Edit Page
</button>)}
{loggedIn && (
<button
disabled={deleteMutation.isPending}
onClick={submitDelete}>
{deleteMutation.isPending ? "Deleting..." : "Delete this page and entire edit history (no backsies)"}
</button>)}
</div>
<Sidebar pagenumber={pagenumber} hidden="true" sendWord={(word) => setCommand((command + " " + word).trim())}>
{!editing && <li><button onClick={() => navigate(`/${pagenumber}/edit`)}>edit</button></li>}
{editing && <li><button disabled={postMutation.isPending} onClick={submitChanges}>save</button></li>}
{editing && <li><button onClick={() => navigate(`/${pagenumber}`)}>return</button></li>}
</Sidebar>
<CommandEntry command={command} onChange={(e) => setCommand(e.target.value)}/>
</>
);
}
export default PageWithSidebar;