react-admin-panel-orient/src/pages/Posts.tsx

322 lines
11 KiB
TypeScript

// Modules
import { v4 as uuidv4 } from "uuid";
import React, { useContext, useEffect, useState } from "react";
import { PostContext } from "../context/PostContext";
// Icons
import { BsFillFileEarmarkPostFill } from "react-icons/bs";
import { BiLinkExternal } from "react-icons/bi";
// Helpers
import { getPosts } from "../helpers/apiRequests";
import { PostType } from "../types/posts";
import { Link } from "react-router-dom";
import { parseDate } from "../helpers/parseDate";
import { capitalizeFirstLetter } from "../helpers/stringMethods";
// Types
import { paramsType } from "../types/posts";
interface pageType {
perPage: number;
pageNumber: number;
}
const Posts = () => {
const [categories, setCategories] = useState<string[]>(["All"]);
const { posts, setPosts } = useContext<any>(PostContext);
const [category, setCategory] = useState<string>("All");
const [sort, setSort] = useState<string>("id");
const [page, setPage] = useState<pageType>({
perPage: 10,
pageNumber: 1,
});
const [params, setParams] = useState<paramsType>({
id: "asc",
category: "asc",
title: "asc",
link: "asc",
date: "asc",
summary: "asc",
});
const [search, setSearch] = useState<string>("");
useEffect(() => {
const key = sort as keyof typeof params;
getPosts(
setPosts,
`?sortBy=${sort}.${params[key]}&strLimit=${page.perPage}&strOffset=${page.pageNumber}&filter=${search}`
);
}, [params, sort, page, search]);
useEffect(() => {
const categoriesTemp: string[] = categories;
if (posts[0]) {
if (posts[0].id !== -1) {
posts.map((post: PostType) =>
categoriesTemp.push(
capitalizeFirstLetter(post.category.toLowerCase())
)
);
let categoriesTempUnique = categoriesTemp.filter((element, index) => {
return categoriesTemp.indexOf(element) === index;
});
setCategories(categoriesTempUnique);
}
}
}, [posts]);
return (
<main className="posts">
<div className="container">
<div className="posts inner">
<div className="dashboard__head">
<BsFillFileEarmarkPostFill className="dashboard__img" />
<h1>Posts</h1>
</div>
<div className="posts__select__wrapper">
<div className="posts__select">
<label htmlFor="category">Category</label>
<select
id="category"
value={category}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
setCategory(e.target.value);
}}
>
{categories.map((category) => {
if (category === "All") {
return (
<option key={uuidv4()} value={category} defaultChecked>
{category}
</option>
);
} else {
return (
<option key={uuidv4()} value={category}>
{category}
</option>
);
}
})}
</select>
</div>
<div className="posts__select">
<label htmlFor="pp">Per page</label>
<select
id="pp"
value={page.perPage}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
setPage({ ...page, perPage: parseInt(e.target.value) });
}}
>
<option value="10" defaultChecked>
10
</option>
<option value="15" defaultChecked>
15
</option>
<option value="20" defaultChecked>
20
</option>
<option value="30" defaultChecked>
30
</option>
<option value="40" defaultChecked>
40
</option>
</select>
</div>
<div className="posts__select">
<label htmlFor="filter">Filter</label>
<input
type="text"
id="filter"
value={search}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value);
}}
/>
</div>
</div>
<table className="posts__table">
<tbody>
<tr className="posts__table__head">
<th
className={sort === "id" ? "active" : ""}
onClick={() => {
setSort("id");
if (params.id === "asc")
setParams({ ...params, id: "asc" });
else setParams({ ...params, id: "desc" });
}}
>
ID
</th>
<th
className={sort === "category" ? "active" : ""}
onClick={() => {
setSort("category");
if (params.id === "asc")
setParams({ ...params, category: "asc" });
else setParams({ ...params, category: "desc" });
}}
>
Category
</th>
<th
className={sort === "title" ? "active" : ""}
onClick={() => {
setSort("title");
if (params.id === "asc")
setParams({ ...params, title: "asc" });
else setParams({ ...params, title: "desc" });
}}
>
Title
</th>
<th
className={sort === "link" ? "active" : ""}
onClick={() => {
setSort("link");
if (params.id === "asc")
setParams({ ...params, link: "asc" });
else setParams({ ...params, link: "desc" });
}}
>
Link
</th>
<th
className={sort === "date" ? "active" : ""}
onClick={() => {
setSort("date");
if (params.id === "asc")
setParams({ ...params, date: "asc" });
else setParams({ ...params, date: "desc" });
}}
>
Date
</th>
<th
className={sort === "summary" ? "active" : ""}
onClick={() => {
setSort("summary");
if (params.id === "asc")
setParams({ ...params, summary: "asc" });
else setParams({ ...params, summary: "desc" });
}}
>
Summary
</th>
</tr>
{posts[0] ? (
posts[0].id !== -1 ? (
category === "All" ? (
posts.map((post: PostType, index: number) => {
return (
<Link
className="post-link"
to={`/posts/${post.id}`}
key={uuidv4()}
>
<tr>
<td>{post.id}</td>
<td>
{capitalizeFirstLetter(
post.category.toLowerCase()
)}
</td>
<td>{post.title}</td>
<td>
<a
href={post.link}
target="_blank"
rel="noopener noreferrer"
>
<BiLinkExternal />
</a>
</td>
<td>{parseDate(post.date)[0]}</td>
<td>{post.summary}</td>
</tr>
</Link>
);
})
) : (
posts.map((post: PostType, index: number) => {
if (
capitalizeFirstLetter(post.category.toLowerCase()) ===
category
) {
return (
<Link
className="post-link"
to={`/posts/${post.id}`}
key={uuidv4()}
>
<tr>
<td>{index + 1}</td>
<td>
{capitalizeFirstLetter(
post.category.toLowerCase()
)}
</td>
<td>{post.title}</td>
<td>
<a
href={post.link}
target="_blank"
rel="noopener noreferrer"
>
<BiLinkExternal />
</a>
</td>
<td>{parseDate(post.date)[0]}</td>
<td>{post.summary}</td>
</tr>
</Link>
);
} else {
return "";
}
})
)
) : (
""
)
) : (
<td>
<tr className="table__empty">No posts</tr>
</td>
)}
</tbody>
</table>
<div className="posts__pagination">
<button
type="button"
disabled={page.pageNumber === 1}
onClick={() =>
setPage({ ...page, pageNumber: page.pageNumber - 1 })
}
>
Previous
</button>
<input type="text" value={page.pageNumber} readOnly />
<button
disabled={posts[0] ? false : true}
type="button"
onClick={() =>
setPage({ ...page, pageNumber: page.pageNumber + 1 })
}
>
Next
</button>
</div>
</div>
</div>
</main>
);
};
export default Posts;