diff options
Diffstat (limited to 'src/web/components/posts/Posts.jsx')
| -rw-r--r-- | src/web/components/posts/Posts.jsx | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/web/components/posts/Posts.jsx b/src/web/components/posts/Posts.jsx new file mode 100644 index 0000000..3944f67 --- /dev/null +++ b/src/web/components/posts/Posts.jsx @@ -0,0 +1,163 @@ +import React, {useState, useEffect, useRef} from "react"; +import {Route, Routes, useLocation, useNavigate} from "react-router-dom"; + + +import Button from "components/button/Button.jsx"; +import Submission from "components/submission/Submission.jsx"; +import Post from "components/post/Post.jsx"; +import {getSubreactFromLocation} from "helpers/Location.jsx"; + +import styles from "./Posts.css"; + +async function makePostsRequest(location, setPosts, setError, mounted) { + const init = { + method: "GET", + referrer: "same-origin", + } + const url = "/api/posts?" + new URLSearchParams({ + page: 0, + amount: 25, + subreact: getSubreactFromLocation(location), + }); + return fetch(url, init) + .then((response) => { + return response.json() + .catch(() => { + throw new Error("unexpected response from server") + }) + }) + .then((json) => { + if ("error" in json) { + throw new Error(json.error); + } + if (!mounted) { + return; + } + setPosts(json.posts); + }) + .catch((error) => { + console.log(error); + if (!mounted) { + return; + } + setError(error.message); + }); +} + +function PostsError({navigate, error}) { + return ( + <div className={styles.container + " " + styles.containerFade}> + <h1>Something's wrong!</h1> + <h2>Sorry, but an unexpected issue has forced us to stop early. Here are the technical details:</h2> + <h3>Error: {error}</h3> + <Button onClick={() => {navigate(0);}}> + Try again + </Button> + </div> + ); +} + +function PostsLoading() { + return ( + <div className={styles.container + " " + styles.containerLoading}> + {[...Array(3)].map((_, i) => + <Post placeholder key={i} /> + )} + </div> + ); +} + +function PostsEmpty({navigate}) { + return ( + <div className={styles.container + " " + styles.containerFade}> + <h1>There's nothing here?!?</h1> + <h2>Try changing subreacts.</h2> + <Button onClick={() => {navigate("/");}}> + Take me home + </Button> + </div> + ); +} + +function PostsStates({error, posts, navigate}) { + if (error !== null) { // Error message. + return ( + <PostsError navigate={navigate} error={error} /> + ); + } + + if (posts == null) { + return ( + <PostsLoading /> + ) + } + + + if (posts.length == 0) { + return ( + <PostsEmpty navigate={navigate} /> + ); + } + + return ( + posts.map(({uid, title, contents, time_updated, thumbnail, subreact}, i) => + <Post key={i} + uid={uid} + title={title} + contents={contents} + timeUpdated={time_updated} + image={thumbnail} + subreact={subreact} />) + ); +} + +export default function Posts() { + const navigate = useNavigate(); + const location = useLocation(); + const locationRef = useRef(location); + + const [posts, setPosts] = useState(null); + const [error, setError] = useState(null); + const [submissionActive, setSubmissionActive] = useState(false); + + + // We make a request if we're at the homepage or if we're changing subreacts. + const shouldMakeRequest = () => { + if (posts === null) { + return true; + } + const [previous, current] = + [locationRef.current, location].map((loc) => getSubreactFromLocation(loc)); + return previous != current; + }; + // This is a bit ugly, we're caching off our previous location so that we know + // if we should update or not. + useEffect(() => { + let mounted = true; + + if (shouldMakeRequest()) { + setPosts(null); + makePostsRequest(location, setPosts, setError, mounted); + } + + locationRef.current = location; + return () => { + setError(null); + mounted = false; + } + }, [location]); + + return ( + <div className={styles.container}> + <div className={styles.containerPadding}> + <div className={styles.postContainer + (submissionActive ? " " + styles.postContainerActive : "")} + onClick={(submissionActive ? () => {setSubmissionActive(false);} : null)}> + <div className={(submissionActive ? styles.blockEvents : "")}> + <PostsStates error={error} posts={posts} navigate={navigate}/> + </div> + </div> + </div> + <Submission active={submissionActive} setActive={setSubmissionActive} /> + </div> + ); +} |
