Merge pull request 'Mise à jour de NextJS et Mui' (#4) from adapt-upgrade-strapi into master

Reviewed-on: https://codeberg.org/OKI/oki.re/pulls/4
This commit is contained in:
Cédric Famibelle-Pronzola
2026-04-22 05:45:33 +02:00
47 changed files with 807 additions and 724 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
# Made with [Nextjs 14](https://nextjs.org/) and [Material-UI 6](https://material-ui.com/)
# Made with [Nextjs 16](https://nextjs.org/) and [Material-UI 9](https://material-ui.com/)
<p align="center">
<a href="https://liberapay.com/OKI/donate/">
@@ -9,7 +9,7 @@
</p>
## Prérequis
- Node >= 16
- Node >= 20
- [API](https://codeberg.org/OKI/api.oki.re)
## Variables d'environement
@@ -26,7 +26,7 @@ yarn && yarn dev
## License
Copyright (C) 2020 - 2024 Cédric Famibelle-Pronzola & ORGANISATION KA INTERNATIONALE (OKI)
Copyright (C) 2020 - 2026 Cédric Famibelle-Pronzola & ORGANISATION KA INTERNATIONALE (OKI)
### FR
+2 -1
View File
@@ -42,7 +42,8 @@ export const { handlers, auth } = NextAuth({
})
],
session: {
strategy: "jwt"
strategy: "jwt",
trustHost: true
},
secret: process.env.NEXT_PUBLIC_JWT_SECRET,
callbacks: {
+11 -11
View File
@@ -10,13 +10,13 @@ const apiUrl = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'
async function jwennAwtis(slug) {
const awtis = await jwennAwtisEpiSlug(slug)
const {data} = await jwennAwtisEpiSlug(slug)
if (!awtis) {
if (!data) {
notFound()
}
return awtis
return data
}
export async function generateMetadata(props) {
@@ -24,11 +24,11 @@ export async function generateMetadata(props) {
const {slug} = params
const anAwtis = await jwennAwtis(slug)
const title = `OKI | ${anAwtis.attributes.alias} - Paroles et Traductions`
const description = `${anAwtis.attributes.alias}${anAwtis?.attributes?.biographie ? ` : ${anAwtis?.attributes?.biographie.slice(0, 100)}...` : ''}`
const title = `OKI | ${anAwtis.alias} - Paroles et Traductions`
const description = `${anAwtis.alias}${anAwtis?.biographie ? ` : ${anAwtis?.biographie.slice(0, 100)}...` : ''}`
const url = `${siteUrl}/awtis/${slug}`
const {photo} = anAwtis.attributes
const {photo} = anAwtis
const kuvetiFormat = formatKuveti(photo)
return {
@@ -57,7 +57,7 @@ export async function generateMetadata(props) {
creator: '@OrganisationKA',
images: {
url: `${apiUrl}${kuvetiFormat?.url}`,
alt: `Photo de ${anAwtis.attributes.alias}`,
alt: `Photo de ${anAwtis.alias}`,
}
}
}
@@ -68,14 +68,14 @@ export default async function AwtisPajSlug(props) {
const {slug} = params
const anAwtis = await jwennAwtis(slug)
const {photo} = anAwtis.attributes
const {photo} = anAwtis
const kuvetiFormat = formatKuveti(photo)
const jsonLd = {
'@context': 'http://schema.org',
'@type': 'Person',
'@id': anAwtis.attributes.musicBrainzUrl || undefined,
name: anAwtis.attributes.alias,
'@id': anAwtis.musicBrainzUrl || undefined,
name: anAwtis.alias,
url: `${siteUrl}/awtis/${slug}`,
image: kuvetiFormat?.url ? `${apiUrl}${kuvetiFormat.url}` : undefined
}
@@ -84,7 +84,7 @@ export default async function AwtisPajSlug(props) {
<>
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
<Box sx={{flexGrow: 1}}>
<AwtisDetay anAwtis={anAwtis.attributes} />
<AwtisDetay anAwtis={anAwtis} />
</Box>
<Footer />
</Box>
+5 -5
View File
@@ -1,7 +1,7 @@
import {notFound} from 'next/navigation'
import Box from '@mui/material/Box'
import Container from '@mui/material/Container'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import ChecheAwtis from '../../components/awtis/cheche-awtis'
import AwtisKat from '../../components/awtis/awtis-kat'
@@ -48,14 +48,14 @@ async function jwennDone(paj) {
notFound()
}
const awtisPouChakPaj = await jwennAwtisPajinasyon(pajParsed)
const pajTotal = Math.ceil(awtisPouChakPaj.meta.pagination.total / awtisPouChakPaj.meta.pagination.limit)
const {data, meta} = await jwennAwtisPajinasyon(pajParsed)
const pajTotal = Math.ceil(meta.pagination.total / meta.pagination.limit)
if (pajParsed > pajTotal || pajParsed < 1) {
notFound()
}
return {pajTotal, awtisPouChakPaj, pajParsed}
return {pajTotal, awtisPouChakPaj: data, pajParsed}
}
export default async function AwitsPaj(props) {
@@ -69,7 +69,7 @@ export default async function AwitsPaj(props) {
<ChecheAwtis />
<Container sx={{marginBottom: 5, flexGrow: 100}}>
<Grid container spacing={{xs: 2, md: 3}}>
{awtisPouChakPaj.data.map(artiste => <AwtisKat key={artiste.id} artiste={artiste.attributes} />)}
{awtisPouChakPaj.map(artiste => <AwtisKat key={artiste.id} artiste={artiste} />)}
</Grid>
</Container>
<Footer />
+2 -1
View File
@@ -11,7 +11,8 @@ export default function Error() {
width={192}
height={192}
src='/logo-192x192.png'
quality={20}
quality={[20, 75]}
loading='eager'
/>
<Typography variant='h2' align='center' >500 - Erreur du serveur 😭</Typography>
<Typography style={{marginTop: '1em', color: 'green'}} variant='h3' align='center'>Nous mettons tout en œuvre pour rétablir le site dans les plus brefs délais 💪🏾</Typography>
+2 -2
View File
@@ -1,4 +1,4 @@
import NextTopLoader from 'nextjs-toploader'
import TopLoader from '../components/top-loader'
import Navigasyon from '../components/navigasyon'
import AuthProvider from './auth-provider'
import ThemeRegistry from './theme-registy'
@@ -55,7 +55,7 @@ export default async function RootLayout({children, Session}) {
return (
<html lang='fr' suppressHydrationWarning>
<body>
<NextTopLoader color='#ffeb3b' />
<TopLoader color='#ffeb3b' />
<AuthProvider session={Session}>
<ThemeRegistry>
<Navigasyon />
+2 -1
View File
@@ -11,7 +11,8 @@ export default function NotFound() {
width={192}
height={192}
src='/logo-192x192.png'
quality={20}
quality={[20, 75]}
loading='eager'
/>
</Link>
<Typography variant='h2' align='center' >404 - La page nexiste pas 😔</Typography>
+16 -17
View File
@@ -24,14 +24,14 @@ export async function generateMetadata(props) {
const params = await props.params;
const {slug} = params
const anTeks = await jwennAnTeks(slug)
const anTeks = await jwennAnTeks(slug)
const awtis = anTeks.attributes.artistes.length === 1 ? anTeks.attributes.artistes[0].data.attributes.alias : getAlias(anTeks.attributes.artistes, anTeks.attributes.prioriteArtistes)
const title = `OKI | ${awtis} - ${anTeks.attributes.titre} | Paroles et Traductions`
const description = `Paroles de « ${anTeks?.attributes?.titre} » : ${anTeks?.attributes?.transcription.slice(0, 100)}...`
const awtis = anTeks?.artistes?.length === 1 ? anTeks?.artistes[0].alias : getAlias(anTeks.artistes, anTeks.prioriteArtistes)
const title = `OKI | ${awtis} - ${anTeks.titre} | Paroles et Traductions`
const description = `Paroles de « ${anTeks?.titre} » : ${anTeks?.transcription.slice(0, 100)}...`
const url = `${siteUrl}/paroles/${slug}`
const {couverture} = anTeks.attributes
const {couverture} = anTeks
const kuvetiFormat = formatKuveti(couverture)
return {
@@ -71,30 +71,29 @@ export default async function AnPawolPaj(props) {
const {slug} = params
const anTeks = await jwennAnTeks(slug)
const {couverture} = anTeks.attributes
const teksKuvetiFormat = formatKuveti(couverture)
const {couverture} = anTeks
const teksKuvetiFormat = formatKuveti(couverture)
const jsonLd = {
'@context': 'http://schema.org',
'@type': 'MusicRecording',
'@id': anTeks.attributes.musicBrainzUrl || undefined,
name: anTeks.attributes.titre,
'@id': anTeks.musicBrainzUrl || undefined,
name: anTeks.titre,
url: `${siteUrl}/paroles/${slug}`,
image: teksKuvetiFormat?.url ? `${apiUrl}${teksKuvetiFormat?.url}` : undefined,
thumbnailUrl: couverture?.data?.attributes?.formats?.thumbnail?.url ? `${apiUrl}${couverture.data.attributes.formats.thumbnail.url}` : undefined,
byArtist: anTeks.attributes.artistes.data.map(({attributes}) => {
const {photo} = attributes
thumbnailUrl: couverture?.formats?.thumbnail?.url ? `${apiUrl}${couverture.formats.thumbnail.url}` : undefined,
byArtist: anTeks.artistes.map(({photo, musicBrainzUrl, alias, slug}) => {
const kuvetiFormat = formatKuveti(photo)
return {
'@type': 'Person',
'@id': attributes.musicBrainzUrl || undefined,
name: attributes.alias,
url: `${siteUrl}/awtis/${attributes.slug}`,
'@id': musicBrainzUrl || undefined,
name: alias,
url: `${siteUrl}/awtis/${slug}`,
image: kuvetiFormat?.url ? `${apiUrl}${kuvetiFormat?.url}` : undefined
}
}),
datePublished: anTeks.attributes?.annee
datePublished: anTeks?.annee
}
return (
@@ -104,7 +103,7 @@ export default async function AnPawolPaj(props) {
component='main'
sx={{flexGrow: 1, p: 2, mt: 2}}
>
<AnTeks parole={anTeks.attributes} paroleId={anTeks.id} />
<AnTeks parole={anTeks} paroleId={anTeks.id} />
</Box>
<Footer />
</Box>
+2 -2
View File
@@ -11,10 +11,10 @@ export default function Sipote() {
const [paymentMethod, setPaymentMethod] = useState(0)
return (
<Box sx={{display: 'flex', marginTop: 3, flexDirection: 'column', minHeight: '100vh'}}>
<Box sx={{display: 'flex', marginTop: 10, flexDirection: 'column', minHeight: '100vh'}}>
<Box sx={{flexGrow: 1, marginBottom: 10}}>
<Container>
<Typography gutterBottom sx={{fontWeight: 'bold'}} textAlign='center' variant='h4' component='h1'>
<Typography gutterBottom sx={{fontWeight: 'bold', textAlign:'center' }} variant='h4' component='h1'>
Soutenir ORGANISATION KA INTERNATIONALE !
</Typography>
<Paper sx={{padding: 2, marginTop: 3}}>
+1 -1
View File
@@ -3,7 +3,7 @@ import {Container, Link, Typography} from '@mui/material'
export default function Aso() {
return (
<Container sx={{my: 3, textAlign: 'center'}} >
<Typography gutterBottom variant='h5' sx={{fontWeight: 'bold', mb: 2}} textAlign='center' component='h2'>
<Typography gutterBottom variant='h5' sx={{fontWeight: 'bold', mb: 2}} textalign='center' component='h2'>
Qui sommes-nous ?
</Typography>
<Typography gutterBottom component='h3'>
+5 -4
View File
@@ -2,14 +2,14 @@ import PropTypes from 'prop-types'
import Container from '@mui/material/Container'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Button from '@mui/material/Button'
import Image from 'next/image'
import Link from 'next/link'
export default function Akey({logo}) {
return (
<Box sx={{flexGrow: 1, marginBottom: 3, marginTop: 3}}>
<Box sx={{flexGrow: 1, marginBottom: 3, marginTop: 7}}>
<Container align='center'>
<Box sx={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
@@ -22,6 +22,7 @@ export default function Akey({logo}) {
height={32}
alt='OKI logo'
src={logo}
loading='eager'
/>
</Box>
<Typography sx={{fontWeight: 'bold'}} variant='h6' component='h2'>
@@ -32,8 +33,8 @@ export default function Akey({logo}) {
</Typography>
</Container>
<Container sx={{marginTop: 2}}>
<Grid container justifyContent='center' spacing={2}>
<Grid>
<Grid container sx={{justifyContent: 'center'}} spacing={2}>
<Grid textalign='center'>
<Link passHref href='/pwopose'>
<Button color='primary' variant='outlined'>
<strong>Proposer des paroles</strong>
+1 -1
View File
@@ -3,7 +3,7 @@
import PropTypes from 'prop-types'
import {useRouter} from 'next/navigation'
import {useTheme} from '@mui/material/styles'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Card from '@mui/material/Card'
import CardActionArea from '@mui/material/CardActionArea'
import CardContent from '@mui/material/CardContent'
+1 -1
View File
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import KatAkey from './kat-akey'
export default function Statistik({statistik}) {
+17 -17
View File
@@ -11,7 +11,7 @@ import Button from '@mui/material/Button'
import CardActionArea from '@mui/material/CardActionArea'
import Chip from '@mui/material/Chip'
import Container from '@mui/material/Container'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Paper from '@mui/material/Paper'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
@@ -28,12 +28,12 @@ import MizikLyen from './mizik-lyen'
const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible'
const sortTeks = paroles => paroles.sort((a, b) => a.attributes.titre.localeCompare(b.attributes.titre, 'fr', {sensitivity: 'base'}))
const sortTeks = paroles => paroles.sort((a, b) => a.titre.localeCompare(b.titre, 'fr', {sensitivity: 'base'}))
export default function AwtisDetay({anAwtis}) {
const [esByografiOuve, meteEsByografiOuve] = useState(false)
const {alias, biographie, paroles, photo} = anAwtis
const sortedTeks = sortTeks(paroles?.data)
const sortedTeks = sortTeks(paroles)
const gwanBiyo = biographie && biographie.length > 100
const biyo = gwanBiyo ? `${biographie.slice(0, 100)}...` : biographie
@@ -44,19 +44,19 @@ export default function AwtisDetay({anAwtis}) {
return (
<Container>
<Box sx={{marginBlock: 2}}>
<Typography textAlign='center' variant='h6' component='h1'>
<Box sx={{marginTop: 8, marginBottom: 2}}>
<Typography sx={{textAlign: 'center'}} variant='h6' component='h1'>
{alias}
</Typography>
</Box>
<Box sx={{justifyContent: 'center', display: 'flex', marginBottom: 2}}>
<Avatar
src={`${photo?.data?.attributes?.url ? `${IMAGE_URL}${photo?.data?.attributes?.url}` : noImageUrl}`}
src={`${photo?.url ? `${IMAGE_URL}${photo?.url}` : noImageUrl}`}
alt={`Photo ${alias}`}
sx={{width: 200, height: 200, border: `2px solid ${green[500]}`}}
/>
</Box>
<Grid container direction='column' justifyContent='center' alignItems='center' spacing={3}>
<Grid sx={{alignItems:'center'}} container direction='column' spacing={3}>
{biyo && (
<Grid size={{xs: 12, md: 6}}>
<Card sx={{minWidth: 300}}>
@@ -65,7 +65,7 @@ export default function AwtisDetay({anAwtis}) {
<Typography gutterBottom variant='body1' component='h2'>
<strong>Biographie</strong>
</Typography>
<Typography textAlign='justify' variant='subtitle1' component='h3'>
<Typography textalign='justify' variant='subtitle1' component='h3'>
{biyo}
</Typography>
</CardContent>
@@ -74,20 +74,20 @@ export default function AwtisDetay({anAwtis}) {
</Grid>
)}
<Grid size={{xs: 12, md: 6}}>
<Box marginBottom={3}>
{paroles.data.length > 1 ? (
<Box marginbottom={3}>
{paroles.length > 1 ? (
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls='panel-teks-content'
id='panel-teks-header'
>
<Typography marginRight={2} textAlign='center' variant='body1' component='h2'><strong>Liste des paroles</strong></Typography>
<Chip color='primary' label={paroles.data.length} size='small' variant='contained' />
<Typography sx={{marginRight: 2, textAlign:'center' }} variant='body1' component='h2'><strong>Liste des paroles</strong></Typography>
<Chip color='primary' label={paroles.length} size='small' variant='contained' />
</AccordionSummary>
<AccordionDetails sx={{paddingInline: 0}}>
{sortedTeks.map(anPawol => {
const {couverture} = anPawol.attributes
const {couverture} = anPawol
const kuvetiFormat = formatKuveti(couverture)
return (
@@ -99,13 +99,13 @@ export default function AwtisDetay({anAwtis}) {
</AccordionDetails>
</Accordion>
) : (
paroles.data.length === 0 ? (
paroles.length === 0 ? (
<Typography gutterBottom textAlign='center' variant='body1' component='h2'><strong>Aucune parole pour le moment</strong></Typography>
) : (
<Box>
<Typography gutterBottom textAlign='center' variant='body1' component='h2'><strong>Parole</strong></Typography>
<Typography gutterBottom textalign='center' variant='body1' component='h2'><strong>Parole</strong></Typography>
<Paper sx={{height: '100%', paddingBlock: 2}}>
<MizikLyen anPawol={paroles.data[0]} kuveti={formatKuveti(paroles.data[0].attributes.couverture)} />
<MizikLyen anPawol={paroles[0]} kuveti={formatKuveti(paroles[0].couverture)} />
</Paper>
</Box>
)
@@ -123,7 +123,7 @@ export default function AwtisDetay({anAwtis}) {
{esByografiOuve && (
<AwtisBiyografi
alias={alias}
paroles={paroles.data}
paroles={paroles}
biographie={biographie}
esByografiOuve={esByografiOuve}
meteEsByografiOuve={meteEsByografiOuve}
+4 -4
View File
@@ -5,7 +5,7 @@ import {useRouter} from 'next/navigation'
import PropTypes from 'prop-types'
import CardActionArea from '@mui/material/CardActionArea'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Card from '@mui/material/Card'
import CardMedia from '@mui/material/CardMedia'
import CardContent from '@mui/material/CardContent'
@@ -66,7 +66,7 @@ export default function AwtisKat({artiste}) {
className={classes.media}
component='img'
alt={alias}
image={`${photo?.data?.attributes?.url ? `${IMAGE_URL}${photo?.data?.attributes?.url}` : noImageUrl}`}
image={`${photo?.url ? `${IMAGE_URL}${photo?.url}` : noImageUrl}`}
title={alias}
/>
<CardContent>
@@ -74,7 +74,7 @@ export default function AwtisKat({artiste}) {
{alias}
</Typography>
<Typography align='center' variant='body2' color='textSecondary' component='h5'>
{`${paroles.data.length === 0 ? 'Aucune parole pour le moment' : `${paroles.data.length} ${paroles.data.length > 1 ? 'paroles' : 'parole'}`}`}
{`${paroles.length === 0 ? 'Aucune parole pour le moment' : `${paroles.length} ${paroles.length > 1 ? 'paroles' : 'parole'}`}`}
</Typography>
</CardContent>
</CardActionArea>
@@ -82,7 +82,7 @@ export default function AwtisKat({artiste}) {
{esByografiOuve && (
<AwtisBiyografi
alias={alias}
paroles={paroles.data}
paroles={paroles}
biographie={biographie}
esByografiOuve={esByografiOuve}
meteEsByografiOuve={meteEsByografiOuve}
+39 -32
View File
@@ -1,6 +1,6 @@
'use client'
import {useEffect, useState} from 'react'
import {useEffect, useState, useMemo} from 'react'
import {useRouter} from 'next/navigation'
import TextField from '@mui/material/TextField'
import Autocomplete from '@mui/material/Autocomplete'
@@ -27,12 +27,13 @@ export default function ChecheAwtis() {
(async () => {
try {
const data = await jwennToutAwtis()
const {data} = await jwennToutAwtis()
const filteredData = data.map(artiste => {
const firstLetter = artiste.attributes.alias[0].toUpperCase()
const firstLetter = artiste.alias[0].toUpperCase()
return {
firstLetter: /\d/.test(firstLetter) ? '0-9' : firstLetter,
...artiste.attributes
...artiste
}
})
if (active) {
@@ -48,8 +49,16 @@ export default function ChecheAwtis() {
}
}, [loading])
const sortedOptions = useMemo(() => {
return [...options].sort((a, b) =>
-b.firstLetter.localeCompare(a.firstLetter)
);
}, [options]);
return (
<Container sx={{display: 'flex', justifyContent: 'center', marginBottom: 3}}>
<Container
sx={{ display: 'flex', justifyContent: 'center', marginBottom: 3 }}
>
<Autocomplete
autoHighlight
disableClearable
@@ -59,42 +68,40 @@ export default function ChecheAwtis() {
loadingText='Chargement...'
noOptionsText='Aucun résultat'
id='cheche-awtis'
options={options.sort((a, b) => -b.firstLetter.localeCompare(a.firstLetter))}
groupBy={option => option?.firstLetter}
getOptionLabel={option => option?.alias}
renderOption={(props, option) => (
<li {...props}>
<Avatar style={{marginRight: 8}} alt={option?.alias} src={`${IMAGE_URL}${option?.photo?.data?.attributes?.formats?.thumbnail?.url}`} />
{option?.alias}
</li>
)}
sx={{width: 300}}
renderInput={params => (
options={sortedOptions}
groupBy={(option) => option?.firstLetter}
getOptionLabel={(option) => option?.alias}
renderOption={(props, option) => {
const {key, ...rest} = props;
return (
<li key={key} {...rest}>
<Avatar
style={{ marginRight: 8 }}
alt={option?.alias}
src={`${IMAGE_URL}${option?.photo?.formats?.thumbnail?.url}`}
/>
{option?.alias}
</li>
);
}}
sx={{ width: 300 }}
renderInput={(params) => (
<TextField
{...params}
label='Rechercher un artiste'
InputProps={{
...params.InputProps,
endAdornment: (
<>
{loading ? <CircularProgress color='primary' size={20} /> : null}
{params.InputProps.endAdornment}
</>
),
slotProps={{
...params.slotProps,
htmlInput: { ...params.slotProps.htmlInput },
}}
/>
)}
onChange={(event, newValue) => {
router.push(`/awtis/${newValue.slug}`)
}}
onOpen={() => {
setOpen(true)
}}
onClose={() => {
setOpen(false)
router.push(`/awtis/${newValue.slug}`);
}}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
/>
</Container>
)
}
+1 -1
View File
@@ -105,7 +105,7 @@ export default function MizikBadjMeni({paroles}) {
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id='menu-list-grow' onKeyDown={() => handleListKeyDown()}>
{sortedTeks.map(({id, attributes}) => <MenuItem key={id} onClick={() => handleClick(attributes.slug)}>{attributes.titre}</MenuItem>)}
{sortedTeks.map(({id, slug, titre}) => <MenuItem key={id} onClick={() => handleClick(slug)}>{titre}</MenuItem>)}
</MenuList>
</ClickAwayListener>
</Paper>
+3 -3
View File
@@ -13,8 +13,8 @@ import {formatKuveti} from '../../lib/kuveti'
import MizikLyen from './mizik-lyen'
function grupPawol(pawol) {
const pawolTrie = pawol.sort((a, b) => a.attributes.titre.localeCompare(b.attributes.titre, 'fr', {sensitivity: 'base'}))
const grupPawol = groupBy(pawol, anPawol => anPawol.attributes.titre[0].toUpperCase())
const pawolTrie = pawol.sort((a, b) => a.titre.localeCompare(b.titre, 'fr', {sensitivity: 'base'}))
const grupPawol = groupBy(pawol, anPawol => anPawol.titre[0].toUpperCase())
const grupCounts = Object.values(grupPawol).map(anPawol => anPawol.length)
const grup = Object.keys(grupPawol)
grup.sort((a, b) => a[0].localeCompare(b[0], 'fr', {sensitivity: 'base'}))
@@ -33,7 +33,7 @@ export default function MizikLis({niAwtis, paroles, meteEsMobilOuve}) {
groupContent={index => <div>{grup[index]}</div>}
itemContent={index => {
const anPawol = pawol[index]
const {couverture} = anPawol.attributes
const {couverture} = anPawol
const kuvetiFormat = formatKuveti(couverture)
return (
+10 -10
View File
@@ -20,23 +20,23 @@ export default function MizikLyen({niAwtis, anPawol, kuveti, slug, meteEsMobilOu
return (
<Link
passHref
href={`/paroles/${anPawol.attributes.slug}#${anPawol.attributes.slug}`}
href={`/paroles/${anPawol.slug}#${anPawol.slug}`}
style={{textDecoration: 'none', width: '100%', display: 'flex', alignItems: 'center'}}
onClick={() => meteEsMobilOuve(false)}
>
<ListItemButton
sx={{padding: 0}}
id={anPawol.attributes.slug}
selected={slug === anPawol.attributes.slug}
id={anPawol.slug}
selected={slug === anPawol.slug}
>
<ListItemAvatar sx={{ml: 2.5}}>
<Avatar alt={anPawol.attributes.titre} src={`${apiUrl}${kuveti?.url}`} />
<Avatar alt={anPawol.titre} src={`${apiUrl}${kuveti?.url}`} />
</ListItemAvatar>
<ListItemText
primary={<Typography sx={{fontWeight: 'bold'}} color='info.main'>{anPawol.attributes.titre}</Typography>}
secondary={niAwtis ? getAlias(anPawol.attributes.artistes, anPawol.attributes.prioriteArtistes) : null} />
primary={<Typography sx={{fontWeight: 'bold', color: 'info.main'}} >{anPawol.titre}</Typography>}
secondary={niAwtis ? getAlias(anPawol.artistes, anPawol.prioriteArtistes) : null} />
{anPawol.attributes.creativeCommons && (
{anPawol.creativeCommons && (
<Box marginInline={1}>
<Image
width={24}
@@ -48,14 +48,14 @@ export default function MizikLyen({niAwtis, anPawol, kuveti, slug, meteEsMobilOu
</Box>
)}
{esBrandNew(anPawol.attributes.publishedAt) && (
{esBrandNew(anPawol.publishedAt) && (
<FiberNewOutlinedIcon style={{fontSize: 30, marginRight: 5}} color='primary' />
)}
{anPawol.attributes.explicitLyrics && (
{anPawol.explicitLyrics && (
<ExplicitIcon style={{marginRight: 5}} color='error' />
)}
{anPawol.attributes.okiMizikID && (
{anPawol.okiMizikID && (
<LibraryMusicIcon style={{fontSize: 30, marginRight: 5}} color='primary' />
)}
</ListItemButton>
+2 -2
View File
@@ -3,7 +3,7 @@
import PropTypes from 'prop-types'
import {useRouter} from 'next/navigation'
import Pagination from '@mui/material/Pagination'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
export default function Pajinasyon({pajTotal, paj}) {
const router = useRouter()
@@ -14,7 +14,7 @@ export default function Pajinasyon({pajTotal, paj}) {
}
return (
<Grid container sx={{marginBlock: 3}} justifyContent='center'>
<Grid container sx={{marginTop: 10, marginBottom: 3, justifyContent: 'center'}}>
<Pagination size='small' page={paj} count={pajTotal} color='primary' onChange={handleChange} />
</Grid>
)
+49 -49
View File
@@ -21,25 +21,25 @@ export default function Cgu() {
Définitions
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Prestations et Services </strong>: <Link href='https://oki.re'><strong>oki.re</strong></Link> met à disposition :
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Contenu </strong>: Ensemble des éléments constituants linformation présente sur le site, notamment textes images vidéos.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Informations utilisateurs </strong>: Ci après dénommé « Information (s) »
qui correspondent à lensemble des données personnelles susceptibles d’être détenues par
<Link href='https://oki.re'> <strong>oki.re</strong></Link> pour la gestion de votre compte, et à des fins danalyses et de statistiques.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Utilisateur </strong>: Internaute, utilisant le site susnommé.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Utilisateur enregistré</strong>: Internaute ayant compte utilisateur, utilisant le site susnommé.
</Typography>
@@ -47,7 +47,7 @@ export default function Cgu() {
<strong>Informations personnelles </strong>: « Les informations qui permettent, sous quelque forme que ce soit, directement ou non,
lidentification des personnes physiques auxquelles elles sappliquent » (article 4 de la loi n° 78-17 du 6 janvier 1978).
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les termes « données à caractère personnel », « personne concernée », « sous traitant » et « données sensibles » ont le sens défini par le Règlement
Général sur la Protection des Données (RGPD : n° 2016-679)
</Typography>
@@ -56,18 +56,18 @@ export default function Cgu() {
1. Présentation du site internet
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
En vertu de larticle 6 de la loi n° 2004-575 du 21 juin 2004 pour la confiance dans léconomie numérique, il est précisé aux utilisateurs du site internet
<Link href='https://oki.re'> <strong>oki.re</strong></Link> lidentité des différents intervenants dans le cadre de sa réalisation et de son suivi :
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Propriétaire</strong> : ORGANISATION KA INTERNATIONALE (Association loi 1901)
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<strong>Responsable publication</strong> : ORGANISATION KA INTERNATIONALE <Link href='mailto:kontak@o-k-i.net'><strong>kontak@o-k-i.net</strong></Link>
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Le responsable publication est une personne morale
</Typography>
<Typography variant='body1'>
@@ -114,7 +114,7 @@ export default function Cgu() {
<strong>Délégué à la protection des données</strong> : ORGANISATION KA INTERNATIONALE <Link href='mailto:kontak@o-k-i.net'><strong>kontak@o-k-i.net</strong></Link>
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Ces mentions légales RGPD sont issues du <Link target='_blank' rel='noreferrer' href='https://fr.orson.io/1371/generateur-mentions-legales'>générateur gratuit de mentions légales pour un site internet (orson.io)</Link>.
</Typography>
@@ -122,13 +122,13 @@ export default function Cgu() {
2. Conditions générales dutilisation du site et des services proposés.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Lutilisation du site <Link href='https://oki.re'><strong>oki.re</strong></Link> implique lacceptation pleine et entière des conditions générales dutilisation ci-après décrites.
Ces conditions dutilisation sont susceptibles dêtre modifiées ou complétées à tout moment, les utilisateurs du site <Link href='https://oki.re'><strong>oki.re </strong></Link>
sont donc invités à les consulter de manière régulière.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Ce site internet est normalement accessible à tout moment aux utilisateurs. Une interruption pour raison de maintenance technique peut être toutefois
décidée par <Link href='https://oki.re'><strong>oki.re</strong></Link>, qui sefforcera alors de communiquer préalablement aux utilisateurs les dates et heures de lintervention.
Le site web <Link href='https://oki.re'><strong>oki.re</strong></Link> est mis à jour régulièrement par <strong>ORGANISATION KA INTERNATIONALE</strong>. De la même façon, les mentions légales peuvent être
@@ -139,13 +139,13 @@ export default function Cgu() {
3. Description des services fournis
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> sefforce de fournir sur le site, des informations
aussi précises que possible. Toutefois, il ne pourra être tenu responsable des oublis, des inexactitudes et des carences dans la mise à jour, quelles soient de son fait ou du fait
des tiers partenaires qui lui fournissent ces informations.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Toutes les informations indiquées sur le site <Link href='https://oki.re'><strong>oki.re</strong></Link> sont données à titre indicatif,
et sont susceptibles dévoluer. Par ailleurs, les renseignements figurant sur le site <Link href='https://oki.re'><strong>oki.re</strong></Link> ne sont pas exhaustifs.
Ils sont donnés sous réserve de modifications ayant été apportées depuis leur mise en ligne.
@@ -155,7 +155,7 @@ export default function Cgu() {
4. Limitations contractuelles sur les données techniques
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Le site utilise la technologie JavaScript.
Le site Internet ne pourra être tenu responsable de dommages matériels liés à lutilisation du site. De plus, lutilisateur du site sengage à accéder au site en utilisant un matériel récent,
ne contenant pas de virus et avec un navigateur de dernière génération mis-à-jour.
@@ -163,14 +163,14 @@ export default function Cgu() {
Règlement Général sur la Protection des Données (RGPD : n° 2016-679).
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Lobjectif est dapporter une prestation qui assure le meilleur taux daccessibilité.
Lhébergeur assure la continuité de son service 24 Heures sur 24, tous les jours de lannée. Il se réserve néanmoins la possibilité dinterrompre le service dhébergement
pour les durées les plus courtes possibles notamment à des fins de maintenance, damélioration de ses infrastructures, de défaillance de ses infrastructures ou si les
Prestations et Services génèrent un trafic réputé anormal.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> et lhébergeur ne pourront être tenus responsables en cas de dysfonctionnement du réseau Internet,
des lignes téléphoniques ou du matériel informatique et de téléphonie lié notamment à lencombrement du réseau empêchant laccès au serveur.
</Typography>
@@ -179,12 +179,12 @@ export default function Cgu() {
5. Limitations de responsabilité
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> agit en tant quéditeur du site. <Link href='https://oki.re'><strong>oki.re</strong></Link> est responsable
de la qualité et de la véracité du Contenu quil publie.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> ne pourra être tenu responsable des dommages directs et indirects causés au matériel de lutilisateur,
lors de laccès au site internet <Link href='https://oki.re'><strong>oki.re</strong></Link>, et résultant soit de lutilisation dun matériel
ne répondant pas aux spécifications indiquées au point 4, soit de lapparition dun bug ou dune incompatibilité.
@@ -198,12 +198,12 @@ export default function Cgu() {
6.1 Responsables de la collecte des données personnelles
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Pour les données personnelles collectées dans le cadre de la création du compte personnel de lutilisateur et de sa navigation sur le site
le responsable du traitement des données personnelles est : ORGANISATION KA INTERNATIONALE. <Link href='https://oki.re'><strong>oki.re</strong></Link>.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
En tant que responsable du traitement des données quil collecte, <Link href='https://oki.re'><strong>oki.re</strong></Link> sengage à respecter le cadre des dispositions légales en vigueur.
Chaque fois que <Link href='https://oki.re'><strong>oki.re</strong></Link> traite des Données Personnelles, <Link href='https://oki.re'><strong>oki.re</strong></Link> prend toutes les mesures raisonnables
pour sassurer de lexactitude et de la pertinence des Données Personnelles au regard des finalités pour lesquelles <Link href='https://oki.re'><strong>oki.re</strong></Link> les traite.
@@ -298,22 +298,22 @@ export default function Cgu() {
</ListItem>
</List>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Dès que <Link href='https://oki.re'><strong>oki.re</strong></Link> a connaissance du décès dun Utilisateur et à défaut dinstructions de sa part, <Link href='https://oki.re'><strong>oki.re</strong></Link> sengage à détruire
ses données, sauf si leur conservation savère nécessaire à des fins probatoires ou pour répondre à une obligation légale.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Si lUtilisateur souhaite savoir comment <Link href='https://oki.re'><strong>oki.re</strong></Link> utilise ses Données Personnelles, demander à les rectifier ou soppose à leur traitement,
lUtilisateur peut contacter <Link href='https://oki.re'><strong>oki.re</strong></Link> par courriel à ladresse suivante, <Link href='mailto:kontak@o-k-i.net'><strong>kontak@o-k-i.net</strong></Link> ou via XMPP à <Link href='xmpp:oki@xmpp.cz'><strong>oki@xmpp.cz</strong></Link>.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Dans ce cas, lUtilisateur doit indiquer les Données Personnelles quil souhaiterait que <Link href='https://oki.re'><strong>oki.re</strong></Link> corrige,
mette à jour ou supprime, en sidentifiant précisément avec une copie dune pièce didentité (carte didentité ou passeport).
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les demandes de suppression de Données Personnelles seront soumises aux obligations qui sont imposées à <Link href='https://oki.re'><strong>oki.re</strong></Link> par la loi,
notamment en matière de conservation ou darchivage des documents. Enfin, les Utilisateurs de <Link href='https://oki.re'><strong>oki.re</strong></Link> peuvent déposer une réclamation
auprès des autorités de contrôle, et notamment de la CNIL (https://www.cnil.fr/fr/plaintes).
@@ -323,14 +323,14 @@ export default function Cgu() {
6.4 Non-communication des données personnelles
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> sinterdit de traiter, héberger ou transférer les Informations collectées sur ses utilisateurs vers un pays situé en dehors de
lUnion européenne ou reconnu comme « non adéquat » par la Commission européenne sans en informer préalablement lutilisateur. Pour autant, <Link href='https://oki.re'><strong>oki.re</strong></Link> reste
libre du choix de ses sous-traitants techniques et commerciaux à la condition quil présentent les garanties suffisantes au regard des exigences du Règlement Général sur la Protection des
Données (RGPD : n° 2016-679).
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> sengage à prendre toutes les précautions nécessaires afin de préserver la sécurité des Informations et notamment quelles ne soient pas communiquées
à des personnes non autorisées. Cependant, si un incident impactant lintégrité ou la confidentialité des Informations de lutilisateur est portée
à la connaissance de <Link href='https://oki.re'><strong>oki.re</strong></Link>, celle-ci devra dans les meilleurs délais informer lutilisateur
@@ -341,7 +341,7 @@ export default function Cgu() {
6.5 Inscription et connexion
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les utilisateurs peuvent sinscrire sur <Link href='https://oki.re'><strong>oki.re</strong></Link> en renseignant leur adresse e-mail, un nom dutilisateur ainsi quun mot de passe.
À la suite de linscription, un lien de vérification est envoyé à ladresse utilisée. Ce lien permet dactiver le compte. Sans cette activation, lutilisateur naura pas la possibilité de se connecter au site.
Si un utilisateur na pas reçu le lien dactivation, il a la possibilité de demander son renvoi.
@@ -358,7 +358,7 @@ export default function Cgu() {
6.6 Proposition de paroles
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les utilisateurs connectés ont la possibilité de proposer des paroles depuis un espace dédié.
Il se trouve à ladresse <Link href='https://oki.re/pwopose'><strong>oki.re/pwopose</strong></Link>.
Les textes soumis ne sont pas directement publiés sur le site. Ils doivent être approuvé par léquipe de vérification.
@@ -369,7 +369,7 @@ export default function Cgu() {
7. Notification dincident
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Quels que soient les efforts fournis, aucune méthode de transmission sur Internet et aucune méthode de stockage électronique nest complètement sûre.
Nous ne pouvons en conséquence pas garantir une sécurité absolue.
Si nous prenions connaissance dune brèche de la sécurité, nous avertirions les utilisateurs concernés afin quils puissent prendre les mesures appropriées.
@@ -378,7 +378,7 @@ export default function Cgu() {
obligations réglementaires en matière de reporting.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Aucune information personnelle de lutilisateur du site <Link href='https://oki.re'><strong>oki.re</strong></Link> nest publiée à linsu de lutilisateur, échangée, transférée,
cédée ou vendue sur un support quelconque à des tiers. Seule lhypothèse du rachat de <Link href='https://oki.re'><strong>oki.re</strong></Link> et de ses droits permettrait
la transmission des dites informations à léventuecodel acquéreur qui serait à son tour tenu de la même obligation de conservation et de modification des données vis à vis de
@@ -389,12 +389,12 @@ export default function Cgu() {
Sécurité
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Pour assurer la sécurité et la confidentialité des Données Personnelles et des Données Personnelles de Santé, <Link href='https://oki.re'><strong>oki.re</strong></Link> utilise des réseaux protégés
par des dispositifs standards tels que par pare-feu, la pseudonymisation, lencryption et mot de passe.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Lors du traitement des Données Personnelles, <Link href='https://oki.re'><strong>oki.re</strong></Link> prend toutes les mesures raisonnables visant à les protéger contre toute perte,
utilisation détournée, accès non autorisé, divulgation, altération ou destruction.
</Typography>
@@ -403,7 +403,7 @@ export default function Cgu() {
8. Liens hypertextes « cookies » et balises (tags) internet
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Le site <Link href='https://oki.re'><strong>oki.re</strong></Link> contient un certain nombre de liens hypertextes vers dautres sites,
mis en place avec lautorisation de <Link href='https://oki.re'><strong>oki.re</strong></Link>. Cependant, <Link href='https://oki.re'><strong>oki.re</strong></Link> na pas la possibilité de vérifier
le contenu des sites ainsi visités, et nassumera en conséquence aucune responsabilité de ce fait.
@@ -416,18 +416,18 @@ export default function Cgu() {
8.1 « COOKIES »
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Un « cookie » est un petit fichier dinformation envoyé sur le navigateur de lUtilisateur et enregistré au sein du terminal de lUtilisateur (ex : ordinateur, smartphone),
(ci-après « Cookies »). Ce fichier comprend des informations telles que le nom de domaine de lUtilisateur, le fournisseur daccès Internet de lUtilisateur,
le système dexploitation de lUtilisateur, ainsi que la date et lheure daccès. Les Cookies ne risquent en aucun cas dendommager le terminal de lUtilisateur.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
<Link href='https://oki.re'><strong>oki.re</strong></Link> est susceptible de traiter les informations de lUtilisateur concernant sa visite du Site, telles que les pages consultées,
les recherches effectuées. Ces informations permettent à <Link href='https://oki.re'><strong>oki.re</strong></Link> daméliorer le contenu du Site, de la navigation de lUtilisateur.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les Cookies facilitant la navigation et/ou la fourniture des services proposés par le Site, lUtilisateur peut configurer son navigateur pour quil lui permette de décider sil souhaite
ou non les accepter de manière à ce que des Cookies soient enregistrés dans le terminal ou, au contraire, quils soient rejetés, soit systématiquement, soit selon leur émetteur.
LUtilisateur peut également configurer son logiciel de navigation de manière à ce que lacceptation ou le refus des Cookies lui soient proposés ponctuellement, avant quun Cookie soit
@@ -435,13 +435,13 @@ export default function Cgu() {
de navigation ne soient pas toutes disponibles.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Si lUtilisateur refuse lenregistrement de Cookies dans son terminal ou son navigateur, ou si lUtilisateur supprime ceux qui y sont enregistrés,
lUtilisateur est informé que sa navigation et son expérience sur le Site peuvent être limitées. Cela pourrait également être le cas lorsque <Link href='https://oki.re'><strong>oki.re</strong></Link> ne peut pas reconnaître,
à des fins de compatibilité technique, le type de navigateur utilisé par le terminal, les paramètres de langue et daffichage ou le pays depuis lequel le terminal semble connecté à Internet.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Le cas échéant, <Link href='https://oki.re'><strong>oki.re</strong></Link> décline toute responsabilité pour les conséquences liées au fonctionnement dégradé du Site
et des services éventuellement proposés par <Link href='https://oki.re'><strong>oki.re</strong></Link>, résultant du refus de Cookies par lUtilisateur de limpossibilité
pour <Link href='https://oki.re'><strong>oki.re</strong></Link> denregistrer ou de consulter les Cookies nécessaires à leur fonctionnement du fait du choix de lUtilisateur.
@@ -449,13 +449,13 @@ export default function Cgu() {
qui permettra de savoir de quelle manière lUtilisateur peut modifier ses souhaits en matière de Cookies.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Enfin, en cliquant sur licône dédiée au réseau social Twitter, figurant sur le Site de <Link href='https://oki.re'><strong>oki.re</strong></Link> ou dans son application mobile
et si lUtilisateur a accepté le dépôt de cookies en poursuivant sa navigation sur le Site Internet ou lapplication mobile de <Link href='https://oki.re'><strong>oki.re</strong></Link>, Twitter,
peut également déposer des cookies sur vos terminaux (ordinateur, tablette, téléphone portable).
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Ces types de cookies ne sont déposés sur vos terminaux quà condition que vous y consentiez, en continuant votre navigation sur le Site Internet ou
lapplication mobile de <Link href='https://oki.re'><strong>oki.re</strong></Link>. À tout moment, lUtilisateur peut néanmoins revenir sur son consentement à ce
que <Link href='https://oki.re'><strong>oki.re</strong></Link> dépose ce type de cookies.
@@ -465,7 +465,7 @@ export default function Cgu() {
9. Les dons
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Le site dispose dune page permettant de faire des dons à « ORGANISATION KA INTERNATIONALE » de manière sécurisée.
Pour se faire, il faut se rendre sur la page « <Link href='/soutyen'><strong>soutyen</strong></Link> ». Lutilisateur a 2 onglets disponibles :
</Typography>
@@ -493,11 +493,11 @@ export default function Cgu() {
9.1 LIBERAPAY / PAYPAL
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
La plateforme <Link target='_blank' rel='noreferrer' href='https://liberapay.com/OKi/donate'><strong>Liberapay</strong></Link> est mise à disposition. Elle permet non seulement de personnaliser le montant, mais aussi la récurrence des dons. Cest à dire quavec cet outil, lutilisateur peut effectuer des dons hebdomadaires, mensuels ou annuels.
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Lutilisateur peut faire un don en passant par la plateforme <Link target='_blank' rel='noreferrer' href='https://www.paypal.com/donate/?hosted_button_id=5Q3KPR79CAZVW'><strong>PayPal</strong></Link>. En cliquant sur le bouton prévu à cet effet, il est redirigé vers la page de don associée à ORGANISATION KA INTERNATIONALE. Il peut ensuite choisir un montant et valider le don en utilisant son compte <Link target='_blank' rel='noreferrer' href='https://www.paypal.com/donate/?hosted_button_id=5Q3KPR79CAZVW'><strong>PayPal</strong></Link> ou une carte bancaire sil nest pas enregistré.
</Typography>
@@ -505,7 +505,7 @@ export default function Cgu() {
9.2 CARTE BANCAIRE
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
En cliquant sur le bouton « CARTE BANCAIRE », lutilisateur se voit proposer plusieurs choix. Parmi ces derniers, deux options sont possibles :
<List>
<ListItem>
@@ -527,7 +527,7 @@ export default function Cgu() {
</List>
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Les dons peuvent donc être fait une seule fois ou de manière récurrente.
Quelque soit le choix, lutilisateur est redirigé vers le sous-domaine don.o-k-i.net suivi de lID du montant choisit. Cette URL est gérée par la plateforme de paiement sécurisée <Link href='https://stripe.com/' target='_blank' rel='noopener noreferrer'> <strong>Stripe</strong></Link>.
@@ -538,7 +538,7 @@ export default function Cgu() {
10. Propriété intellectuelle et licence
</Typography>
<Typography paragraph gutterBottom variant='body1'>
<Typography paragraph='true' gutterBottom variant='body1'>
Le site internet <Link href='https://oki.re'><strong>oki.re</strong></Link> et les éléments qui y sont accessibles
(textes, images, graphismes, logos, vidéos, icônes, sons, etc.) sont, sauf mention contraire,
mis à disposition sous la licence <Link href='https://www.gnu.org/licenses/agpl-3.0.html' target='_blank' rel='noopener noreferrer'> <strong>GNU Affero General Public License Version 3 (AGPL-3.0)</strong></Link>. Cette licence garantit aux utilisateurs les libertés suivantes :
@@ -587,7 +587,7 @@ export default function Cgu() {
11. Droit applicable et attribution de juridiction
</Typography>
<Typography paragraph variant='body1'>
<Typography paragraph='true' variant='body1'>
Tout litige en relation avec lutilisation du site <Link href='https://oki.re'><strong>oki.re</strong></Link> est soumis au droit français.
En dehors des cas la loi ne le permet pas, il est fait attribution exclusive de juridiction aux tribunaux compétents.
</Typography>
+11 -11
View File
@@ -50,8 +50,8 @@ export default function FilesList({files}) {
const theme = useTheme()
const {mode} = useColorScheme()
const musicFiles = files.filter(file => file.attributes.mime.startsWith('audio'))
const pdfFiles = files.filter(file => file.attributes.mime === 'application/pdf')
const musicFiles = files.filter(file => file.mime.startsWith('audio'))
const pdfFiles = files.filter(file => file.mime === 'application/pdf')
const sortedMusicFiles = musicFiles.sort((a, b) => {
const extensionOrder = {
@@ -60,7 +60,7 @@ export default function FilesList({files}) {
'.aac': 2,
'.mp3': 3
}
return extensionOrder[a.attributes.ext.toLowerCase()] - extensionOrder[b.attributes.ext.toLowerCase()]
return extensionOrder[a.ext.toLowerCase()] - extensionOrder[b.ext.toLowerCase()]
})
const handleClick = (e, url, fileName) => {
@@ -170,7 +170,7 @@ export default function FilesList({files}) {
{sortedMusicFiles.map(file => (
<StyledTableRow key={file.id}>
<StyledTableCell>
{getQuality(file.attributes.ext.toLowerCase(), file?.attributes?.caption?.toUpperCase())}
{getQuality(file.ext.toLowerCase(), file?.caption?.toUpperCase())}
</StyledTableCell>
<StyledTableCell align='left'>
<Link
@@ -178,11 +178,11 @@ export default function FilesList({files}) {
underline='hover'
sx={{fontWeight: 'bold'}}
aria-label='download'
onClick={e => handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)}
onClick={e => handleClick(e, `${apiUrl}${file.url}`, file.name)}
>
{file.attributes.name}
{file.name}
</Link>
<small style={{marginLeft: 3}}>({formatSize(file.attributes.size)})</small>
<small style={{marginLeft: 3}}>({formatSize(file.size)})</small>
</StyledTableCell>
</StyledTableRow>
))}
@@ -217,7 +217,7 @@ export default function FilesList({files}) {
<StyledTableRow key={file.id}>
<StyledTableCell>
<strong>
{file.attributes.caption}
{file.caption}
</strong>
</StyledTableCell>
<StyledTableCell align='left'>
@@ -226,11 +226,11 @@ export default function FilesList({files}) {
underline='hover'
sx={{fontWeight: 'bold'}}
aria-label='download'
onClick={e => handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)}
onClick={e => handleClick(e, `${apiUrl}${file.url}`, file.name)}
>
{file.attributes.name}
{file.name}
</Link>
<small style={{marginLeft: 3}}>({formatSize(file.attributes.size)})</small>
<small style={{marginLeft: 3}}>({formatSize(file.size)})</small>
</StyledTableCell>
</StyledTableRow>
))}
+4 -4
View File
@@ -38,20 +38,20 @@ const StyledList = styled(List)((
export default function KomanteList({commentaires}) {
return (
<StyledList className={classes.root}>
{commentaires.map(({id, attributes}) => (
{commentaires.map(({id, user, contenu, datePublication}) => (
<div key={id}>
<ListItemText
primary={
<Typography gutterBottom style={{textDecoration: 'underline'}} variant='body1'>
<small>{attributes.user.data.attributes.username}</small>
<small>{user.username}</small>
</Typography>
}
/>
<ListItemText
primary={formatJsonString(attributes.contenu)}
primary={formatJsonString(contenu)}
secondary={
<Typography gutterBottom style={{marginBlock: 5, fontStyle: 'italic'}} variant='caption' display='block'>
{format(new Date(attributes.datePublication), 'Pp', {locale: fr})}
{format(new Date(datePublication), 'Pp', {locale: fr})}
</Typography>
}
/>
+23 -22
View File
@@ -106,28 +106,29 @@ export default function Navigasyon() {
<Appdiv>
<div className={classes.root}>
<AppBar style={{zIndex: 1, boxShadow: 'none'}} position='fixed' color='default'>
<Tabs
allowScrollButtonsMobile
scrollButtons
centered={Boolean(!isMobile)}
value={selectedTab}
indicatorColor='primary'
textColor='primary'
aria-label='tabs menu'
variant={isMobile ? 'scrollable' : 'fullWidth'}
sx={{
[`& .${tabsClasses.scrollButtons}`]: {
'&.Mui-disabled': {opacity: 0.3},
},
}}
onChange={handleChange}
>
<Tab icon={<HomeIcon />} aria-label='Accueil' {...a11yProps(0)} />
<Tab icon={<VolunteerActivismIcon />} aria-label='Nous soutenir' {...a11yProps(1)} />
<Tab icon={<MusicNoteIcon />} aria-label='Paroles' {...a11yProps(2)} />
<Tab icon={<RecordVoiceOverIcon />} aria-label='Artistes' {...a11yProps(3)} />
<Tab icon={<EditNoteIcon />} aria-label='Proposer des paroles' {...a11yProps(4)} />
</Tabs>
{selectedTab !== undefined && <Tabs
allowScrollButtonsMobile
scrollButtons
centered={Boolean(!isMobile)}
value={selectedTab}
indicatorColor='primary'
textColor='primary'
aria-label='tabs menu'
variant={isMobile ? 'scrollable' : 'fullWidth'}
sx={{
[`& .${tabsClasses.scrollButtons}`]: {
'&.Mui-disabled': {opacity: 0.3},
},
}}
onChange={handleChange}
>
<Tab icon={<HomeIcon />} aria-label='Accueil' {...a11yProps(0)} />
<Tab icon={<VolunteerActivismIcon />} aria-label='Nous soutenir' {...a11yProps(1)} />
<Tab icon={<MusicNoteIcon />} aria-label='Paroles' {...a11yProps(2)} />
<Tab icon={<RecordVoiceOverIcon />} aria-label='Artistes' {...a11yProps(3)} />
<Tab icon={<EditNoteIcon />} aria-label='Proposer des paroles' {...a11yProps(4)} />
</Tabs>
}
</AppBar>
<TabPanel value={value} index={0} />
<TabPanel value={value} index={1} />
+1 -1
View File
@@ -4,7 +4,7 @@ import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import CardActionArea from '@mui/material/CardActionArea'
import Divider from '@mui/material/Divider'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Typography from '@mui/material/Typography'
import {CardMedia} from '@mui/material'
+5 -5
View File
@@ -15,7 +15,7 @@ import Snackbar from '@mui/material/Snackbar'
import Tab from '@mui/material/Tab'
import Tabs from '@mui/material/Tabs'
import Typography from '@mui/material/Typography'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Visibility from '@mui/icons-material/Visibility'
import VisibilityOff from '@mui/icons-material/VisibilityOff'
import MuiAlert from '@mui/material/Alert'
@@ -241,7 +241,7 @@ function Koneksyon({chimen}) {
}
return (
<Container sx={{marginTop: 2}} maxWidth='sm'>
<Container sx={{marginTop: 6}} maxWidth='sm'>
<Box sx={{width: '100%'}}>
<Tabs centered value={value} aria-label='basic tabs example' onChange={handleChange}>
@@ -251,10 +251,10 @@ function Koneksyon({chimen}) {
<TabPanel value={value} index={0}>
<Box sx={{textAlign: 'center', marginBottom: 3}}>
<Typography gutterBottom textAlign='center'>Connectez-vous avec</Typography>
<Grid container alignItems='center' justifyContent='center' columnSpacing={{xs: 1, sm: 2, md: 3}}>
<Typography gutterBottom textalign='center'>Connectez-vous avec</Typography>
<Grid sx={{justifyContent: 'center'}} container columnSpacing={{xs: 1, sm: 2, md: 3}}>
{PROVIDERS.map(({id, title, width, height}) => (
<Grid key={id} marginTop={1}>
<Grid sx={{marginTop: 1}} key={id}>
<LoginProvider id={id} title={title} width={width} height={height} callbackUrl={`${siteUrl}${chimen}`} />
</Grid>
))}
+2 -2
View File
@@ -8,7 +8,7 @@ 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 Grid from '@mui/material/Grid'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
import InputLabel from '@mui/material/InputLabel'
@@ -191,7 +191,7 @@ function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
username: user.username,
email: user.email
},
artistes: [artiste.data.id],
artistes: [artiste.id],
traductionAuto: tradiksyonOtomatik
}
}, {
+1 -1
View File
@@ -6,7 +6,7 @@ import Button from '@mui/material/Button'
import {Paypal, Liberapay} from '@icons-pack/react-simple-icons'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import CardMethod from './card-method'
const PAYPAL_ID = process.env.NEXT_PUBLIC_PAYPAL_DONATE_ID
+6 -6
View File
@@ -13,17 +13,17 @@ export default function Presantasyon() {
<>
<CGUDialog open={open} setOpen={setOpen} />
<Paper sx={{padding: 3, textAlign: 'justify', marginTop: 5}}>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
Tous les services que nous proposons sont <strong>gratuits</strong> et ne contiennent <strong>aucune publicité</strong>. Les réseaux que nous utilisons sont hébergés sur <strong>nos serveurs</strong>. <br />
Tout ceci est possible grâce aux <strong>dons</strong>
</Typography>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
<strong>Toute contribution, aussi modeste soit-elle, nous permet daugmenter nos capacités</strong>.
</Typography>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
Concernant les dons, ils peuvent s&apos;effectuer via <Link underline='hover' href='https://liberapay.com/OKi/donate' target='_blank' rel='noreferrer'><strong>Liberapay</strong></Link>, <Link underline='hover' href='https://www.paypal.com/donate/?hosted_button_id=5Q3KPR79CAZVW' target='_blank' rel='noreferrer'><strong>PayPal</strong></Link>.
</Typography>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
Veuillez prendre connaissance des <Link underline='hover' href='#' onClick={() => setOpen(true)}><strong>CGU et de la politique de confidentialité</strong></Link> au chapitre 9 &quot;Les dons&quot;. <Link underline='hover' href={CGU_PDF_LINK}><small>Cliquez ici pour la version pdf</small></Link>.
</Typography>
<Typography variant='subtitle1' component='div'>
@@ -55,10 +55,10 @@ export default function Presantasyon() {
</ListItemText>
</ListItem>
</List>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
Pour toute question, nhésitez pas à nous contacter par courriel <Link href='mailto:kontak@o-k-i.net'><strong>kontak@o-k-i.net</strong></Link>.
</Typography>
<Typography paragraph variant='subtitle1' component='div'>
<Typography paragraph='true' variant='subtitle1' component='div'>
<strong>Merci par avance pour votre soutien 🥰</strong>
</Typography>
</Paper>
+1 -1
View File
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Typography from '@mui/material/Typography'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import TraductionsStats from './traductions-stats'
+1 -1
View File
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import BarStats from './bar-stats'
+1 -1
View File
@@ -8,7 +8,7 @@ export default function AnTeks({parole, paroleId}) {
<Teks
parole={parole}
paroleId={paroleId}
commentaires={parole?.commentaires.data}
commentaires={parole?.commentaires}
/>
)
}
+2 -2
View File
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import Container from '@mui/material/Container'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Typography from '@mui/material/Typography'
import {styled} from '@mui/material/styles'
@@ -17,7 +17,7 @@ const classes = {
const Root = styled('div')(() => ({
[`&.${classes.container}`]: {
marginTop: '4em',
marginTop: '6em',
marginBottom: '2em',
},
+1 -1
View File
@@ -49,7 +49,7 @@ export default function DiferansDialog({difference}) {
<DialogTitle>Liste des modifications</DialogTitle>
<List sx={{width: '100%', maxWidth: 360, bgcolor: 'background.paper'}}>
{difference.map(({id, admin_user, date, jsonDiff}) => {
const {firstname} = admin_user.data.attributes
const {firstname} = admin_user
const diferansDate = format(new Date(date), 'PPPppp', {locale: fr})
return (
+5 -5
View File
@@ -17,13 +17,13 @@ import MizikLis from '../awtis/mizik-lis'
const getMizikFiltered = (paroles, filter) => {
if (paroles) {
const filteredTitre = paroles.filter(({attributes}) => {
const deburredTit = deburr(attributes.titre)
const filteredTitre = paroles.filter(({titre}) => {
const deburredTit = deburr(titre)
return deburredTit.toLowerCase().includes(deburr(filter.toLowerCase()))
})
})
const filteredAlias = paroles.filter(({attributes}) => {
const aliasLis = attributes.artistes.data.map(({attributes}) => deburr(attributes.alias)).join(', ')
const filteredAlias = paroles.filter(({artistes}) => {
const aliasLis = artistes.map(({alias}) => deburr(alias)).join(', ')
return aliasLis.toLowerCase().includes(deburr(filter.toLowerCase()))
})
+5 -5
View File
@@ -70,7 +70,7 @@ export default function Lekte({audio, url, parole}) {
const minute = Math.floor(value / 60)
const secondLeft = value - (minute * 60)
if (Number.isNaN(minute) || Number.isNaN(secondLeft)) {
return 'Information indisponible'
return '...'
}
return `${minute}:${secondLeft <= 9 ? `0${secondLeft}` : secondLeft}`
@@ -137,9 +137,9 @@ export default function Lekte({audio, url, parole}) {
audioRef.current.volume = value / 100
}
const imagePath = parole?.couverture?.data?.attributes?.formats?.thumbnail?.url
const width = parole?.couverture?.data?.attributes?.formats?.thumbnail?.width || 192
const height = parole?.couverture?.data?.attributes?.formats?.thumbnail?.height || 192
const imagePath = parole?.couverture?.formats?.thumbnail?.url
const width = parole?.couverture?.formats?.thumbnail?.width || 192
const height = parole?.couverture?.formats?.thumbnail?.height || 192
const imageSrc = imagePath
? new URL(imagePath, IMAGE_URL).toString()
@@ -243,7 +243,7 @@ export default function Lekte({audio, url, parole}) {
)}
</IconButton>
</Box>
<Stack spacing={2} direction='row' sx={{mb: 1, px: 1}} alignItems='center'>
<Stack spacing={2} direction='row' sx={{mb: 1, px: 1}} alignitems='center'>
<VolumeDownRounded htmlColor={lightIconColor} />
<Slider
aria-label='Volume'
+4 -4
View File
@@ -50,10 +50,10 @@ export default function Pataje({parole, setError, setSuccess}) {
const [open, setOpen] = useState(false)
const patajeUrl = `${SITE_URL}/paroles/${slug}`
const alias = artistes.data.map(({attributes}) => attributes.alias)
const alias = artistes.map(({alias}) => alias)
const renderAwtis = new Intl.ListFormat('fr').format(alias)
const text = parole.user.data || parole.userAdmin.data ? `${renderAwtis} - ${titre} (Paroles et Traductions) - (parole soumise par ${parole?.user?.data?.attributes?.username || parole.userAdmin?.data?.attributes?.username || parole.userAdmin?.data?.attributes?.firstname})` : `${renderAwtis} - ${titre} (Paroles et Traductions)`
const text = parole.user || parole.userAdmin ? `${renderAwtis} - ${titre} (Paroles et Traductions) - (parole soumise par ${parole?.user?.username || parole.userAdmin?.username || parole.userAdmin?.firstname})` : `${renderAwtis} - ${titre} (Paroles et Traductions)`
const handleClose = () => {
setOpen(false)
@@ -114,8 +114,8 @@ export default function Pataje({parole, setError, setSuccess}) {
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipPlacement='right'
tooltipTitle={action.name}
placement='right'
title={action.name}
onClick={() => handleClick(action.code)}
/>
))}
+6 -6
View File
@@ -32,7 +32,7 @@ export default function TeksDrawer({paroles}) {
const [error, setError] = useState('')
const [success, setSuccess] = useState('')
const parole = paroles.find(({attributes}) => attributes.slug === slug)
const parole = paroles.find((parole) => parole.slug === slug)
useEffect(() => {
if (error || success) {
@@ -93,17 +93,17 @@ export default function TeksDrawer({paroles}) {
{parole && (
<Box sx={{display: 'flex', position: 'relative', top: '-20px'}}>
<Box>
<Pataje parole={parole.attributes} setError={setError} setSuccess={setSuccess} />
<Pataje parole={parole} setError={setError} setSuccess={setSuccess} />
</Box>
{parole.attributes.streamVideo && parole.attributes.streamVideo.length > 0 && (
{parole.streamVideo && parole.streamVideo.length > 0 && (
<Box>
<VweKouteAchte niVideyo parole={parole.attributes} />
<VweKouteAchte niVideyo parole={parole} />
</Box>
)}
{parole.attributes.streamAudio && parole.attributes.streamAudio.length > 0 && (
{parole.streamAudio && parole.streamAudio.length > 0 && (
<Box>
<VweKouteAchte niOdyo parole={parole.attributes} />
<VweKouteAchte niOdyo parole={parole} />
</Box>
)}
</Box>
+10 -11
View File
@@ -12,7 +12,7 @@ import CardContent from '@mui/material/CardContent'
import CardMedia from '@mui/material/CardMedia'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import ExplicitIcon from '@mui/icons-material/Explicit'
import {styled} from '@mui/material/styles'
@@ -40,11 +40,10 @@ const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible'
export default function TeksKat({parole}) {
const router = useRouter()
const {attributes} = parole
const {titre, artistes, annee, couverture, publishedAt, slug} = attributes
const {titre, artistes, annee, couverture, publishedAt, slug} = parole
const datPiblikasyon = format(new Date(publishedAt), 'P', {locale: fr})
const aliases = getAlias(artistes, attributes.prioriteArtistes)
const aliases = getAlias(artistes, parole.prioriteArtistes)
const handleClick = slug => {
router.push(`/paroles/${slug}`)?.then(() => window.scrollTo(0, 0))
@@ -58,7 +57,7 @@ export default function TeksKat({parole}) {
className={classes.media}
component='img'
alt={titre}
image={couverture?.data?.attributes?.url ? `${IMAGE_URL}${couverture.data.attributes.url}` : noImageUrl}
image={couverture?.url ? `${IMAGE_URL}${couverture.url}` : noImageUrl}
title={titre}
/>
<CardContent>
@@ -66,7 +65,7 @@ export default function TeksKat({parole}) {
<Typography display='inline' style={{marginRight: 5}} variant='h6' component='h2'>
{titre}
</Typography>
{attributes.creativeCommons && (
{parole.creativeCommons && (
<Box marginInline={1}>
<Image
width={24}
@@ -78,7 +77,7 @@ export default function TeksKat({parole}) {
</Box>
)}
{attributes.explicitLyrics && (
{parole.explicitLyrics && (
<ExplicitIcon style={{marginRight: 5}} color='error' fontSize='small' />
)}
</Box>
@@ -90,14 +89,14 @@ export default function TeksKat({parole}) {
{annee}
</Typography>
<Typography sx={{fontStyle: 'italic'}} variant='caption'>
{attributes.user && (
{parole.user && (
<>
(<i>parole soumise par {attributes.user.username}</i>)
(<i>parole soumise par {parole.user.username}</i>)
</>
)}
{attributes.userAdmin && !attributes.user && (
{parole.userAdmin && !parole.user && (
<>
(<i>parole soumise par {attributes.userAdmin}</i>)
(<i>parole soumise par {parole.userAdmin}</i>)
</>
)}
</Typography>
+13 -13
View File
@@ -3,7 +3,7 @@
import {useEffect} from 'react'
import PropTypes from 'prop-types'
import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid2'
import Grid from '@mui/material/Grid'
import Typography from '@mui/material/Typography'
import Tooltip from '@mui/material/Tooltip'
import {useMediaQuery} from '@mui/material'
@@ -138,8 +138,8 @@ export default function Teks({parole}) {
return (
<Root className={classes.container}>
<Box sx={{textAlign: 'center', marginTop: 1}}>
<Typography variant='h4' component='div' display='block' marginBottom={2}>
<Box sx={{textAlign: 'center', marginTop: 12}}>
<Typography variant='h4' component='div' display='block' marginbottom={2}>
<Typography gutterBottom color='primary' variant='h6' component='div'>
{enhancedAliases.map(({type, value}) => {
if (type === 'element') {
@@ -151,7 +151,7 @@ export default function Teks({parole}) {
return <span key={value} className={classes.separation}>{value}</span>
})}
</Typography>
<Box display='flex' justifyContent='center' alignItems='center'>
<Box display='flex' justifycontent='center' alignitems='center'>
<Typography variant='h5' component='div'>
{parole.titre} <small>({parole?.annee})</small>
</Typography>
@@ -169,14 +169,14 @@ export default function Teks({parole}) {
</Box>
</Typography>
{parole?.user?.data && (
{parole?.user && (
<Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'>
<i>parole soumise par {parole.user.data.attributes.username}</i>
<i>parole soumise par {parole.user.username}</i>
</Typography>
)}
{parole?.userAdmin?.data && !parole.user.data && (
{parole?.userAdmin&& !parole.user && (
<Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'>
<i>parole soumise par {parole.userAdmin.data.attributes.firstname}</i>
<i>parole soumise par {parole.userAdmin.firstname}</i>
</Typography>
)}
{parole.creativeCommons && (
@@ -184,8 +184,8 @@ export default function Teks({parole}) {
<LicenseModal license={parole.creativeCommons.toLowerCase()} />
</Box>
)}
{parole?.files?.data && (
<FilesDialog files={parole.files.data} />
{parole?.files && (
<FilesDialog files={parole.files} />
)}
{(parole.okiMizikID || parole.streamAudio.length > 0 || parole.gadeEmbed) && (
<Box sx={{textAlign: 'center'}}>
@@ -199,13 +199,13 @@ export default function Teks({parole}) {
<DiferansDialog difference={parole.difference} />
)}
</Box>
<Grid container justifyContent='center' spacing={1}>
<Grid container justifycontent='center' spacing={1}>
<Grid size={{xs: 12, md: langArray.length > 0 ? 6 : null}}>
<Box className={classes.gridText}>
<Typography align='center' sx={{marginBottom: '0.5em'}} variant='h4'>
Transcription
</Typography>
<Typography paragraph align={alignTeks(langArray, isMobile)} component='span'>
<Typography paragraph='true' align={alignTeks(langArray, isMobile)} component='span'>
{formatJsonString(parole.transcription)}
</Typography>
</Box>
@@ -240,7 +240,7 @@ export default function Teks({parole}) {
</span>
)} {title}
</Typography>
<Typography paragraph align='justify' component='span'>
<Typography paragraph='true' align='justify' component='span'>
{formatJsonString(lang)}
</Typography>
</Box>
+2 -2
View File
@@ -96,7 +96,7 @@ export default function VweKouteAchte({parole, niVideyo, niOdyo}) {
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
title={action.name}
onClick={() => handleClick(action.link)}
/>
))}
@@ -104,7 +104,7 @@ export default function VweKouteAchte({parole, niVideyo, niOdyo}) {
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
title={action.name}
onClick={() => handleClick(action.link)}
/>
))}
+7
View File
@@ -0,0 +1,7 @@
'use client'
import NextTopLoader from 'nextjs-toploader'
export default function TopLoader({color}) {
return <NextTopLoader color={color} />
}
+8 -8
View File
@@ -1,19 +1,19 @@
export const formatKuveti = kuveti => {
if (!kuveti?.data?.attributes) {
if (!kuveti) {
return null
}
if (kuveti.data.attributes && kuveti.data.attributes.formats && kuveti.data.attributes.formats.large) {
return kuveti.data.attributes.formats.large
if (kuveti && kuveti.formats && kuveti.formats.large) {
return kuveti.formats.large
}
if (kuveti.data.attributes && kuveti.data.attributes.formats && kuveti.data.attributes.formats.medium) {
return kuveti.data.attributes.formats.medium
if (kuveti && kuveti.formats && kuveti.formats.medium) {
return kuveti.formats.medium
}
if (kuveti.data.attributes && kuveti.data.attributes.formats && kuveti.data.attributes.formats.small) {
return kuveti.data.attributes.formats.small
if (kuveti && kuveti.formats && kuveti.formats.small) {
return kuveti.formats.small
}
return kuveti.data.attributes
return kuveti
}
+13 -24
View File
@@ -46,12 +46,7 @@ export async function jwennTeksEpiSlug(slug) {
populate: '*'
},
artistes: {
fields: ['alias', 'slug', 'musicBrainzUrl', 'photo'],
populate: {
photo: {
fields: ['name', 'url'],
},
},
fields: ['alias', 'slug', 'musicBrainzUrl'],
},
streamAudio: {
populate: '*'
@@ -61,14 +56,6 @@ export async function jwennTeksEpiSlug(slug) {
},
traductions: {
populate: '*'
},
difference: {
fileds: ['date', 'id', 'paroles', 'jsonDiff', 'source', 'admin_user'],
populate: {
admin_user: {
fields: ['firstname']
}
}
}
},
filters: {
@@ -96,8 +83,9 @@ export async function jwennAwtisEpiSlug(slug) {
encodeValuesOnly: true
})
const {data} = await request(`/artistes?${query}`, headers)
return data[0]
const {data, meta} = await request(`/artistes?${query}`, headers)
return {data: data[0], meta}
}
export async function jwennAwtisPajinasyon(paj) {
@@ -113,8 +101,9 @@ export async function jwennAwtisPajinasyon(paj) {
encodeValuesOnly: true
})
const data = await request(`/artistes?${query}`, headers)
return data
const {data, meta} = await request(`/artistes?${query}`, headers)
return {data, meta}
}
export async function jwennToutAwtis() {
@@ -128,7 +117,7 @@ export async function jwennToutAwtis() {
encodeValuesOnly: true
})
const {data} = await request(`/artistes?${query}`, headers)
const data = await request(`/artistes?${query}`, headers)
return data
}
@@ -188,7 +177,7 @@ export async function jwennAwtisSlug() {
})
const {data} = await request(`/artistes?${query}`, headers)
return data.map(({attributes}) => attributes.slug)
return data.map(({slug}) => slug)
}
export async function jwennTeksSlug() {
@@ -202,7 +191,7 @@ export async function jwennTeksSlug() {
})
const {data} = await request(`/paroles?${query}`, headers)
return data.map(({attributes}) => attributes.slug)
return data.map(({slug}) => slug)
}
export async function jwennDenyeTeks() {
@@ -227,7 +216,7 @@ export async function jwennAnTeks(teksId, token) {
Authorization: `Bearer ${token}`
}
const {data} = await request(`/paroles/${teksId}`, {headers})
const data = await request(`/paroles/${teksId}`, {headers})
return data
}
@@ -246,7 +235,7 @@ export async function jwennKomanteEpiTeksId(teksId) {
encodeValuesOnly: true
})
const {data} = await request(`/commentaires?${query}`, headers)
const data = await request(`/commentaires?${query}`, headers)
return data
}
@@ -292,7 +281,7 @@ export async function jwennUserEpiEmail(email) {
encodeValuesOnly: true
})
const {data} = await request(`/users?${query}`, headers)
const data = await request(`/users?${query}`, headers)
return data[0]
}
+8 -8
View File
@@ -4,14 +4,14 @@ export const formatJsonString = stringToFormat =>
stringToFormat.split('\n').map((string, index) => <div key={index}>{`${string}`}<br /></div>) // eslint-disable-line react/no-array-index-key
export const getAlias = (artistes, priorite = null, enhanced = false) => {
if (artistes.data.length === 1 && !enhanced) {
return artistes.data[0].attributes.alias
if (artistes.length === 1 && !enhanced) {
return artistes[0].alias
}
if (artistes.data.length === 1 && enhanced) {
if (artistes.length === 1 && enhanced) {
return [{
type: 'element',
value: artistes.data[0].attributes.alias
value: artistes[0].alias
}]
}
@@ -21,12 +21,12 @@ export const getAlias = (artistes, priorite = null, enhanced = false) => {
if (splittedPriority) {
for (const element of splittedPriority) {
const foundedArtistes = artistes.data.find(({id}) => id === element)
alias.push(foundedArtistes.attributes.alias)
const foundedArtistes = artistes.find(({id}) => id === element)
alias.push(foundedArtistes.alias)
}
} else {
for (const artiste of artistes.data) {
alias.push(artiste.attributes.alias)
for (const artiste of artistes) {
alias.push(artiste.alias)
}
}
+8 -6
View File
@@ -15,7 +15,7 @@
},
"scripts": {
"lint": "xo",
"dev": "next dev --turbopack -p 3001",
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start -p 3001"
},
@@ -26,10 +26,12 @@
"@emotion/styled": "^11.13.0",
"@fontsource/roboto": "^5.0.5",
"@icons-pack/react-simple-icons": "^3.13.0",
"@mui/icons-material": "^5.16.6",
"@mui/lab": "^5.0.0-alpha.89",
"@mui/material": "^6.1.4",
"@mui/styles": "^5.8.7",
"@mui/icons-material": "^9.0.0",
"@mui/lab": "^9.0.0-beta.2",
"@mui/material": "^9.0.0",
"@mui/material-pigment-css": "^9.0.0",
"@mui/styles": "^6.4.8",
"@pigment-css/react": "^0.0.30",
"@svgr/webpack": "^6.5.0",
"axios": "^0.21.0",
"compression": "^1.7.4",
@@ -41,7 +43,7 @@
"next": "16.2.4",
"next-auth": "^5.0.0-beta.31",
"next-pwa": "5.6.0",
"nextjs-toploader": "^1.4.2",
"nextjs-toploader": "^3.9.17",
"nodemailer": "^6.7.2",
"nprogress": "^0.2.0",
"react": "19.2.5",
+481 -406
View File
File diff suppressed because it is too large Load Diff