434 lines
13 KiB
JavaScript
434 lines
13 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 from '@mui/material/Box'
|
||
import Button from '@mui/material/Button'
|
||
import Container from '@mui/material/Container'
|
||
import FormControl from '@mui/material/FormControl'
|
||
import FormHelperText from '@mui/material/FormHelperText'
|
||
import Grid from '@mui/material/Grid2'
|
||
import IconButton from '@mui/material/IconButton'
|
||
import InputAdornment from '@mui/material/InputAdornment'
|
||
import InputLabel from '@mui/material/InputLabel'
|
||
import LinearProgress from '@mui/material/LinearProgress'
|
||
import OutlinedInput from '@mui/material/OutlinedInput'
|
||
import Snackbar from '@mui/material/Snackbar'
|
||
import TextField from '@mui/material/TextField'
|
||
import Tooltip from '@mui/material/Tooltip'
|
||
import Typography from '@mui/material/Typography'
|
||
|
||
import MuiAlert from '@mui/material/Alert'
|
||
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
|
||
|
||
import {jwennAnTeks} from '../../lib/oki-api'
|
||
|
||
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 = async () => {
|
||
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) {
|
||
try {
|
||
const teks = await jwennAnTeks(currentTeksId, jwt)
|
||
const teksResponse = await axios.put(`${API_URL}/paroles/${currentTeksId}`, {
|
||
data: {
|
||
id: teks.id,
|
||
titre: tit,
|
||
transcription: transkripsyon,
|
||
traductions: {
|
||
francais: fr === '' ? null : fr,
|
||
anglais: en === '' ? null : en,
|
||
espagnol: es === '' ? null : es,
|
||
allemand: de === '' ? null : de,
|
||
italien: it === '' ? null : it
|
||
},
|
||
user: {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email
|
||
},
|
||
artistes: teks.artistes.map(({id}) => id),
|
||
traductionAuto: tradiksyonOtomatik
|
||
}
|
||
}, {
|
||
headers
|
||
})
|
||
|
||
const {data} = teksResponse
|
||
setSuccess(`Le morceau "${data.tit}" a été modifié avec succès. Il apparaîtra sur le site après validation.`)
|
||
setLoading(false)
|
||
} catch (error) {
|
||
setError(error?.response?.data)
|
||
setLoading(false)
|
||
}
|
||
} else {
|
||
try {
|
||
const artiste = await axios.post(`${API_URL}/artistes`, {
|
||
data: {
|
||
alias: awtis,
|
||
user: {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email
|
||
}
|
||
}
|
||
}, {
|
||
headers
|
||
})
|
||
|
||
const parole = await axios.post(`${API_URL}/paroles`, {
|
||
data: {
|
||
titre: tit,
|
||
transcription: transkripsyon,
|
||
traductions: {
|
||
francais: fr === '' ? null : fr,
|
||
anglais: en === '' ? null : en,
|
||
espagnol: es === '' ? null : es,
|
||
allemand: de === '' ? null : de,
|
||
italien: it === '' ? null : it
|
||
},
|
||
user: {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email
|
||
},
|
||
artistes: [artiste.data.id],
|
||
traductionAuto: tradiksyonOtomatik
|
||
}
|
||
}, {
|
||
headers
|
||
})
|
||
|
||
const {data} = parole
|
||
|
||
setSuccess(`Le texte "${data.titre}" a été soumis avec succès. Il apparaîtra sur le site après validation.`)
|
||
setLoading(false)
|
||
} catch (error) {
|
||
setError(error?.response?.data)
|
||
setLoading(false)
|
||
}
|
||
}
|
||
}
|
||
|
||
const handleReset = () => {
|
||
setTeksEkri({awtis: '', tit: '', transkripsyon: ''})
|
||
setTradiksyon({fr: '', en: '', es: '', de: '', it: ''})
|
||
setKiChwalang(['fr'])
|
||
setCurrentTeksId(null)
|
||
setTradiksyonOtomatik(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (success) {
|
||
setOpen(true)
|
||
handleReset()
|
||
}
|
||
}, [success])
|
||
|
||
useEffect(() => {
|
||
if (error) {
|
||
setOpen(true)
|
||
}
|
||
}, [error])
|
||
|
||
useEffect(() => {
|
||
if (selectedTeks) {
|
||
setTradiksyonOtomatik(false)
|
||
setCurrentTeksId(selectedTeks.id)
|
||
setTeksEkri({
|
||
awtis: new Intl.ListFormat('fr').format(selectedTeks.artistes.map(({alias}) => alias)),
|
||
tit: selectedTeks.titre,
|
||
transkripsyon: selectedTeks.transcription
|
||
})
|
||
setTradiksyon({
|
||
fr: selectedTeks?.traductions?.francais || '',
|
||
en: selectedTeks?.traductions?.anglais || '',
|
||
es: selectedTeks?.traductions?.espagnol || '',
|
||
de: selectedTeks?.traductions?.allemand || '',
|
||
it: selectedTeks?.traductions?.italien || ''
|
||
})
|
||
|
||
const jennLangId = () => {
|
||
const ids = []
|
||
|
||
if (selectedTeks?.traductions?.francais) {
|
||
ids.push('fr')
|
||
}
|
||
|
||
if (selectedTeks?.traductions?.anglais) {
|
||
ids.push('en')
|
||
}
|
||
|
||
if (selectedTeks?.traductions?.espagnol) {
|
||
ids.push('es')
|
||
}
|
||
|
||
if (selectedTeks?.traductions?.allemand) {
|
||
ids.push('de')
|
||
}
|
||
|
||
if (selectedTeks?.traductions?.italien) {
|
||
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='h6' component='h1'>
|
||
Proposer une parole
|
||
</Typography>
|
||
</Box>
|
||
<form noValidate autoComplete='off'>
|
||
<Grid container style={{textAlign: 'center'}} spacing={1}>
|
||
<Grid xs='true'>
|
||
<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 xs='true'>
|
||
<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 === '' || tradiksyon.en !== '' || tradiksyon.es !== '' || tradiksyon.de !== '' || tradiksyon.it !== ''}
|
||
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='error'
|
||
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={10_000} onClose={handleClose}>
|
||
<Alert severity='error' onClose={handleClose}>
|
||
<strong>Une erreur s’est produite</strong> : <i>{error?.error?.message}</i>
|
||
</Alert>
|
||
</Snackbar>
|
||
)}
|
||
</StyledContainer>
|
||
)
|
||
}
|
||
|
||
EkriTeks.propTypes = {
|
||
canAutoTranslate: PropTypes.bool,
|
||
selectedTeks: PropTypes.object,
|
||
setSelectedTeks: PropTypes.func.isRequired,
|
||
}
|
||
|
||
export default EkriTeks
|