From 89cb8b9739846cb4e97c84dd259ba3e07cef7dc6 Mon Sep 17 00:00:00 2001 From: Alexander Harding Date: Wed, 18 Dec 2024 23:06:16 -0600 Subject: [PATCH] feat: sortable profile posts and comments --- src/features/feed/helpers.ts | 4 +- .../profile/BaseProfileFeedItemsPage.tsx | 53 +++++++++++ .../pages/profile/ProfileFeedCommentsPage.tsx | 58 ++++++++++++ .../pages/profile/ProfileFeedItemsPage.tsx | 90 ------------------- .../pages/profile/ProfileFeedPostsPage.tsx | 45 ++++++++++ .../pages/profile/ProfileFeedSavedPage.tsx | 31 +++++++ .../pages/profile/ProfileFeedVotedPage.tsx | 39 ++++++++ src/routes/tabs/general.tsx | 15 ++-- 8 files changed, 238 insertions(+), 97 deletions(-) create mode 100644 src/routes/pages/profile/BaseProfileFeedItemsPage.tsx create mode 100644 src/routes/pages/profile/ProfileFeedCommentsPage.tsx delete mode 100644 src/routes/pages/profile/ProfileFeedItemsPage.tsx create mode 100644 src/routes/pages/profile/ProfileFeedPostsPage.tsx create mode 100644 src/routes/pages/profile/ProfileFeedSavedPage.tsx create mode 100644 src/routes/pages/profile/ProfileFeedVotedPage.tsx diff --git a/src/features/feed/helpers.ts b/src/features/feed/helpers.ts index 1ae6537b95..e2ee32327b 100644 --- a/src/features/feed/helpers.ts +++ b/src/features/feed/helpers.ts @@ -6,7 +6,9 @@ type InternalFeedType = | "PostsSearch" | "CommentsSearch" | "CommunitiesSearch" - | "CommunitiesExplore"; + | "CommunitiesExplore" + | "ProfilePosts" + | "ProfileComments"; export type AnyFeed = | { diff --git a/src/routes/pages/profile/BaseProfileFeedItemsPage.tsx b/src/routes/pages/profile/BaseProfileFeedItemsPage.tsx new file mode 100644 index 0000000000..a0c3f865d7 --- /dev/null +++ b/src/routes/pages/profile/BaseProfileFeedItemsPage.tsx @@ -0,0 +1,53 @@ +import { IonButtons, IonTitle, IonToolbar } from "@ionic/react"; +import { IonPage } from "@ionic/react"; +import { IonBackButton } from "@ionic/react"; +import { useParams } from "react-router-dom"; + +import { FetchFn } from "#/features/feed/Feed"; +import PostCommentFeed, { + PostCommentItem, +} from "#/features/feed/PostCommentFeed"; +import AppHeader from "#/features/shared/AppHeader"; +import { useBuildGeneralBrowseLink } from "#/helpers/routes"; +import FeedContent from "#/routes/pages/shared/FeedContent"; + +interface BaseProfileFeedItemsPageProps { + label: string; + fetchFn: FetchFn; + sortComponent?: React.ReactNode; +} + +export default function BaseProfileFeedItemsPage({ + fetchFn, + sortComponent, + label, +}: BaseProfileFeedItemsPageProps) { + const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); + const { handle } = useParams<{ handle: string }>(); + + return ( + + + + {label} + + 10 ? `${handle.slice(0, 10)}...` : handle} + defaultHref={buildGeneralBrowseLink(`/u/${handle}`)} + /> + + + {sortComponent && {sortComponent}} + + + + + + + ); +} diff --git a/src/routes/pages/profile/ProfileFeedCommentsPage.tsx b/src/routes/pages/profile/ProfileFeedCommentsPage.tsx new file mode 100644 index 0000000000..5a66c08aa6 --- /dev/null +++ b/src/routes/pages/profile/ProfileFeedCommentsPage.tsx @@ -0,0 +1,58 @@ +import { CommentSortType, PostSortType } from "lemmy-js-client"; +import { useParams } from "react-router-dom"; + +import CommentSort from "#/features/comment/CommentSort"; +import { FetchFn } from "#/features/feed/Feed"; +import { PostCommentItem } from "#/features/feed/PostCommentFeed"; +import useFeedSort from "#/features/feed/sort/useFeedSort"; +import useClient from "#/helpers/useClient"; +import { LIMIT } from "#/services/lemmy"; + +import BaseProfileFeedItemsPage from "./BaseProfileFeedItemsPage"; + +export default function ProfileFeedCommentsPage() { + const client = useClient(); + const { handle } = useParams<{ handle: string }>(); + + const [sort, setSort] = useFeedSort( + "comments", + { + internal: `ProfileComments`, + }, + "New", + ); + + const fetchFn: FetchFn = async (pageData, ...rest) => { + const { comments } = await client.getPersonDetails( + { + ...pageData, + limit: LIMIT, + username: handle, + sort: sort ? convertCommentSortToPostSort(sort) : "New", + }, + ...rest, + ); + + return comments; + }; + + return ( + } + /> + ); +} + +function convertCommentSortToPostSort(sort: CommentSortType): PostSortType { + switch (sort) { + case "Controversial": + case "Hot": + case "New": + case "Old": + return sort; + case "Top": + return "TopAll"; + } +} diff --git a/src/routes/pages/profile/ProfileFeedItemsPage.tsx b/src/routes/pages/profile/ProfileFeedItemsPage.tsx deleted file mode 100644 index e6189b4a90..0000000000 --- a/src/routes/pages/profile/ProfileFeedItemsPage.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { - IonBackButton, - IonButtons, - IonPage, - IonTitle, - IonToolbar, -} from "@ionic/react"; -import { GetComments, GetPosts } from "lemmy-js-client"; -import { useParams } from "react-router"; - -import { FetchFn } from "#/features/feed/Feed"; -import PostCommentFeed, { - PostCommentItem, -} from "#/features/feed/PostCommentFeed"; -import AppHeader from "#/features/shared/AppHeader"; -import { sortPostCommentByPublished } from "#/helpers/lemmy"; -import { useBuildGeneralBrowseLink } from "#/helpers/routes"; -import useClient from "#/helpers/useClient"; -import FeedContent from "#/routes/pages/shared/FeedContent"; -import { LIMIT } from "#/services/lemmy"; - -interface ProfileFeedItemsPageProps { - type: "Comments" | "Posts" | "Saved" | "Upvoted" | "Downvoted"; -} -export default function ProfileFeedItemsPage({ - type, -}: ProfileFeedItemsPageProps) { - const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); - const { handle } = useParams<{ handle: string }>(); - const client = useClient(); - - const fetchFn: FetchFn = async (pageData, ...rest) => { - if (type === "Upvoted" || type === "Downvoted") { - const requestPayload: GetPosts & GetComments = { - ...pageData, - limit: Math.floor(LIMIT / 2), - sort: "New", - liked_only: type === "Upvoted", - disliked_only: type === "Downvoted", - show_read: true, - }; - - const [{ posts }, { comments }] = await Promise.all([ - client.getPosts(requestPayload, ...rest), - client.getComments(requestPayload, ...rest), - ]); - - return [...comments, ...posts].sort(sortPostCommentByPublished); - } - const { comments, posts } = await client.getPersonDetails( - { - ...pageData, - limit: LIMIT, - username: handle, - sort: "New", - saved_only: type === "Saved", - }, - ...rest, - ); - - if (type === "Saved") { - return [...comments, ...posts].sort(sortPostCommentByPublished); - } - - return type === "Comments" ? comments : posts; - }; - - return ( - - - - {type} - - - - - - - - - - ); -} diff --git a/src/routes/pages/profile/ProfileFeedPostsPage.tsx b/src/routes/pages/profile/ProfileFeedPostsPage.tsx new file mode 100644 index 0000000000..d8a8ac8126 --- /dev/null +++ b/src/routes/pages/profile/ProfileFeedPostsPage.tsx @@ -0,0 +1,45 @@ +import { useParams } from "react-router-dom"; + +import { FetchFn } from "#/features/feed/Feed"; +import { PostCommentItem } from "#/features/feed/PostCommentFeed"; +import PostSort from "#/features/feed/PostSort"; +import useFeedSort from "#/features/feed/sort/useFeedSort"; +import useClient from "#/helpers/useClient"; +import { LIMIT } from "#/services/lemmy"; + +import BaseProfileFeedItemsPage from "./BaseProfileFeedItemsPage"; + +export default function ProfileFeedPostsPage() { + const client = useClient(); + const { handle } = useParams<{ handle: string }>(); + + const [sort, setSort] = useFeedSort( + "posts", + { + internal: `ProfilePosts`, + }, + "New", + ); + + const fetchFn: FetchFn = async (pageData, ...rest) => { + const { posts } = await client.getPersonDetails( + { + ...pageData, + limit: LIMIT, + username: handle, + sort: sort ?? "New", + }, + ...rest, + ); + + return posts; + }; + + return ( + } + /> + ); +} diff --git a/src/routes/pages/profile/ProfileFeedSavedPage.tsx b/src/routes/pages/profile/ProfileFeedSavedPage.tsx new file mode 100644 index 0000000000..03bed0c8e2 --- /dev/null +++ b/src/routes/pages/profile/ProfileFeedSavedPage.tsx @@ -0,0 +1,31 @@ +import { useParams } from "react-router-dom"; + +import { FetchFn } from "#/features/feed/Feed"; +import { PostCommentItem } from "#/features/feed/PostCommentFeed"; +import { sortPostCommentByPublished } from "#/helpers/lemmy"; +import useClient from "#/helpers/useClient"; +import { LIMIT } from "#/services/lemmy"; + +import BaseProfileFeedItemsPage from "./BaseProfileFeedItemsPage"; + +export default function ProfileFeedSavedPage() { + const { handle } = useParams<{ handle: string }>(); + const client = useClient(); + + const fetchFn: FetchFn = async (pageData, ...rest) => { + const { comments, posts } = await client.getPersonDetails( + { + ...pageData, + limit: LIMIT, + username: handle, + sort: "New", + saved_only: true, + }, + ...rest, + ); + + return [...comments, ...posts].sort(sortPostCommentByPublished); + }; + + return ; +} diff --git a/src/routes/pages/profile/ProfileFeedVotedPage.tsx b/src/routes/pages/profile/ProfileFeedVotedPage.tsx new file mode 100644 index 0000000000..2e1c5bf0ed --- /dev/null +++ b/src/routes/pages/profile/ProfileFeedVotedPage.tsx @@ -0,0 +1,39 @@ +import { GetComments, GetPosts } from "lemmy-js-client"; + +import { FetchFn } from "#/features/feed/Feed"; +import { PostCommentItem } from "#/features/feed/PostCommentFeed"; +import { sortPostCommentByPublished } from "#/helpers/lemmy"; +import useClient from "#/helpers/useClient"; +import { LIMIT } from "#/services/lemmy"; + +import BaseProfileFeedItemsPage from "./BaseProfileFeedItemsPage"; + +interface ProfileFeedVotedPageProps { + type: "Upvoted" | "Downvoted"; +} + +export default function ProfileFeedVotedPage({ + type, +}: ProfileFeedVotedPageProps) { + const client = useClient(); + + const fetchFn: FetchFn = async (pageData, ...rest) => { + const requestPayload: GetPosts & GetComments = { + ...pageData, + limit: Math.floor(LIMIT / 2), + sort: "New", + liked_only: type === "Upvoted", + disliked_only: type === "Downvoted", + show_read: true, + }; + + const [{ posts }, { comments }] = await Promise.all([ + client.getPosts(requestPayload, ...rest), + client.getComments(requestPayload, ...rest), + ]); + + return [...comments, ...posts].sort(sortPostCommentByPublished); + }; + + return ; +} diff --git a/src/routes/tabs/general.tsx b/src/routes/tabs/general.tsx index dc1c1b80ae..cb18a36caf 100644 --- a/src/routes/tabs/general.tsx +++ b/src/routes/tabs/general.tsx @@ -2,8 +2,11 @@ import Route from "#/routes/common/Route"; import ConversationPage from "#/routes/pages/inbox/ConversationPage"; import PostDetail from "#/routes/pages/posts/PostPage"; +import ProfileFeedCommentsPage from "#/routes/pages/profile/ProfileFeedCommentsPage"; import ProfileFeedHiddenPostsPage from "#/routes/pages/profile/ProfileFeedHiddenPostsPage"; -import ProfileFeedItemsPage from "#/routes/pages/profile/ProfileFeedItemsPage"; +import ProfileFeedPostsPage from "#/routes/pages/profile/ProfileFeedPostsPage"; +import ProfileFeedSavedPage from "#/routes/pages/profile/ProfileFeedSavedPage"; +import ProfileFeedVotedPage from "#/routes/pages/profile/ProfileFeedVotedPage"; import UserPage from "#/routes/pages/profile/UserPage"; import SearchFeedResultsPage from "#/routes/pages/search/results/SearchFeedResultsPage"; import CommentsPage from "#/routes/pages/shared/CommentsPage"; @@ -74,22 +77,22 @@ export default [ , - + , - + , - + , , - + , - + ,