89fd63c8d7
- Extraction message d'erreur depuis objet Directus - Gestion fallback pour différents formats d'erreur - Affichage correct messages extension backend en français
137 lines
3.9 KiB
JavaScript
137 lines
3.9 KiB
JavaScript
import {useState, useEffect} from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import Box from '@mui/material/Box'
|
|
import IconButton from '@mui/material/IconButton'
|
|
import Typography from '@mui/material/Typography'
|
|
import ThumbUpIcon from '@mui/icons-material/ThumbUp'
|
|
import ThumbDownIcon from '@mui/icons-material/ThumbDown'
|
|
import {useSession} from 'next-auth/react'
|
|
import {handleVote, getUserVote} from '@/lib/directus.js'
|
|
|
|
export default function VoteButtons({versionId, isDisabled = false, hasCountsVisible = false, voteCounts = null, onVoteResult = null}) {
|
|
const {data: session} = useSession()
|
|
const [currentVote, setCurrentVote] = useState(null)
|
|
|
|
useEffect(() => {
|
|
const fetchVote = async () => {
|
|
if (session?.user && versionId) {
|
|
try {
|
|
const vote = await getUserVote({
|
|
accessToken: session.user.accessToken,
|
|
userId: session.user.userId,
|
|
versionId
|
|
})
|
|
setCurrentVote(vote)
|
|
} catch (error) {
|
|
console.error('Error fetching vote:', error)
|
|
}
|
|
}
|
|
}
|
|
|
|
fetchVote()
|
|
}, [session, versionId])
|
|
|
|
const handleVoteClick = async voteValue => {
|
|
if (isDisabled) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
const newVoteValue = await handleVote({
|
|
accessToken: session.user.accessToken,
|
|
userId: session.user.userId,
|
|
versionId,
|
|
voteValue
|
|
})
|
|
setCurrentVote(newVoteValue)
|
|
|
|
if (onVoteResult) {
|
|
onVoteResult({
|
|
success: true,
|
|
message: newVoteValue === null ? 'Vote annulé' : 'Vote enregistré avec succès'
|
|
})
|
|
}
|
|
} catch (error) {
|
|
if (onVoteResult) {
|
|
onVoteResult({
|
|
success: false,
|
|
message: error.message || 'Erreur lors du vote'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!session?.user) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<Box sx={{display: 'flex', alignItems: 'center', gap: 1}}>
|
|
<Box sx={{display: 'flex', alignItems: 'center'}}>
|
|
<IconButton
|
|
size='small'
|
|
aria-label='vote positif'
|
|
disabled={isDisabled}
|
|
sx={{
|
|
color: currentVote === 1 ? '#2E7D32' : '#666666',
|
|
backgroundColor: currentVote === 1 ? 'rgba(46, 125, 50, 0.1)' : 'transparent',
|
|
'&:hover': {
|
|
backgroundColor: 'rgba(46, 125, 50, 0.2)',
|
|
color: '#2E7D32'
|
|
},
|
|
'&:disabled': {
|
|
color: '#CCCCCC'
|
|
}
|
|
}}
|
|
onClick={() => handleVoteClick(1)}
|
|
>
|
|
<ThumbUpIcon />
|
|
</IconButton>
|
|
{hasCountsVisible && voteCounts && (
|
|
<Typography variant='caption' sx={{color: '#333333', ml: 0.5, fontWeight: 'bold'}}>
|
|
{voteCounts.positive || 0}
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
|
|
<Box sx={{display: 'flex', alignItems: 'center'}}>
|
|
<IconButton
|
|
size='small'
|
|
aria-label='vote négatif'
|
|
disabled={isDisabled}
|
|
sx={{
|
|
color: currentVote === -1 ? '#D32F2F' : '#666666',
|
|
backgroundColor: currentVote === -1 ? 'rgba(211, 47, 47, 0.1)' : 'transparent',
|
|
'&:hover': {
|
|
backgroundColor: 'rgba(211, 47, 47, 0.2)',
|
|
color: '#D32F2F'
|
|
},
|
|
'&:disabled': {
|
|
color: '#CCCCCC'
|
|
}
|
|
}}
|
|
onClick={() => handleVoteClick(-1)}
|
|
>
|
|
<ThumbDownIcon />
|
|
</IconButton>
|
|
{hasCountsVisible && voteCounts && (
|
|
<Typography variant='caption' sx={{color: '#333333', ml: 0.5, fontWeight: 'bold'}}>
|
|
{voteCounts.negative || 0}
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
VoteButtons.propTypes = {
|
|
versionId: PropTypes.string.isRequired,
|
|
isDisabled: PropTypes.bool,
|
|
hasCountsVisible: PropTypes.bool,
|
|
voteCounts: PropTypes.shape({
|
|
positive: PropTypes.number,
|
|
negative: PropTypes.number
|
|
}),
|
|
onVoteResult: PropTypes.func
|
|
}
|