Skip to content

Commit

Permalink
add player voting
Browse files Browse the repository at this point in the history
  • Loading branch information
Aero56 committed Oct 28, 2023
1 parent 76671e5 commit 3679fe3
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 12 deletions.
74 changes: 74 additions & 0 deletions src/components/PlayerVote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import queryClient from '@api/queryClient';
import { useAuth } from '@contexts/AuthContext';
import { ArrowDownIcon, ArrowUpIcon } from '@heroicons/react/24/outline';
import usePlayerVoteMutation from '@hooks/mutations/usePlayerVoteMutation';
import usePlayerTotalVotesQuery from '@hooks/queries/usePlayerTotalVotesQuery';
import usePlayerVoteQuery from '@hooks/queries/usePlayerVoteQuery';
import toast from 'react-hot-toast/headless';

interface PlayerVoteProps {
playerId: string;
}

const PlayerVote = ({ playerId }: PlayerVoteProps) => {
const { user } = useAuth();

const { mutateAsync } = usePlayerVoteMutation();

const { data: playerVote } = usePlayerVoteQuery(playerId);
const { data: totalVotes } = usePlayerTotalVotesQuery(playerId);

const handleVote = async (vote: number) => {
try {
await mutateAsync({ playerId, vote }).then(() => {
queryClient.setQueryData(['playerVote', playerId, user?.id], vote);
queryClient.invalidateQueries(['playerTotalVotes', playerId]);
});
} catch (error) {
if (error instanceof Error) {
toast('Something went wrong!');
return;
}
}
};

const isPlayerMe = user?.id === playerId;

return (
<div className="flex items-center gap-1">
{!isPlayerMe && (
<button
className={`btn btn-circle btn-ghost btn-sm ${
playerVote === 1 ? 'btn-active' : ''
}`}
onClick={() => handleVote(playerVote === 1 ? 0 : 1)}
>
<ArrowUpIcon className="h-5 w-5" />
</button>
)}
<p
className={`${
totalVotes && totalVotes > 0
? 'text-green-500'
: totalVotes && totalVotes < 0
? 'text-red-500'
: ''
}`}
>
{totalVotes ?? 0}
</p>
{!isPlayerMe && (
<button
className={`btn btn-circle btn-ghost btn-sm ${
playerVote === -1 ? 'btn-active' : ''
}`}
onClick={() => handleVote(playerVote === -1 ? 0 : -1)}
>
<ArrowDownIcon className="h-5 w-5" />
</button>
)}
</div>
);
};

export default PlayerVote;
30 changes: 30 additions & 0 deletions src/hooks/mutations/usePlayerVoteMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { supabase } from '@api/supabase';
import { useAuth } from '@contexts/AuthContext';
import { useMutation } from '@tanstack/react-query';

interface PlayerVoteMutationProps {
playerId: string;
vote: number;
}

const usePlayerVoteMutation = () => {
const { user } = useAuth();

return useMutation(async ({ playerId, vote }: PlayerVoteMutationProps) => {
if (!user) {
throw new Error('You must be logged in to do this.');
}

const { data, error } = await supabase
.from('player_votes')
.upsert({ user_id: user.id, player_id: playerId, vote });

if (error) {
throw new Error(error.message);
}

return data;
});
};

export default usePlayerVoteMutation;
17 changes: 17 additions & 0 deletions src/hooks/queries/usePlayerTotalVotesQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { supabase } from '@api/supabase';
import { useQuery } from '@tanstack/react-query';

const usePlayerTotalVotesQuery = (playerId: string) => {
const queryKey = ['playerTotalVotes', playerId];

return useQuery(queryKey, async () => {
const { data } = await supabase.rpc('get_player_votes', {
var_player_id: playerId,
});
console.log(data);

return data ?? 0;
});
};

export default usePlayerTotalVotesQuery;
26 changes: 26 additions & 0 deletions src/hooks/queries/usePlayerVoteQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { supabase } from '@api/supabase';
import { useAuth } from '@contexts/AuthContext';
import { useQuery } from '@tanstack/react-query';

const usePlayerVoteQuery = (playerId: string) => {
const { user } = useAuth();

const queryKey = ['playerVote', playerId, user?.id];

return useQuery(queryKey, async () => {
if (!user) {
return null;
}

const { data } = await supabase
.from('player_votes')
.select('vote')
.eq('user_id', user.id)
.eq('player_id', playerId)
.single();

return data?.vote ?? null;
});
};

export default usePlayerVoteQuery;
28 changes: 17 additions & 11 deletions src/pages/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { format } from 'date-fns';

import usePlayerQuery from '@hooks/queries/usePlayerQuery';
import Stats from '@components/Stats';
import PlayerVote from '@components/PlayerVote';

const Player = () => {
const { username = '' } = useParams();
Expand All @@ -18,18 +19,23 @@ const Player = () => {
}

return (
<div className="container grid grid-cols-1 gap-4 pt-4 sm:grid-cols-5">
<div className="col-span-1 rounded-xl bg-black-pearl-900 p-4 sm:col-span-2">
<p className="text-center text-xl font-bold">{username}</p>
<div className="divider my-1" />
<p className="text-xs font-bold">
{'Member since: '}
<span className="font-normal">
{format(new Date(player.created_at), 'd MMM yyyy')}
</span>
</p>
<div className="container pt-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-5">
<div className="col-span-1 rounded-xl bg-black-pearl-900 p-4 sm:col-span-2">
<div className="align flex items-center justify-between">
<p className="text-xl font-bold">{username}</p>
<PlayerVote playerId={player.id} />
</div>
<div className="divider my-1" />
<p className="text-xs font-bold">
{'Member since: '}
<span className="font-normal">
{format(new Date(player.created_at), 'd MMM yyyy')}
</span>
</p>
</div>
{player.stats && <Stats stats={player.stats} />}
</div>
{player.stats && <Stats stats={player.stats} />}
</div>
);
};
Expand Down
41 changes: 40 additions & 1 deletion src/types/supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,40 @@ export interface Database {
},
];
};
player_votes: {
Row: {
created_at: string;
player_id: string;
user_id: string;
vote: number;
};
Insert: {
created_at?: string;
player_id: string;
user_id?: string;
vote?: number;
};
Update: {
created_at?: string;
player_id?: string;
user_id?: string;
vote?: number;
};
Relationships: [
{
foreignKeyName: 'player_votes_player_id_fkey';
columns: ['player_id'];
referencedRelation: 'users';
referencedColumns: ['id'];
},
{
foreignKeyName: 'player_votes_user_id_fkey';
columns: ['user_id'];
referencedRelation: 'users';
referencedColumns: ['id'];
},
];
};
users: {
Row: {
created_at: string;
Expand Down Expand Up @@ -136,7 +170,12 @@ export interface Database {
[_ in never]: never;
};
Functions: {
[_ in never]: never;
get_player_votes: {
Args: {
var_player_id: string;
};
Returns: number;
};
};
Enums: {
group_status_enum: 'open' | 'closed';
Expand Down

0 comments on commit 3679fe3

Please sign in to comment.