parent
13fb4db1d1
commit
090ded9e85
@ -0,0 +1,49 @@ |
|||||||
|
import { useQuery } from '@tanstack/react-query'; |
||||||
|
import { useParams, useNavigate } from 'react-router-dom'; |
||||||
|
import { fetchPageHistory } from '../apiTools.jsx'; |
||||||
|
import { useFixLinks } from '../clientStuff.jsx'; |
||||||
|
|
||||||
|
import './Pages.css'; |
||||||
|
|
||||||
|
function HistoryView() { |
||||||
|
const noLoad = useFixLinks(); |
||||||
|
const { pagenumber, editid } = useParams(); |
||||||
|
const navigate = useNavigate(); |
||||||
|
|
||||||
|
const { isPending, error, data } = useQuery({ // fetch the currrent values |
||||||
|
queryKey: ['page history', pagenumber], |
||||||
|
queryFn: () => fetchPageHistory(pagenumber) |
||||||
|
}) |
||||||
|
const edits = data; |
||||||
|
|
||||||
|
const ready = !(error || isPending); |
||||||
|
|
||||||
|
const pageTitle = edits ? edits[0]?.title : "[no title]"; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="main-column"> |
||||||
|
<div> |
||||||
|
<header> |
||||||
|
<h1><a href="/" {...noLoad}>🌳</a>{pagenumber}. {ready ? pageTitle : "..."}</h1> |
||||||
|
<hr/> |
||||||
|
</header> |
||||||
|
<section className="page-contents"> |
||||||
|
{ ready ? |
||||||
|
<ol> |
||||||
|
{ edits.map(({id, number, title, time, author}) => |
||||||
|
<li key={id}> |
||||||
|
<a href={`/${number}/${id}`} {...noLoad}>{id} : "{title}", {time} by user #{author}</a> |
||||||
|
</li> |
||||||
|
) } |
||||||
|
</ol> |
||||||
|
: |
||||||
|
(isPending ? "Loading..." : JSON.stringify(error)) |
||||||
|
} |
||||||
|
</section> |
||||||
|
<button onClick={() => navigate(`/${pagenumber}`)}>Return to page</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default HistoryView; |
@ -0,0 +1,116 @@ |
|||||||
|
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 './Pages.css'; |
||||||
|
|
||||||
|
function Page({ editing }) { |
||||||
|
const queryClient = useQueryClient(); |
||||||
|
const navigate = useNavigate(); |
||||||
|
const { pagenumber, editid } = useParams(); |
||||||
|
const loggedIn = useLoggedIn(); |
||||||
|
const noLoad = useFixLinks(); |
||||||
|
|
||||||
|
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}. |
||||||
|
<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> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default Page; |
@ -1,97 +0,0 @@ |
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; |
|
||||||
import { useParams, useNavigate } from 'react-router-dom'; |
|
||||||
import { apiUrl, fetchPage, postPage, deletePage } from '../apiTools.jsx'; |
|
||||||
|
|
||||||
import './Pages.css'; |
|
||||||
|
|
||||||
function PageEdit() { |
|
||||||
const queryClient = useQueryClient(); |
|
||||||
const navigate = useNavigate(); |
|
||||||
const { pagenumber } = useParams(); |
|
||||||
|
|
||||||
const fetchQuery = useQuery({ // fetch the currrent values |
|
||||||
queryKey: ['page', pagenumber], |
|
||||||
queryFn: () => 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] }) |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
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 ready = !(fetchQuery.error || fetchQuery.isPending); |
|
||||||
|
|
||||||
let {id, title, description, html} = fetchQuery.data || {}; |
|
||||||
if (!title) title = " "; |
|
||||||
if (!description) description = " "; |
|
||||||
|
|
||||||
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="/">🌳</a> |
|
||||||
{pagenumber}. |
|
||||||
<span |
|
||||||
contentEditable="true" |
|
||||||
dangerouslySetInnerHTML={{__html: ready ? title : "..." }} /> |
|
||||||
</h1> |
|
||||||
<hr/> |
|
||||||
</header> |
|
||||||
<section> |
|
||||||
{ ready ? |
|
||||||
<> |
|
||||||
<div className="page-contents"> |
|
||||||
<pre |
|
||||||
contentEditable="true" |
|
||||||
dangerouslySetInnerHTML={{__html: description}} /> |
|
||||||
</div> |
|
||||||
<button |
|
||||||
disabled={postMutation.isPending} |
|
||||||
onClick={submitChanges}> |
|
||||||
{postMutation.isPending ? "Updating..." : "Update"} |
|
||||||
</button> |
|
||||||
<button |
|
||||||
disabled={deleteMutation.isPending} |
|
||||||
onClick={submitDelete}> |
|
||||||
{deleteMutation.isPending ? "Deleting..." : "Delete this page (no backsies)"} |
|
||||||
</button> |
|
||||||
</> |
|
||||||
: |
|
||||||
<div className="page-contents"> |
|
||||||
{ fetchQuery.isPending ? "Loading..." : JSON.stringify(fetchQuery.error) } |
|
||||||
</div> |
|
||||||
} |
|
||||||
</section> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
export default PageEdit; |
|
@ -1,48 +0,0 @@ |
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; |
|
||||||
import { useParams, useNavigate } from 'react-router-dom'; |
|
||||||
import { apiUrl, fetchPage, postPage } from '../apiTools.jsx'; |
|
||||||
import { useFixLinks } from '../clientStuff.jsx'; |
|
||||||
|
|
||||||
import './Pages.css'; |
|
||||||
|
|
||||||
function PageView() { |
|
||||||
const queryClient = useQueryClient(); |
|
||||||
const navigate = useNavigate(); |
|
||||||
const noLoad = useFixLinks(); |
|
||||||
const { pagenumber } = useParams(); |
|
||||||
|
|
||||||
const { isPending, error, data } = useQuery({ // fetch the currrent values |
|
||||||
queryKey: ['page', pagenumber], |
|
||||||
queryFn: () => fetchPage(pagenumber) |
|
||||||
}) |
|
||||||
|
|
||||||
const ready = !(error || isPending); |
|
||||||
|
|
||||||
let {id, title, description, html} = data || {}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="main-column"> |
|
||||||
<div> |
|
||||||
<header> |
|
||||||
<h1> |
|
||||||
<a href="/" {...noLoad}>🌳</a>{pagenumber}. {ready ? (title || " ") : "..."}</h1> |
|
||||||
<hr/> |
|
||||||
</header> |
|
||||||
<section> |
|
||||||
{ ready ? |
|
||||||
<div |
|
||||||
className="page-contents" |
|
||||||
dangerouslySetInnerHTML={{ __html: (html || " ") }} |
|
||||||
{...noLoad} |
|
||||||
/> |
|
||||||
: |
|
||||||
(isPending ? "Loading..." : JSON.stringify(error)) |
|
||||||
} |
|
||||||
<button onClick={(e) => { e.preventDefault(); navigate(`/${pagenumber}/edit`, {replace: true})}}>Edit this page!</button> |
|
||||||
</section> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
export default PageView; |
|
Loading…
Reference in new issue