feat: récupère le total des votes
This commit is contained in:
@@ -46,7 +46,7 @@ const renderMarkdownToHtml = async content => {
|
||||
}
|
||||
}
|
||||
|
||||
export default function ExportPdfButton({versionData, isOutdated = false, size = 'medium', variant = 'outlined'}) {
|
||||
export default function ExportPdfButton({versionData, isOutdated = false, voteCounts = null, size = 'medium', variant = 'outlined'}) {
|
||||
const [isExporting, setIsExporting] = useState(false)
|
||||
|
||||
const handleExportPdf = async () => {
|
||||
@@ -146,6 +146,11 @@ export default function ExportPdfButton({versionData, isOutdated = false, size =
|
||||
const voteStatus = (isExpired || isOutdated) ? 'fermé' : 'ouvert'
|
||||
const voteColor = voteStatus === 'ouvert' ? '#2e7d32' : '#d32f2f'
|
||||
|
||||
// Vote counts display
|
||||
const voteTotal = voteCounts ? voteCounts.total : 0
|
||||
const voteTotalColor = voteTotal > 0 ? '#2e7d32' : (voteTotal < 0 ? '#d32f2f' : '#666')
|
||||
const voteTotalSign = voteTotal >= 0 ? '+' : ''
|
||||
|
||||
// Render markdown content to HTML
|
||||
const renderedContent = await renderMarkdownToHtml(versionData.delta?.contenu)
|
||||
|
||||
@@ -165,6 +170,22 @@ export default function ExportPdfButton({versionData, isOutdated = false, size =
|
||||
<strong>Statut du vote :</strong>
|
||||
<span style="color: ${voteColor}; font-weight: bold;">${voteStatus}</span>
|
||||
</p>
|
||||
${voteCounts ? `
|
||||
<div style="margin-top: 15px; padding: 15px; background-color: #f5f5f5; border-radius: 8px;">
|
||||
<p style="margin: 0 0 10px 0; font-size: 16px; font-weight: bold; color: #333;">
|
||||
📊 Résultats des votes
|
||||
</p>
|
||||
<p style="margin: 5px 0; font-size: 14px;">
|
||||
👍 Votes positifs : <strong style="color: #2e7d32;">${voteCounts.positive}</strong>
|
||||
</p>
|
||||
<p style="margin: 5px 0; font-size: 14px;">
|
||||
👎 Votes négatifs : <strong style="color: #d32f2f;">${voteCounts.negative}</strong>
|
||||
</p>
|
||||
<p style="margin: 10px 0 0 0; font-size: 16px; font-weight: bold;">
|
||||
🏆 Total : <span style="color: ${voteTotalColor};">${voteTotalSign}${voteTotal}</span>
|
||||
</p>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -253,6 +274,11 @@ export default function ExportPdfButton({versionData, isOutdated = false, size =
|
||||
ExportPdfButton.propTypes = {
|
||||
versionData: PropTypes.object.isRequired,
|
||||
isOutdated: PropTypes.bool,
|
||||
voteCounts: PropTypes.shape({
|
||||
positive: PropTypes.number,
|
||||
negative: PropTypes.number,
|
||||
total: PropTypes.number
|
||||
}),
|
||||
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
||||
variant: PropTypes.oneOf(['text', 'outlined', 'contained'])
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import ShareButton from './share-button.js'
|
||||
import ExportPdfButton from './export-pdf-button.js'
|
||||
import PrintButton from './print-button.js'
|
||||
import {formatDate} from '@/lib/format.js'
|
||||
import {compareVersion} from '@/lib/directus.js'
|
||||
import {compareVersion, getVoteCounts} from '@/lib/directus.js'
|
||||
import {filterVersions, getFilterStats} from '@/lib/version-utils.js'
|
||||
|
||||
const columns = [
|
||||
@@ -85,7 +85,8 @@ function rowContent({
|
||||
setIsErrorAlertOpen,
|
||||
setIsOpenComparison,
|
||||
setVersionCompare,
|
||||
outdatedStatusMap
|
||||
outdatedStatusMap,
|
||||
voteCountsMap
|
||||
}) {
|
||||
const handleButtonClick = async versionId => {
|
||||
const version = await compareVersion({
|
||||
@@ -104,6 +105,7 @@ function rowContent({
|
||||
}
|
||||
|
||||
const isOutdated = outdatedStatusMap[row.id] || false
|
||||
const voteCounts = voteCountsMap[row.id] || null
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -141,12 +143,14 @@ function rowContent({
|
||||
<ExportPdfButton
|
||||
versionData={row}
|
||||
isOutdated={isOutdated}
|
||||
voteCounts={voteCounts}
|
||||
size='small'
|
||||
variant='text'
|
||||
/>
|
||||
<PrintButton
|
||||
versionData={row}
|
||||
isOutdated={isOutdated}
|
||||
voteCounts={voteCounts}
|
||||
size='small'
|
||||
variant='text'
|
||||
/>
|
||||
@@ -188,11 +192,13 @@ export default function ListVersions({
|
||||
status: ''
|
||||
})
|
||||
const [outdatedStatusMap, setOutdatedStatusMap] = useState({})
|
||||
const [voteCountsMap, setVoteCountsMap] = useState({})
|
||||
|
||||
// Fetch outdated status for all versions
|
||||
// Fetch outdated status and vote counts for all versions
|
||||
useEffect(() => {
|
||||
async function fetchOutdatedStatus() {
|
||||
async function fetchVersionsData() {
|
||||
const statusMap = {}
|
||||
const countsMap = {}
|
||||
|
||||
await Promise.all(
|
||||
data.map(async version => {
|
||||
@@ -209,18 +215,27 @@ export default function ListVersions({
|
||||
if (comparisonData) {
|
||||
statusMap[version.id] = comparisonData.outdated || false
|
||||
}
|
||||
|
||||
// Fetch vote counts
|
||||
const counts = await getVoteCounts({
|
||||
accessToken,
|
||||
versionId: version.id
|
||||
})
|
||||
countsMap[version.id] = counts
|
||||
} catch (error) {
|
||||
console.warn(`Failed to fetch outdated status for version ${version.id}:`, error)
|
||||
console.warn(`Failed to fetch data for version ${version.id}:`, error)
|
||||
statusMap[version.id] = false
|
||||
countsMap[version.id] = {positive: 0, negative: 0, total: 0}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
setOutdatedStatusMap(statusMap)
|
||||
setVoteCountsMap(countsMap)
|
||||
}
|
||||
|
||||
if (data.length > 0) {
|
||||
fetchOutdatedStatus()
|
||||
fetchVersionsData()
|
||||
}
|
||||
}, [data, accessToken, userId, countdownRef, setError, setIsErrorAlertOpen])
|
||||
|
||||
@@ -230,6 +245,19 @@ export default function ListVersions({
|
||||
|
||||
const versionData = data.find(({id}) => id === versionCompare?.versionId)
|
||||
|
||||
// Function to refresh vote counts for a specific version after voting
|
||||
const refreshVoteCounts = async versionId => {
|
||||
try {
|
||||
const counts = await getVoteCounts({
|
||||
accessToken,
|
||||
versionId
|
||||
})
|
||||
setVoteCountsMap(prev => ({...prev, [versionId]: counts}))
|
||||
} catch (error) {
|
||||
console.warn(`Failed to refresh vote counts for version ${versionId}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearchChange = newSearchTerm => {
|
||||
setSearchTerm(newSearchTerm)
|
||||
}
|
||||
@@ -305,7 +333,7 @@ export default function ListVersions({
|
||||
components={VirtuosoTableComponents}
|
||||
fixedHeaderContent={fixedHeaderContent}
|
||||
itemContent={(index, row) => rowContent({
|
||||
index, row, accessToken, userId, countdownRef, setError, setIsErrorAlertOpen, setIsOpenComparison, setVersionCompare, outdatedStatusMap
|
||||
index, row, accessToken, userId, countdownRef, setError, setIsErrorAlertOpen, setIsOpenComparison, setVersionCompare, outdatedStatusMap, voteCountsMap
|
||||
})}
|
||||
/>
|
||||
</Paper>
|
||||
@@ -316,13 +344,20 @@ export default function ListVersions({
|
||||
userId={userId}
|
||||
setError={setError}
|
||||
setIsErrorAlertOpen={setIsErrorAlertOpen}
|
||||
onVoteSuccess={refreshVoteCounts}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{isOpenComparison && (
|
||||
<VersionDialog versionData={versionData} versionCompare={versionCompare} isOpen={isOpenComparison} setIsOpen={setIsOpenComparison} />
|
||||
<VersionDialog
|
||||
versionData={versionData}
|
||||
versionCompare={versionCompare}
|
||||
isOpen={isOpenComparison}
|
||||
setIsOpen={setIsOpenComparison}
|
||||
onVoteSuccess={refreshVoteCounts}
|
||||
/>
|
||||
)}
|
||||
<SessionExpired ref={countdownRef} setError={setError} setIsErrorAlertOpen={setIsErrorAlertOpen} />
|
||||
</>
|
||||
|
||||
@@ -49,7 +49,7 @@ const renderMarkdownToHtml = async content => {
|
||||
}
|
||||
}
|
||||
|
||||
export default function PrintButton({versionData, isOutdated = false, size = 'medium', variant = 'outlined'}) {
|
||||
export default function PrintButton({versionData, isOutdated = false, voteCounts = null, size = 'medium', variant = 'outlined'}) {
|
||||
const [isPrinting, setIsPrinting] = useState(false)
|
||||
const [snackbar, setSnackbar] = useState({open: false, message: '', severity: 'success'})
|
||||
|
||||
@@ -65,6 +65,11 @@ export default function PrintButton({versionData, isOutdated = false, size = 'me
|
||||
const voteStatus = (isExpired || isOutdated) ? 'fermé' : 'ouvert'
|
||||
const voteColor = voteStatus === 'ouvert' ? '#2e7d32' : '#d32f2f'
|
||||
|
||||
// Vote counts display
|
||||
const voteTotal = voteCounts ? voteCounts.total : 0
|
||||
const voteTotalColor = voteTotal > 0 ? '#2e7d32' : (voteTotal < 0 ? '#d32f2f' : '#666')
|
||||
const voteTotalSign = voteTotal >= 0 ? '+' : ''
|
||||
|
||||
// Render markdown content to HTML
|
||||
const renderedContent = await renderMarkdownToHtml(versionData.delta?.contenu)
|
||||
|
||||
@@ -309,6 +314,22 @@ export default function PrintButton({versionData, isOutdated = false, size = 'me
|
||||
<strong>Statut du vote :</strong>
|
||||
<span class="vote-status">${voteStatus}</span>
|
||||
</div>
|
||||
${voteCounts ? `
|
||||
<div style="margin-top: 15px; padding: 15px; background-color: #f8f9fa; border-radius: 8px; border: 1px solid #e0e0e0;">
|
||||
<p style="margin: 0 0 10px 0; font-size: 16px; font-weight: bold; color: #333;">
|
||||
📊 Résultats des votes
|
||||
</p>
|
||||
<p style="margin: 5px 0; font-size: 14px;">
|
||||
👍 Votes positifs : <strong style="color: #2e7d32;">${voteCounts.positive}</strong>
|
||||
</p>
|
||||
<p style="margin: 5px 0; font-size: 14px;">
|
||||
👎 Votes négatifs : <strong style="color: #d32f2f;">${voteCounts.negative}</strong>
|
||||
</p>
|
||||
<p style="margin: 10px 0 0 0; font-size: 16px; font-weight: bold;">
|
||||
🏆 Total : <span style="color: ${voteTotalColor};">${voteTotalSign}${voteTotal}</span>
|
||||
</p>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<div class="content-section">
|
||||
@@ -392,6 +413,11 @@ export default function PrintButton({versionData, isOutdated = false, size = 'me
|
||||
PrintButton.propTypes = {
|
||||
versionData: PropTypes.object.isRequired,
|
||||
isOutdated: PropTypes.bool,
|
||||
voteCounts: PropTypes.shape({
|
||||
positive: PropTypes.number,
|
||||
negative: PropTypes.number,
|
||||
total: PropTypes.number
|
||||
}),
|
||||
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
||||
variant: PropTypes.oneOf(['text', 'outlined', 'contained'])
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import CopyButton from './copy-button.js'
|
||||
import {formatDate} from '@/lib/format.js'
|
||||
import {getVoteCounts} from '@/lib/directus.js'
|
||||
|
||||
export default function VersionComparison({versionData, versionCompare, voteRefreshKey = 0, onVoteResult}) {
|
||||
export default function VersionComparison({versionData, versionCompare, voteRefreshKey = 0, onVoteResult, onVoteSuccess}) {
|
||||
const {data: session} = useSession()
|
||||
const {current, main, outdated} = versionCompare
|
||||
const [snackbar, setSnackbar] = useState({open: false, message: '', severity: 'success'})
|
||||
@@ -44,6 +44,10 @@ export default function VersionComparison({versionData, versionCompare, voteRefr
|
||||
})
|
||||
|
||||
setVoteCounts(counts)
|
||||
|
||||
if (onVoteSuccess) {
|
||||
onVoteSuccess(versionCompare.versionId)
|
||||
}
|
||||
}
|
||||
|
||||
if (onVoteResult) {
|
||||
@@ -265,5 +269,6 @@ VersionComparison.propTypes = {
|
||||
versionId: PropTypes.string
|
||||
}).isRequired,
|
||||
voteRefreshKey: PropTypes.number,
|
||||
onVoteResult: PropTypes.func
|
||||
onVoteResult: PropTypes.func,
|
||||
onVoteSuccess: PropTypes.func
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import CompareArrowsIcon from '@mui/icons-material/CompareArrows'
|
||||
import {useTheme} from '@mui/material/styles'
|
||||
import VersionComparison from './version-comparison.js'
|
||||
|
||||
export default function VersionDialog({versionData, versionCompare, isOpen, setIsOpen}) {
|
||||
export default function VersionDialog({versionData, versionCompare, isOpen, setIsOpen, onVoteSuccess}) {
|
||||
const theme = useTheme()
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('md'))
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function VersionDialog({versionData, versionCompare, isOpen, setI
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{minHeight: '60vh'}}>
|
||||
<VersionComparison versionData={versionData} versionCompare={versionCompare} />
|
||||
<VersionComparison versionData={versionData} versionCompare={versionCompare} onVoteSuccess={onVoteSuccess} />
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{px: 3, py: 2}}>
|
||||
@@ -84,5 +84,6 @@ VersionDialog.propTypes = {
|
||||
main: PropTypes.object.isRequired
|
||||
}).isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
setIsOpen: PropTypes.func.isRequired
|
||||
setIsOpen: PropTypes.func.isRequired,
|
||||
onVoteSuccess: PropTypes.func
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import CopyButton from './copy-button.js'
|
||||
import ExportPdfButton from './export-pdf-button.js'
|
||||
import PrintButton from './print-button.js'
|
||||
import VersionComparison from './version-comparison.js'
|
||||
import {getVersion, compareVersion} from '@/lib/directus.js'
|
||||
import {getVersion, compareVersion, getVoteCounts} from '@/lib/directus.js'
|
||||
import {formatDate} from '@/lib/format.js'
|
||||
|
||||
export default function VersionPage({session, versionId, viewMode}) {
|
||||
@@ -39,6 +39,7 @@ export default function VersionPage({session, versionId, viewMode}) {
|
||||
const [isErrorAlertOpen, setIsErrorAlertOpen] = useState(false)
|
||||
const [snackbar, setSnackbar] = useState({open: false, message: '', severity: 'success'})
|
||||
const [voteRefreshKey, setVoteRefreshKey] = useState(0)
|
||||
const [voteCounts, setVoteCounts] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchVersionData() {
|
||||
@@ -67,6 +68,13 @@ export default function VersionPage({session, versionId, viewMode}) {
|
||||
if (comparison) {
|
||||
setVersionCompare({...comparison, versionId})
|
||||
}
|
||||
|
||||
const counts = await getVoteCounts({
|
||||
accessToken,
|
||||
versionId
|
||||
})
|
||||
|
||||
setVoteCounts(counts)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch version:', error)
|
||||
setError('Impossible de charger cette version')
|
||||
@@ -83,7 +91,7 @@ export default function VersionPage({session, versionId, viewMode}) {
|
||||
router.push('/dashboard')
|
||||
}
|
||||
|
||||
const handleVoteResult = result => {
|
||||
const handleVoteResult = async result => {
|
||||
setSnackbar({
|
||||
open: true,
|
||||
message: result.message,
|
||||
@@ -91,6 +99,14 @@ export default function VersionPage({session, versionId, viewMode}) {
|
||||
})
|
||||
// Force refresh of both VoteButtons components by changing the key
|
||||
setVoteRefreshKey(prev => prev + 1)
|
||||
|
||||
if (result.success) {
|
||||
const counts = await getVoteCounts({
|
||||
accessToken,
|
||||
versionId
|
||||
})
|
||||
setVoteCounts(counts)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseSnackbar = () => {
|
||||
@@ -222,8 +238,8 @@ export default function VersionPage({session, versionId, viewMode}) {
|
||||
</Button>
|
||||
|
||||
<Box sx={{display: 'flex', alignItems: 'center', gap: 2}}>
|
||||
<ExportPdfButton versionData={versionData} size='medium' />
|
||||
<PrintButton versionData={versionData} size='medium' />
|
||||
<ExportPdfButton versionData={versionData} isOutdated={versionCompare?.outdated} voteCounts={voteCounts} size='medium' />
|
||||
<PrintButton versionData={versionData} isOutdated={versionCompare?.outdated} voteCounts={voteCounts} size='medium' />
|
||||
<Tooltip title='Partager cette version'>
|
||||
<IconButton color='primary' onClick={handleShare}>
|
||||
<ShareIcon />
|
||||
|
||||
@@ -207,7 +207,8 @@ export default function VersionTimeline({
|
||||
accessToken,
|
||||
userId,
|
||||
setError,
|
||||
setIsErrorAlertOpen
|
||||
setIsErrorAlertOpen,
|
||||
onVoteSuccess
|
||||
}) {
|
||||
const countdownRef = useRef()
|
||||
const [isOpenComparison, setIsOpenComparison] = useState(false)
|
||||
@@ -216,12 +217,16 @@ export default function VersionTimeline({
|
||||
|
||||
const versionData = data.find(({id}) => id === versionCompare?.versionId)
|
||||
|
||||
const handleVoteResult = result => {
|
||||
const handleVoteResult = (result, versionId) => {
|
||||
setSnackbar({
|
||||
open: true,
|
||||
message: result.message,
|
||||
severity: result.success ? 'success' : 'error'
|
||||
})
|
||||
|
||||
if (result.success && onVoteSuccess && versionId) {
|
||||
onVoteSuccess(versionId)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -239,7 +244,7 @@ export default function VersionTimeline({
|
||||
setIsErrorAlertOpen={setIsErrorAlertOpen}
|
||||
setIsOpenComparison={setIsOpenComparison}
|
||||
setVersionCompare={setVersionCompare}
|
||||
onVoteResult={handleVoteResult}
|
||||
onVoteResult={result => handleVoteResult(result, version.id)}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
@@ -283,7 +288,8 @@ VersionTimeline.propTypes = {
|
||||
accessToken: PropTypes.string.isRequired,
|
||||
userId: PropTypes.string.isRequired,
|
||||
setError: PropTypes.func.isRequired,
|
||||
setIsErrorAlertOpen: PropTypes.func.isRequired
|
||||
setIsErrorAlertOpen: PropTypes.func.isRequired,
|
||||
onVoteSuccess: PropTypes.func
|
||||
}
|
||||
|
||||
VersionItem.propTypes = {
|
||||
|
||||
Reference in New Issue
Block a user