From 0f16c0edfcba24f033c69136dd6f0cf1e98418aa Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Tue, 9 Jul 2024 21:02:37 +0800 Subject: [PATCH] cleaned up rykel's mess --- client/src/components/NavigationBar.tsx | 2 +- client/src/icons.tsx | 133 +++++++++++ client/src/layouts/default.tsx | 6 + client/src/pages/CommunityPage.tsx | 289 +++++++++++------------- client/src/pages/CreatePostPage.tsx | 230 ++++++++++--------- client/src/pages/EditPostPage.tsx | 37 +-- 6 files changed, 405 insertions(+), 292 deletions(-) diff --git a/client/src/components/NavigationBar.tsx b/client/src/components/NavigationBar.tsx index ea6f863..8be17f0 100644 --- a/client/src/components/NavigationBar.tsx +++ b/client/src/components/NavigationBar.tsx @@ -95,7 +95,7 @@ export default function NavigationBar() { navigate("/community"); }} > -

Community

+

Community Forums

diff --git a/client/src/icons.tsx b/client/src/icons.tsx index 44c535b..ca83e42 100644 --- a/client/src/icons.tsx +++ b/client/src/icons.tsx @@ -135,3 +135,136 @@ export const ArrowRightStartOnRectangleIcon = () => { ); }; + +export const EllipsisHorizontalIcon = () => { + return ( + + + + ); +}; + +export const PlusIcon = () => { + return ( + + + + ); +}; + +export const ArrowUTurnLeftIcon = () => { + return ( + + + + ); +}; + +export const MagnifyingGlassIcon = () => { + return ( + + + + ); +}; + +export const XMarkIcon = () => { + return ( + + + + ); +}; + +export const HandThumbsUpIcon = () => { + return ( + + + + ); +}; + +export const ChatBubbleOvalLeftEllipsisIcon = () => { + return ( + + + + ); +}; diff --git a/client/src/layouts/default.tsx b/client/src/layouts/default.tsx index 49de78b..034492f 100644 --- a/client/src/layouts/default.tsx +++ b/client/src/layouts/default.tsx @@ -13,6 +13,12 @@ export default function DefaultLayout({
{children}
+ + {/* + A div that becomes black in dark mode to cover white color parts + of the website when scrolling past the window's original view. + */} +
); } diff --git a/client/src/pages/CommunityPage.tsx b/client/src/pages/CommunityPage.tsx index 965617c..162496a 100644 --- a/client/src/pages/CommunityPage.tsx +++ b/client/src/pages/CommunityPage.tsx @@ -1,10 +1,35 @@ // import { title } from "@/components/primitives"; import DefaultLayout from "../layouts/default"; -import { SetStateAction, useEffect, useState } from 'react'; -import { Button, Avatar, Link, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Input } from "@nextui-org/react"; -import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure } from "@nextui-org/react"; +import { SetStateAction, useEffect, useState } from "react"; +import { + Button, + Avatar, + Dropdown, + DropdownTrigger, + DropdownMenu, + DropdownItem, + Input, + Chip, +} from "@nextui-org/react"; +import { + Modal, + ModalContent, + ModalHeader, + ModalBody, + ModalFooter, + useDisclosure, +} from "@nextui-org/react"; import config from "../config"; import instance from "../security/http"; +import { + ChatBubbleOvalLeftEllipsisIcon, + EllipsisHorizontalIcon, + HandThumbsUpIcon, + MagnifyingGlassIcon, + PlusIcon, + XMarkIcon, +} from "../icons"; +import { useNavigate } from "react-router-dom"; interface Post { title: string; @@ -14,6 +39,7 @@ interface Post { } export default function CommunityPage() { + const navigate = useNavigate(); const { isOpen, onOpen, onOpenChange } = useDisclosure(); const [selectedPost, setSelectedPost] = useState(null); @@ -24,21 +50,21 @@ export default function CommunityPage() { const [communityList, setCommunityList] = useState([]); // Search Function - const [search, setSearch] = useState(''); - const onSearchChange = (e: { target: { value: SetStateAction; }; }) => { + const [search, setSearch] = useState(""); + const onSearchChange = (e: { target: { value: SetStateAction } }) => { setSearch(e.target.value); }; const getPosts = () => { - instance - .get(config.serverAddress + '/post').then((res) => { - setCommunityList(res.data); - }); + instance.get(config.serverAddress + "/post").then((res) => { + setCommunityList(res.data); + }); }; const searchPosts = () => { instance - .get(config.serverAddress + `/post?search=${search}`).then((res) => { + .get(config.serverAddress + `/post?search=${search}`) + .then((res) => { setCommunityList(res.data); }); }; @@ -47,7 +73,7 @@ export default function CommunityPage() { getPosts(); }, []); - const onSearchKeyDown = (e: { key: string; }) => { + const onSearchKeyDown = (e: { key: string }) => { if (e.key === "Enter") { searchPosts(); } @@ -55,18 +81,17 @@ export default function CommunityPage() { const onClickSearch = () => { searchPosts(); - } + }; const onClickClear = () => { - setSearch(''); + setSearch(""); getPosts(); }; useEffect(() => { - instance - .get(config.serverAddress + '/post').then((res) => { - console.log(res.data); - setCommunityList(res.data); - }); + instance.get(config.serverAddress + "/post").then((res) => { + console.log(res.data); + setCommunityList(res.data); + }); }, []); const handleDeleteClick = (post: Post) => { @@ -76,58 +101,55 @@ export default function CommunityPage() { const handleDeleteConfirm = async () => { if (selectedPost) { try { - await instance - .delete(config.serverAddress + `/post/${selectedPost.id}`); - setCommunityList((prevList) => prevList.filter(post => post.id !== selectedPost.id)); + await instance.delete( + config.serverAddress + `/post/${selectedPost.id}` + ); + setCommunityList((prevList) => + prevList.filter((post) => post.id !== selectedPost.id) + ); onOpenChange(); } catch (error) { - console.error('Error deleting post:', error); + console.error("Error deleting post:", error); } } }; - return ( -
-
- { - communityList.map((post) => { +
+
+
+

Community Forums

+

+ Socialize, share your experience or ask a question! +

+
+
+ {communityList.map((post) => { return ( -
-
- +
+
+
-
-
-
-
-
-

Adam

-
-
-

- {post.title} -

-
+
+
+
+
+

{post.title}

+

Adam

-
+
-
@@ -135,13 +157,17 @@ export default function CommunityPage() { { - // Navigate to editPost page with post.id - const editPostUrl = `/editPost/${post.id}`; // Replace with your actual edit post route - window.location.href = editPostUrl; - }}> + navigate(`/editPost/${post.id}`); + }} + > Edit - handleDeleteClick(post)}> + handleDeleteClick(post)} + > Delete @@ -149,112 +175,69 @@ export default function CommunityPage() {
-

- {post.content} -

+

{post.content}

-
-
-

tag1

+
+
+ Tag 1 + Tag 2
-
-

tag2

-
-
-
-
-

Like

-
-
-

Comment

-
-
-

...

+
+ + +
); - }) - } -
-
- - - -
- - - + })}
-
-
+
+
+ + + + +
+ } + /> +
+
{(onClose) => ( <> - Confirm Delete + + Confirm Delete +

Are you sure you want to delete this post?

diff --git a/client/src/pages/CreatePostPage.tsx b/client/src/pages/CreatePostPage.tsx index b37b216..0d1b6a4 100644 --- a/client/src/pages/CreatePostPage.tsx +++ b/client/src/pages/CreatePostPage.tsx @@ -1,127 +1,131 @@ -import DefaultLayout from '../layouts/default'; -import { Button, Link } from "@nextui-org/react"; +import DefaultLayout from "../layouts/default"; +import { Button } from "@nextui-org/react"; import { Formik, Form } from "formik"; -import * as Yup from 'yup'; +import * as Yup from "yup"; import axios from "axios"; -import { useNavigate } from 'react-router-dom'; -import NextUIFormikInput from '../components/NextUIFormikInput'; -import NextUIFormikTextarea from '../components/NextUIFormikTextarea'; -import config from '../config'; +import { useNavigate } from "react-router-dom"; +import NextUIFormikInput from "../components/NextUIFormikInput"; +import NextUIFormikTextarea from "../components/NextUIFormikTextarea"; +import config from "../config"; +import { ArrowUTurnLeftIcon } from "../icons"; const validationSchema = Yup.object({ - title: Yup.string().trim() - .min(3, 'Title must be at least 3 characters') - .max(200, 'Title must be at most 200 characters') - .matches(/^[a-zA-Z0-9\s]+$/, "Title can only contain letters, numbers, and spaces") - .required('Title is required'), - content: Yup.string().trim() - .min(3, 'Content must be at least 3 characters') - .max(500, 'Content must be at most 500 characters') - .matches(/^[a-zA-Z0-9,\s!"'-]*$/, 'Only letters, numbers, commas, spaces, exclamation marks, quotations, and common symbols are allowed') - .required('Content is required') + title: Yup.string() + .trim() + .min(3, "Title must be at least 3 characters") + .max(200, "Title must be at most 200 characters") + .matches( + /^[a-zA-Z0-9\s]+$/, + "Title can only contain letters, numbers, and spaces" + ) + .required("Title is required"), + content: Yup.string() + .trim() + .min(3, "Content must be at least 3 characters") + .max(500, "Content must be at most 500 characters") + .matches( + /^[a-zA-Z0-9,\s!"'-]*$/, + "Only letters, numbers, commas, spaces, exclamation marks, quotations, and common symbols are allowed" + ) + .required("Content is required"), }); function CreatePostPage() { - const navigate = useNavigate(); + const navigate = useNavigate(); - const initialValues = { - title: '', - content: '', - tags: '' - }; + const initialValues = { + title: "", + content: "", + tags: "", + }; - const handleSubmit = async (values: any, { setSubmitting, resetForm, setFieldError }: any) => { - try { - const response = await axios - .post(config.serverAddress + '/post', values); // Assuming an API route - if (response.status === 200) { - console.log('Post created successfully:', response.data); - resetForm(); // Clear form after successful submit - navigate("/community"); - } else { - console.error('Error creating post:', response.statusText); - } - } catch (error: any) { - if (error.response && error.response.data && error.response.data.field) { - setFieldError(error.response.data.field, error.response.data.error); - } else { - console.error('Unexpected error:', error); - } - } finally { - setSubmitting(false); - } - }; + const handleSubmit = async ( + values: any, + { setSubmitting, resetForm, setFieldError }: any + ) => { + try { + const response = await axios.post(config.serverAddress + "/post", values); // Assuming an API route + if (response.status === 200) { + console.log("Post created successfully:", response.data); + resetForm(); // Clear form after successful submit + navigate("/community"); + } else { + console.error("Error creating post:", response.statusText); + } + } catch (error: any) { + if (error.response && error.response.data && error.response.data.field) { + setFieldError(error.response.data.field, error.response.data.error); + } else { + console.error("Unexpected error:", error); + } + } finally { + setSubmitting(false); + } + }; - return ( - -
- - - - - - -
-
- +
+ +
+
+ + {({ isValid, dirty, isSubmitting }) => ( +
+
+ +
+
+

Image

+
+
+ +
+
+ +
+
+ -
-
- )} -
-
- - ); +

Post

+ +
+ + )} + +
+
+ ); } export default CreatePostPage; diff --git a/client/src/pages/EditPostPage.tsx b/client/src/pages/EditPostPage.tsx index f6a177b..d0fc401 100644 --- a/client/src/pages/EditPostPage.tsx +++ b/client/src/pages/EditPostPage.tsx @@ -1,5 +1,5 @@ import DefaultLayout from "../layouts/default"; -import { Button, Link } from "@nextui-org/react"; +import { Button } from "@nextui-org/react"; import { Formik, Form } from "formik"; import * as Yup from "yup"; import { useEffect, useState } from "react"; @@ -9,6 +9,7 @@ import NextUIFormikInput from "../components/NextUIFormikInput"; import NextUIFormikTextarea from "../components/NextUIFormikTextarea"; import config from "../config"; import instance from "../security/http"; +import { ArrowUTurnLeftIcon } from "../icons"; const validationSchema = Yup.object({ title: Yup.string() @@ -34,13 +35,6 @@ const validationSchema = Yup.object({ function editPost() { const { id } = useParams(); const navigate = useNavigate(); - - // const initialValues = { - // title: '', - // content: '', - // tags: '' - // }; - const [post, setPost] = useState({ title: "", content: "", @@ -62,10 +56,10 @@ function editPost() { const response = await instance.put( config.serverAddress + `/post/${id}`, values - ); // Assuming an API route + ); if (response.status === 200) { console.log("Post updated successfully:", response.data); - resetForm(); // Clear form after successful submit + resetForm(); navigate("/community"); } else { console.error("Error updating post:", response.statusText); @@ -84,21 +78,14 @@ function editPost() { return (
- - - - - - +
{!loading && (