I'm working on an application which allows users to influence player rankings and trends on a live board (fantasy football).
As you can see, you can upvote, or downvote players (only if you are logged in and authenticated via Firebase (Google accounts)). Otherwise, if you aren't logged in, no vote registers. That is currently working fine.
My question is, what would be the easiest way to have each user only be able to vote on a player once. The current implementation allows unlimited up or down votes for any player. I would like it so I can upvote Tom Brady, but not upvote him again. From that point, I could only change it to no vote (by clicking up again) or downvote. I see there are User UID's in firebase, so I could check to see if the UserUID has voted on the specific player in the firebase DB or not before allowing the vote to go through, but what if the user just wants to change from an up vote to a down vote?
Here's the code which deals with voting --
downvotePlayer(playerId) {
this.state.user ?
this.database.child(playerId).transaction(function (player) {
if (player) {
player.votes--
}
return player;
})
:
console.log("Must log in to vote")
}
upvotePlayer(playerId) {
this.state.user ?
this.database.child(playerId).transaction(function (player) {
if (player) {
console.log(player)
player.votes++
}
return player;
})
:
console.log("Must be logged in to vote.")
}
Here's the layout on Firebase:
If I left anything critical out, please let me know and I'll throw it in a gist. Thanks in advance.
Edit:
Initial DB ref is
this.database = firebase.database().ref().child('players');
When adding an upvote to a player, I'm doing this:
this.database.child(playerId).transaction(function (player) {
if (player) {
var ref = firebase.database().ref('players').child('voters');
ref.child(uid).set(1);
}
Which is doing almost what it needs to, except it's creating a new node all together in firebase.
The "voters" should be inside of the unique player above it. Is my issue obvious? I appreciate the help sir.
The simplest way to model this is to store a single counter per player per "things they can vote on". For example:
"Votes": {
"Tom Brady": {
"uidOfVoter1": 1,
"uidOfVoter2": -1
}
}
The uidOfVoter
values are the unique that you give each player, i.e. the UID they get from Firebase Authentication. In a structure like this, each UID can be present only once. You then ensure that each user can only write their own vote, with Firebase security rules:
{
"rules": {
"Votes": {
"$thing": {
"$uid": {
".write": "auth.uid === $uid",
".validate": "data.isNumber() && data.val() >= -1 && data.val() <= 1"
}
}
}
}
}
Now to get the total votes, either:
Boolean. + is true and - is false. The existence of the UID indicates a vote(r).
I can't speak to coding react specifically, but it seems that this would be the most simple (best) way to represent what you are after.
Disable/grey-out the respective vote button on the client UI once they vote either way. Even if they hack the UI, server-side (db side) it's a boolean so you can't true true it for +2.
DB Structure
thing
votes
<uid1>:true,
<uid2>:true,
<uid3>:false,
If user undoes vote, simply delete the uid from the thing they voted on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With