433 lines
12 KiB
JavaScript
433 lines
12 KiB
JavaScript
import {useCallback, useEffect, forwardRef, useState} from 'react'
|
||
import {styled} from '@mui/material/styles'
|
||
import PropTypes from 'prop-types'
|
||
import axios from 'axios'
|
||
import {useSession} from 'next-auth/react'
|
||
import {
|
||
Box,
|
||
Button,
|
||
Container,
|
||
FormControl,
|
||
FormHelperText,
|
||
Grid,
|
||
IconButton,
|
||
InputAdornment,
|
||
InputLabel,
|
||
LinearProgress,
|
||
OutlinedInput,
|
||
Snackbar,
|
||
TextField,
|
||
Tooltip,
|
||
Typography
|
||
} from '@mui/material'
|
||
import MuiAlert from '@mui/material/Alert'
|
||
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
|
||
|
||
import AjouteTradiksyon from './ajoute-tradiksyon'
|
||
|
||
const PREFIX = 'EkriTeks'
|
||
|
||
const classes = {
|
||
tooltip: `${PREFIX}-tooltip`
|
||
}
|
||
|
||
const StyledContainer = styled(Container)(() => ({
|
||
[`& .${classes.tooltip}`]: {
|
||
fontSize: 18
|
||
}
|
||
}))
|
||
|
||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
|
||
|
||
const textLabels = {
|
||
fr: {
|
||
title: 'Traduction',
|
||
help: 'Traduction des paroles',
|
||
emoji: '🇫🇷'
|
||
},
|
||
en: {
|
||
title: 'Translation',
|
||
help: 'Translation of the lyrics',
|
||
emoji: '🇬🇧'
|
||
},
|
||
es: {
|
||
title: 'Traducción',
|
||
help: 'Traducción de la letra',
|
||
emoji: '🇪🇸'
|
||
},
|
||
de: {
|
||
title: 'Übersetzung',
|
||
help: 'Übersetzung von Liedtexten',
|
||
emoji: '🇩🇪'
|
||
},
|
||
it: {
|
||
title: 'Traduzione',
|
||
help: 'Traduzione del testo',
|
||
emoji: '🇮🇹'
|
||
}
|
||
}
|
||
|
||
const Alert = forwardRef(function Alert(props, ref) {
|
||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||
})
|
||
|
||
const RemoveTooltip = Tooltip
|
||
|
||
function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
|
||
const {data: session} = useSession()
|
||
const {jwt, user} = session
|
||
const [teksEkri, setTeksEkri] = useState({awtis: '', tit: '', transkripsyon: ''})
|
||
const [tradiksyon, setTradiksyon] = useState({fr: '', en: '', es: '', de: '', it: ''})
|
||
const [kiChawLang, setKiChwalang] = useState(['fr'])
|
||
const [error, setError] = useState('')
|
||
const [success, setSuccess] = useState('')
|
||
const [loading, setLoading] = useState(false)
|
||
const [currentTeksId, setCurrentTeksId] = useState(null)
|
||
const [open, setOpen] = useState(false)
|
||
const [tradiksyonOtomatik, setTradiksyonOtomatik] = useState(false)
|
||
|
||
const handleUpdate = useCallback(update => {
|
||
setTeksEkri({...teksEkri, ...update})
|
||
}, [teksEkri])
|
||
|
||
const handleUpdateTradiksyon = useCallback(update => {
|
||
setTradiksyon({...tradiksyon, ...update})
|
||
}, [tradiksyon])
|
||
|
||
const handleRemoveTradiksyon = useCallback(idTradiksyon => {
|
||
setKiChwalang(kiChawLang.filter(t => t !== idTradiksyon))
|
||
}, [kiChawLang, setKiChwalang])
|
||
|
||
const handleClose = (event, reason) => {
|
||
if (reason === 'clickaway') {
|
||
return
|
||
}
|
||
|
||
setOpen(false)
|
||
setSuccess('')
|
||
setError('')
|
||
}
|
||
|
||
const handleClick = () => {
|
||
setLoading(true)
|
||
const {awtis, tit, transkripsyon} = teksEkri
|
||
const {fr, en, es, de, it} = tradiksyon
|
||
|
||
if (teksEkri.awtis === '' || teksEkri.tit === '' || teksEkri.transkripsyon === '') {
|
||
setError({message: 'Certains champs sont obligatoires'})
|
||
setLoading(false)
|
||
|
||
return
|
||
}
|
||
|
||
const headers = {
|
||
'content-type': 'application/json',
|
||
Authorization: `Bearer ${jwt}`
|
||
}
|
||
|
||
if (currentTeksId) {
|
||
axios.get(`${API_URL}/teks/${currentTeksId}?_publicationState=preview&_where[published_at_null]=true`)
|
||
.then(awtisResponse => {
|
||
if (awtisResponse.data.user._id !== user._id) {
|
||
setLoading(false)
|
||
return setError({message: 'Opération non autorisé'})
|
||
}
|
||
|
||
axios.put(`${API_URL}/teks/${currentTeksId}`, {
|
||
tit,
|
||
transkripsyon,
|
||
tradiksyon: {
|
||
francais: fr === '' ? null : fr,
|
||
english: en === '' ? null : en,
|
||
espagnol: es === '' ? null : es,
|
||
deutsch: de === '' ? null : de,
|
||
italiano: it === '' ? null : it
|
||
},
|
||
user,
|
||
awtis: awtisResponse.data.awtis.map(id => id),
|
||
tradiksyonOtomatik
|
||
}, {
|
||
headers
|
||
})
|
||
.then(teksResponse => {
|
||
const {data} = teksResponse
|
||
setSuccess(`Le texte "${data.tit}" a été modifié avec succès. Il apparaîtra sur le site après validation.`)
|
||
setLoading(false)
|
||
})
|
||
.catch(error => {
|
||
setError(error)
|
||
setLoading(false)
|
||
})
|
||
})
|
||
.catch(error => {
|
||
setError(error)
|
||
setLoading(false)
|
||
})
|
||
} else {
|
||
axios.post(`${API_URL}/awtis`, {
|
||
alias: awtis,
|
||
user
|
||
}, {
|
||
headers
|
||
})
|
||
.then(awtisResponse => {
|
||
axios.post(`${API_URL}/teks`, {
|
||
tit,
|
||
transkripsyon,
|
||
tradiksyon: {
|
||
francais: fr === '' ? null : fr,
|
||
english: en === '' ? null : en,
|
||
espagnol: es === '' ? null : es,
|
||
deutsch: de === '' ? null : de,
|
||
italiano: it === '' ? null : it
|
||
},
|
||
user,
|
||
awtis: [awtisResponse.data._id],
|
||
tradiksyonOtomatik
|
||
}, {
|
||
headers
|
||
})
|
||
.then(teksResponse => {
|
||
const {data} = teksResponse
|
||
setSuccess(`Le texte "${data.tit}" a été soumis avec succès. Il apparaîtra sur le site après validation.`)
|
||
setLoading(false)
|
||
})
|
||
.catch(error => {
|
||
setError(error)
|
||
setLoading(false)
|
||
})
|
||
})
|
||
.catch(error => {
|
||
setError(error)
|
||
setLoading(false)
|
||
})
|
||
}
|
||
}
|
||
|
||
const handleReset = () => {
|
||
setTeksEkri({awtis: '', tit: '', transkripsyon: ''})
|
||
setTradiksyon({fr: '', en: '', es: '', de: '', it: ''})
|
||
setKiChwalang([])
|
||
setCurrentTeksId(null)
|
||
setTradiksyonOtomatik(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (success) {
|
||
setOpen(true)
|
||
handleReset()
|
||
}
|
||
}, [success])
|
||
|
||
useEffect(() => {
|
||
if (error) {
|
||
setOpen(true)
|
||
}
|
||
}, [error])
|
||
|
||
useEffect(() => {
|
||
if (selectedTeks) {
|
||
setCurrentTeksId(selectedTeks._id)
|
||
setTeksEkri({
|
||
awtis: new Intl.ListFormat('fr').format(selectedTeks.awtis.map(({alias}) => alias)),
|
||
tit: selectedTeks.tit,
|
||
transkripsyon: selectedTeks.transkripsyon
|
||
})
|
||
setTradiksyon({
|
||
fr: selectedTeks.tradiksyon.francais || '',
|
||
en: selectedTeks.tradiksyon.english || '',
|
||
es: selectedTeks.tradiksyon.espagnol || '',
|
||
de: selectedTeks.tradiksyon.deutsch || '',
|
||
it: selectedTeks.tradiksyon.italiano || ''
|
||
})
|
||
|
||
const jennLangId = () => {
|
||
const ids = []
|
||
const {francais, english, espagnol, deutsch, italiano} = selectedTeks.tradiksyon
|
||
|
||
if (francais) {
|
||
ids.push('fr')
|
||
}
|
||
|
||
if (english) {
|
||
ids.push('en')
|
||
}
|
||
|
||
if (espagnol) {
|
||
ids.push('es')
|
||
}
|
||
|
||
if (deutsch) {
|
||
ids.push('de')
|
||
}
|
||
|
||
if (italiano) {
|
||
ids.push('it')
|
||
}
|
||
|
||
return ids
|
||
}
|
||
|
||
const langIds = jennLangId()
|
||
|
||
setKiChwalang(langIds)
|
||
}
|
||
|
||
return () => {
|
||
setSelectedTeks(null)
|
||
}
|
||
}, [teksEkri, selectedTeks, setSelectedTeks, kiChawLang])
|
||
|
||
return (
|
||
<StyledContainer maxWidth='sm'>
|
||
<Box sx={{textAlign: 'center', marginBottom: 2}}>
|
||
<Typography display='inline' variant='h5' component='h1'>
|
||
Soumettre un texte
|
||
</Typography>
|
||
</Box>
|
||
<form noValidate autoComplete='off'>
|
||
<Grid container style={{textAlign: 'center'}} spacing={1}>
|
||
<Grid item xs>
|
||
<TextField
|
||
required
|
||
id='awtis'
|
||
name='awtis'
|
||
label='Artiste'
|
||
value={teksEkri.awtis}
|
||
disabled={Boolean(currentTeksId)}
|
||
variant='outlined'
|
||
helperText='Nom de l’artiste (obligatoire)'
|
||
onChange={event => handleUpdate({awtis: event.target.value})}
|
||
/>
|
||
</Grid>
|
||
<Grid item xs>
|
||
<TextField
|
||
required
|
||
id='tit'
|
||
name='tit'
|
||
label='Titre'
|
||
value={selectedTeks?.tit || teksEkri.tit}
|
||
variant='outlined'
|
||
helperText='Titre de la musique (obligatoire)'
|
||
onChange={event => handleUpdate({tit: event.target.value})}
|
||
/>
|
||
</Grid>
|
||
</Grid>
|
||
<TextField
|
||
fullWidth
|
||
multiline
|
||
required
|
||
helperText='Transcription des paroles (obligatoire)'
|
||
style={{marginTop: '1em'}}
|
||
id='transkripsyon'
|
||
label='Transcription'
|
||
value={teksEkri.transkripsyon}
|
||
rows={8}
|
||
variant='outlined'
|
||
onChange={event => handleUpdate({transkripsyon: event.target.value})}
|
||
/>
|
||
{kiChawLang.length > 0 && kiChawLang.map(k => (
|
||
<FormControl key={k} fullWidth style={{marginBlock: 10}}>
|
||
<InputLabel htmlFor={`tradiksyon-${k}`}>
|
||
<span dangerouslySetInnerHTML={{__html: textLabels[k].emoji}} /> {textLabels[k].title}
|
||
</InputLabel>
|
||
<OutlinedInput
|
||
multiline
|
||
style={{marginTop: '1em'}}
|
||
id={`tradiksyon-${k}`}
|
||
name={`tradiksyon-${k}`}
|
||
label={`${textLabels[k].title}`}
|
||
value={tradiksyon[k]}
|
||
rows={8}
|
||
endAdornment={
|
||
<InputAdornment position='end'>
|
||
<RemoveTooltip
|
||
title='Cacher la fenêtre'
|
||
placement='left'
|
||
classes={{
|
||
tooltip: classes.tooltip
|
||
}}
|
||
>
|
||
<IconButton
|
||
style={{bottom: 75}}
|
||
aria-label='remove-tradiksyon'
|
||
edge='end'
|
||
size='large'
|
||
onClick={() => handleRemoveTradiksyon(k)}
|
||
>
|
||
<VisibilityOffIcon />
|
||
</IconButton>
|
||
</RemoveTooltip>
|
||
</InputAdornment>
|
||
}
|
||
onChange={event => handleUpdateTradiksyon({[k]: event.target.value})}
|
||
/>
|
||
<FormHelperText id={`tradiksyon-${k}`}>{textLabels[k].help}</FormHelperText>
|
||
</FormControl>
|
||
))}
|
||
</form>
|
||
<AjouteTradiksyon
|
||
showSwitch={Boolean(canAutoTranslate) && Boolean(!currentTeksId)}
|
||
disableSwitch={tradiksyon.fr === ''}
|
||
tradiksyonOtomatik={tradiksyonOtomatik}
|
||
setTradiksyonOtomatik={setTradiksyonOtomatik}
|
||
chwaLang={kiChawLang}
|
||
setChwaLang={setKiChwalang}
|
||
/>
|
||
<div>
|
||
<Button
|
||
fullWidth
|
||
disabled={loading || teksEkri.awtis === '' || teksEkri.tit === '' || teksEkri.transkripsyon === ''}
|
||
style={{marginTop: 20}}
|
||
variant='contained'
|
||
color='primary'
|
||
onClick={handleClick}
|
||
>
|
||
<Typography style={{fontWeight: 'bold'}}>
|
||
Valider
|
||
</Typography>
|
||
</Button>
|
||
<Button
|
||
fullWidth
|
||
disabled={loading || (teksEkri.awtis === '' && teksEkri.tit === '' && teksEkri.transkripsyon === '')}
|
||
style={{marginTop: 20}}
|
||
variant='contained'
|
||
color='secondary'
|
||
onClick={handleReset}
|
||
>
|
||
<Typography style={{fontWeight: 'bold'}}>
|
||
Tout effacer
|
||
</Typography>
|
||
</Button>
|
||
{loading && <LinearProgress size={24} style={{width: '100%', marginBlock: '1em'}} />}
|
||
</div>
|
||
{success && (
|
||
<Snackbar open={open} autoHideDuration={10_000} onClose={handleClose}>
|
||
<Alert severity='success' onClose={handleClose}>
|
||
<strong>{success}</strong>
|
||
</Alert>
|
||
</Snackbar>
|
||
)}
|
||
{error && (
|
||
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
|
||
<Alert severity='error' onClose={handleClose}>
|
||
<strong>Une erreur s’est produite</strong> : <i>{error.message}</i>
|
||
</Alert>
|
||
</Snackbar>
|
||
)}
|
||
</StyledContainer>
|
||
)
|
||
}
|
||
|
||
EkriTeks.defaultProps = {
|
||
selectedTeks: null
|
||
}
|
||
|
||
EkriTeks.propTypes = {
|
||
canAutoTranslate: PropTypes.bool.isRequired,
|
||
selectedTeks: PropTypes.object,
|
||
setSelectedTeks: PropTypes.func.isRequired,
|
||
}
|
||
|
||
export default EkriTeks
|