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.

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 used useFeed hook in the NewsList. By default, it will only fetch the basic fields of the posts. Now because we want to get the reactions too, we have to specify it in the fields.

const {data} = useFeed({
fields: {
reactions: {
fields: 'all',
variables: {
limit: 100,
}
}
},
variables: {
limit: 100,
}
})

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.

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";
function NewsList() {
const {data} = useFeed({
fields: {
reactions: {
fields: 'all',
variables: {
limit: 100,
}
}
},
variables: {
limit: 100,
}
})
const {nodes: posts} = simplifyPaginatedResult<Post>(data)
return (
<div className="w-3/4 m-auto flex flex-col gap-5">
{posts.map((post, i) => (
<div className="flex gap-2 bg-gray-100 rounded-lg p-2" key={post?.id}>
<div className="flex flex-col justify-center">
{i + 1}.
</div>
<Upvote post={post}/>
<div className="flex flex-col">
<Link to={`/${post.id}`}>
<div>
{post.title}
</div>
</Link>
<div className="text-xs text-gray-500">
{post.reactionsCount} upvotes
</div>
</div>
</div>
))}
</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 Tribe. You can only focus on what community you want to build and what features you want to have, we handle the implementation for you.