Files
konstitisyon.nu/components/versions/version-page.js
T

246 lines
7.2 KiB
JavaScript

'use client'
import {useState, useEffect, useRef} from 'react'
import PropTypes from 'prop-types'
import Box from '@mui/material/Box'
import Container from '@mui/material/Container'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import Paper from '@mui/material/Paper'
import Chip from '@mui/material/Chip'
import IconButton from '@mui/material/IconButton'
import Tooltip from '@mui/material/Tooltip'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import ShareIcon from '@mui/icons-material/Share'
import {useRouter} from 'next/navigation'
import SessionExpired from '../session/session-expired.js'
import AuthAlert from '../auth-form/auth-alert.js'
import {Loading} from '../loading.js'
import Footer from '../footer.js'
import VoteButtons from './vote-buttons.js'
import CopyButton from './copy-button.js'
import VersionComparison from './version-comparison.js'
import {getVersion, compareVersion} from '@/lib/directus.js'
import {formatDate} from '@/lib/format.js'
export default function VersionPage({session, versionId, viewMode}) {
const router = useRouter()
const {accessToken, userId} = session.user
const countdownRef = useRef()
const [versionData, setVersionData] = useState(null)
const [versionCompare, setVersionCompare] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
const [isErrorAlertOpen, setIsErrorAlertOpen] = useState(false)
useEffect(() => {
async function fetchVersionData() {
try {
setLoading(true)
// Fetch version details
const version = await getVersion({
accessToken,
userId,
versionId
})
setVersionData(version)
// If in comparison mode, also fetch comparison data
if (viewMode === 'comparison') {
const comparison = await compareVersion({
accessToken,
userId,
versionId,
countdownRef,
setError,
setIsErrorAlertOpen
})
if (comparison) {
setVersionCompare({...comparison, versionId})
}
}
} catch (error) {
console.error('Failed to fetch version:', error)
setError('Impossible de charger cette version')
setIsErrorAlertOpen(true)
} finally {
setLoading(false)
}
}
fetchVersionData()
}, [accessToken, userId, versionId, viewMode])
const handleBack = () => {
router.push('/dashboard')
}
const handleShare = async () => {
const url = window.location.href
try {
if (navigator.share) {
// Use native share API if available
await navigator.share({
title: `Version: ${versionData?.name || 'Version'}`,
text: 'Découvrez cette version sur Konstitisyon.la',
url
})
} else {
// Fallback: copy URL to clipboard
await navigator.clipboard.writeText(url)
// Could show a toast notification here
}
} catch (error) {
console.error('Failed to share:', error)
}
}
if (loading) {
return (
<Container>
<Loading />
<SessionExpired ref={countdownRef} setError={setError} setIsErrorAlertOpen={setIsErrorAlertOpen} />
</Container>
)
}
if (error && !versionData) {
return (
<Container>
<AuthAlert
isOpen={isErrorAlertOpen}
setIsOpen={setIsErrorAlertOpen}
message={error}
severity='error'
/>
<Box sx={{textAlign: 'center', py: 4}}>
<Typography gutterBottom variant='h6'>
Version introuvable
</Typography>
<Button variant='contained' startIcon={<ArrowBackIcon />} onClick={handleBack}>
Retour au tableau de bord
</Button>
</Box>
<SessionExpired ref={countdownRef} setError={setError} setIsErrorAlertOpen={setIsErrorAlertOpen} />
</Container>
)
}
const createdAt = new Date(versionData.date_created)
const threeDaysAgo = new Date(Date.now() - (3 * 24 * 60 * 60 * 1000))
const isVoteDisabled = createdAt < threeDaysAgo
const authorName = versionData.user_created?.split('-')[0] || 'Système'
return (
<Box sx={{
display: 'flex',
flexDirection: 'column',
minHeight: '100vh'
}}
>
<Container sx={{flex: 1}}>
{error && (
<AuthAlert
isOpen={isErrorAlertOpen}
setIsOpen={setIsErrorAlertOpen}
message={error}
severity='error'
/>
)}
{/* Header */}
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
my: 3
}}
>
<Button
startIcon={<ArrowBackIcon />}
variant='outlined'
onClick={handleBack}
>
Retour
</Button>
<Box sx={{display: 'flex', alignItems: 'center', gap: 2}}>
<Tooltip title='Partager cette version'>
<IconButton color='primary' onClick={handleShare}>
<ShareIcon />
</IconButton>
</Tooltip>
</Box>
</Box>
{/* Version Info */}
<Paper sx={{p: 3, mb: 3}}>
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
mb: 2
}}
>
<Box>
<Typography gutterBottom variant='h4'>
{versionData.name}
</Typography>
<Typography gutterBottom variant='body2' color='text.secondary'>
Créée par @{authorName} le {formatDate(versionData.date_created, 'PPpp')}
</Typography>
<Chip
label={isVoteDisabled ? 'Vote fermé' : 'Vote ouvert'}
color={isVoteDisabled ? 'default' : 'success'}
size='small'
variant='outlined'
/>
</Box>
<Box sx={{display: 'flex', alignItems: 'center', gap: 1}}>
<CopyButton
content={versionData.delta?.contenu || versionData.name || ''}
label='Copier le contenu de cette version'
/>
{!isVoteDisabled && (
<VoteButtons versionId={versionId} />
)}
</Box>
</Box>
</Paper>
{/* Content */}
{viewMode === 'comparison' && versionCompare ? (
<VersionComparison
versionData={versionData}
versionCompare={versionCompare}
/>
) : (
<Paper sx={{p: 3}}>
<Typography gutterBottom variant='h6'>
Contenu
</Typography>
<Typography variant='body1' sx={{whiteSpace: 'pre-wrap'}}>
{versionData.delta?.contenu || 'Aucun contenu disponible'}
</Typography>
</Paper>
)}
<SessionExpired ref={countdownRef} setError={setError} setIsErrorAlertOpen={setIsErrorAlertOpen} />
</Container>
<Footer />
</Box>
)
}
VersionPage.propTypes = {
session: PropTypes.object.isRequired,
versionId: PropTypes.string.isRequired,
viewMode: PropTypes.oneOf(['comparison', 'content']).isRequired
}