Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added a sort by option on the posts page #583

Merged
merged 1 commit into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions backend/src/routes/post/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ export const getPostsWithPagination = async (req: Request, res: Response) => {
const pageSize = parseInt(req.query.pageSize as string);
const searchQuery = req.query.searchQuery as string || "";
const tags = req.query.tags ? (req.query.tags as string).split(',') : [];

const sortOrder = req.query.sortOrder as string || 'reactions';
const sortDirection = req.query.sortDirection as string || 'desc';
const totalPosts = await prisma.post.count({
where: {
AND: [
Expand All @@ -265,7 +266,13 @@ export const getPostsWithPagination = async (req: Request, res: Response) => {
}
});
const totalPages = Math.ceil(totalPosts / pageSize);

const orderPosts = sortOrder === 'reactions' ? {
reactions: {
_count: sortDirection as 'asc' | 'desc'
} as const
} : {
createdAt: sortDirection as 'asc' | 'desc'
} as const ;
const posts = await prisma.post.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
Expand Down Expand Up @@ -294,11 +301,7 @@ export const getPostsWithPagination = async (req: Request, res: Response) => {
tags.length > 0 ? { tags: { hasSome: tags } } : {}
]
},
orderBy: {
reactions: {
_count: "desc"
}
}
orderBy: orderPosts,
});
res.status(200).json({
posts,
Expand Down
15 changes: 11 additions & 4 deletions frontend/src/hooks/usePosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,26 @@ const usePosts = ({ initialPage = 1, pageSize = 12 }: Props) => {
const [searchQuery, setSearchQuery] = useState("");
const [tags, setTags] = useState<string[]>([]);
const [searchParams, setSearchParams] = useSearchParams();
const [sortOrder, setSortOrder] = useState("reactions");
const [sortDirection, setSortDirection] = useState("desc");

const fetchPosts = async (
page: number,
pageSize: number,
searchQuery: string,
tags: string[]
tags: string[],
sortOrder: string,
sortDirection: string
) => {

setSortOrder(sortOrder);
setSortDirection(sortDirection);
setLoading(true);
try {
const response = await axios.get(
`/api/v1/posts?page=${page}&pageSize=${pageSize}&searchQuery=${searchQuery}&tags=${tags.join(
","
)}`
)}&sortOrder=${sortOrder}&sortDirection=${sortDirection}`
);
setPosts(response.data.posts);
setTotalPages(response.data.totalPages);
Expand All @@ -44,7 +51,7 @@ const usePosts = ({ initialPage = 1, pageSize = 12 }: Props) => {
const tagsFromParams = searchParams.get("tags");
const initialTags = tagsFromParams ? tagsFromParams.split(",") : [];
setTags(initialTags);
fetchPosts(page, pageSize, searchQuery, initialTags);
fetchPosts(page, pageSize, searchQuery, initialTags, sortOrder, sortDirection);
}, [page, searchParams]);

const handlePreviousPage = () => {
Expand All @@ -64,7 +71,7 @@ const usePosts = ({ initialPage = 1, pageSize = 12 }: Props) => {
};

const handleDelete = () => {
fetchPosts(page, pageSize, searchQuery, tags);
fetchPosts(page, pageSize, searchQuery, tags, sortOrder, sortDirection);
};

const addTag = (tagInput: string) => {
Expand Down
130 changes: 81 additions & 49 deletions frontend/src/pages/Posts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const Posts = () => {
const [tagInput, setTagInput] = useState("");
const [filterTags, setFilterTags] = useState<string[]>([]);
const filterRef = useRef<HTMLDivElement>(null);
const [sortOrder, setSortOrder] = useState("reactions");
const [sortDirection, setSortDirection] = useState('desc');

const filteredPosts = posts;
const allTags = filteredPosts.map(post => post.tags).flat();
const uniqueTags = [...new Set(allTags)];
Expand All @@ -47,17 +50,30 @@ const Posts = () => {
};

document.title = "Style Share | Our Posts 📃";

document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

useEffect(() => {
fetchPosts(page, 12, searchQuery, filterTags, sortOrder, sortDirection);
}, [sortOrder, sortDirection]);

const toggleFilterDialog = () => {
setShowFilterDialog(!showFilterDialog);
};

const handleSortChange = (selectedSort: any) => {
if (selectedSort === sortOrder) {
setSortDirection(prevDirection => (prevDirection === 'desc' ? 'asc' : 'desc'));
} else {
setSortOrder(selectedSort);
setSortDirection('desc');
}
};

const addTag = () => {
if (tagInput && !filterTags.includes(tagInput.toLowerCase())) {
setFilterTags([...filterTags, tagInput.toLowerCase()]);
Expand All @@ -79,7 +95,7 @@ const Posts = () => {
};

const handleSearch = () => {
fetchPosts(page, 12, searchQuery, filterTags);
fetchPosts(page, 12, searchQuery, filterTags, sortOrder, sortDirection);
};

if (loading) {
Expand Down Expand Up @@ -162,14 +178,29 @@ const Posts = () => {
</div>
)}
<div className="flex items-center w-full sm:w-auto">
<div className="flex items-center">
<span className="p-2 text-[#5f67de] whitespace-nowrap">Sort by:</span>
<select
value={sortOrder}
onChange={(e) => handleSortChange(e.target.value)}
className="p-2 rounded-md text-[#000435] bg-white dark:text-white dark:bg-[#000435] border border-sky-400 focus:outline-none focus:ring-2 focus:ring-blue-500 mr-4"
>
<option value="reactions" onClick={() => handleSortChange('reactions')}>
Reactions {sortOrder === 'reactions' && (sortDirection === 'asc' ? '↓' : '↑')}
</option>
<option value="createdAt" onClick={() => handleSortChange('createdAt')}>
Date {sortOrder === 'createdAt' && (sortDirection === 'asc' ? '↓' : '↑')}
</option>
</select>
</div>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="🔍 Search anything"
className="p-2 w-full max-w-xs rounded-md text-[#000435] bg-white dark:text-white dark:bg-[#000435] border border-sky-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
onKeyDown={(event)=>{
if(event.key == "Enter"){
onKeyDown={(event) => {
if (event.key == "Enter") {
handleSearch()
}
}}
Expand All @@ -185,53 +216,54 @@ const Posts = () => {
{filteredPosts.length === 0 ? (
<div className="text-center text-black dark:text-white">No Posts</div>
) : (
<div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 w-full">
{filteredPosts.map((post) => (
<PostCard
key={post.id}
post={post}
currentUser={currentUser}
onDelete={handleDelete}
/>
))}
</div>
<div className="flex justify-center items-center mt-4 w-full space-x-2">
<button
onClick={handlePreviousPage}
disabled={page === 1}
className={`text-white px-4 py-2 rounded ${page === 1
? "bg-gray-600 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Previous
</button>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => handlePageClick(i + 1)}
className={`text-white px-4 py-2 rounded ${page === i + 1
? "bg-blue-500 text-white"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
{i + 1}
</button>
))}
<button
onClick={handleNextPage}
disabled={page === totalPages}
className={`text-white px-6 py-2 rounded ${page === totalPages
? "bg-gray-600 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Next
</button>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 w-full">
{filteredPosts.map((post) => (
<PostCard
key={post.id}
post={post}
currentUser={currentUser}
onDelete={handleDelete}
/>
))}
</div>
)}
<div className="flex justify-center items-center mt-4 w-full space-x-2">
<button
onClick={handlePreviousPage}
disabled={page === 1}
className={`text-white px-4 py-2 rounded ${
page === 1
? "bg-gray-600 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Previous
</button>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => handlePageClick(i + 1)}
className={`text-white px-4 py-2 rounded ${
page === i + 1
? "bg-blue-500 text-white"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
{i + 1}
</button>
))}
<button
onClick={handleNextPage}
disabled={page === totalPages}
className={`text-white px-6 py-2 rounded ${
page === totalPages
? "bg-gray-600 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Next
</button>
</div>
</div>
</div>
);
Expand Down
Loading