{"version":3,"sources":["components/Posts/index.tsx","reportWebVitals.ts","utils/api.ts","components/AddPost/index.tsx","components/PostCard/index.tsx","components/ListPosts/index.tsx","views/Home/index.view.tsx","views/Error/index.view.tsx","routes/routes.tsx","index.tsx"],"names":["FetchStatus","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","API_ENDPOINT","process","addPost","title","content","username","formData","FormData","append","Promise","resolve","reject","fetch","method","mode","cache","credentials","body","res","json","message","post","catch","err","AddPost","updatePostFn","useState","display","setDisplay","disabled","setDisabled","status","setStatus","titleRef","useRef","usernameRef","contentRef","onSubmit","a","current","value","length","textContent","minForm","onClick","className","maxLength","placeholder","fullForm","ref","defaultValue","PostCard","likesRef","date","Date","created_at","toLocaleString","likeButton","children","likesCount","removeChild","id","headers","likes","likePost","console","log","remarkPlugins","remarkGfm","atob","ListPosts","posts","statusMessage","Loading","Success","Failed","sort","b","map","Posts","setPosts","useEffect","HomeView","rel","target","href","ErrorView","MainRouter","path","element","ReactDOM","render","StrictMode","document","getElementById"],"mappings":"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","file":"static/js/main.f09a97ba.chunk.js","sourcesContent":["import React, { useEffect, useState } from \"react\"\nimport AddPost from \"components/AddPost\"\nimport ListPosts from \"components/ListPosts\"\nimport { getPosts, Post } from \"utils/api\"\nimport \"./index.scss\"\n\nexport enum FetchStatus {\n Loading,\n Success,\n Failed,\n}\n\nexport const Posts: React.FC = () => {\n const [posts, setPosts] = useState([])\n const [status, setStatus] = useState(FetchStatus.Loading)\n\n // fetch posts when component mounts\n useEffect(() => {\n getPosts()\n .then((posts) => {\n setPosts(posts)\n setStatus(FetchStatus.Success)\n })\n .catch((err) => {\n console.log(err)\n setStatus(FetchStatus.Failed)\n })\n }, [])\n\n const onUpdatePost = (post: Post) => {\n setPosts([post, ...posts])\n }\n\n return (\n
\n \n \n
\n )\n}\n\nexport default Posts\n","import { ReportHandler } from \"web-vitals\"\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import(\"web-vitals\").then(\n ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry)\n getFID(onPerfEntry)\n getFCP(onPerfEntry)\n getLCP(onPerfEntry)\n getTTFB(onPerfEntry)\n }\n )\n }\n}\n\nexport default reportWebVitals\n","export const API_ENDPOINT =\n process.env.REACT_APP_API_ENDPOINT || \"http://localhost:8787\"\n\nexport interface Post {\n id: string\n title: string\n username: string\n content: string\n created_at: number\n likes: number\n}\n\n/**\n * A Promise that returns a list of Post objects fetched from the backend API.\n */\nexport const getPosts = () => {\n return new Promise(\n (resolve: (val: Post[]) => void, reject: (err: any) => void) => {\n return fetch(`${API_ENDPOINT}/posts`)\n .then((res) => res.json())\n .then((res) => {\n if (res.message === \"success\") {\n resolve(res[\"posts\"])\n } else {\n reject(res)\n }\n })\n .catch((err) => reject(err))\n }\n )\n}\n\n/**\n * Given a Post object, like it.\n */\nexport const likePost = (post: Post) => {\n return new Promise(\n (resolve: (likes: number) => void, reject: (err: any) => void) => {\n return fetch(`${API_ENDPOINT}/posts/${post.id}/like`, {\n method: \"POST\",\n mode: \"cors\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n })\n .then((res) => res.json())\n .then((res) => {\n if (res.message === \"success\") {\n resolve(res.likes)\n } else {\n reject(res)\n }\n })\n .catch((err) => reject(err))\n }\n )\n}\n\n/**\n * Submit a post to the backend API.\n */\nexport const addPost = (title: string, content: string, username?: string) => {\n const formData = new FormData()\n formData.append(\"title\", title)\n formData.append(\"content\", content)\n if (username) formData.append(\"username\", username)\n\n return new Promise(\n (resolve: (post: Post) => void, reject: (err: any) => void) => {\n return fetch(`${API_ENDPOINT}/posts`, {\n method: \"POST\",\n mode: \"cors\",\n cache: \"no-cache\",\n credentials: \"same-origin\",\n body: formData,\n })\n .then((res) => res.json())\n .then((res) => {\n if (res.message === \"success\") {\n resolve(res.post)\n } else {\n reject(res)\n }\n })\n .catch((err) => reject(err))\n }\n )\n}\n","import React, { useRef, useState } from \"react\"\nimport { addPost, Post } from \"utils/api\"\nimport \"./index.scss\"\n\ninterface AddPostProps {\n // this function should be called when the new post is successfully added\n updatePostFn: (post: Post) => void\n}\n\nexport const AddPost: React.FC = ({\n updatePostFn,\n}: AddPostProps) => {\n // If true, display the full submission form (title, content, username, etc)\n const [display, setDisplay] = useState(false)\n\n const [disabled, setDisabled] = useState(false)\n const [status, setStatus] = useState(\"\")\n\n const titleRef = useRef(null)\n const usernameRef = useRef(null)\n const contentRef = useRef(null)\n\n const onSubmit = async () => {\n if (!titleRef.current || !contentRef.current) {\n setStatus(\"Something went wrong...\")\n return\n }\n\n const title = titleRef.current.value\n const username = usernameRef.current?.value\n const content = contentRef.current.value\n\n setDisabled(true)\n\n if (title.length < 3 || title.length > 50) {\n setStatus(\"Invalid title\")\n setDisabled(false)\n return\n }\n if (username && (username.length < 3 || username.length > 20)) {\n setStatus(\"Invalid username\")\n setDisabled(false)\n return\n }\n if (content.length < 3 || content.length > 500) {\n setStatus(\"Invalid message\")\n setDisabled(false)\n return\n }\n\n addPost(title, content, username)\n .then((post) => {\n setStatus(\"Success!\")\n\n // call hook\n if (updatePostFn) {\n updatePostFn(post)\n }\n\n // clear inputs\n if (titleRef.current) titleRef.current.textContent = \"\"\n if (contentRef.current) contentRef.current.textContent = \"\"\n\n setDisplay(false)\n setDisabled(false)\n })\n .catch(() => {\n setStatus(\"An error occurred. :(\")\n setDisabled(false)\n })\n }\n\n // most form inputs are hidden by default\n const minForm = (\n setDisplay(true)}\n className=\"add-post-component__content add-post-component__content--fake\"\n maxLength={250}\n placeholder=\"Share your thoughts here...\"\n />\n )\n\n const fullForm = (\n <>\n \n \n
\n \n \n Submit\n \n
\n \n )\n\n return (\n
\n
Add post
\n\n
\n {status && (\n
\n • {status}\n
\n )}\n\n {!display && minForm}\n {display && fullForm}\n
\n
\n )\n}\n\nexport default AddPost\n","import React, { useRef } from \"react\"\nimport ReactMarkdown from \"react-markdown\"\nimport remarkGfm from \"remark-gfm\"\nimport { likePost, Post } from \"utils/api\"\nimport \"./index.scss\"\n\ninterface PostCardProps {\n post: Post\n}\n\nexport const PostCard: React.FC = ({ post }: PostCardProps) => {\n const likesRef = useRef(null)\n\n const handleLikePost = () => {\n if (likesRef.current) {\n const likeButton = likesRef.current.children[0]\n const likesCount = likesRef.current.children[1]\n\n // remove like button\n likesRef.current.removeChild(likeButton)\n\n likePost(post)\n .then((likes) => {\n likesCount.textContent = `+${likes}`\n })\n .catch((err) => console.log(err))\n }\n }\n\n const date = new Date(post.created_at).toLocaleString()\n return (\n
\n \n 👍{\" \"}\n +{post.likes}\n
\n\n
\n {post.username} post on {date}:\n
\n

{post.title}

\n\n \n {atob(post.content)}\n \n \n )\n}\n\nexport default PostCard\n","import React from \"react\"\nimport PostCard from \"components/PostCard\"\nimport { Post } from \"utils/api\"\nimport { FetchStatus } from \"components/Posts\"\nimport \"./index.scss\"\n\ninterface ListPostsProps {\n status: FetchStatus\n\n // an array of posts to list\n posts: Post[]\n}\n\nexport const ListPosts: React.FC = ({\n status,\n posts,\n}: ListPostsProps) => {\n let statusMessage = null\n switch (status) {\n case FetchStatus.Loading:\n statusMessage = \"Loading posts...\"\n break\n case FetchStatus.Success:\n // no need to display message\n break\n default:\n case FetchStatus.Failed:\n statusMessage = \"Oh noes! Failed to load posts.\"\n break\n }\n\n return (\n
\n {statusMessage && (\n
{statusMessage}
\n )}\n\n {status === FetchStatus.Success && posts.length === 0 && (\n
\n There's nothing here. Add a post yourself!\n
\n )}\n\n {status === FetchStatus.Success && (\n
\n {posts\n .sort((a, b) => b.likes - a.likes)\n .map((post) => (\n \n ))}\n
\n )}\n
\n )\n}\n\nexport default ListPosts\n","import React from \"react\"\nimport Posts from \"components/Posts\"\nimport \"./index.scss\"\n\nconst HomeView = () => {\n return (\n
\n
\n Welcome to William's little corner of the Internet!\n
\n
\n \n
\n
\n Built with{\" \"}\n by{\" \"}\n \n William Gao\n \n . Powered by Cloudflare Workers and Pages.\n
\n
\n )\n}\n\nexport default HomeView\n","import React from \"react\"\nimport \"./index.scss\"\n\ninterface ErrorProps {\n message: string\n}\n\nconst ErrorView = ({ message }: ErrorProps) => (\n
\n
\n

- Error -

\n {message}\n
\n
\n)\n\nexport default ErrorView\n","import React from \"react\"\nimport { BrowserRouter, Route, Routes } from \"react-router-dom\"\nimport HomeView from \"views/Home/index.view\"\nimport ErrorView from \"views/Error/index.view\"\n\nconst MainRouter = () => {\n return (\n \n \n } />\n }\n />\n \n \n )\n}\n\nexport default MainRouter\n","import React from \"react\"\nimport ReactDOM from \"react-dom\"\nimport \"./scss/index.scss\"\nimport reportWebVitals from \"./reportWebVitals\"\nimport MainRouter from \"./routes/routes\"\n\nReactDOM.render(\n \n \n ,\n document.getElementById(\"root\")\n)\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n"],"sourceRoot":""}