Skip to content

Commit

Permalink
feat: sortable profile posts and comments (#1782)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeharding authored Dec 19, 2024
1 parent 81457ca commit 97fce73
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 97 deletions.
4 changes: 3 additions & 1 deletion src/features/feed/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ type InternalFeedType =
| "PostsSearch"
| "CommentsSearch"
| "CommunitiesSearch"
| "CommunitiesExplore";
| "CommunitiesExplore"
| "ProfilePosts"
| "ProfileComments";

export type AnyFeed =
| {
Expand Down
53 changes: 53 additions & 0 deletions src/routes/pages/profile/BaseProfileFeedItemsPage.tsx
Original file line number Diff line number Diff line change
@@ -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<PostCommentItem>;
sortComponent?: React.ReactNode;
}

export default function BaseProfileFeedItemsPage({
fetchFn,
sortComponent,
label,
}: BaseProfileFeedItemsPageProps) {
const buildGeneralBrowseLink = useBuildGeneralBrowseLink();
const { handle } = useParams<{ handle: string }>();

return (
<IonPage>
<AppHeader>
<IonToolbar>
<IonTitle>{label}</IonTitle>
<IonButtons slot="start">
<IonBackButton
// Kinda hacky since Ionic doesn't handle clipping
text={handle.length > 10 ? `${handle.slice(0, 10)}...` : handle}
defaultHref={buildGeneralBrowseLink(`/u/${handle}`)}
/>
</IonButtons>

{sortComponent && <IonButtons slot="end">{sortComponent}</IonButtons>}
</IonToolbar>
</AppHeader>
<FeedContent>
<PostCommentFeed
fetchFn={fetchFn}
filterHiddenPosts={false}
filterKeywordsAndWebsites={false}
/>
</FeedContent>
</IonPage>
);
}
58 changes: 58 additions & 0 deletions src/routes/pages/profile/ProfileFeedCommentsPage.tsx
Original file line number Diff line number Diff line change
@@ -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<PostCommentItem> = async (pageData, ...rest) => {
const { comments } = await client.getPersonDetails(
{
...pageData,
limit: LIMIT,
username: handle,
sort: sort ? convertCommentSortToPostSort(sort) : "New",
},
...rest,
);

return comments;
};

return (
<BaseProfileFeedItemsPage
label="Comments"
fetchFn={fetchFn}
sortComponent={<CommentSort sort={sort} setSort={setSort} />}
/>
);
}

function convertCommentSortToPostSort(sort: CommentSortType): PostSortType {
switch (sort) {
case "Controversial":
case "Hot":
case "New":
case "Old":
return sort;
case "Top":
return "TopAll";
}
}
90 changes: 0 additions & 90 deletions src/routes/pages/profile/ProfileFeedItemsPage.tsx

This file was deleted.

45 changes: 45 additions & 0 deletions src/routes/pages/profile/ProfileFeedPostsPage.tsx
Original file line number Diff line number Diff line change
@@ -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<PostCommentItem> = async (pageData, ...rest) => {
const { posts } = await client.getPersonDetails(
{
...pageData,
limit: LIMIT,
username: handle,
sort: sort ?? "New",
},
...rest,
);

return posts;
};

return (
<BaseProfileFeedItemsPage
label="Posts"
fetchFn={fetchFn}
sortComponent={<PostSort sort={sort} setSort={setSort} />}
/>
);
}
31 changes: 31 additions & 0 deletions src/routes/pages/profile/ProfileFeedSavedPage.tsx
Original file line number Diff line number Diff line change
@@ -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<PostCommentItem> = 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 <BaseProfileFeedItemsPage label="Saved" fetchFn={fetchFn} />;
}
39 changes: 39 additions & 0 deletions src/routes/pages/profile/ProfileFeedVotedPage.tsx
Original file line number Diff line number Diff line change
@@ -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<PostCommentItem> = 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 <BaseProfileFeedItemsPage label={type} fetchFn={fetchFn} />;
}
15 changes: 9 additions & 6 deletions src/routes/tabs/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -74,22 +77,22 @@ export default [
<UserPage />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/posts">
<ProfileFeedItemsPage type="Posts" />
<ProfileFeedPostsPage />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/comments">
<ProfileFeedItemsPage type="Comments" />
<ProfileFeedCommentsPage />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/saved">
<ProfileFeedItemsPage type="Saved" />
<ProfileFeedSavedPage />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/hidden">
<ProfileFeedHiddenPostsPage />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/upvoted">
<ProfileFeedItemsPage type="Upvoted" />
<ProfileFeedVotedPage type="Upvoted" />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/downvoted">
<ProfileFeedItemsPage type="Downvoted" />
<ProfileFeedVotedPage type="Downvoted" />
</Route>,
<Route exact path="/:tab/:actor/u/:handle/message">
<ConversationPage />
Expand Down

0 comments on commit 97fce73

Please sign in to comment.