Merge branch 'dev' into 'master'

Migration de strapi v3 vers la v4. Adapte les routes et le modèle de données

See merge request cedric-famibelle-pronzola/oki-front!1
This commit is contained in:
2022-05-19 22:42:39 +00:00
31 changed files with 625 additions and 446 deletions
+1
View File
@@ -2,6 +2,7 @@ PORT=3000
API_URL=http://localhost:1337 API_URL=http://localhost:1337
NEXT_PUBLIC_API_URL=$API_URL NEXT_PUBLIC_API_URL=$API_URL
SITE_URL=http://localhost:3001 SITE_URL=http://localhost:3001
NEXT_PUBLIC_READ_TOKEN=
# FUNKWHALE VARIABLE # FUNKWHALE VARIABLE
NEXT_PUBLIC_OKI_MIZIK_URL=https://funkwhale-server.com NEXT_PUBLIC_OKI_MIZIK_URL=https://funkwhale-server.com
+8 -8
View File
@@ -14,7 +14,7 @@ import {
import MizikBadjMeni from './mizik-badj-meni' import MizikBadjMeni from './mizik-badj-meni'
export default function AwtisBiyografi({alias, teks, biyografi, esByografiOuve, meteEsByografiOuve}) { export default function AwtisBiyografi({alias, paroles, biographie, esByografiOuve, meteEsByografiOuve}) {
const handleClose = () => { const handleClose = () => {
meteEsByografiOuve(false) meteEsByografiOuve(false)
} }
@@ -40,7 +40,7 @@ export default function AwtisBiyografi({alias, teks, biyografi, esByografiOuve,
> >
<Box display='flex' justifyContent='center' alignItems='center'> <Box display='flex' justifyContent='center' alignItems='center'>
<DialogTitle id='scroll-dialog-title' align='center'>{alias}</DialogTitle> <DialogTitle id='scroll-dialog-title' align='center'>{alias}</DialogTitle>
<MizikBadjMeni teks={teks} /> <MizikBadjMeni paroles={paroles} />
</Box> </Box>
<DialogContent dividers> <DialogContent dividers>
<DialogContentText <DialogContentText
@@ -49,9 +49,9 @@ export default function AwtisBiyografi({alias, teks, biyografi, esByografiOuve,
id='scroll-dialog-description' id='scroll-dialog-description'
tabIndex={-1} tabIndex={-1}
> >
{biyografi ? ( {biographie ? (
<Typography component='span'> <Typography component='span'>
{biyografi} {biographie}
</Typography> </Typography>
) : ( ) : (
<Typography component='span'> <Typography component='span'>
@@ -62,7 +62,7 @@ export default function AwtisBiyografi({alias, teks, biyografi, esByografiOuve,
</DialogContent> </DialogContent>
<DialogActions style={{margin: 'auto'}}> <DialogActions style={{margin: 'auto'}}>
<Button variant='outlined' color='primary' onClick={handleClose}> <Button variant='outlined' color='primary' onClick={handleClose}>
Fèmen Fermer
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
@@ -72,12 +72,12 @@ export default function AwtisBiyografi({alias, teks, biyografi, esByografiOuve,
AwtisBiyografi.propTypes = { AwtisBiyografi.propTypes = {
alias: PropTypes.string.isRequired, alias: PropTypes.string.isRequired,
teks: PropTypes.array.isRequired, paroles: PropTypes.array.isRequired,
biyografi: PropTypes.string, biographie: PropTypes.string,
esByografiOuve: PropTypes.bool.isRequired, esByografiOuve: PropTypes.bool.isRequired,
meteEsByografiOuve: PropTypes.func.isRequired meteEsByografiOuve: PropTypes.func.isRequired
} }
AwtisBiyografi.defaultProps = { AwtisBiyografi.defaultProps = {
biyografi: null biographie: null
} }
+13 -12
View File
@@ -13,18 +13,19 @@ import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace'
import AwtisBiyografi from './awtis-biyografi' import AwtisBiyografi from './awtis-biyografi'
import MizikLis from './mizik-lis' import MizikLis from './mizik-lis'
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337' const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible'
const sortTeks = teks => teks.sort((a, b) => b.id - a.id) const sortTeks = paroles => paroles.sort((a, b) => b.id - a.id)
export default function AwtisDetay({anAwtis}) { export default function AwtisDetay({anAwtis}) {
const router = useRouter() const router = useRouter()
const [esByografiOuve, meteEsByografiOuve] = useState(false) const [esByografiOuve, meteEsByografiOuve] = useState(false)
const {alias, biyografi, teks, foto} = anAwtis const {alias, biographie, paroles, photo} = anAwtis
const sortedTeks = sortTeks(teks) const sortedTeks = sortTeks(paroles.data)
const gwanBiyo = anAwtis.biyografi.length > 100 const gwanBiyo = biographie && biographie.length > 100
const biyo = gwanBiyo ? `${anAwtis.biyografi.slice(0, 100)}...` : anAwtis.biyografi const biyo = gwanBiyo ? `${biographie.slice(0, 100)}...` : biographie
const handleClick = () => { const handleClick = () => {
meteEsByografiOuve(true) meteEsByografiOuve(true)
@@ -45,7 +46,7 @@ export default function AwtisDetay({anAwtis}) {
</Box> </Box>
<Box sx={{justifyContent: 'center', display: 'flex', marginBottom: 2}}> <Box sx={{justifyContent: 'center', display: 'flex', marginBottom: 2}}>
<Avatar <Avatar
src={`${API_URL}${foto[0].url}`} src={`${photo?.data?.attributes?.url ? `${IMAGE_URL}${photo?.data?.attributes?.url}` : noImageUrl}`}
alt={`Photo ${alias}`} alt={`Photo ${alias}`}
sx={{width: 200, height: 200, border: `2px solid ${green[500]}`}} sx={{width: 200, height: 200, border: `2px solid ${green[500]}`}}
/> />
@@ -69,7 +70,7 @@ export default function AwtisDetay({anAwtis}) {
)} )}
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Box marginBottom={3}> <Box marginBottom={3}>
{teks.length > 1 ? ( {paroles.data.length > 1 ? (
<Accordion> <Accordion>
<AccordionSummary <AccordionSummary
expandIcon={<ExpandMoreIcon />} expandIcon={<ExpandMoreIcon />}
@@ -77,7 +78,7 @@ export default function AwtisDetay({anAwtis}) {
id='panel-teks-header' id='panel-teks-header'
> >
<Typography marginRight={2} textAlign='center' variant='body1' component='h2'><strong>Liste des textes</strong></Typography> <Typography marginRight={2} textAlign='center' variant='body1' component='h2'><strong>Liste des textes</strong></Typography>
<Chip color='primary' label={teks.length} size='small' variant='contained' /> <Chip color='primary' label={paroles.data.length} size='small' variant='contained' />
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<MizikLis teks={sortedTeks} /> <MizikLis teks={sortedTeks} />
@@ -87,7 +88,7 @@ export default function AwtisDetay({anAwtis}) {
<> <>
<Typography gutterBottom textAlign='center' variant='body1' component='h2'><strong>Texte</strong></Typography> <Typography gutterBottom textAlign='center' variant='body1' component='h2'><strong>Texte</strong></Typography>
<Paper> <Paper>
<MizikLis teks={teks} /> <MizikLis paroles={paroles.data} />
</Paper> </Paper>
</> </>
)} )}
@@ -102,8 +103,8 @@ export default function AwtisDetay({anAwtis}) {
{esByografiOuve && ( {esByografiOuve && (
<AwtisBiyografi <AwtisBiyografi
alias={alias} alias={alias}
teks={teks} paroles={paroles.data}
biyografi={biyografi} biographie={biographie}
esByografiOuve={esByografiOuve} esByografiOuve={esByografiOuve}
meteEsByografiOuve={meteEsByografiOuve} meteEsByografiOuve={meteEsByografiOuve}
/> />
+11 -9
View File
@@ -23,6 +23,7 @@ import AwtisBiyografi from './awtis-biyografi'
const PREFIX = 'awtis-kat' const PREFIX = 'awtis-kat'
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3001' const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3001'
const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const classes = { const classes = {
root: `${PREFIX}-root`, root: `${PREFIX}-root`,
@@ -54,12 +55,13 @@ const Kat = styled('div')((
} }
})) }))
export default function AwtisKat({anAwtis}) { const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible'
export default function AwtisKat({artiste}) {
const router = useRouter() const router = useRouter()
const [esByografiOuve, meteEsByografiOuve] = useState(false) const [esByografiOuve, meteEsByografiOuve] = useState(false)
const noImageUrl = 'https://place-hold.it/140x140?text=Pa%20ni%20imaj'
const {alias, biyografi, teks, foto, slug} = anAwtis const {alias, biographie, paroles, photo, slug} = artiste
const [expanded, setExpanded] = useState(false) const [expanded, setExpanded] = useState(false)
@@ -76,7 +78,7 @@ export default function AwtisKat({anAwtis}) {
className={classes.media} className={classes.media}
component='img' component='img'
alt={alias} alt={alias}
image={`${foto.length > 0 ? `${process.env.NEXT_PUBLIC_API_URL}${foto[0].url}` : noImageUrl}`} image={`${photo?.data?.attributes?.url ? `${IMAGE_URL}${photo?.data?.attributes?.url}` : noImageUrl}`}
title={alias} title={alias}
/> />
<CardContent> <CardContent>
@@ -84,7 +86,7 @@ export default function AwtisKat({anAwtis}) {
{alias} {alias}
</Typography> </Typography>
<Typography align='center' variant='body2' color='textSecondary' component='h5'> <Typography align='center' variant='body2' color='textSecondary' component='h5'>
{anAwtis.teks.length} tèks {`${paroles.data.length} ${paroles.data.length > 1 ? 'textes' : 'texte'}`}
</Typography> </Typography>
</CardContent> </CardContent>
</CardActionArea> </CardActionArea>
@@ -104,15 +106,15 @@ export default function AwtisKat({anAwtis}) {
</CardActions> </CardActions>
<Collapse unmountOnExit in={expanded} timeout='auto'> <Collapse unmountOnExit in={expanded} timeout='auto'>
<CardContent> <CardContent>
<MizikLis teks={teks} /> <MizikLis paroles={paroles.data} />
</CardContent> </CardContent>
</Collapse> </Collapse>
</Card> </Card>
{esByografiOuve && ( {esByografiOuve && (
<AwtisBiyografi <AwtisBiyografi
alias={alias} alias={alias}
teks={teks} paroles={paroles.data}
biyografi={biyografi} biographie={biographie}
esByografiOuve={esByografiOuve} esByografiOuve={esByografiOuve}
meteEsByografiOuve={meteEsByografiOuve} meteEsByografiOuve={meteEsByografiOuve}
/> />
@@ -123,5 +125,5 @@ export default function AwtisKat({anAwtis}) {
} }
AwtisKat.propTypes = { AwtisKat.propTypes = {
anAwtis: PropTypes.object.isRequired artiste: PropTypes.object.isRequired
} }
+6 -6
View File
@@ -37,13 +37,13 @@ const Root = styled('div')((
} }
})) }))
const sortTeks = teks => teks.sort((a, b) => b.id - a.id) const sortTeks = paroles => paroles.sort((a, b) => b.id - a.id)
export default function MizikBadjMeni({teks}) { export default function MizikBadjMeni({paroles}) {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const anchorRef = useRef(null) const anchorRef = useRef(null)
const router = useRouter() const router = useRouter()
const sortedTeks = sortTeks(teks) const sortedTeks = sortTeks(paroles)
const handleToggle = () => { const handleToggle = () => {
setOpen(previousOpen_ => !previousOpen_) setOpen(previousOpen_ => !previousOpen_)
@@ -90,7 +90,7 @@ export default function MizikBadjMeni({teks}) {
vertical: 'top', vertical: 'top',
horizontal: 'right' horizontal: 'right'
}} }}
badgeContent={teks.length} badgeContent={paroles.length}
color='primary' color='primary'
> >
<MenuBookIcon style={{fontSize: 30}} /> <MenuBookIcon style={{fontSize: 30}} />
@@ -105,7 +105,7 @@ export default function MizikBadjMeni({teks}) {
<Paper> <Paper>
<ClickAwayListener onClickAway={handleClose}> <ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id='menu-list-grow' onKeyDown={() => handleListKeyDown()}> <MenuList autoFocusItem={open} id='menu-list-grow' onKeyDown={() => handleListKeyDown()}>
{sortedTeks.map(t => <MenuItem key={t.id} onClick={() => handleClick(t.slug)}>{t.tit}</MenuItem>)} {sortedTeks.map(({id, attributes}) => <MenuItem key={id} onClick={() => handleClick(attributes.slug)}>{attributes.titre}</MenuItem>)}
</MenuList> </MenuList>
</ClickAwayListener> </ClickAwayListener>
</Paper> </Paper>
@@ -117,5 +117,5 @@ export default function MizikBadjMeni({teks}) {
} }
MizikBadjMeni.propTypes = { MizikBadjMeni.propTypes = {
teks: PropTypes.array.isRequired paroles: PropTypes.array.isRequired
} }
+11 -11
View File
@@ -27,7 +27,7 @@ const StyledList = styled(List)((
} }
})) }))
export default function MizikLis({meteEsMobilOuve, niAwtis, teks, slugTeksChwazi, meteSlugTeksChwazi}) { export default function MizikLis({meteEsMobilOuve, niAwtis, paroles, slugTeksChwazi, meteSlugTeksChwazi}) {
const router = useRouter() const router = useRouter()
const handleClick = slug => { const handleClick = slug => {
@@ -50,22 +50,22 @@ export default function MizikLis({meteEsMobilOuve, niAwtis, teks, slugTeksChwazi
return ( return (
<StyledList component='nav' className={classes.root} aria-label='mizik'> <StyledList component='nav' className={classes.root} aria-label='mizik'>
{teks.map(({slug, tit, awtis, published_at, okiMizikID, eksplisit}) => ( {paroles.map(({id, attributes}) => (
<ListItem <ListItem
key={slug} key={id}
button button
id={slug} id={attributes.slug}
selected={slugTeksChwazi === slug} selected={slugTeksChwazi === attributes.slug}
onClick={() => handleClick(slug)} onClick={() => handleClick(attributes.slug)}
> >
<ListItemText primary={tit} secondary={niAwtis ? new Intl.ListFormat('fr').format(awtis.map(({alias}) => alias)) : null} /> <ListItemText primary={attributes.titre} secondary={niAwtis ? new Intl.ListFormat('fr').format(attributes.artistes.data.map(({attributes}) => attributes.alias)) : null} />
{eksplisit && ( {attributes.explicite && (
<ExplicitIcon style={{marginRight: 5}} color='secondary' /> <ExplicitIcon style={{marginRight: 5}} color='secondary' />
)} )}
{okiMizikID && ( {attributes.okiMizikID && (
<LibraryMusicIcon style={{fontSize: 40}} color='primary' /> <LibraryMusicIcon style={{fontSize: 40}} color='primary' />
)} )}
{esBrandNew(published_at) && ( {esBrandNew(attributes.publishedAt) && (
<FiberNewOutlinedIcon style={{fontSize: 40}} color='primary' /> <FiberNewOutlinedIcon style={{fontSize: 40}} color='primary' />
)} )}
</ListItem> </ListItem>
@@ -77,7 +77,7 @@ export default function MizikLis({meteEsMobilOuve, niAwtis, teks, slugTeksChwazi
MizikLis.propTypes = { MizikLis.propTypes = {
meteEsMobilOuve: PropTypes.func, meteEsMobilOuve: PropTypes.func,
niAwtis: PropTypes.bool, niAwtis: PropTypes.bool,
teks: PropTypes.array.isRequired, paroles: PropTypes.array.isRequired,
slugTeksChwazi: PropTypes.string, slugTeksChwazi: PropTypes.string,
meteSlugTeksChwazi: PropTypes.func meteSlugTeksChwazi: PropTypes.func
} }
+26 -20
View File
@@ -11,26 +11,25 @@ import {
} from '@mui/material' } from '@mui/material'
import MuiAlert from '@mui/material/Alert' import MuiAlert from '@mui/material/Alert'
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337' const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337/api'
const Alert = forwardRef(function Alert(props, ref) { const Alert = forwardRef(function Alert(props, ref) {
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} /> return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
}) })
function EkriKomante({session, teks, meteEsKomanteOuve}) { function EkriKomante({session, paroleId, meteEsKomanteOuve}) {
const {jwt, user} = session const {jwt, user} = session
const {id} = teks
const [komante, meteKomante] = useState({kontni: ''}) const [komante, meteKomante] = useState({kontni: ''})
const [ere, meteEre] = useState('') const [ere, meteEre] = useState('')
const [sikse, meteSikse] = useState('') const [sikse, meteSikse] = useState('')
const [chaje, meteChaje] = useState(false) const [chaje, meteChaje] = useState(false)
const [esOuve, meteEsOuve] = useState(false) const [esOuve, meteEsOuve] = useState(false)
const handleClick = () => { const handleClick = async () => {
meteChaje(true) meteChaje(true)
const {kontni} = komante const {kontni} = komante
if (kontni === '') { if (kontni === '') {
meteEre({mesaj: 'Champ obligatoire'}) meteEre({error: {message: 'Champ obligatoire'}})
meteChaje(false) meteChaje(false)
return return
@@ -41,21 +40,28 @@ function EkriKomante({session, teks, meteEsKomanteOuve}) {
Authorization: `Bearer ${jwt}` Authorization: `Bearer ${jwt}`
} }
axios.post(`${API_URL}/komante`, { try {
kontni, await axios.post(`${API_URL}/commentaires`, {
teks: id, data: {
user: user.id contenu: kontni,
parole: paroleId,
user: {
id: user.id,
username: user.username,
email: user.email
},
datePublication: new Date()
}
}, { }, {
headers headers
}) })
.then(() => {
meteSikse('Commentaire envoyé avec succès. Il apparaîtra sur le site après validation.') meteSikse('Commentaire envoyé avec succès. Il apparaîtra sur le site après validation.')
meteChaje(false) meteChaje(false)
}) } catch (error) {
.catch(error => { meteEre(error?.response?.data)
meteEre(error)
meteChaje(false) meteChaje(false)
}) }
} }
const handleUpdate = useCallback(update => { const handleUpdate = useCallback(update => {
@@ -97,10 +103,10 @@ function EkriKomante({session, teks, meteEsKomanteOuve}) {
fullWidth fullWidth
multiline multiline
required required
helperText='Votre commentaire (obligatoire)' helperText='*Obligatoire. 500 caractères maximum'
style={{marginTop: '1em'}} style={{marginTop: '1em'}}
id='komante' id='komante'
label='Kòmantè' label='Commentaire'
value={komante.kontni} value={komante.kontni}
rows={8} rows={8}
variant='outlined' variant='outlined'
@@ -123,16 +129,16 @@ function EkriKomante({session, teks, meteEsKomanteOuve}) {
{chaje && <LinearProgress size={24} style={{width: '100%', marginBlock: '1em'}} />} {chaje && <LinearProgress size={24} style={{width: '100%', marginBlock: '1em'}} />}
</div> </div>
{sikse && ( {sikse && (
<Snackbar open={esOuve} autoHideDuration={3000} onClose={handleClose}> <Snackbar open={esOuve} autoHideDuration={10_000} onClose={handleClose}>
<Alert severity='success' onClose={handleClose}> <Alert severity='success' onClose={handleClose}>
<strong>{sikse}</strong> <strong>{sikse}</strong>
</Alert> </Alert>
</Snackbar> </Snackbar>
)} )}
{ere && ( {ere && (
<Snackbar open={esOuve} autoHideDuration={3000} onClose={handleClose}> <Snackbar open={esOuve} autoHideDuration={10_000} onClose={handleClose}>
<Alert severity='error' onClose={handleClose}> <Alert severity='error' onClose={handleClose}>
<strong>Une erreur sest produite</strong> : <i>{ere.message}</i> <strong>Une erreur sest produite</strong> : <i>{ere?.error?.message}</i>
</Alert> </Alert>
</Snackbar> </Snackbar>
)} )}
@@ -142,7 +148,7 @@ function EkriKomante({session, teks, meteEsKomanteOuve}) {
EkriKomante.propTypes = { EkriKomante.propTypes = {
session: PropTypes.object.isRequired, session: PropTypes.object.isRequired,
teks: PropTypes.object.isRequired, paroleId: PropTypes.number.isRequired,
meteEsKomanteOuve: PropTypes.func.isRequired meteEsKomanteOuve: PropTypes.func.isRequired
} }
+7 -7
View File
@@ -35,23 +35,23 @@ const StyledList = styled(List)((
} }
})) }))
export default function KomanteList({komante}) { export default function KomanteList({commentaires}) {
return ( return (
<StyledList className={classes.root}> <StyledList className={classes.root}>
{komante.map(({id, username, kontni, sentAt}) => ( {commentaires.map(({id, attributes}) => (
<div key={id}> <div key={id}>
<ListItemText <ListItemText
primary={ primary={
<Typography gutterBottom style={{fontWeight: 'bold'}} variant='body1'> <Typography gutterBottom style={{textDecoration: 'underline'}} variant='body1'>
{username} <small>{attributes.user.data.attributes.username}</small>
</Typography> </Typography>
} }
/> />
<ListItemText <ListItemText
primary={formatJsonString(kontni)} primary={formatJsonString(attributes.contenu)}
secondary={ secondary={
<Typography gutterBottom style={{marginBlock: 5, fontStyle: 'italic'}} variant='caption' display='block'> <Typography gutterBottom style={{marginBlock: 5, fontStyle: 'italic'}} variant='caption' display='block'>
{format(new Date(sentAt), 'Pp', {locale: fr})} {format(new Date(attributes.datePublication), 'Pp', {locale: fr})}
</Typography> </Typography>
} }
/> />
@@ -63,5 +63,5 @@ export default function KomanteList({komante}) {
} }
KomanteList.propTypes = { KomanteList.propTypes = {
komante: PropTypes.array.isRequired commentaires: PropTypes.array.isRequired
} }
+9 -8
View File
@@ -45,7 +45,7 @@ const Root = styled('div')((
const KomanteTooltip = Tooltip const KomanteTooltip = Tooltip
export default function VweKomante({komante, teks}) { export default function VweKomante({commentaires, parole, paroleId}) {
const [esOuve, meteEsOuve] = useState(false) const [esOuve, meteEsOuve] = useState(false)
const [esKoneksyonOuve, meteEsKoneksyonOuve] = useState(false) const [esKoneksyonOuve, meteEsKoneksyonOuve] = useState(false)
const [esKomenteOuve, meteEsKomanteOuve] = useState(false) const [esKomenteOuve, meteEsKomanteOuve] = useState(false)
@@ -88,7 +88,7 @@ export default function VweKomante({komante, teks}) {
size='large' size='large'
onClick={handleClick} onClick={handleClick}
> >
<Badge badgeContent={komante.length} color='primary'> <Badge badgeContent={commentaires.length} color='primary'>
<CommentIcon /> <CommentIcon />
</Badge> </Badge>
</IconButton> </IconButton>
@@ -109,8 +109,8 @@ export default function VweKomante({komante, teks}) {
tabIndex={-1} tabIndex={-1}
component='div' component='div'
> >
{komante.length > 0 ? ( {commentaires.length > 0 ? (
<KomanteList komante={komante} /> <KomanteList commentaires={commentaires} />
) : ( ) : (
<Typography component='div' align='center'> <Typography component='div' align='center'>
Aucun commentaire Aucun commentaire
@@ -140,7 +140,7 @@ export default function VweKomante({komante, teks}) {
)} )}
{session && session.user && esKomenteOuve && ( {session && session.user && esKomenteOuve && (
<> <>
<EkriKomante session={session} teks={teks} meteEsKomanteOuve={meteEsKomanteOuve} /> <EkriKomante session={session} parole={parole} paroleId={paroleId} meteEsKomanteOuve={meteEsKomanteOuve} />
<Button fullWidth style={{marginBottom: 10}} color='primary' onClick={() => meteEsKomanteOuve(false)}> <Button fullWidth style={{marginBottom: 10}} color='primary' onClick={() => meteEsKomanteOuve(false)}>
Fermer Fermer
</Button> </Button>
@@ -152,10 +152,11 @@ export default function VweKomante({komante, teks}) {
} }
VweKomante.defaultProps = { VweKomante.defaultProps = {
komante: null commentaires: null
} }
VweKomante.propTypes = { VweKomante.propTypes = {
komante: PropTypes.array, commentaires: PropTypes.array,
teks: PropTypes.object.isRequired parole: PropTypes.object.isRequired,
paroleId: PropTypes.number.isRequired
} }
+2 -7
View File
@@ -1,6 +1,5 @@
import {useState} from 'react' import {useState} from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import axios from 'axios'
import Button from '@mui/material/Button' import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField' import TextField from '@mui/material/TextField'
import Dialog from '@mui/material/Dialog' import Dialog from '@mui/material/Dialog'
@@ -10,9 +9,7 @@ import DialogContentText from '@mui/material/DialogContentText'
import DialogTitle from '@mui/material/DialogTitle' import DialogTitle from '@mui/material/DialogTitle'
import {validateEmail} from '../../lib/utils/emails' import {validateEmail} from '../../lib/utils/emails'
import {jwennUserEpiEmail} from '../../lib/oki-api' import {jwennUserEpiEmail, passwordRequest} from '../../lib/oki-api'
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
export default function ResetDialog({lyen, title, activation, content, open, setOpen, setLoading, setError, setSuccess}) { export default function ResetDialog({lyen, title, activation, content, open, setOpen, setLoading, setError, setSuccess}) {
const [email, setEmail] = useState('') const [email, setEmail] = useState('')
@@ -20,9 +17,7 @@ export default function ResetDialog({lyen, title, activation, content, open, set
const forgotPasswordRequest = async () => { const forgotPasswordRequest = async () => {
setLoading(true) setLoading(true)
try { try {
await axios.post(`${API_URL}/auth/${lyen}`, { await passwordRequest(lyen, email)
email
})
if (activation) { if (activation) {
const user = await jwennUserEpiEmail(email) const user = await jwennUserEpiEmail(email)
+5 -5
View File
@@ -67,7 +67,7 @@ function AjouteTradiksyon({showSwitch, disableSwitch, tradiksyonOtomatik, setTra
return ( return (
<> <>
{showSwitch && ( {showSwitch && (
<OtomatikSwitch tradiksyonOtomatik={tradiksyonOtomatik} setTradiksyonOtomatik={setTradiksyonOtomatik} disabled={!chwaLang.includes('fr') || disableSwitch} /> <OtomatikSwitch tradiksyonOtomatik={tradiksyonOtomatik} setTradiksyonOtomatik={setTradiksyonOtomatik} disabled={disableSwitch} />
)} )}
<Root style={{textAlign: 'center', marginTop: 20}}> <Root style={{textAlign: 'center', marginTop: 20}}>
<Button <Button
@@ -101,28 +101,28 @@ function AjouteTradiksyon({showSwitch, disableSwitch, tradiksyonOtomatik, setTra
root: classes.root root: classes.root
}} }}
onClick={handleClose} onClick={handleClose}
>🇬🇧 English</StyledMenuItem> >🇬🇧 Anglais</StyledMenuItem>
<StyledMenuItem <StyledMenuItem
id='es' id='es'
classes={{ classes={{
root: classes.root root: classes.root
}} }}
onClick={handleClose} onClick={handleClose}
>🇪🇸 Español</StyledMenuItem> >🇪🇸 Espagnol</StyledMenuItem>
<StyledMenuItem <StyledMenuItem
id='de' id='de'
classes={{ classes={{
root: classes.root root: classes.root
}} }}
onClick={handleClose} onClick={handleClose}
>🇩🇪 Deutsch</StyledMenuItem> >🇩🇪 Allemand</StyledMenuItem>
<StyledMenuItem <StyledMenuItem
id='it' id='it'
classes={{ classes={{
root: classes.root root: classes.root
}} }}
onClick={handleClose} onClick={handleClose}
>🇮🇹 Italiano</StyledMenuItem> >🇮🇹 Italien</StyledMenuItem>
</StyledMenu> </StyledMenu>
</Root> </Root>
</> </>
+7 -6
View File
@@ -15,7 +15,7 @@ import CircularProgress from '@mui/material/CircularProgress'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import AudiotrackIcon from '@mui/icons-material/Audiotrack' import AudiotrackIcon from '@mui/icons-material/Audiotrack'
import {jwennTeksEpiUserId} from '../../lib/oki-api' import {jwennUserEpiToken} from '../../lib/oki-api'
function Chwa(props) { function Chwa(props) {
const {onClose, teksLis, selectedTeks, loading, open} = props const {onClose, teksLis, selectedTeks, loading, open} = props
@@ -37,14 +37,14 @@ function Chwa(props) {
</Container> </Container>
) : ( ) : (
<List sx={{pt: 0}}> <List sx={{pt: 0}}>
{teksLis.length > 0 ? teksLis.map(({id, tit, awtis}) => ( {teksLis.length > 0 ? teksLis.map(({id, titre, artistes}) => (
<ListItem key={id} button onClick={() => handleListItemClick(id)}> <ListItem key={id} button onClick={() => handleListItemClick(id)}>
<ListItemAvatar> <ListItemAvatar>
<Avatar sx={{bgcolor: green[100], color: green[600]}}> <Avatar sx={{bgcolor: green[100], color: green[600]}}>
<AudiotrackIcon /> <AudiotrackIcon />
</Avatar> </Avatar>
</ListItemAvatar> </ListItemAvatar>
<ListItemText primary={`${new Intl.ListFormat('fr').format(awtis.map(({alias}) => alias))} - ${tit}`} /> <ListItemText primary={`${new Intl.ListFormat('fr').format(artistes.map(({alias}) => alias))} - ${titre}`} />
</ListItem> </ListItem>
)) : ( )) : (
<Typography sx={{textAlign: 'center'}} variant='button' component='div'>Aucun texte</Typography> <Typography sx={{textAlign: 'center'}} variant='button' component='div'>Aucun texte</Typography>
@@ -70,7 +70,6 @@ Chwa.propTypes = {
export default function ChwaTeks({selectedTeks, setSelectedTeks}) { export default function ChwaTeks({selectedTeks, setSelectedTeks}) {
const {data: session} = useSession() const {data: session} = useSession()
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const {user} = session
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [teksLis, setTeksLis] = useState([]) const [teksLis, setTeksLis] = useState([])
@@ -78,9 +77,11 @@ export default function ChwaTeks({selectedTeks, setSelectedTeks}) {
setOpen(true) setOpen(true)
setLoading(true) setLoading(true)
const jwennTeks = await jwennTeksEpiUserId(user.id) const user = await jwennUserEpiToken(session?.jwt)
const {paroles} = user
const parolesList = paroles && paroles.length > 0 ? paroles : []
setTeksLis(jwennTeks) setTeksLis(parolesList)
setLoading(false) setLoading(false)
} }
+75 -70
View File
@@ -23,6 +23,8 @@ import {
import MuiAlert from '@mui/material/Alert' import MuiAlert from '@mui/material/Alert'
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff' import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
import {jwennAnTeks} from '../../lib/oki-api'
import AjouteTradiksyon from './ajoute-tradiksyon' import AjouteTradiksyon from './ajoute-tradiksyon'
const PREFIX = 'EkriTeks' const PREFIX = 'EkriTeks'
@@ -108,7 +110,7 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
setError('') setError('')
} }
const handleClick = () => { const handleClick = async () => {
setLoading(true) setLoading(true)
const {awtis, tit, transkripsyon} = teksEkri const {awtis, tit, transkripsyon} = teksEkri
const {fr, en, es, de, it} = tradiksyon const {fr, en, es, de, it} = tradiksyon
@@ -126,81 +128,85 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
} }
if (currentTeksId) { if (currentTeksId) {
axios.get(`${API_URL}/teks/${currentTeksId}?_publicationState=preview&_where[published_at_null]=true`) try {
.then(awtisResponse => { const teks = await jwennAnTeks(currentTeksId, jwt)
if (awtisResponse.data.user.id !== user.id) { const teksResponse = await axios.put(`${API_URL}/paroles/${currentTeksId}`, {
setLoading(false) data: {
return setError({message: 'Opération non autorisée'}) id: teks.id,
} titre: tit,
transcription: transkripsyon,
axios.put(`${API_URL}/teks/${currentTeksId}`, { traductions: {
tit,
transkripsyon,
tradiksyon: {
francais: fr === '' ? null : fr, francais: fr === '' ? null : fr,
english: en === '' ? null : en, anglais: en === '' ? null : en,
espagnol: es === '' ? null : es, espagnol: es === '' ? null : es,
deutsch: de === '' ? null : de, allemand: de === '' ? null : de,
italiano: it === '' ? null : it italien: it === '' ? null : it
}, },
user, user: {
awtis: awtisResponse.data.awtis.map(id => id), id: user.id,
tradiksyonOtomatik username: user.username,
email: user.email
},
artistes: teks.artistes.map(({id}) => id),
traductionAuto: tradiksyonOtomatik
}
}, { }, {
headers headers
}) })
.then(teksResponse => {
const {data} = teksResponse const {data} = teksResponse
setSuccess(`Le texte "${data.tit}" a été modifié avec succès. Il apparaîtra sur le site après validation.`) setSuccess(`Le texte "${data.tit}" a été modifié avec succès. Il apparaîtra sur le site après validation.`)
setLoading(false) setLoading(false)
}) } catch (error) {
.catch(error => { setError(error?.response?.data)
setError(error)
setLoading(false) setLoading(false)
}) }
})
.catch(error => {
setError(error)
setLoading(false)
})
} else { } else {
axios.post(`${API_URL}/awtis`, { try {
const artiste = await axios.post(`${API_URL}/artistes`, {
data: {
alias: awtis, alias: awtis,
user user: {
id: user.id,
username: user.username,
email: user.email
}
}
}, { }, {
headers headers
}) })
.then(awtisResponse => {
axios.post(`${API_URL}/teks`, { const parole = await axios.post(`${API_URL}/paroles`, {
tit, data: {
transkripsyon, titre: tit,
tradiksyon: { transcription: transkripsyon,
traductions: {
francais: fr === '' ? null : fr, francais: fr === '' ? null : fr,
english: en === '' ? null : en, anglais: en === '' ? null : en,
espagnol: es === '' ? null : es, espagnol: es === '' ? null : es,
deutsch: de === '' ? null : de, allemand: de === '' ? null : de,
italiano: it === '' ? null : it italien: it === '' ? null : it
}, },
user, user: {
awtis: [awtisResponse.data.id], id: user.id,
tradiksyonOtomatik username: user.username,
email: user.email
},
artistes: [artiste.data.id],
traductionAuto: tradiksyonOtomatik
}
}, { }, {
headers headers
}) })
.then(teksResponse => {
const {data} = teksResponse const {data} = parole
setSuccess(`Le texte "${data.tit}" a été soumis avec succès. Il apparaîtra sur le site après validation.`)
setSuccess(`Le texte "${data.titre}" a été soumis avec succès. Il apparaîtra sur le site après validation.`)
setLoading(false) setLoading(false)
}) } catch (error) {
.catch(error => { setError(error?.response?.data)
setError(error)
setLoading(false) setLoading(false)
}) }
})
.catch(error => {
setError(error)
setLoading(false)
})
} }
} }
@@ -230,39 +236,38 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
setTradiksyonOtomatik(false) setTradiksyonOtomatik(false)
setCurrentTeksId(selectedTeks.id) setCurrentTeksId(selectedTeks.id)
setTeksEkri({ setTeksEkri({
awtis: new Intl.ListFormat('fr').format(selectedTeks.awtis.map(({alias}) => alias)), awtis: new Intl.ListFormat('fr').format(selectedTeks.artistes.map(({alias}) => alias)),
tit: selectedTeks.tit, tit: selectedTeks.titre,
transkripsyon: selectedTeks.transkripsyon transkripsyon: selectedTeks.transcription
}) })
setTradiksyon({ setTradiksyon({
fr: selectedTeks.tradiksyon.francais || '', fr: selectedTeks?.traductions?.francais || '',
en: selectedTeks.tradiksyon.english || '', en: selectedTeks?.traductions?.anglais || '',
es: selectedTeks.tradiksyon.espagnol || '', es: selectedTeks?.traductions?.espagnol || '',
de: selectedTeks.tradiksyon.deutsch || '', de: selectedTeks?.traductions?.allemand || '',
it: selectedTeks.tradiksyon.italiano || '' it: selectedTeks?.traductions?.italien || ''
}) })
const jennLangId = () => { const jennLangId = () => {
const ids = [] const ids = []
const {francais, english, espagnol, deutsch, italiano} = selectedTeks.tradiksyon
if (francais) { if (selectedTeks?.traductions?.francais) {
ids.push('fr') ids.push('fr')
} }
if (english) { if (selectedTeks?.traductions?.anglais) {
ids.push('en') ids.push('en')
} }
if (espagnol) { if (selectedTeks?.traductions?.espagnol) {
ids.push('es') ids.push('es')
} }
if (deutsch) { if (selectedTeks?.traductions?.allemand) {
ids.push('de') ids.push('de')
} }
if (italiano) { if (selectedTeks?.traductions?.italien) {
ids.push('it') ids.push('it')
} }
@@ -369,7 +374,7 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
</form> </form>
<AjouteTradiksyon <AjouteTradiksyon
showSwitch={Boolean(canAutoTranslate) && Boolean(!currentTeksId)} showSwitch={Boolean(canAutoTranslate) && Boolean(!currentTeksId)}
disableSwitch={tradiksyon.fr === ''} disableSwitch={tradiksyon.fr === '' || tradiksyon.en !== '' || tradiksyon.es !== '' || tradiksyon.de !== '' || tradiksyon.it !== ''}
tradiksyonOtomatik={tradiksyonOtomatik} tradiksyonOtomatik={tradiksyonOtomatik}
setTradiksyonOtomatik={setTradiksyonOtomatik} setTradiksyonOtomatik={setTradiksyonOtomatik}
chwaLang={kiChawLang} chwaLang={kiChawLang}
@@ -410,9 +415,9 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
</Snackbar> </Snackbar>
)} )}
{error && ( {error && (
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}> <Snackbar open={open} autoHideDuration={10_000} onClose={handleClose}>
<Alert severity='error' onClose={handleClose}> <Alert severity='error' onClose={handleClose}>
<strong>Une erreur sest produite</strong> : <i>{error.message}</i> <strong>Une erreur sest produite</strong> : <i>{error?.error?.message}</i>
</Alert> </Alert>
</Snackbar> </Snackbar>
)} )}
+5 -1
View File
@@ -10,7 +10,11 @@ export default function OtomatikSwitch({tradiksyonOtomatik, setTradiksyonOtomati
return ( return (
<FormGroup sx={{marginTop: 1}}> <FormGroup sx={{marginTop: 1}}>
<FormControlLabel control={<Switch checked={tradiksyonOtomatik && !disabled} onChange={handleChange} />} disabled={disabled} label='Traduction automatique après validation (français vers les autres langues)' /> <FormControlLabel
control={<Switch checked={tradiksyonOtomatik && !disabled} onChange={handleChange} />}
disabled={disabled}
label='Traduction du français vers les autres langues (remplir uniquement la traduction française)'
/>
</FormGroup> </FormGroup>
) )
} }
+1 -1
View File
@@ -30,7 +30,7 @@ export default function DenyeTeks({denyeTeks}) {
</Container> </Container>
)} )}
<Grid container spacing={3}> <Grid container spacing={3}>
{denyeTeks.map(t => <TeksKat key={t.id} teks={t} />)} {denyeTeks.map(t => <TeksKat key={t.id} parole={t} />)}
</Grid> </Grid>
</Container> </Container>
</Root> </Root>
+13 -13
View File
@@ -44,15 +44,15 @@ const Root = styled('div')((
} }
})) }))
const getMizikFiltered = (teks, filter) => { const getMizikFiltered = (paroles, filter) => {
if (teks) { if (paroles) {
const filteredTitre = teks.filter(({tit}) => { const filteredTitre = paroles.filter(({attributes}) => {
const deburredTit = deburr(tit) const deburredTit = deburr(attributes.titre)
return deburredTit.toLowerCase().includes(deburr(filter.toLowerCase())) return deburredTit.toLowerCase().includes(deburr(filter.toLowerCase()))
}) })
const filteredAlias = teks.filter(({awtis}) => { const filteredAlias = paroles.filter(({attributes}) => {
const aliasLis = awtis.map(({alias}) => deburr(alias)).join(', ') const aliasLis = attributes.artistes.data.map(({attributes}) => deburr(attributes.alias)).join(', ')
return aliasLis.toLowerCase().includes(deburr(filter.toLowerCase())) return aliasLis.toLowerCase().includes(deburr(filter.toLowerCase()))
}) })
@@ -60,13 +60,13 @@ const getMizikFiltered = (teks, filter) => {
} }
} }
export default function DrawerBar({meteEsMobilOuve, teks, anTeks}) { export default function DrawerBar({meteEsMobilOuve, paroles, parole}) {
const slug = anTeks ? anTeks.slug : null const slug = parole ? parole.slug : null
const [search, setSearch] = useState('') const [search, setSearch] = useState('')
const [slugTeksChwazi, meteSlugTeksChwazi] = useState(slug) const [slugTeksChwazi, meteSlugTeksChwazi] = useState(slug)
const mizikFiltered = getMizikFiltered(teks, search) const mizikFiltered = getMizikFiltered(paroles, search)
const handleSearch = event => { const handleSearch = event => {
event.preventDefault() event.preventDefault()
@@ -94,7 +94,7 @@ export default function DrawerBar({meteEsMobilOuve, teks, anTeks}) {
<MizikLis <MizikLis
niAwtis niAwtis
meteEsMobilOuve={meteEsMobilOuve} meteEsMobilOuve={meteEsMobilOuve}
teks={mizikFiltered} paroles={mizikFiltered}
slugTeksChwazi={slugTeksChwazi} slugTeksChwazi={slugTeksChwazi}
meteSlugTeksChwazi={meteSlugTeksChwazi} meteSlugTeksChwazi={meteSlugTeksChwazi}
/> />
@@ -105,11 +105,11 @@ export default function DrawerBar({meteEsMobilOuve, teks, anTeks}) {
DrawerBar.propTypes = { DrawerBar.propTypes = {
meteEsMobilOuve: PropTypes.func, meteEsMobilOuve: PropTypes.func,
teks: PropTypes.array.isRequired, paroles: PropTypes.array.isRequired,
anTeks: PropTypes.object parole: PropTypes.object
} }
DrawerBar.defaultProps = { DrawerBar.defaultProps = {
meteEsMobilOuve: null, meteEsMobilOuve: null,
anTeks: null parole: null
} }
+18 -18
View File
@@ -17,9 +17,9 @@ const kouteyAchteyIcons = {
Soundcloud: <Soundcloud /> Soundcloud: <Soundcloud />
} }
function RannIframe({boutik, url, isMobile}) { function RannIframe({plateforme, url, isMobile}) {
let src = '' let src = ''
switch (boutik) { switch (plateforme) {
case 'Tidal': { case 'Tidal': {
const trackArray = url.split('/') const trackArray = url.split('/')
const trackId = trackArray[trackArray.length - 1] const trackId = trackArray[trackArray.length - 1]
@@ -54,7 +54,7 @@ function RannIframe({boutik, url, isMobile}) {
return ( return (
<div style={{marginTop: 5}}> <div style={{marginTop: 5}}>
{boutik === 'Tidal' && ( {plateforme === 'Tidal' && (
<iframe <iframe
src={src} src={src}
allowFullScreen='allowfullscreen' allowFullScreen='allowfullscreen'
@@ -64,7 +64,7 @@ function RannIframe({boutik, url, isMobile}) {
/> />
)} )}
{boutik === 'Deezer' && ( {plateforme === 'Deezer' && (
<iframe <iframe
title='deezer-widget' title='deezer-widget'
frameBorder='0' frameBorder='0'
@@ -74,7 +74,7 @@ function RannIframe({boutik, url, isMobile}) {
/> />
)} )}
{boutik === 'Spotify' && ( {plateforme === 'Spotify' && (
<iframe <iframe
src={src} src={src}
width={`${isMobile ? '100%' : '50%'}`} width={`${isMobile ? '100%' : '50%'}`}
@@ -85,7 +85,7 @@ function RannIframe({boutik, url, isMobile}) {
/> />
)} )}
{boutik === 'Soundcloud' && ( {plateforme === 'Soundcloud' && (
<iframe <iframe
src={src} src={src}
width={`${isMobile ? '100%' : '50%'}`} width={`${isMobile ? '100%' : '50%'}`}
@@ -99,18 +99,18 @@ function RannIframe({boutik, url, isMobile}) {
) )
} }
function EntegreMizik({anTeks, isMobile}) { function EntegreMizik({parole, isMobile}) {
const [chwaMizik, meteChwaMizik] = useState(null) const [chwaMizik, meteChwaMizik] = useState(null)
const router = useRouter() const router = useRouter()
const {kouteyAchtey, slug, okiMizikID} = anTeks const {streamAudio, slug, okiMizikID} = parole
const filteredKouteyAchtey = kouteyAchtey.filter(({boutik}) => boutik === 'Tidal' || boutik === 'Spotify' || boutik === 'Deezer' || boutik === 'Soundcloud') const filteredKouteyAchtey = streamAudio.filter(({plateforme}) => plateforme === 'Tidal' || plateforme === 'Spotify' || plateforme === 'Deezer' || plateforme === 'Soundcloud')
const handleClick = (boutik, url) => { const handleClick = (plateforme, url) => {
if (chwaMizik && chwaMizik.boutik === boutik) { if (chwaMizik && chwaMizik.plateforme === plateforme) {
return meteChwaMizik(null) return meteChwaMizik(null)
} }
meteChwaMizik({boutik, url}) meteChwaMizik({plateforme, url})
} }
useEffect(() => { useEffect(() => {
@@ -121,31 +121,31 @@ function EntegreMizik({anTeks, isMobile}) {
return ( return (
<Box align='center'> <Box align='center'>
{!okiMizikID && filteredKouteyAchtey.map(({id, boutik, url}) => ( {!okiMizikID && filteredKouteyAchtey.map(({id, plateforme, url}) => (
<IconButton <IconButton
key={id} key={id}
aria-label='player' aria-label='player'
size='large' size='large'
onClick={() => handleClick(boutik, url)} onClick={() => handleClick(plateforme, url)}
> >
{kouteyAchteyIcons[boutik]} {kouteyAchteyIcons[plateforme]}
</IconButton> </IconButton>
))} ))}
{chwaMizik && ( {chwaMizik && (
<RannIframe boutik={chwaMizik.boutik} url={chwaMizik.url} isMobile={isMobile} /> <RannIframe plateforme={chwaMizik.plateforme} url={chwaMizik.url} isMobile={isMobile} />
)} )}
</Box> </Box>
) )
} }
EntegreMizik.propTypes = { EntegreMizik.propTypes = {
anTeks: PropTypes.object.isRequired, parole: PropTypes.object.isRequired,
isMobile: PropTypes.bool.isRequired isMobile: PropTypes.bool.isRequired
} }
RannIframe.propTypes = { RannIframe.propTypes = {
boutik: PropTypes.string.isRequired, plateforme: PropTypes.string.isRequired,
url: PropTypes.string.isRequired, url: PropTypes.string.isRequired,
isMobile: PropTypes.bool.isRequired isMobile: PropTypes.bool.isRequired
} }
+10 -10
View File
@@ -14,7 +14,7 @@ import Image from 'next/image'
import {grey} from '@mui/material/colors' import {grey} from '@mui/material/colors'
import {Link} from '@mui/material' import {Link} from '@mui/material'
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337' const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const Widget = styled('div')(({theme}) => ({ const Widget = styled('div')(({theme}) => ({
padding: 16, padding: 16,
@@ -49,7 +49,7 @@ const TinyText = styled(Typography)({
letterSpacing: 0.2, letterSpacing: 0.2,
}) })
export default function Lekte({audio, url, teks}) { export default function Lekte({audio, url, parole}) {
const audioRef = useRef(new Audio(audio)) const audioRef = useRef(new Audio(audio))
const intervalRef = useRef() const intervalRef = useRef()
const isReady = useRef(false) const isReady = useRef(false)
@@ -58,7 +58,7 @@ export default function Lekte({audio, url, teks}) {
const [position, setPosition] = useState(0) const [position, setPosition] = useState(0)
const [volume, setVolume] = useState(100) const [volume, setVolume] = useState(100)
const [isPlaying, setIsPlaying] = useState(false) const [isPlaying, setIsPlaying] = useState(false)
const awtis = teks.awtis.map(({alias}) => alias) const awtis = parole.artistes.data.map(({attributes}) => attributes.alias)
function formatDuration(value) { function formatDuration(value) {
const minute = Math.floor(value / 60) const minute = Math.floor(value / 60)
@@ -139,10 +139,10 @@ export default function Lekte({audio, url, teks}) {
<Box sx={{display: 'flex', alignItems: 'center'}}> <Box sx={{display: 'flex', alignItems: 'center'}}>
<CoverImage> <CoverImage>
<Image <Image
alt={teks.tit} alt={parole.titre}
src={teks?.kouveti?.formats?.thumbnail ? `${apiUrl}${teks.kouveti.formats.thumbnail.url}` : '/oki-logo-192x192.png'} src={parole?.couverture?.data?.attributes?.formats?.thumbnail ? `${IMAGE_URL}${parole.couverture.data.attributes.formats.thumbnail.url}` : '/oki-logo-192x192.png'}
width={teks?.kouveti?.formats?.thumbnail ? teks.kouveti.formats.thumbnail.width : 192} width={parole?.kouveti?.data?.attributes?.formats?.thumbnail ? parole.couverture.data.attributes.formats.thumbnail.width : 192}
height={teks?.kouveti?.formats?.thumbnail ? teks.kouveti.formats.thumbnail.height : 192} height={parole?.kouveti?.data?.attributes?.formats?.thumbnail ? parole.couverture.data.attributes.formats.thumbnail.height : 192}
/> />
</CoverImage> </CoverImage>
<Box sx={{ml: 1.5, minWidth: 0}}> <Box sx={{ml: 1.5, minWidth: 0}}>
@@ -151,11 +151,11 @@ export default function Lekte({audio, url, teks}) {
</Typography> </Typography>
<Typography> <Typography>
<Link underline='hover' sx={{cursor: 'pointer'}} target='_blank' rel='noreferrer' href={url}> <Link underline='hover' sx={{cursor: 'pointer'}} target='_blank' rel='noreferrer' href={url}>
<strong>{teks.tit}</strong> <strong>{parole.titre}</strong>
</Link> </Link>
</Typography> </Typography>
<Typography variant='caption'> <Typography variant='caption'>
<i>{teks.lanne}</i> <i>{parole.annee}</i>
</Typography> </Typography>
</Box> </Box>
</Box> </Box>
@@ -263,5 +263,5 @@ export default function Lekte({audio, url, teks}) {
Lekte.propTypes = { Lekte.propTypes = {
audio: PropTypes.string.isRequired, audio: PropTypes.string.isRequired,
url: PropTypes.string.isRequired, url: PropTypes.string.isRequired,
teks: PropTypes.object.isRequired parole: PropTypes.object.isRequired
} }
+3 -3
View File
@@ -11,18 +11,18 @@ const DinamikLekte = dynamic(
{ssr: false, loading: () => <CircularProgress sx={{color: '#29d'}} />} {ssr: false, loading: () => <CircularProgress sx={{color: '#29d'}} />}
) )
export default function OkiMizik({id, teks}) { export default function OkiMizik({id, parole}) {
const mizikStreamUrl = `${MIZIK_URL}/rest/stream?u=${MIZIK_API_USER}&p=${MIZIK_API_PASSWORD}&id=${id}` const mizikStreamUrl = `${MIZIK_URL}/rest/stream?u=${MIZIK_API_USER}&p=${MIZIK_API_PASSWORD}&id=${id}`
const detailsUrl = `${MIZIK_URL}/library/tracks/${id}` const detailsUrl = `${MIZIK_URL}/library/tracks/${id}`
return ( return (
<Box style={{marginTop: '0.3em', display: 'flex', flexDirection: 'column', alignItems: 'center'}}> <Box style={{marginTop: '0.3em', display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
<DinamikLekte audio={mizikStreamUrl} url={detailsUrl} teks={teks} /> <DinamikLekte audio={mizikStreamUrl} url={detailsUrl} parole={parole} />
</Box> </Box>
) )
} }
OkiMizik.propTypes = { OkiMizik.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
teks: PropTypes.object.isRequired parole: PropTypes.object.isRequired
} }
+5 -5
View File
@@ -43,15 +43,15 @@ const actions = [
{icon: <FileCopyIcon />, name: 'Copier le lien', code: 'copy'} {icon: <FileCopyIcon />, name: 'Copier le lien', code: 'copy'}
] ]
export default function Pataje({teks, setError, setSuccess}) { export default function Pataje({parole, setError, setSuccess}) {
const {tit, awtis, slug} = teks const {titre, artistes, slug} = parole
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const patajeUrl = `${SITE_URL}/paroles/${slug}` const patajeUrl = `${SITE_URL}/paroles/${slug}`
const alias = awtis.map(({alias}) => alias) const alias = artistes.data.map(({attributes}) => attributes.alias)
const renderAwtis = new Intl.ListFormat('fr').format(alias) const renderAwtis = new Intl.ListFormat('fr').format(alias)
const text = teks.user || teks.userAdmin ? `${renderAwtis} - ${tit} (Paroles et Traductions) - (texte soumis par ${teks?.user?.username || teks.userAdmin})` : `${renderAwtis} - ${tit} (Paroles et Traductions)` const text = parole.user || parole.userAdmin ? `${renderAwtis} - ${titre} (Paroles et Traductions) - (texte soumis par ${parole?.user?.username || parole.userAdmin})` : `${renderAwtis} - ${parole} (Paroles et Traductions)`
const handleClose = () => { const handleClose = () => {
setOpen(false) setOpen(false)
@@ -123,7 +123,7 @@ export default function Pataje({teks, setError, setSuccess}) {
} }
Pataje.propTypes = { Pataje.propTypes = {
teks: PropTypes.object.isRequired, parole: PropTypes.object.isRequired,
setError: PropTypes.func.isRequired, setError: PropTypes.func.isRequired,
setSuccess: PropTypes.func.isRequired setSuccess: PropTypes.func.isRequired
} }
+19 -16
View File
@@ -117,7 +117,7 @@ const Root = styled('div')((
const drawerWidth = 240 const drawerWidth = 240
export default function TeksDrawer({teks, anTeks, komante, denyeTeks}) { export default function TeksDrawer({paroles, parole, paroleId, commentaires, denyeTeks}) {
const theme = useTheme() const theme = useTheme()
const [esMobilOuve, meteEsMobilOuve] = useState(false) const [esMobilOuve, meteEsMobilOuve] = useState(false)
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
@@ -161,21 +161,21 @@ export default function TeksDrawer({teks, anTeks, komante, denyeTeks}) {
> >
<MenuIcon /> <MenuIcon />
</IconButton> </IconButton>
{anTeks ? ( {parole ? (
<> <>
<Link passHref href='/paroles'> <Link passHref href='/paroles'>
<IconButton aria-label='return' size='medium'> <IconButton aria-label='return' size='medium'>
<KeyboardBackspaceIcon style={{fontSize: '1.5em'}} /> <KeyboardBackspaceIcon style={{fontSize: '1.5em'}} />
</IconButton> </IconButton>
</Link> </Link>
{anTeks.lyen && anTeks.lyen.length > 0 && ( {parole.streamVideo && parole.streamVideo.length > 0 && (
<div className={classes.vwe}> <div className={classes.vwe}>
<VweKouteAchte niVideyo anTeks={anTeks} /> <VweKouteAchte niVideyo parole={parole} />
</div> </div>
)} )}
{anTeks.kouteyAchtey && anTeks.kouteyAchtey.length > 0 && ( {parole.streamVideo && parole.streamVideo.length > 0 && (
<div className={classes.koute}> <div className={classes.koute}>
<VweKouteAchte niOdyo anTeks={anTeks} /> <VweKouteAchte niOdyo parole={parole} />
</div> </div>
)} )}
</> </>
@@ -201,7 +201,7 @@ export default function TeksDrawer({teks, anTeks, komante, denyeTeks}) {
}} }}
onClose={handleDrawerToggle} onClose={handleDrawerToggle}
> >
<DrawerBar meteEsMobilOuve={meteEsMobilOuve} teks={teks} anTeks={anTeks} /> <DrawerBar meteEsMobilOuve={meteEsMobilOuve} paroles={paroles} parole={parole} />
</Drawer> </Drawer>
</Hidden> </Hidden>
<Hidden smDown implementation='css'> <Hidden smDown implementation='css'>
@@ -212,15 +212,16 @@ export default function TeksDrawer({teks, anTeks, komante, denyeTeks}) {
}} }}
variant='permanent' variant='permanent'
> >
<DrawerBar teks={teks} anTeks={anTeks} /> <DrawerBar paroles={paroles} parole={parole} />
</Drawer> </Drawer>
</Hidden> </Hidden>
</nav> </nav>
<main className={classes.content}> <main className={classes.content}>
{anTeks ? ( {parole ? (
<Teks <Teks
anTeks={anTeks} parole={parole}
komante={komante} paroleId={paroleId}
commentaires={commentaires}
open={open} open={open}
success={success} success={success}
error={error} error={error}
@@ -239,14 +240,16 @@ export default function TeksDrawer({teks, anTeks, komante, denyeTeks}) {
} }
TeksDrawer.propTypes = { TeksDrawer.propTypes = {
teks: PropTypes.array.isRequired, paroles: PropTypes.array.isRequired,
anTeks: PropTypes.object, parole: PropTypes.object,
komante: PropTypes.array, paroleId: PropTypes.number,
commentaires: PropTypes.array,
denyeTeks: PropTypes.array denyeTeks: PropTypes.array
} }
TeksDrawer.defaultProps = { TeksDrawer.defaultProps = {
anTeks: null, parole: null,
komante: null, paroleId: null,
commentaires: null,
denyeTeks: null denyeTeks: null
} }
+20 -16
View File
@@ -14,6 +14,7 @@ import ExplicitIcon from '@mui/icons-material/Explicit'
import {styled} from '@mui/material/styles' import {styled} from '@mui/material/styles'
const PREFIX = 'teks-kat' const PREFIX = 'teks-kat'
const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const classes = { const classes = {
root: `${PREFIX}-root`, root: `${PREFIX}-root`,
@@ -30,12 +31,15 @@ const StyledGrid = styled(Grid)({
} }
}) })
export default function TeksKat({teks}) { const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible'
export default function TeksKat({parole}) {
const router = useRouter() const router = useRouter()
const noImageUrl = 'https://place-hold.it/140x140?text=Pa%20ni%20imaj' const {attributes} = parole
const {tit, awtis, lanne, kouveti, published_at, slug} = teks const {titre, artistes, annee, couverture, publishedAt, slug} = attributes
const datPiblikasyon = format(new Date(published_at), 'P', {locale: fr})
const alias = awtis.map(({alias}) => alias) const datPiblikasyon = format(new Date(publishedAt), 'P', {locale: fr})
const alias = artistes.data.map(({attributes}) => attributes.alias)
const handleClick = slug => { const handleClick = slug => {
router.push(`/paroles/${slug}#${slug}`).then(() => window.scrollTo(0, 0)) router.push(`/paroles/${slug}#${slug}`).then(() => window.scrollTo(0, 0))
@@ -48,26 +52,26 @@ export default function TeksKat({teks}) {
<CardMedia <CardMedia
className={classes.media} className={classes.media}
component='img' component='img'
alt={tit} alt={titre}
image={kouveti ? `${process.env.NEXT_PUBLIC_API_URL}${kouveti.url}` : noImageUrl} image={couverture?.data?.attributes?.url ? `${IMAGE_URL}${couverture.data.attributes.url}` : noImageUrl}
title={tit} title={titre}
/> />
<CardContent> <CardContent>
<Typography display='inline' style={{marginRight: 5}} variant='h6' component='h2'> <Typography display='inline' style={{marginRight: 5}} variant='h6' component='h2'>
{tit} {titre}
</Typography> </Typography>
{teks.eksplisit && ( {parole.eksplisit && (
<ExplicitIcon style={{marginRight: 5}} color='secondary' fontSize='small' /> <ExplicitIcon style={{marginRight: 5}} color='secondary' fontSize='small' />
)} )}
<Typography variant='caption'> <Typography variant='caption'>
{teks.user && ( {parole.user && (
<> <>
(<i>texte soumis par {teks.user.username}</i>) (<i>texte soumis par {parole.user.username}</i>)
</> </>
)} )}
{teks.userAdmin && !teks.user && ( {parole.userAdmin && !parole.user && (
<> <>
(<i>texte soumis par {teks.userAdmin}</i>) (<i>texte soumis par {parole.userAdmin}</i>)
</> </>
)} )}
</Typography> </Typography>
@@ -75,7 +79,7 @@ export default function TeksKat({teks}) {
{new Intl.ListFormat('fr').format(alias)} {new Intl.ListFormat('fr').format(alias)}
</Typography> </Typography>
<Typography variant='body2' color='textSecondary' component='p'> <Typography variant='body2' color='textSecondary' component='p'>
{lanne} {annee}
</Typography> </Typography>
<Typography align='center' style={{marginTop: '0.5em'}} variant='body1' color='textSecondary' component='p'> <Typography align='center' style={{marginTop: '0.5em'}} variant='body1' color='textSecondary' component='p'>
Publié le : {datPiblikasyon} Publié le : {datPiblikasyon}
@@ -88,5 +92,5 @@ export default function TeksKat({teks}) {
} }
TeksKat.propTypes = { TeksKat.propTypes = {
teks: PropTypes.object.isRequired parole: PropTypes.object.isRequired
} }
+30 -29
View File
@@ -66,30 +66,30 @@ const Root = styled('div')((
} }
})) }))
const langToArray = anTeks => { const langToArray = parole => {
const langArray = [] const langArray = []
if (anTeks && anTeks.tradiksyon) { if (parole && parole.traductions) {
const {francais, english, espagnol, deutsch, italiano} = anTeks.tradiksyon const {francais, anglais, espagnol, allemand, italien} = parole.traductions
if (francais) { if (francais) {
langArray.push({title: 'Traduction', flag: 'fr', lang: francais}) langArray.push({title: 'Traduction', flag: 'fr', lang: francais})
} }
if (english) { if (anglais) {
langArray.push({title: 'Translation', flag: 'en', lang: english}) langArray.push({title: 'Translation', flag: 'en', lang: anglais})
} }
if (espagnol) { if (espagnol) {
langArray.push({title: 'Traducción', flag: 'es', lang: espagnol}) langArray.push({title: 'Traducción', flag: 'es', lang: espagnol})
} }
if (deutsch) { if (allemand) {
langArray.push({title: 'Übersetzung', flag: 'de', lang: deutsch}) langArray.push({title: 'Übersetzung', flag: 'de', lang: allemand})
} }
if (italiano) { if (italien) {
langArray.push({title: 'Traduzione', flag: 'it', lang: italiano}) langArray.push({title: 'Traduzione', flag: 'it', lang: italien})
} }
} }
@@ -120,15 +120,15 @@ const Alert = forwardRef(function Alert(props, ref) {
const ExplicitTooltip = Tooltip const ExplicitTooltip = Tooltip
export default function Teks({anTeks, komante, open, success, error, setSuccess, setError, handleClose}) { export default function Teks({parole, paroleId, commentaires, open, success, error, setSuccess, setError, handleClose}) {
const isMobile = useMediaQuery('(max-width:800px)') const isMobile = useMediaQuery('(max-width:800px)')
const langArray = langToArray(anTeks) const langArray = langToArray(parole)
const awtis = anTeks.awtis.map(({alias}) => alias) const awtis = parole.artistes.data.map(({attributes}) => attributes.alias)
return ( return (
<Root> <Root>
<div className={classes.pataje}> <div className={classes.pataje}>
<Pataje teks={anTeks} setError={setError} setSuccess={setSuccess} /> <Pataje parole={parole} setError={setError} setSuccess={setSuccess} />
</div> </div>
<Box sx={{textAlign: 'center', marginTop: 9}}> <Box sx={{textAlign: 'center', marginTop: 9}}>
<Typography style={{marginTop: '0.8em'}} variant='h4' component='div' display='block'> <Typography style={{marginTop: '0.8em'}} variant='h4' component='div' display='block'>
@@ -136,8 +136,8 @@ export default function Teks({anTeks, komante, open, success, error, setSuccess,
{new Intl.ListFormat('fr').format(awtis)} {new Intl.ListFormat('fr').format(awtis)}
</Typography> </Typography>
<Typography variant='h5' component='div'> <Typography variant='h5' component='div'>
{anTeks.tit} <small>({anTeks?.lanne})</small> {parole.titre} <small>({parole?.annee})</small>
{anTeks.eksplisit && ( {parole.explicite && (
<ExplicitTooltip <ExplicitTooltip
title='Explicit Lyrics' title='Explicit Lyrics'
placement='bottom' placement='bottom'
@@ -151,29 +151,29 @@ export default function Teks({anTeks, komante, open, success, error, setSuccess,
)} )}
</Typography> </Typography>
<Grid container alignItems='center' justifyContent='center'> <Grid container alignItems='center' justifyContent='center'>
{komante && ( {commentaires && (
<VweKomante komante={komante} teks={anTeks} /> <VweKomante commentaires={commentaires} parole={parole} paroleId={paroleId} />
)} )}
</Grid> </Grid>
</Typography> </Typography>
{anTeks.user && ( {parole?.user?.data && (
<Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'> <Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'>
<i>texte soumis par {anTeks.user.username}</i> <i>texte soumis par {parole.user.data.attributes.username}</i>
</Typography> </Typography>
)} )}
{anTeks.userAdmin && !anTeks.user && ( {parole.userAdmin && !parole.user && (
<Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'> <Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'>
<i>texte soumis par {anTeks.userAdmin}</i> <i>texte soumis par {parole.userAdmin}</i>
</Typography> </Typography>
)} )}
</Box> </Box>
{(anTeks.okiMizikID || anTeks.kouteyAchtey.length > 0) && ( {(parole.okiMizikID || parole.streamAudio.length > 0) && (
<Box sx={{textAlign: 'center'}}> <Box sx={{textAlign: 'center'}}>
<EntegreMizik anTeks={anTeks} isMobile={isMobile} /> <EntegreMizik parole={parole} isMobile={isMobile} />
</Box> </Box>
)} )}
{anTeks.okiMizikID && ( {parole.okiMizikID && (
<OkiMizik id={anTeks.okiMizikID} teks={anTeks} /> <OkiMizik id={parole.okiMizikID} parole={parole} />
)} )}
<Grid container justifyContent='start' spacing={1}> <Grid container justifyContent='start' spacing={1}>
<Grid item xs={12} md={langArray.length > 0 ? 6 : null}> <Grid item xs={12} md={langArray.length > 0 ? 6 : null}>
@@ -182,7 +182,7 @@ export default function Teks({anTeks, komante, open, success, error, setSuccess,
Transcription Transcription
</Typography> </Typography>
<Typography paragraph align={alignTeks(langArray, isMobile)} component='span'> <Typography paragraph align={alignTeks(langArray, isMobile)} component='span'>
{formatJsonString(anTeks.transkripsyon)} {formatJsonString(parole.transcription)}
</Typography> </Typography>
</div> </div>
</Grid> </Grid>
@@ -242,8 +242,9 @@ export default function Teks({anTeks, komante, open, success, error, setSuccess,
} }
Teks.propTypes = { Teks.propTypes = {
anTeks: PropTypes.object.isRequired, parole: PropTypes.object.isRequired,
komante: PropTypes.array, paroleId: PropTypes.number.isRequired,
commentaires: PropTypes.array,
open: PropTypes.bool.isRequired, open: PropTypes.bool.isRequired,
success: PropTypes.string, success: PropTypes.string,
error: PropTypes.string, error: PropTypes.string,
@@ -253,7 +254,7 @@ Teks.propTypes = {
} }
Teks.defaultProps = { Teks.defaultProps = {
komante: null, commentaires: null,
success: '', success: '',
error: '' error: ''
} }
+10 -10
View File
@@ -49,22 +49,22 @@ const vweyIcons = {
Dailymotion: <Dailymotion />, Dailymotion: <Dailymotion />,
Lbry: <Lbry />, Lbry: <Lbry />,
Rumble: <PlayCircleFilledIcon />, Rumble: <PlayCircleFilledIcon />,
Peertube: <Peertube /> Gadé: <Peertube />
} }
export default function VweKouteAchte({anTeks, niVideyo, niOdyo}) { export default function VweKouteAchte({parole, niVideyo, niOdyo}) {
const [ouve, meteOuve] = useState(false) const [ouve, meteOuve] = useState(false)
const {kouteyAchtey, lyen} = anTeks const {streamAudio, streamVideo} = parole
const kouteyAchteyActions = kouteyAchtey.map(({boutik, url}) => ({ const kouteyAchteyActions = streamAudio.map(({plateforme, url}) => ({
icon: kouteyAchteyIcons[boutik], icon: kouteyAchteyIcons[plateforme],
name: boutik, name: plateforme,
link: url link: url
})) }))
const vweyActions = lyen.map(({url, sit}) => ({ const vweyActions = streamVideo.map(({plateforme, url}) => ({
icon: vweyIcons[sit], icon: vweyIcons[plateforme],
name: sit, name: plateforme,
link: url link: url
})) }))
@@ -115,7 +115,7 @@ export default function VweKouteAchte({anTeks, niVideyo, niOdyo}) {
} }
VweKouteAchte.propTypes = { VweKouteAchte.propTypes = {
anTeks: PropTypes.object.isRequired, parole: PropTypes.object.isRequired,
niVideyo: PropTypes.bool, niVideyo: PropTypes.bool,
niOdyo: PropTypes.bool niOdyo: PropTypes.bool
} }
+137 -41
View File
@@ -1,21 +1,44 @@
import axios from 'axios' import axios from 'axios'
import qs from 'qs'
const OKI_API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337' const OKI_API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
const AWTIS_POU_CHAK_PAJ = process.env.NEXT_PUBLIC_AWTIS_POU_CHAK_PAJ || 6 const AWTIS_POU_CHAK_PAJ = process.env.NEXT_PUBLIC_AWTIS_POU_CHAK_PAJ || 6
const readToken = process.env.NEXT_PUBLIC_READ_TOKEN || 'read-token'
const readAxiosInstance = axios.create({
headers: {
Authorization: `Bearer ${readToken}`
}
})
export async function jwennTeksEpiSlug(slug) { export async function jwennTeksEpiSlug(slug) {
const response = await axios.get(`${OKI_API}/teks?slug=${slug}&_where[published_at_null]=false`) const query = qs.stringify({
return response.data[0] populate: ['artistes', 'couverture'],
filters: {
slug: {
$eq: slug
}
}
}, {
encodeValuesOnly: true
})
const {data} = await readAxiosInstance.get(`${OKI_API}/paroles?${query}`)
return data.data[0]
} }
export async function jwennAwtisEpiSlug(slug) { export async function jwennAwtisEpiSlug(slug) {
const response = await axios.get(`${OKI_API}/awtis?slug=${slug}&_where[published_at_null]=false`) const query = qs.stringify({
return response.data[0] populate: ['paroles', 'photo'],
} filters: {
slug: {
export async function jwennAwtisKantite() { $eq: slug
const response = await axios.get(`${OKI_API}/awtis/count?_where[published_at_null]=false`) }
return response.data }
}, {
encodeValuesOnly: true
})
const {data} = await readAxiosInstance.get(`${OKI_API}/artistes?${query}`)
return data.data[0]
} }
export async function jwennTeksKantite() { export async function jwennTeksKantite() {
@@ -25,55 +48,98 @@ export async function jwennTeksKantite() {
export async function jwennAwtisPajinasyon(paj) { export async function jwennAwtisPajinasyon(paj) {
const start = AWTIS_POU_CHAK_PAJ * (paj - 1) const start = AWTIS_POU_CHAK_PAJ * (paj - 1)
const query = `_sort=published_at:DESC&_start=${start}&_limit=${AWTIS_POU_CHAK_PAJ}&_where[published_at_null]=false` const query = qs.stringify({
populate: ['paroles', 'photo'],
sort: ['publishedAt:desc'],
pagination: {
start,
limit: AWTIS_POU_CHAK_PAJ
}
}, {
encodeValuesOnly: true
})
const response = await axios.get(`${OKI_API}/awtis?${query}`) const {data} = await readAxiosInstance.get(`${OKI_API}/artistes?${query}`)
return response.data return data
} }
export async function jwennTeks() { export async function jwennTeks() {
const query = '_sort=tit:ASC&_where[published_at_null]=false' const query = qs.stringify({
populate: ['artistes', 'couverture', 'user', 'userAdmin', 'commentaires', 'traductions', 'streamVideo', 'streamAudio'],
sort: ['titre:asc'],
pagination: {
pageSize: 100
}
}, {
encodeValuesOnly: true
})
const response = await axios.get(`${OKI_API}/teks?${query}`) const {data} = await readAxiosInstance.get(`${OKI_API}/paroles?${query}`)
return response.data return data.data
} }
export async function jwennAwtisSlug() { export async function jwennAwtisSlug() {
const query = '_sort=published_at:DESC&_where[published_at_null]=false' const query = qs.stringify({
sort: ['publishedAt:desc']
})
const response = await axios.get(`${OKI_API}/awtis?${query}`) const response = await readAxiosInstance.get(`${OKI_API}/artistes?${query}`)
const {data} = response const {data} = response
return data.map(({slug}) => slug) return data.data.map(({attributes}) => attributes.slug)
}
export async function jwennTeksSlug() {
const query = qs.stringify({
sort: ['publishedAt:desc']
})
const response = await readAxiosInstance.get(`${OKI_API}/paroles?${query}`)
const {data} = response
return data.data.map(({attributes}) => attributes.slug)
} }
export async function jwennDenyeTeks() { export async function jwennDenyeTeks() {
const query = '_sort=published_at:DESC&_limit=6&_where[published_at_null]=false' const query = qs.stringify({
populate: ['artistes', 'couverture'],
sort: ['publishedAt:desc'],
pagination: {
limit: 6
}
}, {
encodeValuesOnly: true
})
const response = await axios.get(`${OKI_API}/teks?${query}`) const {data} = await readAxiosInstance.get(`${OKI_API}/paroles?${query}`)
return response.data return data.data
} }
export async function jwennAnTeks(teksId) { export async function jwennAnTeks(teksId, token) {
const response = await axios.get(`${OKI_API}/teks/${teksId}`) const headers = {
return response.data 'content-type': 'application/json',
} Authorization: `Bearer ${token}`
}
export async function jwennTeksEpiUserId(userId) { const response = await axios.get(`${OKI_API}/paroles/${teksId}`, {headers})
const query = `_sort=tit:ASC&_where[user.id]=${userId}&_publicationState=preview&published_at_null=true`
const response = await axios.get(`${OKI_API}/teks?${query}`)
return response.data
}
export async function jwennSlugs() {
const response = await axios.get(`${OKI_API}/slugs`)
return response.data return response.data
} }
export async function jwennKomanteEpiTeksId(teksId) { export async function jwennKomanteEpiTeksId(teksId) {
const query = `_sort=published_at:DESC&_where[teks]=${teksId}&_where[published_at_null]=false` const query = qs.stringify({
const response = await axios.get(`${OKI_API}/komante?${query}`) sort: ['publishedAt:desc'],
return response.data populate: ['paroles', 'user'],
filters: {
parole: {
id: {
$eq: teksId
}
}
}
}, {
encodeValuesOnly: true
})
const {data} = await readAxiosInstance.get(`${OKI_API}/commentaires?${query}`)
return data.data
} }
export async function jwennUserEpiToken(userToken) { export async function jwennUserEpiToken(userToken) {
@@ -86,13 +152,43 @@ export async function jwennUserEpiToken(userToken) {
} }
export async function jwennUserEpiUsername(username) { export async function jwennUserEpiUsername(username) {
const query = `_where[username]=${username}&_where[confirmed]=true` const query = qs.stringify({
const response = await axios.get(`${OKI_API}/users?${query}`) filters: {
username: {
$eq: username
}
}
}, {
encodeValuesOnly: true
})
const response = await readAxiosInstance.get(`${OKI_API}/users?${query}`)
return response.data[0] return response.data[0]
} }
export async function jwennUserEpiEmail(email) { export async function jwennUserEpiEmail(email) {
const query = `_where[email]=${email}&_where[confirmed]=false&_where[blocked]=false` const query = qs.stringify({
const response = await axios.get(`${OKI_API}/users?${query}`) filters: {
email: {
$eq: email
},
confirmed: {
$eq: false
},
blocked: {
$eq: false
}
}
}, {
encodeValuesOnly: true
})
const response = await readAxiosInstance.get(`${OKI_API}/users?${query}`)
return response.data[0] return response.data[0]
} }
export async function passwordRequest(lyen, email) {
await axios.post(`${OKI_API}/auth/${lyen}`, {
email
})
}
+1 -1
View File
@@ -22,7 +22,7 @@ const options = {
return null return null
} catch (error) { } catch (error) {
const errorMessage = error.response.data.message[0].messages[0].message const errorMessage = error.response.data.error.message
throw new Error(errorMessage) throw new Error(errorMessage)
} }
} }
+46 -21
View File
@@ -7,34 +7,38 @@ import HeadLayout from '../../components/head-layout'
import {jwennAwtisEpiSlug} from '../../lib/oki-api' import {jwennAwtisEpiSlug} from '../../lib/oki-api'
import Custom404 from '../404' import Custom404 from '../404'
import Custom500 from '../500'
export default function SlugAwtis({error, anAwtis}) { export default function SlugAwtis({errorCode, error404, errorMessage, anAwtis}) {
if (error) { if (error404) {
return <Custom404 statusCode={error} /> return <Custom404 statusCode={error404} />
} }
const {foto} = anAwtis if (errorCode) {
console.log('⚠️ error', errorMessage)
return <Custom500 statusCode={errorCode} />
}
const {photo} = anAwtis
const formatKouveti = () => { const formatKouveti = () => {
if (foto.length === 0) { if (!photo) {
return null return null
} }
const [anFoto] = foto if (photo && photo.formats && photo.formats.large) {
return photo.formats.large
if (anFoto && anFoto.formats && anFoto.formats.large) {
return anFoto.formats.large
} }
if (anFoto && anFoto.formats && anFoto.formats.medium) { if (photo && photo.formats && photo.formats.medium) {
return anFoto.formats.medium return photo.formats.medium
} }
if (anFoto && anFoto.formats && anFoto.formats.small) { if (photo && photo.formats && photo.formats.small) {
return anFoto.formats.small return photo.formats.small
} }
return anFoto return photo
} }
return ( return (
@@ -43,10 +47,10 @@ export default function SlugAwtis({error, anAwtis}) {
imageWidth={formatKouveti() ? formatKouveti().width : null} imageWidth={formatKouveti() ? formatKouveti().width : null}
imageHeight={formatKouveti() ? formatKouveti().height : null} imageHeight={formatKouveti() ? formatKouveti().height : null}
imageMime={formatKouveti() ? formatKouveti().mime : null} imageMime={formatKouveti() ? formatKouveti().mime : null}
title={`${anAwtis.alias} - Paroles et Traductions`} tab={2} slug={`awtis/${anAwtis.slug}`} title={`${anAwtis.attributes.alias} - Paroles et Traductions`} tab={2} slug={`awtis/${anAwtis.attributes.slug}`}
> >
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}> <Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
<AwtisDetay anAwtis={anAwtis} /> <AwtisDetay anAwtis={anAwtis.attributes} />
</Box> </Box>
<Footer /> <Footer />
</HeadLayout> </HeadLayout>
@@ -55,21 +59,42 @@ export default function SlugAwtis({error, anAwtis}) {
export async function getServerSideProps({query}) { export async function getServerSideProps({query}) {
const {slug} = query const {slug} = query
const anAwtis = await jwennAwtisEpiSlug(slug) let anAwtis
let error404
let errorCode
let errorMessage
try {
anAwtis = await jwennAwtisEpiSlug(slug)
} catch (error) {
errorMessage = error.message
errorCode = true
}
if (!anAwtis) {
error404 = true
}
return { return {
props: { props: {
error: Boolean(!anAwtis), error404: error404 || null,
anAwtis: anAwtis ? anAwtis : null errorCode: errorCode || null,
errorMessage: errorMessage || null,
anAwtis: anAwtis || null
} }
} }
} }
SlugAwtis.defaultProps = { SlugAwtis.defaultProps = {
anAwtis: null anAwtis: null,
error404: null,
errorCode: null,
errorMessage: null,
} }
SlugAwtis.propTypes = { SlugAwtis.propTypes = {
error: PropTypes.bool.isRequired, error404: PropTypes.bool,
errorCode: PropTypes.bool,
errorMessage: PropTypes.string,
anAwtis: PropTypes.object anAwtis: PropTypes.object
} }
+54 -19
View File
@@ -1,51 +1,86 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {Container, Grid} from '@mui/material' import {Box, Container, Grid} from '@mui/material'
import {jwennAwtisKantite, jwennAwtisPajinasyon} from '../../lib/oki-api' import {jwennAwtisPajinasyon} from '../../lib/oki-api'
import AwtisKat from '../../components/awtis/awtis-kat' import AwtisKat from '../../components/awtis/awtis-kat'
import Pajinasyon from '../../components/awtis/pajinasyon' import Pajinasyon from '../../components/awtis/pajinasyon'
import HeadLayout from '../../components/head-layout' import HeadLayout from '../../components/head-layout'
import Footer from '../../components/footer'
const AWTIS_POU_CHAK_PAJ = process.env.NEXT_PUBLIC_AWTIS_POU_CHAK_PAJ || 6 import Custom404 from '../404'
import Custom500 from '../500'
export default function Awtis({errorCode, error404, errorMessage, pajTotal, awtisPouChakPaj, paj}) {
if (error404) {
return <Custom404 statusCode={error404} />
}
if (errorCode) {
console.log('⚠️ error', errorMessage)
return <Custom500 statusCode={errorCode} />
}
export default function Awtis({pajTotal, awtisPouChakPaj, paj}) {
return ( return (
<HeadLayout title='Awtis - Liste des artistes' tab={2} slug='awtis'> <HeadLayout title='Awtis - Liste des artistes' tab={2} slug='awtis'>
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
<Pajinasyon pajTotal={pajTotal} paj={paj} /> <Pajinasyon pajTotal={pajTotal} paj={paj} />
<Container> <Container sx={{marginBottom: 5, flexGrow: 100}}>
<Grid container spacing={{xs: 2, md: 3}}> <Grid container spacing={{xs: 2, md: 3}}>
{awtisPouChakPaj.map(anAwtis => <AwtisKat key={anAwtis.id} anAwtis={anAwtis} />)} {awtisPouChakPaj.map(artiste => <AwtisKat key={artiste.id} artiste={artiste.attributes} />)}
</Grid> </Grid>
</Container> </Container>
<Footer />
</Box>
</HeadLayout> </HeadLayout>
) )
} }
Awtis.propTypes = {
pajTotal: PropTypes.number.isRequired,
awtisPouChakPaj: PropTypes.array.isRequired,
paj: PropTypes.number.isRequired
}
export async function getServerSideProps({query}) { export async function getServerSideProps({query}) {
const {paj} = query const {paj} = query
let error404
let errorCode
let errorMessage
let awtisPouChakPaj
const pajParsed = Array.isArray(paj) ? Number.parseInt(paj[1], 10) : Number.parseInt(paj, 10) const pajParsed = Array.isArray(paj) ? Number.parseInt(paj[1], 10) : Number.parseInt(paj, 10)
const awtisPouChakPaj = await jwennAwtisPajinasyon(pajParsed)
const awtisCountRequest = await jwennAwtisKantite()
const awtisCount = Number.parseInt(awtisCountRequest, 10)
const pajTotal = Math.ceil(awtisCount / AWTIS_POU_CHAK_PAJ)
if (pajParsed > pajTotal) { try {
throw new Error('Pa twouvé paj-la') awtisPouChakPaj = await jwennAwtisPajinasyon(pajParsed)
} catch (error) {
errorMessage = error.message
errorCode = true
}
const pajTotal = Math.ceil(awtisPouChakPaj.meta.pagination.total / awtisPouChakPaj.meta.pagination.limit)
if (pajParsed > pajTotal || pajParsed < 1) {
error404 = true
} }
return { return {
props: { props: {
error404: error404 || null,
errorCode: errorCode || null,
errorMessage: errorMessage || null,
pajTotal, pajTotal,
awtisPouChakPaj, awtisPouChakPaj: awtisPouChakPaj.data,
paj: pajParsed paj: pajParsed
} }
} }
} }
Awtis.defaultProps = {
error404: null,
errorCode: null,
errorMessage: null,
}
Awtis.propTypes = {
error404: PropTypes.bool,
errorCode: PropTypes.bool,
errorMessage: PropTypes.string,
pajTotal: PropTypes.number.isRequired,
awtisPouChakPaj: PropTypes.array.isRequired,
paj: PropTypes.number.isRequired
}
+33 -32
View File
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {jwennTeksEpiSlug, jwennTeks, jwennKomanteEpiTeksId} from '../../lib/oki-api' import {jwennTeks, jwennKomanteEpiTeksId} from '../../lib/oki-api'
import TeksDrawer from '../../components/teks/teks-drawer' import TeksDrawer from '../../components/teks/teks-drawer'
import HeadLayout from '../../components/head-layout' import HeadLayout from '../../components/head-layout'
@@ -8,41 +8,41 @@ import HeadLayout from '../../components/head-layout'
import Custom500 from '../500' import Custom500 from '../500'
import Custom404 from '../404' import Custom404 from '../404'
const jwennAwtis = awtis => { const jwennAwtis = artiste => {
const alias = awtis.map(({alias}) => alias) const alias = artiste.data.map(({attributes}) => attributes.alias)
return new Intl.ListFormat('fr').format(alias) return new Intl.ListFormat('fr').format(alias)
} }
export default function SlugTeks({hasError, errorMessage, teks, anTeks, slug, komante}) { export default function SlugTeks({hasError, errorMessage, paroles, parole, slug, commentaires}) {
if (hasError) { if (hasError) {
console.log('⚠️ error :', errorMessage) console.log('⚠️ error :', errorMessage)
return <Custom500 /> return <Custom500 />
} }
if (!anTeks) { if (!parole) {
return <Custom404 /> return <Custom404 />
} }
const awtis = anTeks.awtis.length === 1 ? anTeks.awtis[0].alias : jwennAwtis(anTeks.awtis) const artistes = parole.attributes.artistes.length === 1 ? parole.attributes.artistes[0].data.attributes.alias : jwennAwtis(parole.attributes.artistes)
const {kouveti} = anTeks const {couverture} = parole.attributes
const formatKouveti = () => { const formatKouveti = () => {
if (!kouveti) { if (!couverture) {
return null return null
} }
if (kouveti && kouveti.formats && kouveti.formats.large) { if (couverture && couverture.formats && couverture.formats.large) {
return kouveti.formats.large return couverture.formats.large
} }
if (kouveti && kouveti.formats && kouveti.formats.medium) { if (couverture && couverture.formats && couverture.formats.medium) {
return kouveti.formats.medium return couverture.formats.medium
} }
if (kouveti && kouveti.formats && kouveti.formats.small) { if (couverture && couverture.formats && couverture.formats.small) {
return kouveti.formats.small return couverture.formats.small
} }
return kouveti return couverture
} }
return ( return (
@@ -51,25 +51,26 @@ export default function SlugTeks({hasError, errorMessage, teks, anTeks, slug, ko
imageWidth={formatKouveti() ? formatKouveti().width : null} imageWidth={formatKouveti() ? formatKouveti().width : null}
imageHeight={formatKouveti() ? formatKouveti().height : null} imageHeight={formatKouveti() ? formatKouveti().height : null}
imageMime={formatKouveti() ? formatKouveti().mime : null} imageMime={formatKouveti() ? formatKouveti().mime : null}
title={`${awtis} - ${anTeks.tit} | Paroles et Traductions`} tab={1} slug={`paroles/${slug}`} title={`${artistes} - ${parole.attributes.titre} | Paroles et Traductions`} tab={1} slug={`paroles/${slug}`}
> >
<TeksDrawer teks={teks} anTeks={anTeks} komante={komante} /> <TeksDrawer paroles={paroles} parole={parole.attributes} paroleId={parole.id} commentaires={commentaires} />
</HeadLayout> </HeadLayout>
) )
} }
export async function getServerSideProps({query}) { export async function getServerSideProps({query}) {
const {slug} = query const {slug} = query
let teks let paroles
let anTeks let parole
let hasError let hasError
let errorMessage let errorMessage
let komante let commentaires
try { try {
teks = await jwennTeks() paroles = await jwennTeks()
anTeks = await jwennTeksEpiSlug(slug) parole = paroles.find(({attributes}) => attributes.slug === slug)
komante = await jwennKomanteEpiTeksId(anTeks?.id) commentaires = paroles.map(({attributes}) => attributes.commentaires)
commentaires = await jwennKomanteEpiTeksId(parole?.id)
} catch (error) { } catch (error) {
errorMessage = error errorMessage = error
hasError = true hasError = true
@@ -79,10 +80,10 @@ export async function getServerSideProps({query}) {
props: { props: {
hasError: hasError || null, hasError: hasError || null,
errorMessage: errorMessage ? errorMessage.message : null, errorMessage: errorMessage ? errorMessage.message : null,
teks: teks || null, paroles: paroles || null,
anTeks: anTeks || null, parole: parole || null,
slug, slug,
komante: komante || null commentaires: commentaires || null
} }
} }
} }
@@ -90,16 +91,16 @@ export async function getServerSideProps({query}) {
SlugTeks.defaultProps = { SlugTeks.defaultProps = {
hasError: null, hasError: null,
errorMessage: null, errorMessage: null,
teks: null, paroles: null,
anTeks: null, parole: null,
komante: null commentaires: null
} }
SlugTeks.propTypes = { SlugTeks.propTypes = {
hasError: PropTypes.bool, hasError: PropTypes.bool,
errorMessage: PropTypes.string, errorMessage: PropTypes.string,
teks: PropTypes.array, paroles: PropTypes.array,
anTeks: PropTypes.object, parole: PropTypes.object,
slug: PropTypes.string.isRequired, slug: PropTypes.string.isRequired,
komante: PropTypes.array commentaires: PropTypes.array
} }
+7 -7
View File
@@ -7,7 +7,7 @@ import HeadLayout from '../../components/head-layout'
import Custom500 from '../500' import Custom500 from '../500'
export default function Teks({errorCode, errorMessage, teks, denyeTeks}) { export default function Teks({errorCode, errorMessage, paroles, denyeTeks}) {
if (errorCode) { if (errorCode) {
console.log('⚠️ error', errorMessage) console.log('⚠️ error', errorMessage)
return <Custom500 /> return <Custom500 />
@@ -15,19 +15,19 @@ export default function Teks({errorCode, errorMessage, teks, denyeTeks}) {
return ( return (
<HeadLayout title='Paroles et Traductions' tab={1} slug='paroles'> <HeadLayout title='Paroles et Traductions' tab={1} slug='paroles'>
<TeksDrawer teks={teks} denyeTeks={denyeTeks} /> <TeksDrawer paroles={paroles} denyeTeks={denyeTeks} />
</HeadLayout> </HeadLayout>
) )
} }
export async function getServerSideProps() { export async function getServerSideProps() {
let teks let paroles
let denyeTeks let denyeTeks
let hasError let hasError
let errorMessage let errorMessage
try { try {
teks = await jwennTeks() paroles = await jwennTeks()
denyeTeks = await jwennDenyeTeks() denyeTeks = await jwennDenyeTeks()
} catch (error) { } catch (error) {
errorMessage = error.message errorMessage = error.message
@@ -38,7 +38,7 @@ export async function getServerSideProps() {
props: { props: {
errorCode: hasError || null, errorCode: hasError || null,
errorMessage: errorMessage || null, errorMessage: errorMessage || null,
teks: teks || null, paroles: paroles || null,
denyeTeks: denyeTeks || null denyeTeks: denyeTeks || null
} }
} }
@@ -47,13 +47,13 @@ export async function getServerSideProps() {
Teks.defaultProps = { Teks.defaultProps = {
errorCode: null, errorCode: null,
errorMessage: null, errorMessage: null,
teks: null, paroles: null,
denyeTeks: null denyeTeks: null
} }
Teks.propTypes = { Teks.propTypes = {
errorCode: PropTypes.bool, errorCode: PropTypes.bool,
errorMessage: PropTypes.string, errorMessage: PropTypes.string,
teks: PropTypes.array, paroles: PropTypes.array,
denyeTeks: PropTypes.array denyeTeks: PropTypes.array
} }
+7 -9
View File
@@ -1,8 +1,8 @@
import {jwennAwtisSlug, jwennSlugs} from '../lib/oki-api' import {jwennAwtisSlug, jwennTeksSlug} from '../lib/oki-api'
const url = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost' const url = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost'
const createSitemap = (teks, awtisSlug) => ( const createSitemap = (teksSlug, awtisSlug) => (
`<?xml version="1.0" encoding="UTF-8"?> `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url> <url>
@@ -25,10 +25,10 @@ const createSitemap = (teks, awtisSlug) => (
<loc>${url}/soumet</loc> <loc>${url}/soumet</loc>
<priority>0.5</priority> <priority>0.5</priority>
</url> </url>
${teks ${teksSlug
.map(m => ` .map(slug => `
<url> <url>
<loc>${`${url}/paroles/${m}`}</loc> <loc>${`${url}/paroles/${slug}`}</loc>
</url> </url>
`) `)
.join('')} .join('')}
@@ -48,13 +48,11 @@ export default function Sitemap() {
} }
export async function getServerSideProps({res}) { export async function getServerSideProps({res}) {
const request = await jwennSlugs() const teksSlug = await jwennTeksSlug()
const awtisSlug = await jwennAwtisSlug() const awtisSlug = await jwennAwtisSlug()
console.log('awtisSlug', awtisSlug)
res.setHeader('Content-Type', 'text/xml') res.setHeader('Content-Type', 'text/xml')
res.write(createSitemap(request, awtisSlug)) res.write(createSitemap(teksSlug, awtisSlug))
res.end() res.end()
return { return {