Add components to write comments

This commit is contained in:
2024-06-18 11:11:15 +04:00
parent 157951b10e
commit 28177439e1
3 changed files with 223 additions and 20 deletions
+117
View File
@@ -0,0 +1,117 @@
'use client'
import {useRef} from 'react'
import PropTypes from 'prop-types'
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
import Dialog from '@mui/material/Dialog'
import DialogActions from '@mui/material/DialogActions'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogTitle from '@mui/material/DialogTitle'
import {createItem, withToken} from '@directus/sdk'
import LogoutCountdown from '../session/logout-countdown.js'
import {directusClient} from '@/lib/directus.js'
function hasRestrictedChar(text) {
const regex = /[<>&'"]/g
return Boolean(regex.test(text))
}
export default function HandleComments({session, selectedTitre, isOpen, setIsOpen, setError, setSuccess, setIsErrorAlertOpen, setIsSuccessAlertOpen}) {
const countdownRef = useRef()
const handleClose = () => {
setIsOpen(false)
}
const handleFormSubmit = async e => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
const formJson = Object.fromEntries(formData.entries())
const {comment} = formJson
try {
if (hasRestrictedChar(comment)) {
setError('Le texte ne doit pas contenir certains caractères spéciaux : <, >, \', ".')
setIsErrorAlertOpen(true)
return
}
await directusClient.request(withToken(
session.user.accessToken,
createItem('commentaires', {
text: comment,
titre: selectedTitre,
status: 'draft'
})
))
setSuccess('Envoyé avec succès. Commentaire en attente de validation.')
setIsSuccessAlertOpen(true)
} catch (error) {
if (error?.errors[0]?.message === 'Token expired.') {
countdownRef.current.startCountdown()
} else {
console.log(error?.errors[0]?.message)
setError(error?.errors[0]?.message)
setIsErrorAlertOpen(true)
}
}
handleClose()
}
return (
<>
<Dialog
open={isOpen}
PaperProps={{
component: 'form',
onSubmit(event) {
handleFormSubmit(event)
},
}}
onClose={handleClose}
>
<DialogTitle>{selectedTitre.titre}</DialogTitle>
<DialogContent sx={{color: 'white'}}>
<DialogContentText sx={{color: 'white'}}>
Écrivez votre commentaire
</DialogContentText>
<TextField
autoFocus
required
multiline
fullWidth
mt={2}
rows={4}
id='comment'
name='comment'
label='Commentaire'
/>
</DialogContent>
<DialogActions>
<Button variant='contained' color='success' onClick={handleClose}>Annuler</Button>
<Button variant='contained' color='error' type='submit'>Valider</Button>
</DialogActions>
</Dialog>
<LogoutCountdown ref={countdownRef} setError={setError} setIsErrorAlertOpen={setIsErrorAlertOpen} />
</>
)
}
HandleComments.propTypes = {
session: PropTypes.object,
selectedTitre: PropTypes.object.isRequired,
isOpen: PropTypes.bool.isRequired,
setIsOpen: PropTypes.func.isRequired,
setError: PropTypes.func.isRequired,
setSuccess: PropTypes.func.isRequired,
setIsErrorAlertOpen: PropTypes.func.isRequired,
setIsSuccessAlertOpen: PropTypes.func.isRequired
}
+43 -2
View File
@@ -1,14 +1,16 @@
'use client' 'use client'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {useState} from 'react'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Paper from '@mui/material/Paper' import Paper from '@mui/material/Paper'
import {styled} from '@mui/material/styles' import {styled} from '@mui/material/styles'
import IconButton from '@mui/material/IconButton' import IconButton from '@mui/material/IconButton'
import AddCommentIcon from '@mui/icons-material/AddComment' import AddCommentIcon from '@mui/icons-material/AddComment'
import Tooltip, {tooltipClasses} from '@mui/material/Tooltip' import Tooltip, {tooltipClasses} from '@mui/material/Tooltip'
import AuthAlert from '../auth-form/auth-alert.js'
import Titre from './titre.js' import Titre from './titre.js'
import Article from './article.js' import Article from './article.js'
import HandleComments from './handle-comments.js'
import {formatKonstitisyon} from '@/lib/format.js' import {formatKonstitisyon} from '@/lib/format.js'
const LightTooltip = styled(({className, ...props}) => ( const LightTooltip = styled(({className, ...props}) => (
@@ -24,8 +26,34 @@ const LightTooltip = styled(({className, ...props}) => (
export default function Konstitisyon({session, titres, articles}) { export default function Konstitisyon({session, titres, articles}) {
const konstitisyon = formatKonstitisyon(titres, articles) const konstitisyon = formatKonstitisyon(titres, articles)
const [isOpen, setIsOpen] = useState(false)
const [isErrorAlertOpen, setIsErrorAlertOpen] = useState(false)
const [isSuccessAlertOpen, setIsSuccessAlertOpen] = useState(false)
const [selectedTitre, setSelectedTitre] = useState(null)
const [error, setError] = useState('')
const [success, setSuccess] = useState('')
const handleCommentsDialog = (titreId, titre) => {
setSelectedTitre({id: titreId, titre})
setIsOpen(true)
}
return ( return (
<>
{error && <AuthAlert
isOpen={isErrorAlertOpen}
setIsOpen={setIsErrorAlertOpen}
message={error}
severity='error'
/>}
{success && <AuthAlert
isOpen={isSuccessAlertOpen}
setIsOpen={setIsSuccessAlertOpen}
message={success}
severity='success'
/>}
<Box> <Box>
{konstitisyon.map(({titreId, titre, articles}) => ( {konstitisyon.map(({titreId, titre, articles}) => (
<Paper key={titreId} variant='outlined' sx={{p: 1, marginBlock: 2}} p={2} > <Paper key={titreId} variant='outlined' sx={{p: 1, marginBlock: 2}} p={2} >
@@ -35,7 +63,7 @@ export default function Konstitisyon({session, titres, articles}) {
))} ))}
{session && ( {session && (
<Box sx={{textAlign: 'right'}}> <Box sx={{textAlign: 'right'}}>
<IconButton size='large' aria-label='commenter'> <IconButton size='large' aria-label='commenter' onClick={() => handleCommentsDialog(titreId, titre)}>
<LightTooltip title='Commenter'> <LightTooltip title='Commenter'>
<AddCommentIcon color='warning' fontSize='inherit' /> <AddCommentIcon color='warning' fontSize='inherit' />
</LightTooltip> </LightTooltip>
@@ -44,7 +72,20 @@ export default function Konstitisyon({session, titres, articles}) {
)} )}
</Paper> </Paper>
))} ))}
{selectedTitre && (
<HandleComments
session={session}
selectedTitre={selectedTitre}
isOpen={isOpen}
setIsOpen={setIsOpen}
setError={setError}
setSuccess={setSuccess}
setIsErrorAlertOpen={setIsErrorAlertOpen}
setIsSuccessAlertOpen={setIsSuccessAlertOpen}
/>
)}
</Box> </Box>
</>
) )
} }
+45
View File
@@ -0,0 +1,45 @@
import PropTypes from 'prop-types'
import {
useState, useEffect, forwardRef, useImperativeHandle
} from 'react'
import {signOut} from 'next-auth/react'
const LogoutCountdown = forwardRef(({setError, setIsErrorAlertOpen}, ref) => {
const [counter, setCounter] = useState(5)
const [isCountdownActive, setIsCountdownActive] = useState(false)
useEffect(() => {
let timer
if (isCountdownActive) {
if (counter > 0) {
timer = setInterval(() => {
setCounter(prevCounter => prevCounter - 1)
}, 1000)
} else if (counter === 0) {
signOut()
}
setError(`Session expirée, reconnectez-vous ! Déconnexion dans... ${counter} sec`)
setIsErrorAlertOpen(true)
}
return () => clearInterval(timer)
}, [isCountdownActive, counter, setError, setIsErrorAlertOpen])
useImperativeHandle(ref, () => ({
startCountdown() {
setCounter(5)
setIsCountdownActive(true)
}
}))
return null
})
LogoutCountdown.propTypes = {
setError: PropTypes.func.isRequired,
setIsErrorAlertOpen: PropTypes.func.isRequired
}
export default LogoutCountdown