Skip to main content
Glama
northernvariables

FedMCP - Federal Parliamentary Information

VoteButtons.tsx3.5 kB
'use client'; import { useState } from 'react'; import { ThumbsUp, ThumbsDown } from 'lucide-react'; import { votePost } from '@/actions/forum'; import type { VoteType } from '@/types/forum'; import { useAuth } from '@/contexts/AuthContext'; interface VoteButtonsProps { postId: string; upvotes: number; downvotes: number; userVote?: VoteType | null; size?: 'sm' | 'md' | 'lg'; onVoteChange?: (upvotes: number, downvotes: number) => void; } export function VoteButtons({ postId, upvotes: initialUpvotes, downvotes: initialDownvotes, userVote: initialUserVote, size = 'md', onVoteChange, }: VoteButtonsProps) { const { user } = useAuth(); const [upvotes, setUpvotes] = useState(initialUpvotes); const [downvotes, setDownvotes] = useState(initialDownvotes); const [userVote, setUserVote] = useState<VoteType | null>(initialUserVote || null); const [isVoting, setIsVoting] = useState(false); const handleVote = async (voteType: VoteType) => { if (!user) { alert('Please sign in to vote'); return; } if (isVoting) return; setIsVoting(true); try { const result = await votePost(postId, voteType); if (result.success && result.data) { // Update local state setUpvotes(result.data.upvotes); setDownvotes(result.data.downvotes); // Toggle vote (if same vote, remove it) if (userVote === voteType) { setUserVote(null); } else { setUserVote(voteType); } // Notify parent component onVoteChange?.(result.data.upvotes, result.data.downvotes); } else { alert(result.error || 'Failed to vote'); } } catch (error) { console.error('Error voting:', error); alert('Failed to vote. Please try again.'); } finally { setIsVoting(false); } }; const score = upvotes - downvotes; const sizeClasses = { sm: 'text-sm', md: 'text-base', lg: 'text-lg', }; const iconSizes = { sm: 14, md: 18, lg: 22, }; return ( <div className="flex flex-col items-center gap-1"> <button onClick={() => handleVote('upvote')} disabled={isVoting} className={` p-2 rounded-lg transition-all ${ userVote === 'upvote' ? 'text-accent-red bg-accent-red/10' : 'text-text-secondary hover:text-accent-red hover:bg-accent-red/5' } ${isVoting ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'} disabled:cursor-not-allowed `} aria-label="Upvote" > <ThumbsUp size={iconSizes[size]} /> </button> <span className={` font-semibold ${sizeClasses[size]} ${score > 0 ? 'text-green-500' : score < 0 ? 'text-red-500' : 'text-text-tertiary'} `} > {score > 0 ? '+' : ''} {score} </span> <button onClick={() => handleVote('downvote')} disabled={isVoting} className={` p-2 rounded-lg transition-all ${ userVote === 'downvote' ? 'text-blue-500 bg-blue-500/10' : 'text-text-secondary hover:text-blue-500 hover:bg-blue-500/5' } ${isVoting ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'} disabled:cursor-not-allowed `} aria-label="Downvote" > <ThumbsDown size={iconSizes[size]} /> </button> </div> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/northernvariables/FedMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server