Skip to main content

Upvote

Now we want to add the functionality for the members to upvote the news in the main page. We implement this functionality by using the reactions of the posts.

note

You need to be logged in for this feature to work.

1. Create Upvote Component

We use a simple triangle svg to show the upvote logo.

assets/triangle_up_icon.svg
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg">
<polygon points="8,0 16,16 0,16"/>
</svg>

In the component we use useAddReaction and useRemoveReaction hooks to add a +1 emoji to the post.

const {mutate: upvote} = useAddReaction()
const {mutate: downvote} = useRemoveReaction()

Then we want to know if the user has already reacted to the post or not.

const reacted = post?.reactions?.some(reaction => reaction.reacted && reaction.reaction === '+1')

Now if the user has reacted we want to show a green triangle and clicking on it will remove the reaction. Similarly, if the user has not reacted we want to show a grey triangle and clicking on it will add the reaction.

<TriangleUpIcon width="16" height="16" fill={reacted ? "green" : "grey"} onClick={() => {
reacted ?
downvote({
postId: post?.id,
reaction: '+1'
})
:
upvote({
postId: post?.id,
input: {
reaction: '+1',
}
})
}}/>

Put them all together and add some styling our Upvote.tsx will be similar to this.

components/Upvote.tsx
import {Post} from "@tribeplatform/gql-client/types";
import {useAddReaction, useRemoveReaction} from "@tribeplatform/react-sdk/hooks";
import {ReactComponent as TriangleUpIcon} from "../assets/triangle_up_icon.svg";
import React from "react";

export const Upvote = (props: { post: Post }) => {
const {post} = props
const {mutate: upvote} = useAddReaction()
const {mutate: downvote} = useRemoveReaction()

const reacted = post?.reactions?.some(reaction => reaction.reacted && reaction.reaction === '+1')

return (
<div className="flex flex-col justify-center">
<TriangleUpIcon width="16" height="16" fill={reacted ? "green" : "grey"} onClick={() => {
reacted ?
downvote({
postId: post?.id,
reaction: '+1'
})
:
upvote({
postId: post?.id,
input: {
reaction: '+1',
}
})
}}/>
</div>
)
}

2. Add the Upvote component to the NewsList

We use useFeed hook in the NewsList. By default, it will only fetch the basic fields of the posts. Because we want to get the reactions too, we have to specify it in the fields.

const {
data,
fetchNextPage,
hasNextPage,
} = useFeed({
fields: {
reactions: {
fields: 'all',
variables: {
limit: 10,
}
},
createdBy: {
member: 'basic'
}
},
variables: {
limit: 10,
}
})

Now we can simply add <Upvote post={post}/> in the NewsList to have the clickable triangle. We also add {post.reactionsCount} to show how many upvotes this post currently have. After some styling the NewsList.tsx will be similar to this.

components/NewsList.tsx
import React from 'react';
import {simplifyPaginatedResult} from "@tribeplatform/react-sdk/utils";
import {Post} from "@tribeplatform/gql-client/types";
import {Link} from "react-router-dom";
import {Upvote} from "./Upvote";
import {useFeed} from "@tribeplatform/react-sdk/hooks";
import InfiniteScroll from 'react-infinite-scroller';

function NewsList() {
const {
data,
fetchNextPage,
hasNextPage,
} = useFeed({
fields: {
reactions: {
fields: 'all',
variables: {
limit: 10,
}
},
createdBy: {
member: 'basic'
}
},
variables: {
limit: 10,
}
})
const {nodes: posts} = simplifyPaginatedResult<Post>(data)

return (
<div className="lg:w-3/4 m-auto flex flex-col">
<InfiniteScroll
pageStart={0}
loadMore={fetchNextPage}
hasMore={hasNextPage}
>
{posts.map((post, i) => (
<div className="flex gap-2 bg-hacker-body p-2" key={post?.id}>
<div className="flex flex-col justify-center">
{i + 1}.
</div>
<Upvote post={post}/>
<div className="flex flex-col flex-grow">
<Link to={`/${post.id}`}>
<div>
{post.title}
</div>
</Link>
<div className="flex gap-2 text-xs text-gray-500">
<div>
By {post.createdBy?.member?.name}
</div>
|
<div>
{post.reactionsCount} upvotes
</div>
|
<div>
{post.repliesCount} comments
</div>
</div>
</div>
</div>
))}
</InfiniteScroll>
</div>
);
}

export default NewsList;

Now by clicking on the grey triangle, you can see that the triangle and number of upvotes immediately changes. This is one of the many powerful features of Bettermode. You can only focus on what community you want to build and what features you want to have, we handle the implementation for you.

note

You can see the final result here.