Feat filter posts & follow/unfollow user (#485)
* add users api * add user page * update user page * filter posts by user/type * format
This commit is contained in:
@@ -11,6 +11,7 @@ import { Avatar, AvatarImage, AvatarFallback } from "@renderer/components/ui";
|
||||
import { formatDateTime } from "@renderer/lib/utils";
|
||||
import { t } from "i18next";
|
||||
import Markdown from "react-markdown";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const PostCard = (props: {
|
||||
post: PostType;
|
||||
@@ -23,12 +24,14 @@ export const PostCard = (props: {
|
||||
<div className="rounded p-4 bg-background space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Avatar>
|
||||
<AvatarImage src={post.user.avatarUrl} />
|
||||
<AvatarFallback className="text-xl">
|
||||
{post.user.name[0].toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Link to={`/users/${post.user.id}`}>
|
||||
<Avatar>
|
||||
<AvatarImage src={post.user.avatarUrl} />
|
||||
<AvatarFallback className="text-xl">
|
||||
{post.user.name[0].toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</Link>
|
||||
<div className="flex flex-col justify-between">
|
||||
<div className="">{post.user.name}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { AppSettingsProviderContext } from "@renderer/context";
|
||||
import { PostCard, LoaderSpin } from "@renderer/components";
|
||||
import { toast, Button } from "@renderer/components//ui";
|
||||
import { toast, Button, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@renderer/components//ui";
|
||||
import { t } from "i18next";
|
||||
|
||||
export const Posts = () => {
|
||||
export const Posts = (props: { userId?: string }) => {
|
||||
const { userId } = props;
|
||||
const { webApi } = useContext(AppSettingsProviderContext);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [type, setType] = useState<'all' | 'recording' | 'medium' | 'story' | 'prompt' | 'gpt'>("all");
|
||||
const [by, setBy] = useState<'all' | 'following'>("following");
|
||||
const [posts, setPosts] = useState<PostType[]>([]);
|
||||
const [nextPage, setNextPage] = useState(1);
|
||||
|
||||
@@ -29,9 +32,16 @@ export const Posts = () => {
|
||||
.posts({
|
||||
page,
|
||||
items: 10,
|
||||
userId,
|
||||
by,
|
||||
type
|
||||
})
|
||||
.then((res) => {
|
||||
setPosts([...posts, ...res.posts]);
|
||||
if (page === 1) {
|
||||
setPosts(res.posts);
|
||||
} else {
|
||||
setPosts([...posts, ...res.posts]);
|
||||
}
|
||||
setNextPage(res.next);
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -43,8 +53,8 @@ export const Posts = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchPosts();
|
||||
}, []);
|
||||
fetchPosts(1);
|
||||
}, [type, by]);
|
||||
|
||||
if (loading) {
|
||||
return <LoaderSpin />;
|
||||
@@ -52,8 +62,36 @@ export const Posts = () => {
|
||||
|
||||
return (
|
||||
<div className="max-w-screen-sm mx-auto">
|
||||
<div className="flex justify-end space-x-4 py-4">
|
||||
{
|
||||
!userId && <Select value={by} onValueChange={(value: 'all' | 'following') => setBy(value)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem key="following" value="following">{t('following')}</SelectItem>
|
||||
<SelectItem key="all" value="all">{t('allUsers')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
}
|
||||
|
||||
<Select value={type} onValueChange={(value: 'all' | 'recording' | 'medium' | 'story' | 'prompt' | 'gpt') => setType(value)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem key="all" value="all">{t('allTypes')}</SelectItem>
|
||||
<SelectItem key="recording" value="recording">{t('recordingType')}</SelectItem>
|
||||
<SelectItem key="prompt" value="prompt">{t('promptType')}</SelectItem>
|
||||
<SelectItem key="gpt" value="gpt">{t('gptType')}</SelectItem>
|
||||
<SelectItem key="medium" value="medium">{t('mediumType')}</SelectItem>
|
||||
<SelectItem key="story" value="story">{t('storyType')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{posts.length === 0 && (
|
||||
<div className="text-center text-gray-500">{t("noOneSharedYet")}</div>
|
||||
<div className="text-center text-muted-foreground py-4">{t("noOneSharedYet")}</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user