A
Anonymous

Post Table - Copy this React, Tailwind Component to your project

"use client"; import { InfoCircleOutlined } from "@ant design/icons"; import { Button, Divider, Flex, Form, Input, message, Modal, Table, } from "antd"; import { useEffect, useState } from "react"; import PostDetailModal from "./post.detail"; import { useRouterAsync } from "@/hooks/useRouterAsync"; import { FiMoon, FiSun } from "react icons/fi"; const PostTable = (props: any) => { const { session } = props; const token = session?.user?.access_token; const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [limit, setLimit] = useState(10); const [listPosts, setListPosts] = useState<any>(); const [darkMode, setDarkMode] = useState<boolean>(false); const [searchTerm, setSearchTerm] = useState<any>(""); const [postSelected, setPostSelected] = useState<any>(); const [isModalShowPostVisible, setIsModalShowPostVisible] = useState<boolean>(false); //report post const [isModalReportPostVisible, setIsModalReportPostVisible] = useState<boolean>(false); const [form] = Form.useForm(); const { handleRoute, isLoadingRouter } = useRouterAsync(); const fetchPostPaginated = async ( currentPage: number, limit: number, searchTerm: string ) => { try { const response = await fetch( `${ process.env.NEXT_PUBLIC_BACKEND_URL }/api/post?page=${+currentPage}&limit=${+limit}&searchTerm=${searchTerm}`, { headers: { Authorization: `Bearer ${token}`, "Content Type": "application/json", }, } ); const data = await response.json(); setListPosts(data.data.posts); setTotalPages(data.data.totalPages); return data; } catch (error) { message.error("Error fetching data"); } }; useEffect(() => { if (searchTerm) { fetchPostPaginated(currentPage, limit, searchTerm); } else { setSearchTerm(""); setLimit(10); setCurrentPage(1); setListPosts([]); setTotalPages(1); setPostSelected(null); } }, [session, currentPage, limit, searchTerm]); const handleAuthorClick = (author: any) => { handleRoute(`/user/${author._id}`); }; const handleDetail = (record: any) => { setPostSelected(record); setIsModalShowPostVisible(true); }; const handleShowModalReport = (record: any) => { setPostSelected(record); setIsModalReportPostVisible(true); }; const toggleDarkMode = () => { setDarkMode(!darkMode); }; const handleReportPost = async () => { try { const values = await form.validateFields(); const reason = values.reason; const body = JSON.stringify({ reportType: "post", reason: reason, reportedBy: session?.user?._id, postReported: postSelected._id, }); const response = await fetch( `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/report`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content Type": "application/json", }, body: body, } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || "An error occurred"); } const data = await response.json(); console.log(data); setIsModalReportPostVisible(false); message.success("Report submitted"); return data; } catch (error) { const errorMessage = (error as Error).message; message.error(`Error submitting report: ${errorMessage}`); } }; const columnsUser = [ { title: "Author", dataIndex: "author", key: "author", render: (author: any) => ( <Button type="link" onClick={() => handleAuthorClick(author)}> {author?.username} </Button> ), }, { title: "Content", dataIndex: "content", key: "content", render: (content: string) => content.length > 30 ? `${content.substring(0, 10)}...` : content, }, { title: "Tags", dataIndex: "tags", key: "tags", render: (tags: string[]) => tags.join(", "), }, { title: "Actions", dataIndex: "action", key: "action", render: (text: any, record: any) => ( <Flex align="center"> <Button title="Details" type="link" onClick={() => handleDetail(record)} > <InfoCircleOutlined /> </Button> <Divider type="vertical" /> <Button danger title="Report" type="link" onClick={() => handleShowModalReport(record)} > Report </Button> </Flex> ), }, ]; return ( <> <div className={`min h screen ${darkMode ? "bg gray 900 text white" : "bg white text gray 800"}`}> <button onClick={toggleDarkMode} className={`p 2 rounded full ${darkMode ? "bg gray 700 text yellow 300" : "bg gray 200 text gray 600"}`}> {darkMode ? <FiSun className="text xl" /> : <FiMoon className="text xl" />} </button> <div style={{ display: "flex", justifyContent: "center", alignItems: "center", marginBottom: 20, }} > <Input style={{ maxWidth: "300px", padding: "10px 20px", borderRadius: "24px", border: "1px solid #ccc", }} placeholder="Search by content and tags..." value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> </div> {listPosts?.length > 0 && ( <Table pagination={{ current: currentPage, total: totalPages * limit, pageSize: limit, onChange: (page) => setCurrentPage(page), }} columns={columnsUser} dataSource={listPosts} className={darkMode ? "bg gray 800" : "bg white"} /> )} <PostDetailModal visible={isModalShowPostVisible} onClose={() => { setIsModalShowPostVisible(false); setPostSelected(null); }} session={session} post={postSelected} totalComments={postSelected?.comments?.length || 0} /> {/* Modal report post */} <Modal title="Report this post" open={isModalReportPostVisible} footer={null} onCancel={() => setIsModalReportPostVisible(false)} > <Form layout="vertical"> <Form layout="vertical" form={form}> <Form.Item label="Report Content" name="reason" required> <Input.TextArea rows={3} required /> </Form.Item> <Form.Item> <div style={{ display: "flex", justifyContent: "flex end" }}> <span style={{ marginRight: "10px", marginTop: "5px", color: "red", }} > (* This action cannot be undone) </span> <Button danger onClick={handleReportPost}> Report </Button> </div> </Form.Item> </Form> </Form> </Modal> </div> </> ); }; export default PostTable; add darkmode

Prompt
Component Preview

About

PostTable - A dynamic table for posts featuring search, pagination, and dark mode. Built with React and Tailwind. Copy now for free!

Share

Last updated 1 month ago