chore: supprimer le code mort (soumission, connexion, stats, CGU)
This commit is contained in:
@@ -1,93 +0,0 @@
|
||||
import {useRef, useEffect} from 'react'
|
||||
import {styled, useTheme} from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography} from '@mui/material'
|
||||
import useMediaQuery from '@mui/material/useMediaQuery'
|
||||
import Cgu from '.'
|
||||
|
||||
const PREFIX = 'cgu-dialog'
|
||||
|
||||
const classes = {
|
||||
dialog: `${PREFIX}-dialog`
|
||||
}
|
||||
|
||||
const Root = styled('div')(() => ({
|
||||
[`& .${classes.dialog}`]: {
|
||||
zIndex: 1
|
||||
}
|
||||
}))
|
||||
|
||||
const CGU_DOWNLOAD_LINK = process.env.NEXT_PUBLIC_CGU_DOWNLOAD_LINK
|
||||
|
||||
export default function CGUDialog({open, setOpen}) {
|
||||
const theme = useTheme()
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('md'))
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const descriptionElementRef = useRef(null)
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const {current: descriptionElement} = descriptionElementRef
|
||||
if (descriptionElement !== null) {
|
||||
descriptionElement.focus()
|
||||
}
|
||||
}
|
||||
}, [open])
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<Dialog
|
||||
fullScreen={fullScreen}
|
||||
open={open}
|
||||
scroll='paper'
|
||||
aria-labelledby='scroll-dialog-title'
|
||||
aria-describedby='scroll-dialog-description'
|
||||
className={classes.dialog}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<DialogTitle className={classes.dialog} id='scroll-dialog-title'>CGU et politique de confidentialité</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography
|
||||
ref={descriptionElementRef}
|
||||
component='div'
|
||||
variant='inherit'
|
||||
id='scroll-dialog-description'
|
||||
tabIndex={-1}
|
||||
>
|
||||
{CGU_DOWNLOAD_LINK ? (
|
||||
<div style={{textAlign: 'center', padding: '2rem'}}>
|
||||
<Typography paragraph>
|
||||
Consultez nos CGU et notre politique de confidentialité :
|
||||
</Typography>
|
||||
<Button
|
||||
variant='contained'
|
||||
component='a'
|
||||
href={CGU_DOWNLOAD_LINK}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Consulter les CGU
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Cgu />
|
||||
)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button color='primary' onClick={handleClose}>
|
||||
Fermer
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
CGUDialog.propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
setOpen: PropTypes.func.isRequired
|
||||
}
|
||||
@@ -1,592 +0,0 @@
|
||||
import {List, ListItem, ListItemText, Link, Typography, ListItemIcon} from '@mui/material'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import ArrowRightAltIcon from '@mui/icons-material/ArrowRightAlt'
|
||||
|
||||
const PREFIX = 'index'
|
||||
|
||||
const classes = {
|
||||
root: `${PREFIX}-root`
|
||||
}
|
||||
|
||||
const Root = styled('div')({
|
||||
[`&.${classes.root}`]: {
|
||||
textAlign: 'justify'
|
||||
}
|
||||
})
|
||||
|
||||
export default function Cgu() {
|
||||
return (
|
||||
<Root className={classes.root}>
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
Définitions
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Prestations et Services </strong>: <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> met à disposition :
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Contenu </strong>: Ensemble des éléments constituants l’information présente sur le site, notamment textes – images – vidéos.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Informations utilisateurs </strong>: Ci après dénommé « Information (s) »
|
||||
qui correspondent à l’ensemble des données personnelles susceptibles d’être détenues par
|
||||
<Link href='https://pawol.nu'> <strong>pawol.nu</strong></Link> pour la gestion de votre compte, et à des fins d’analyses et de statistiques.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Utilisateur </strong>: Internaute, utilisant le site susnommé.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Utilisateur enregistré</strong>: Internaute ayant compte utilisateur, utilisant le site susnommé.
|
||||
</Typography>
|
||||
|
||||
<Typography variant='body1'>
|
||||
<strong>Informations personnelles </strong>: « Les informations qui permettent, sous quelque forme que ce soit, directement ou non,
|
||||
l’identification des personnes physiques auxquelles elles s’appliquent » (article 4 de la loi n° 78-17 du 6 janvier 1978).
|
||||
</Typography>
|
||||
<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>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
1. Présentation du site internet
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
En vertu de l’article 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://pawol.nu'> <strong>pawol.nu</strong></Link> l’identité des différents intervenants dans le cadre de sa réalisation et de son suivi :
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<strong>Propriétaire</strong> : ORGANISATION KA INTERNATIONALE (Association loi 1901)
|
||||
</Typography>
|
||||
<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='true' variant='body1'>
|
||||
Le responsable publication est une personne morale
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
<strong>Réalisation</strong> : Cédric Pronzola
|
||||
</Typography>
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<strong>Courriel</strong> : <Link href='mailto:contact@cedric-pronzola.dev'><strong>contact@cedric-pronzola.dev</strong></Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<strong>WEB</strong> : <Link target='_blank' rel='noreferrer' href='https://cedric-pronzola.dev'><strong>cedric-pronzola.dev</strong></Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<strong>Git</strong> : <Link target='_blank' rel='noreferrer' href='https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE'><strong>LABOLA - OKI</strong></Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
<Typography variant='body1'>
|
||||
<strong>Hébergeur</strong> : OVH – 2 rue Kellermann - 59100 Roubaix - France
|
||||
</Typography>
|
||||
<Typography gutterBottom variant='body1'>
|
||||
<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='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>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
2. Conditions générales d’utilisation du site et des services proposés.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
L’utilisation du site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> implique l’acceptation pleine et entière des conditions générales d’utilisation ci-après décrites.
|
||||
Ces conditions d’utilisation sont susceptibles d’être modifiées ou complétées à tout moment, les utilisateurs du site <Link href='https://pawol.nu'><strong>pawol.nu </strong></Link>
|
||||
sont donc invités à les consulter de manière régulière.
|
||||
</Typography>
|
||||
|
||||
<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://pawol.nu'><strong>pawol.nu</strong></Link>, qui s’efforcera alors de communiquer préalablement aux utilisateurs les dates et heures de l’intervention.
|
||||
Le site web <Link href='https://pawol.nu'><strong>pawol.nu</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
|
||||
modifiées à tout moment : elles s’imposent néanmoins à l’utilisateur qui est invité à s’y référer le plus souvent possible afin d’en prendre connaissance.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
3. Description des services fournis
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> s’efforce 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, qu’elles soient de son fait ou du fait
|
||||
des tiers partenaires qui lui fournissent ces informations.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Toutes les informations indiquées sur le site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> sont données à titre indicatif,
|
||||
et sont susceptibles d’évoluer. Par ailleurs, les renseignements figurant sur le site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> ne sont pas exhaustifs.
|
||||
Ils sont donnés sous réserve de modifications ayant été apportées depuis leur mise en ligne.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
4. Limitations contractuelles sur les données techniques
|
||||
</Typography>
|
||||
|
||||
<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 à l’utilisation du site. De plus, l’utilisateur du site s’engage à 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.
|
||||
Le site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> est hébergé chez un prestataire sur le territoire de l’Union Européenne conformément aux dispositions du
|
||||
Règlement Général sur la Protection des Données (RGPD : n° 2016-679).
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
L’objectif est d’apporter une prestation qui assure le meilleur taux d’accessibilité.
|
||||
L’hébergeur assure la continuité de son service 24 Heures sur 24, tous les jours de l’année. Il se réserve néanmoins la possibilité d’interrompre le service d’hébergement
|
||||
pour les durées les plus courtes possibles notamment à des fins de maintenance, d’amé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='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> et l’hé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 à l’encombrement du réseau empêchant l’accès au serveur.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
5. Limitations de responsabilité
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> agit en tant qu’éditeur du site. <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> est responsable
|
||||
de la qualité et de la véracité du Contenu qu’il publie.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> ne pourra être tenu responsable des dommages directs et indirects causés au matériel de l’utilisateur,
|
||||
lors de l’accès au site internet <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>, et résultant soit de l’utilisation d’un matériel
|
||||
ne répondant pas aux spécifications indiquées au point 4, soit de l’apparition d’un bug ou d’une incompatibilité.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
6. Gestion des données personnelles
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.1 Responsables de la collecte des données personnelles
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Pour les données personnelles collectées dans le cadre de la création du compte personnel de l’utilisateur et de sa navigation sur le site
|
||||
le responsable du traitement des données personnelles est : ORGANISATION KA INTERNATIONALE. <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
En tant que responsable du traitement des données qu’il collecte, <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> s’engage à respecter le cadre des dispositions légales en vigueur.
|
||||
Chaque fois que <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> traite des Données Personnelles, <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> prend toutes les mesures raisonnables
|
||||
pour s’assurer de l’exactitude et de la pertinence des Données Personnelles au regard des finalités pour lesquelles <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> les traite.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.2 Finalité des données collectées
|
||||
</Typography>
|
||||
|
||||
<Typography variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> est susceptible de traiter tout ou partie des données :
|
||||
</Typography>
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
pour permettre la navigation sur le site et la gestion et la traçabilité des prestations et services commandés par l’utilisateur : données de connexion et d’utilisation du site
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
pour prévenir et lutter contre la fraude informatique (spamming, hacking…) : matériel informatique utilisé pour la navigation, l’adresse IP, le mot de passe (hashé)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
pour améliorer la navigation sur le site : données de connexion et d’utilisation
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.3 Droit d’accès, de rectification et d’opposition
|
||||
</Typography>
|
||||
|
||||
<Typography variant='body1'>
|
||||
Conformément à la réglementation européenne en vigueur, les Utilisateurs de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> disposent des droits suivants :
|
||||
</Typography>
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
droit d’accès (article 15 RGPD) et de rectification (article 16 RGPD), de mise à jour, de complétude des données des Utilisateurs droit de verrouillage ou d’effacement
|
||||
des données des Utilisateurs à caractère personnel (article 17 du RGPD), lorsqu’elles sont inexactes, incomplètes, équivoques, périmées, ou dont la collecte, l’utilisation,
|
||||
la communication ou la conservation est interdite
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
droit de retirer à tout moment un consentement (article 13-2c RGPD)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
droit à la limitation du traitement des données des Utilisateurs (article 18 RGPD)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
droit à la portabilité des données que les Utilisateurs auront fournies, lorsque ces données font l’objet de traitements automatisés fondés sur leur consentement ou sur un contrat (article 20 RGPD)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
droit de définir le sort des données des Utilisateurs après leur mort et de choisir à qui <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> devra communiquer (ou non)
|
||||
ses données à un tiers qu’ils aura préalablement désigné
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Dès que <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> a connaissance du décès d’un Utilisateur et à défaut d’instructions de sa part, <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> s’engage à détruire
|
||||
ses données, sauf si leur conservation s’avère nécessaire à des fins probatoires ou pour répondre à une obligation légale.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Si l’Utilisateur souhaite savoir comment <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> utilise ses Données Personnelles, demander à les rectifier ou s’oppose à leur traitement,
|
||||
l’Utilisateur peut contacter <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> par courriel à l’adresse 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='true' variant='body1'>
|
||||
Dans ce cas, l’Utilisateur doit indiquer les Données Personnelles qu’il souhaiterait que <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> corrige,
|
||||
mette à jour ou supprime, en s’identifiant précisément avec une copie d’une pièce d’identité (carte d’identité ou passeport).
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Les demandes de suppression de Données Personnelles seront soumises aux obligations qui sont imposées à <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> par la loi,
|
||||
notamment en matière de conservation ou d’archivage des documents. Enfin, les Utilisateurs de <Link href='https://pawol.nu'><strong>pawol.nu</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).
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.4 Non-communication des données personnelles
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> s’interdit de traiter, héberger ou transférer les Informations collectées sur ses utilisateurs vers un pays situé en dehors de
|
||||
l’Union européenne ou reconnu comme « non adéquat » par la Commission européenne sans en informer préalablement l’utilisateur. Pour autant, <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> reste
|
||||
libre du choix de ses sous-traitants techniques et commerciaux à la condition qu’il 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='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> s’engage à prendre toutes les précautions nécessaires afin de préserver la sécurité des Informations et notamment qu’elles ne soient pas communiquées
|
||||
à des personnes non autorisées. Cependant, si un incident impactant l’intégrité ou la confidentialité des Informations de l’utilisateur est portée
|
||||
à la connaissance de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>, celle-ci devra dans les meilleurs délais informer l’utilisateur
|
||||
et lui communiquer les mesures de corrections prises. Par ailleurs <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> ne collecte aucune « données sensibles ».
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.5 Inscription et connexion
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Les utilisateurs peuvent s’inscrire sur <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> en renseignant leur adresse e-mail, un nom d’utilisateur ainsi qu’un mot de passe.
|
||||
À la suite de l’inscription, un lien de vérification est envoyé à l’adresse utilisée. Ce lien permet d’activer le compte. Sans cette activation, l’utilisateur n’aura pas la possibilité de se connecter au site.
|
||||
Si un utilisateur n’a pas reçu le lien d’activation, il a la possibilité de demander son renvoi.
|
||||
L’utilisateur ayant oublié son mot de passe peut faire la demande de renouvellement de celui-ci.
|
||||
Avant toute inscription, il est important de noté que le nom d’utilisateur est public et donc accessible à tous. En effet, le site fait appel à une API qui permet la consultation de plusieurs éléments, dont l’identifiant de l’utilisateur ainsi que le nom qu’il aura choisi au moment de l’inscription.
|
||||
Cependant, l’adresse e-mail ne figure pas dans les informations accessibles. Seul <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> en à connaissance.
|
||||
Les utilisateurs peuvent également se connecter en utilisant un compte Twitter. Dans ce cas, c’est l’identifiant de cette plateforme qui sera affiché en cas de contribution.
|
||||
Il est également possible de se connecter grâce à un compte Google.
|
||||
En acceptant d’utiliser la fonctionnalité de connexion via Google ou Twitter, vous autorisez <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> à récupérer les informations liées à votre profil, que vous avez transmises à ces plateformes lors de votre inscription.
|
||||
Un compte GitHub permet désormais de se connecter au site. Nous utilisons uniquement le nom d’utilisateur, ainsi que l’adresse e-mail.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
6.6 Proposition de paroles
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Les utilisateurs connectés ont la possibilité de proposer des paroles depuis un espace dédié.
|
||||
Il se trouve à l’adresse <Link href='https://pawol.nu/pwopose'><strong>pawol.nu/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.
|
||||
Après approbation, il apparaît sur le site avec le nom de l’utilisateur l’ayant proposé.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
7. Notification d’incident
|
||||
</Typography>
|
||||
|
||||
<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 n’est complètement sûre.
|
||||
Nous ne pouvons en conséquence pas garantir une sécurité absolue.
|
||||
Si nous prenions connaissance d’une brèche de la sécurité, nous avertirions les utilisateurs concernés afin qu’ils puissent prendre les mesures appropriées.
|
||||
Nos procédures de notification d’incident tiennent compte de nos obligations légales, qu’elles se situent au niveau national ou européen. Nous nous engageons à informer pleinement
|
||||
nos utilisateurs de toutes les questions relevant de la sécurité de leur compte et à leur fournir toutes les informations nécessaires pour les aider à respecter leurs propres
|
||||
obligations réglementaires en matière de reporting.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Aucune information personnelle de l’utilisateur du site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> n’est publiée à l’insu de l’utilisateur, échangée, transférée,
|
||||
cédée ou vendue sur un support quelconque à des tiers. Seule l’hypothèse du rachat de <Link href='https://pawol.nu'><strong>pawol.nu</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
|
||||
l’utilisateur du site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
Sécurité
|
||||
</Typography>
|
||||
|
||||
<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://pawol.nu'><strong>pawol.nu</strong></Link> utilise des réseaux protégés
|
||||
par des dispositifs standards tels que par pare-feu, la pseudonymisation, l’encryption et mot de passe.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Lors du traitement des Données Personnelles, <Link href='https://pawol.nu'><strong>pawol.nu</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>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
8. Liens hypertextes « cookies » et balises (“tags”) internet
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Le site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> contient un certain nombre de liens hypertextes vers d’autres sites,
|
||||
mis en place avec l’autorisation de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>. Cependant, <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> n’a pas la possibilité de vérifier
|
||||
le contenu des sites ainsi visités, et n’assumera en conséquence aucune responsabilité de ce fait.
|
||||
Sauf si vous décidez de désactiver les cookies, vous acceptez que le site puisse les utiliser.
|
||||
Vous pouvez à tout moment désactiver ces cookies et ce gratuitement à partir des possibilités de désactivation qui vous sont offertes et rappelées ci-après,
|
||||
sachant que cela peut réduire ou empêcher l’accessibilité à tout ou partie des Services proposés par le site.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
8.1 « COOKIES »
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Un « cookie » est un petit fichier d’information envoyé sur le navigateur de l’Utilisateur et enregistré au sein du terminal de l’Utilisateur (ex : ordinateur, smartphone),
|
||||
(ci-après « Cookies »). Ce fichier comprend des informations telles que le nom de domaine de l’Utilisateur, le fournisseur d’accès Internet de l’Utilisateur,
|
||||
le système d’exploitation de l’Utilisateur, ainsi que la date et l’heure d’accès. Les Cookies ne risquent en aucun cas d’endommager le terminal de l’Utilisateur.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
<Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> est susceptible de traiter les informations de l’Utilisateur concernant sa visite du Site, telles que les pages consultées,
|
||||
les recherches effectuées. Ces informations permettent à <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> d’améliorer le contenu du Site, de la navigation de l’Utilisateur.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Les Cookies facilitant la navigation et/ou la fourniture des services proposés par le Site, l’Utilisateur peut configurer son navigateur pour qu’il lui permette de décider s’il souhaite
|
||||
ou non les accepter de manière à ce que des Cookies soient enregistrés dans le terminal ou, au contraire, qu’ils soient rejetés, soit systématiquement, soit selon leur émetteur.
|
||||
L’Utilisateur peut également configurer son logiciel de navigation de manière à ce que l’acceptation ou le refus des Cookies lui soient proposés ponctuellement, avant qu’un Cookie soit
|
||||
susceptible d’être enregistré dans son terminal. <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> informe l’Utilisateur que, dans ce cas, il se peut que les fonctionnalités de son logiciel
|
||||
de navigation ne soient pas toutes disponibles.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Si l’Utilisateur refuse l’enregistrement de Cookies dans son terminal ou son navigateur, ou si l’Utilisateur supprime ceux qui y sont enregistrés,
|
||||
l’Utilisateur 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://pawol.nu'><strong>pawol.nu</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 d’affichage ou le pays depuis lequel le terminal semble connecté à Internet.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Le cas échéant, <Link href='https://pawol.nu'><strong>pawol.nu</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://pawol.nu'><strong>pawol.nu</strong></Link>, résultant du refus de Cookies par l’Utilisateur de l’impossibilité
|
||||
pour <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> d’enregistrer ou de consulter les Cookies nécessaires à leur fonctionnement du fait du choix de l’Utilisateur.
|
||||
Pour la gestion des Cookies et des choix de l’Utilisateur, la configuration de chaque navigateur est différente. Elle est décrite dans le menu d’aide du navigateur,
|
||||
qui permettra de savoir de quelle manière l’Utilisateur peut modifier ses souhaits en matière de Cookies.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Enfin, en cliquant sur l’icône dédiée au réseau social Twitter, figurant sur le Site de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> ou dans son application mobile
|
||||
et si l’Utilisateur a accepté le dépôt de cookies en poursuivant sa navigation sur le Site Internet ou l’application mobile de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>, Twitter,
|
||||
peut également déposer des cookies sur vos terminaux (ordinateur, tablette, téléphone portable).
|
||||
</Typography>
|
||||
|
||||
<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
|
||||
l’application mobile de <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link>. À tout moment, l’Utilisateur peut néanmoins revenir sur son consentement à ce
|
||||
que <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> dépose ce type de cookies.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
9. Les dons
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Le site dispose d’une 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> ». L’utilisateur a 2 onglets disponibles :
|
||||
</Typography>
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
LIBERAPAY / PAYPAL
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
CARTE BANCAIRE
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
9.1 LIBERAPAY / PAYPAL
|
||||
</Typography>
|
||||
|
||||
<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. C’est à dire qu’avec cet outil, l’utilisateur peut effectuer des dons hebdomadaires, mensuels ou annuels.
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
L’utilisateur 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 s’il n’est pas enregistré.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h6' component='h3'>
|
||||
9.2 CARTE BANCAIRE
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
En cliquant sur le bouton « CARTE BANCAIRE », l’utilisateur se voit proposer plusieurs choix. Parmi ces derniers, deux options sont possibles :
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<strong>Ponctuel</strong> (1€, 5€, 10€, 20€, 50€, Montant personnalisé)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<strong>Mensuel</strong> (1€ / mois, 5€ / mois, 10€ / mois, 20€ / mois, 50€ / mois)
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Les dons peuvent donc être fait une seule fois ou de manière récurrente.
|
||||
Quelque soit le choix, l’utilisateur est redirigé vers le sous-domaine don.o-k-i.net suivi de l’ID 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>.
|
||||
|
||||
Il est important de noter qu’<strong>aucune information de paiement n’est stockée sur notre site internet</strong>.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
10. Propriété intellectuelle et licence
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' gutterBottom variant='body1'>
|
||||
Le site internet <Link href='https://pawol.nu'><strong>pawol.nu</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 :
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Liberté d’exécuter le programme pour tous les usages,
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Liberté d’étudier le fonctionnement du programme et de l’adapter à vos besoins,
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Liberté de redistribuer des copies du programme,
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArrowRightAltIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Liberté d’améliorer le programme et de publier vos modifications.
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
Conformément aux exigences de la licence AGPL-3.0, si vous redistribuez ou modifiez des éléments du site,
|
||||
vous devez également fournir le code source complet, incluant vos modifications, sous la même licence.
|
||||
Vous pouvez consulter les termes détaillés de la licence AGPL-3.0 sur le site officiel de la <Link href='https://www.gnu.org/licenses/agpl-3.0.html' target='_blank' rel='noopener noreferrer'> <strong>Free Software Foundation</strong></Link>.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
11. Droit applicable et attribution de juridiction
|
||||
</Typography>
|
||||
|
||||
<Typography paragraph='true' variant='body1'>
|
||||
Tout litige en relation avec l’utilisation du site <Link href='https://pawol.nu'><strong>pawol.nu</strong></Link> est soumis au droit français.
|
||||
En dehors des cas où la loi ne le permet pas, il est fait attribution exclusive de juridiction aux tribunaux compétents.
|
||||
</Typography>
|
||||
|
||||
<Typography gutterBottom variant='caption' >
|
||||
Dernières modifications le 26/06/2026
|
||||
</Typography>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import {useCallback, useEffect, useState, forwardRef} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
TextField,
|
||||
Container,
|
||||
Button,
|
||||
Snackbar,
|
||||
LinearProgress,
|
||||
Typography
|
||||
} from '@mui/material'
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337/api'
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
function EkriKomante({session, paroleId, meteEsKomanteOuve}) {
|
||||
const {jwt, user} = session
|
||||
const [komante, meteKomante] = useState({kontni: ''})
|
||||
const [ere, meteEre] = useState('')
|
||||
const [sikse, meteSikse] = useState('')
|
||||
const [chaje, meteChaje] = useState(false)
|
||||
const [esOuve, meteEsOuve] = useState(false)
|
||||
|
||||
const handleClick = async () => {
|
||||
meteChaje(true)
|
||||
const {kontni} = komante
|
||||
|
||||
if (kontni === '') {
|
||||
meteEre({error: {message: 'Champ obligatoire'}})
|
||||
meteChaje(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'content-type': 'application/json',
|
||||
Authorization: `Bearer ${jwt}`
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.post(`${API_URL}/commentaires`, {
|
||||
data: {
|
||||
contenu: kontni,
|
||||
parole: paroleId,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email
|
||||
},
|
||||
datePublication: new Date()
|
||||
}
|
||||
}, {
|
||||
headers
|
||||
})
|
||||
|
||||
meteSikse('Commentaire envoyé avec succès. Il apparaîtra sur le site après validation.')
|
||||
meteChaje(false)
|
||||
} catch (error) {
|
||||
meteEre(error?.response?.data)
|
||||
meteChaje(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdate = useCallback(update => {
|
||||
meteKomante({...komante, ...update})
|
||||
}, [komante])
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
meteEsOuve(false)
|
||||
meteSikse('')
|
||||
meteEre('')
|
||||
meteEsKomanteOuve(false)
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
meteKomante({kontni: ''})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (sikse) {
|
||||
meteEsOuve(true)
|
||||
handleReset()
|
||||
}
|
||||
}, [sikse])
|
||||
|
||||
useEffect(() => {
|
||||
if (ere) {
|
||||
meteEsOuve(true)
|
||||
}
|
||||
}, [ere])
|
||||
|
||||
return (
|
||||
<Container maxWidth='sm'>
|
||||
<form noValidate autoComplete='off'>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
required
|
||||
helperText='*Obligatoire. 500 caractères maximum'
|
||||
style={{marginTop: '1em'}}
|
||||
id='komante'
|
||||
label='Commentaire'
|
||||
value={komante.kontni}
|
||||
rows={8}
|
||||
variant='outlined'
|
||||
onChange={event => handleUpdate({kontni: event.target.value})}
|
||||
/>
|
||||
</form>
|
||||
<div>
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={chaje || komante.komante === ''}
|
||||
style={{marginBlock: 20}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Valider
|
||||
</Typography>
|
||||
</Button>
|
||||
{chaje && <LinearProgress size={24} style={{width: '100%', marginBlock: '1em'}} />}
|
||||
</div>
|
||||
{sikse && (
|
||||
<Snackbar open={esOuve} autoHideDuration={10_000} onClose={handleClose}>
|
||||
<Alert severity='success' onClose={handleClose}>
|
||||
<strong>{sikse}</strong>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
{ere && (
|
||||
<Snackbar open={esOuve} autoHideDuration={10_000} onClose={handleClose}>
|
||||
<Alert severity='error' onClose={handleClose}>
|
||||
<strong>Une erreur s’est produite</strong> : <i>{ere?.error?.message}</i>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
EkriKomante.propTypes = {
|
||||
session: PropTypes.object.isRequired,
|
||||
paroleId: PropTypes.number.isRequired,
|
||||
meteEsKomanteOuve: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default EkriKomante
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import {format} from 'date-fns'
|
||||
import {fr} from 'date-fns/locale'
|
||||
import {styled} from '@mui/material/styles'
|
||||
|
||||
import {
|
||||
Typography,
|
||||
Divider,
|
||||
List,
|
||||
ListItemText
|
||||
} from '@mui/material'
|
||||
|
||||
import {formatJsonString} from '../../lib/utils/format'
|
||||
|
||||
const PREFIX = 'komante-list'
|
||||
|
||||
const classes = {
|
||||
root: `${PREFIX}-root`,
|
||||
inline: `${PREFIX}-inline`
|
||||
}
|
||||
|
||||
const StyledList = styled(List)((
|
||||
{
|
||||
theme
|
||||
}
|
||||
) => ({
|
||||
[`&.${classes.root}`]: {
|
||||
width: '100%',
|
||||
maxWidth: '36ch',
|
||||
backgroundColor: theme.palette.background.paper
|
||||
},
|
||||
|
||||
[`& .${classes.inline}`]: {
|
||||
display: 'inline'
|
||||
}
|
||||
}))
|
||||
|
||||
export default function KomanteList({commentaires}) {
|
||||
return (
|
||||
<StyledList className={classes.root}>
|
||||
{commentaires.map(({id, user, contenu, datePublication}) => (
|
||||
<div key={id}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography gutterBottom style={{textDecoration: 'underline'}} variant='body1'>
|
||||
<small>{user.username}</small>
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<ListItemText
|
||||
primary={formatJsonString(contenu)}
|
||||
secondary={
|
||||
<Typography gutterBottom style={{marginBlock: 5, fontStyle: 'italic'}} variant='caption' display='block'>
|
||||
{format(new Date(datePublication), 'Pp', {locale: fr})}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<Divider style={{marginBottom: '1em'}} />
|
||||
</div>
|
||||
))}
|
||||
</StyledList>
|
||||
)
|
||||
}
|
||||
|
||||
KomanteList.propTypes = {
|
||||
commentaires: PropTypes.array.isRequired
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
import {useState, useEffect, useRef} from 'react'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
import {useSession} from 'next-auth/react'
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Button,
|
||||
Typography,
|
||||
Badge
|
||||
} from '@mui/material'
|
||||
import {useRouter} from 'next/navigation'
|
||||
import Koneksyon from '../sesyon/koneksyon'
|
||||
import KomanteList from './komante-list'
|
||||
import EkriKomante from './ekri-komante'
|
||||
|
||||
const PREFIX = 'vwe-komante'
|
||||
|
||||
const classes = {
|
||||
tooltip: `${PREFIX}-tooltip`,
|
||||
margin: `${PREFIX}-margin`,
|
||||
extendedIcon: `${PREFIX}-extendedIcon`
|
||||
}
|
||||
|
||||
const Root = styled('div')((
|
||||
{
|
||||
theme
|
||||
}
|
||||
) => ({
|
||||
[`& .${classes.margin}`]: {
|
||||
margin: theme.spacing(1)
|
||||
},
|
||||
|
||||
[`& .${classes.extendedIcon}`]: {
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
}))
|
||||
|
||||
export default function VweKomante({commentaires, parole, paroleId}) {
|
||||
const [esOuve, meteEsOuve] = useState(false)
|
||||
const [esKoneksyonOuve, meteEsKoneksyonOuve] = useState(false)
|
||||
const [esKomenteOuve, meteEsKomanteOuve] = useState(false)
|
||||
const {data: session} = useSession()
|
||||
const router = useRouter()
|
||||
|
||||
const handleClick = () => {
|
||||
meteEsOuve(true)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
meteEsOuve(false)
|
||||
}
|
||||
|
||||
const descriptionElementRef = useRef(null)
|
||||
useEffect(() => {
|
||||
if (esOuve) {
|
||||
const {current: descriptionElement} = descriptionElementRef
|
||||
if (descriptionElement !== null) {
|
||||
descriptionElement.focus()
|
||||
}
|
||||
}
|
||||
}, [esOuve])
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<Badge badgeContent={commentaires.length} color='primary'>
|
||||
<Button sx={{marginBlock: 3}} variant='outlined' onClick={handleClick}>
|
||||
Voir les commentaires
|
||||
</Button>
|
||||
</Badge>
|
||||
<Dialog
|
||||
open={esOuve}
|
||||
scroll='paper'
|
||||
aria-labelledby='scroll-dialog-title'
|
||||
aria-describedby='scroll-dialog-description'
|
||||
onClose={handleClose}
|
||||
>
|
||||
<DialogTitle align='center' id='scroll-dialog-title'>Commentaires</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography
|
||||
ref={descriptionElementRef}
|
||||
variant='inherit'
|
||||
id='scroll-dialog-description'
|
||||
tabIndex={-1}
|
||||
component='div'
|
||||
>
|
||||
{commentaires.length > 0 ? (
|
||||
<KomanteList commentaires={commentaires} />
|
||||
) : (
|
||||
<Typography component='div' align='center'>
|
||||
Aucun commentaire
|
||||
</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions align='center' >
|
||||
{session && session.user && !esKomenteOuve && (
|
||||
<Button fullWidth color='primary' onClick={() => meteEsKomanteOuve(true)}>
|
||||
Ajouter un commentaire
|
||||
</Button>
|
||||
)}
|
||||
{!session && !esKoneksyonOuve && (
|
||||
<Button fullWidth color='primary' onClick={() => meteEsKoneksyonOuve(true)}>
|
||||
Se connecter pour commenter
|
||||
</Button>
|
||||
)}
|
||||
{!session && esKoneksyonOuve && (
|
||||
<Koneksyon chimen={router.asPath} />
|
||||
)}
|
||||
</DialogActions>
|
||||
{!session && esKoneksyonOuve && (
|
||||
<Button style={{marginBlock: 10}} color='secondary' onClick={() => meteEsKoneksyonOuve(false)}>
|
||||
<strong>Annuler</strong>
|
||||
</Button>
|
||||
)}
|
||||
{session && session.user && esKomenteOuve && (
|
||||
<>
|
||||
<EkriKomante session={session} parole={parole} paroleId={paroleId} meteEsKomanteOuve={meteEsKomanteOuve} />
|
||||
<Button fullWidth style={{marginBottom: 10}} color='primary' onClick={() => meteEsKomanteOuve(false)}>
|
||||
Fermer
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
VweKomante.propTypes = {
|
||||
commentaires: PropTypes.array,
|
||||
parole: PropTypes.object.isRequired,
|
||||
paroleId: PropTypes.number.isRequired
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
import {useState, forwardRef} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import axios from 'axios'
|
||||
import {useRouter} from 'next/navigation'
|
||||
|
||||
import {FormControl, Snackbar, IconButton, Button, Input, InputAdornment, InputLabel, Box, Container, Typography, LinearProgress} from '@mui/material'
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
import Visibility from '@mui/icons-material/Visibility'
|
||||
import VisibilityOff from '@mui/icons-material/VisibilityOff'
|
||||
import Link from '@mui/material/Link'
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
|
||||
export default function NewPassword({code}) {
|
||||
const router = useRouter()
|
||||
const [showPassword, setShowPassword] = useState('')
|
||||
const [showPasswordConfirmation, setShowPasswordConfirmation] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [passwordConfirmation, setPasswordConfirmation] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [open, setOpen] = useState(true)
|
||||
const [passwordSuccess, setPasswordSuccess] = useState(false)
|
||||
|
||||
const resetForm = () => {
|
||||
setPassword('')
|
||||
setPasswordConfirmation('')
|
||||
}
|
||||
|
||||
const changePassword = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
await axios.post(`${API_URL}/auth/reset-password`, {
|
||||
code,
|
||||
password,
|
||||
passwordConfirmation
|
||||
})
|
||||
setLoading(false)
|
||||
setPasswordSuccess(true)
|
||||
setTimeout(() => {
|
||||
router.push('/pwopose')
|
||||
}, 10_000)
|
||||
} catch {
|
||||
setOpen(true)
|
||||
setError('Une erreur s’est produite. Veuillez réessayer ultérieurement')
|
||||
}
|
||||
}
|
||||
|
||||
const handleMouseDownPassword = event => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleMouseDownPasswordConfirmation = event => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleKeyUpPassword = event => {
|
||||
if (event.keyCode === 13) {
|
||||
handleClick()
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUpPasswordConfirmation = event => {
|
||||
if (event.keyCode === 13) {
|
||||
handleClick()
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = async () => {
|
||||
if (password !== passwordConfirmation) {
|
||||
setOpen(true)
|
||||
setError('Les 2 mots de passe de correspondent pas')
|
||||
return
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
setOpen(true)
|
||||
setError('Le mot de passe est trop court, 6 caratères minimum')
|
||||
return
|
||||
}
|
||||
|
||||
await changePassword()
|
||||
setLoading(false)
|
||||
resetForm()
|
||||
}
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
setError('')
|
||||
}
|
||||
|
||||
return (
|
||||
<Container sx={{marginTop: 2}} maxWidth='sm'>
|
||||
<Box sx={{width: '100%'}}>
|
||||
<Typography sx={{textAlign: 'center'}} variant='h5' component='div'>Nouveau mot de passe</Typography>
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
|
||||
<Input
|
||||
value={password}
|
||||
name='register-password'
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
id='register-password'
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
aria-label='password visibility'
|
||||
size='large'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
onMouseDown={handleMouseDownPassword}
|
||||
>
|
||||
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => setPassword(event.target.value)}
|
||||
onKeyUp={handleKeyUpPassword}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='password'>Vérification du mot de passe</InputLabel>
|
||||
<Input
|
||||
value={passwordConfirmation}
|
||||
name='verification-password'
|
||||
type={showPasswordConfirmation ? 'text' : 'password'}
|
||||
id='verification-password'
|
||||
error={password !== passwordConfirmation}
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
aria-label='password visibility'
|
||||
size='large'
|
||||
onClick={() => setShowPasswordConfirmation(!showPassword)}
|
||||
onMouseDown={handleMouseDownPasswordConfirmation}
|
||||
>
|
||||
{showPasswordConfirmation ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => setPasswordConfirmation(event.target.value)}
|
||||
onKeyUp={handleKeyUpPasswordConfirmation}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{marginTop: 20}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
disabled={loading || password !== passwordConfirmation || password === ''}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Changer de mot de passe
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{marginTop: 20}}
|
||||
variant='outlined'
|
||||
color='primary'
|
||||
onClick={() => router.push('/pwopose')}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Retour à la page de connexion
|
||||
</Typography>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{loading && <LinearProgress size={24} style={{width: '100%', marginTop: '1em'}} />}
|
||||
|
||||
{error && (
|
||||
<Snackbar
|
||||
open={open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='error' onClose={handleClose}><strong>{error}</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
|
||||
{passwordSuccess && (
|
||||
<Snackbar
|
||||
open={passwordSuccess}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='info' onClose={handleClose}>Votre changement de mot de passe a été pris en compte. Vous serez redirigé vers la page de connexion. <Link underline='hover' color='inherit' href='/pwopose'><strong>Cliquez ici si vous n’êtes pas redirigé vers la page de connexion</strong></Link></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
NewPassword.propTypes = {
|
||||
code: PropTypes.string.isRequired
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import {useState} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Button from '@mui/material/Button'
|
||||
import TextField from '@mui/material/TextField'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogContentText from '@mui/material/DialogContentText'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
|
||||
import {validateEmail} from '../../lib/utils/emails'
|
||||
import {jwennUserEpiEmail, passwordRequest} from '../../lib/oki-api'
|
||||
|
||||
export default function ResetDialog({lyen, title, activation, content, open, setOpen, setLoading, setError, setSuccess}) {
|
||||
const [email, setEmail] = useState('')
|
||||
|
||||
const forgotPasswordRequest = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
await passwordRequest(lyen, email)
|
||||
|
||||
if (activation) {
|
||||
const user = await jwennUserEpiEmail(email)
|
||||
localStorage.setItem('user-id', user?.id)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
setSuccess(true)
|
||||
} catch {
|
||||
setError('Une erreur s’est produite. Veuillez réessayer ultérieurement')
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const resetFrom = () => {
|
||||
setEmail('')
|
||||
}
|
||||
|
||||
const handleClick = async () => {
|
||||
forgotPasswordRequest()
|
||||
setOpen(false)
|
||||
resetFrom()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog open={open} onClose={handleClose}>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{content}
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
fullWidth
|
||||
value={email}
|
||||
margin='dense'
|
||||
id='email'
|
||||
label='Adresse e-mail'
|
||||
type='email'
|
||||
variant='standard'
|
||||
onChange={event => setEmail(event.target.value)}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant='contained' color='secondary' onClick={handleClose}>Annuler</Button>
|
||||
<Button disabled={!validateEmail(email)} variant='contained' color='primary' onClick={handleClick}>Valider</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ResetDialog.propTypes = {
|
||||
lyen: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
activation: PropTypes.bool,
|
||||
content: PropTypes.string.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
setOpen: PropTypes.func.isRequired,
|
||||
setLoading: PropTypes.func.isRequired,
|
||||
setError: PropTypes.func.isRequired,
|
||||
setSuccess: PropTypes.func.isRequired,
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import {useState, forwardRef} from 'react'
|
||||
import Button from '@mui/material/Button'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Box from '@mui/material/Box'
|
||||
import Snackbar from '@mui/material/Snackbar'
|
||||
import {LinearProgress} from '@mui/material'
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
import ResetDialog from './reset-dialog'
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
|
||||
export default function ResetPassword() {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [error, setError] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [success, setSuccess] = useState(false)
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
setError('')
|
||||
setSuccess(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box style={{marginTop: 20}}>
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={loading}
|
||||
variant='outlined'
|
||||
color='warning'
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Mot de passe oublié
|
||||
</Typography>
|
||||
</Button>
|
||||
</Box>
|
||||
{loading && <LinearProgress size={24} style={{width: '100%', marginTop: '1em'}} />}
|
||||
{error && (
|
||||
<Snackbar
|
||||
open={Boolean(error)}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='error' onClose={handleClose}><strong>{error}</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
{success && (
|
||||
<Snackbar
|
||||
open={success}
|
||||
autoHideDuration={15_000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='success' onClose={handleClose}><strong>Email envoyé avec succès. Vous pouvez changer votre mot de passe via le lien qui vous a été envoyé.</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
<ResetDialog
|
||||
lyen='forgot-password'
|
||||
title='Mot de passe oublié'
|
||||
content='Indiquez l’adresse e-mail utilisée lors de votre inscription. Vous receverez des instructions par e-mail.'
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
setLoading={setLoading}
|
||||
setError={setError}
|
||||
setSuccess={setSuccess}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import {useState, useEffect, forwardRef} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {useSession} from 'next-auth/react'
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
import Snackbar from '@mui/material/Snackbar'
|
||||
import Box from '@mui/material/Box'
|
||||
|
||||
import Koneksyon from '../../components/sesyon/koneksyon'
|
||||
import Dekoneksyon from '../../components/sesyon/dekoneksyon'
|
||||
import EkriTeks from '../../components/soumet/ekri-teks'
|
||||
import Footer from '../../components/footer'
|
||||
|
||||
import {jwennUserEpiToken, jwennUserEpiUsername} from '../../lib/oki-api'
|
||||
import NewPassword from '../../components/password/new-password'
|
||||
import ChwaTeks from '../../components/soumet/chwa-teks'
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
|
||||
export default function Pwopose({code}) {
|
||||
const {data: session} = useSession()
|
||||
const [localUsername, setLocalUsername] = useState(null)
|
||||
const [username, setUsername] = useState(null)
|
||||
const [open, setOpen] = useState(true)
|
||||
const [selectedTeks, setSelectedTeks] = useState(null)
|
||||
const [canAutoTranslate, setCanAutoTranslate] = useState(false)
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.jwt) {
|
||||
const getUser = async token => {
|
||||
const user = await jwennUserEpiToken(token)
|
||||
setCanAutoTranslate(user.canAutoTranslate)
|
||||
}
|
||||
|
||||
getUser(session.jwt)
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem('username')) {
|
||||
const username = localStorage.getItem('username')
|
||||
setLocalUsername(username)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (localUsername) {
|
||||
const getUser = async username => {
|
||||
const user = await jwennUserEpiUsername(username)
|
||||
setUsername(user?.username)
|
||||
}
|
||||
|
||||
getUser(localUsername)
|
||||
}
|
||||
}, [localUsername])
|
||||
|
||||
useEffect(() => {
|
||||
if (username && localStorage.getItem('username')) {
|
||||
localStorage.removeItem('username')
|
||||
}
|
||||
}, [username])
|
||||
|
||||
return (
|
||||
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
|
||||
<Box sx={{flexGrow: 1, marginTop: 1, marginBottom: 10}}>
|
||||
{!session && !code && (
|
||||
<Koneksyon
|
||||
chimen='/pwopose'
|
||||
/>
|
||||
)}
|
||||
|
||||
{!session && code && (
|
||||
<NewPassword code={code} />
|
||||
)}
|
||||
{session && session.user && (
|
||||
<>
|
||||
<Dekoneksyon position='absolute' top={95} left={5} chimen='/pwopose' />
|
||||
<ChwaTeks selectedTeks={selectedTeks} setSelectedTeks={setSelectedTeks} />
|
||||
<EkriTeks canAutoTranslate={canAutoTranslate} selectedTeks={selectedTeks} setSelectedTeks={setSelectedTeks} />
|
||||
</>
|
||||
)}
|
||||
{session && !session.user && (
|
||||
<Dekoneksyon position='absolute' top={95} left={5} chimen='/pwopose' />
|
||||
)}
|
||||
{username && (
|
||||
<Snackbar
|
||||
open={open}
|
||||
autoHideDuration={10_000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='success' onClose={handleClose}><strong>Bonjour {username}, votre compte a été activé avec succès. Vous pouvez vous connecter.</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
</Box>
|
||||
<Footer />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
Pwopose.propTypes = {
|
||||
code: PropTypes.string
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import {useState} from 'react'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
import {signOut} from 'next-auth/react'
|
||||
import {Tooltip, Fab, Zoom} from '@mui/material'
|
||||
import ExitToAppIcon from '@mui/icons-material/ExitToApp'
|
||||
|
||||
import Alet from '../alet'
|
||||
|
||||
const PREFIX = 'Dekoneksyon'
|
||||
|
||||
const classes = {
|
||||
tooltip: `${PREFIX}-tooltip`,
|
||||
dekoneksyon: `${PREFIX}-dekoneksyon`
|
||||
}
|
||||
|
||||
const Root = styled('div')(() => ({
|
||||
[`& .${classes.dekoneksyon}`]: {
|
||||
position: props => props.position,
|
||||
top: props => props.top,
|
||||
left: props => props.left,
|
||||
zIndex: 0
|
||||
}
|
||||
}))
|
||||
|
||||
const DekoneksonTooltip = Tooltip
|
||||
|
||||
function Dekoneksyon({tooltipPlacement}) {
|
||||
const [esOuve, meteEsOuve] = useState(false)
|
||||
|
||||
return (
|
||||
(
|
||||
<Root>
|
||||
<DekoneksonTooltip
|
||||
title='Se déconnecter'
|
||||
placement={tooltipPlacement}
|
||||
TransitionComponent={Zoom}
|
||||
classes={{
|
||||
tooltip: classes.tooltip
|
||||
}}
|
||||
>
|
||||
<Fab
|
||||
className={classes.dekoneksyon}
|
||||
color='error'
|
||||
aria-label='logout'
|
||||
size='small'
|
||||
onClick={() => meteEsOuve(true)}
|
||||
>
|
||||
<ExitToAppIcon />
|
||||
</Fab>
|
||||
</DekoneksonTooltip>
|
||||
<Alet esOuve={esOuve} meteEsOuve={meteEsOuve} handleKonfime={() => signOut()} />
|
||||
</Root>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Dekoneksyon.propTypes = {
|
||||
tooltipPlacement: PropTypes.string
|
||||
}
|
||||
|
||||
export default Dekoneksyon
|
||||
@@ -1,459 +0,0 @@
|
||||
import {useEffect, useState, forwardRef} from 'react'
|
||||
import {signIn} from 'next-auth/react'
|
||||
import {useRouter} from 'next/navigation'
|
||||
import PropTypes from 'prop-types'
|
||||
import Box from '@mui/material/Box'
|
||||
import Button from '@mui/material/Button'
|
||||
import Container from '@mui/material/Container'
|
||||
import FormControl from '@mui/material/FormControl'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import Input from '@mui/material/Input'
|
||||
import InputAdornment from '@mui/material/InputAdornment'
|
||||
import InputLabel from '@mui/material/InputLabel'
|
||||
import LinearProgress from '@mui/material/LinearProgress'
|
||||
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/Grid'
|
||||
import Visibility from '@mui/icons-material/Visibility'
|
||||
import VisibilityOff from '@mui/icons-material/VisibilityOff'
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
import LoginIcon from '@mui/icons-material/Login'
|
||||
import AppRegistrationRoundedIcon from '@mui/icons-material/AppRegistrationRounded'
|
||||
import axios from 'axios'
|
||||
|
||||
import {validateEmail} from '../../lib/utils/emails'
|
||||
import ResetPassword from '../password/reset-password'
|
||||
import ResetDialog from '../password/reset-dialog'
|
||||
import LoginProvider from './login-provider'
|
||||
|
||||
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3001'
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
|
||||
|
||||
const PROVIDERS = [
|
||||
{
|
||||
id: 'google',
|
||||
title: 'Google',
|
||||
width: 16,
|
||||
height: 16
|
||||
},
|
||||
{
|
||||
id: 'twitter',
|
||||
title: 'Twitter',
|
||||
width: 16,
|
||||
height: 13
|
||||
}
|
||||
]
|
||||
|
||||
function TabPanel(props) {
|
||||
const {children, value, index, ...other} = props
|
||||
|
||||
return (
|
||||
<div
|
||||
role='tabpanel'
|
||||
hidden={value !== index}
|
||||
id={`simple-tabpanel-${index}`}
|
||||
aria-labelledby={`simple-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
{value === index && (
|
||||
<Box sx={{p: 3}}>
|
||||
{children}
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
TabPanel.propTypes = {
|
||||
children: PropTypes.node,
|
||||
index: PropTypes.number.isRequired,
|
||||
value: PropTypes.number.isRequired,
|
||||
}
|
||||
|
||||
function a11yProps(index) {
|
||||
return {
|
||||
id: `simple-tab-${index}`,
|
||||
'aria-controls': `simple-tabpanel-${index}`,
|
||||
}
|
||||
}
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
|
||||
function Koneksyon({chimen}) {
|
||||
const [error, setError] = useState('')
|
||||
const [loginCredentials, setLoginCredentials] = useState({username: '', password: ''})
|
||||
const [registerCredentials, setRegisterCredentials] = useState({username: '', email: '', password: ''})
|
||||
const [passwordVerification, setPasswordVerification] = useState('')
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const [showRegisterPassword, setShowRegisterPassword] = useState(false)
|
||||
const [showVerificationPassword, setShowVerificationPassword] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [open, setOpen] = useState(true)
|
||||
const [success, setSuccess] = useState(false)
|
||||
const [openDialog, setOpenDialog] = useState(false)
|
||||
const [value, setValue] = useState(0)
|
||||
const router = useRouter()
|
||||
|
||||
const handleUpdate = update => {
|
||||
setLoginCredentials({...loginCredentials, ...update})
|
||||
}
|
||||
|
||||
const handleRegisterUpdate = update => {
|
||||
setRegisterCredentials({...registerCredentials, ...update})
|
||||
}
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue)
|
||||
}
|
||||
|
||||
const register = async () => {
|
||||
try {
|
||||
const response = await axios.post(`${apiUrl}/auth/local/register`, {
|
||||
...registerCredentials
|
||||
}, {
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
localStorage.setItem('username', `${response?.data?.user?.username}`)
|
||||
setSuccess(true)
|
||||
resetRegisterForm()
|
||||
} catch (error_) {
|
||||
if (error_.message.endsWith(400)) {
|
||||
setError('E-mail ou utilisateur déjà enregistré')
|
||||
} else {
|
||||
setError('Une erreur s’est produite')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resetRegisterForm = () => {
|
||||
setRegisterCredentials({username: '', email: '', password: ''})
|
||||
setPasswordVerification('')
|
||||
}
|
||||
|
||||
const handleClickLogin = async () => {
|
||||
if (!validateEmail(loginCredentials.username) || loginCredentials.password === '') {
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
const response = await signIn('credentials', {
|
||||
callbackUrl: `${siteUrl}${chimen}`,
|
||||
redirect: false,
|
||||
...loginCredentials
|
||||
})
|
||||
if (response.error) {
|
||||
setError(response.error)
|
||||
setLoading(false)
|
||||
} else if (response.ok) {
|
||||
setLoading(false)
|
||||
router.push(chimen)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClickRegister = async () => {
|
||||
setLoading(true)
|
||||
if (!validateEmail(registerCredentials.email) || registerCredentials.password === '') {
|
||||
return
|
||||
}
|
||||
|
||||
if (registerCredentials.password !== passwordVerification) {
|
||||
setError('Les 2 mots de passe de correspondent pas')
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (registerCredentials.username.length < 3) {
|
||||
setError('Le nom d’utilisateur est trop court, 3 caratères minimum')
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (registerCredentials.password.length < 6) {
|
||||
setError('Le mot de passe est trop court, 6 caratères minimum')
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
await register()
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
setSuccess(false)
|
||||
setError('')
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
return () => {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [error])
|
||||
|
||||
const handleClickShowPassword = () => {
|
||||
setShowPassword(!showPassword)
|
||||
}
|
||||
|
||||
const handleClickShowRegisterPassword = () => {
|
||||
setShowRegisterPassword(!showRegisterPassword)
|
||||
}
|
||||
|
||||
const handleClickShowVerificationPassword = () => {
|
||||
setShowVerificationPassword(!showVerificationPassword)
|
||||
}
|
||||
|
||||
const handleMouseDownPassword = event => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleMouseDownRegisterPassword = event => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleMouseDownVerificationPassword = event => {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleKeyUpLogin = event => {
|
||||
if (event.keyCode === 13) {
|
||||
handleClickLogin()
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUpRegister = event => {
|
||||
if (event.keyCode === 13) {
|
||||
handleClickRegister()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Container sx={{marginTop: 6}} maxWidth='sm'>
|
||||
|
||||
<Box sx={{width: '100%'}}>
|
||||
<Tabs centered value={value} aria-label='basic tabs example' onChange={handleChange}>
|
||||
<Tab icon={<LoginIcon />} label='Se connecter' {...a11yProps(0)} />
|
||||
<Tab icon={<AppRegistrationRoundedIcon />} label='S’inscrire' {...a11yProps(1)} />
|
||||
</Tabs>
|
||||
<TabPanel value={value} index={0}>
|
||||
|
||||
<Box sx={{textAlign: 'center', marginBottom: 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 sx={{marginTop: 1}} key={id}>
|
||||
<LoginProvider id={id} title={title} width={width} height={height} callbackUrl={`${siteUrl}${chimen}`} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
<Box sx={{textAlign: 'center', marginBottom: 3}}>
|
||||
<Typography>ou utilisez votre e-mail pour vous identifier</Typography>
|
||||
</Box>
|
||||
|
||||
<FormControl fullWidth autoComplete='off'>
|
||||
<InputLabel htmlFor='username'>E-mail</InputLabel>
|
||||
<Input
|
||||
autoComplete='new-password'
|
||||
value={loginCredentials.username}
|
||||
name='username'
|
||||
type='email'
|
||||
id='email'
|
||||
onChange={event => handleUpdate({username: event.target.value})}
|
||||
onKeyUp={handleKeyUpLogin}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
|
||||
<Input
|
||||
autoComplete='new-password'
|
||||
value={loginCredentials.password}
|
||||
name='password'
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
id='password'
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
aria-label='password visibility'
|
||||
size='large'
|
||||
onClick={handleClickShowPassword}
|
||||
onMouseDown={handleMouseDownPassword}
|
||||
>
|
||||
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => handleUpdate({password: event.target.value})}
|
||||
onKeyUp={handleKeyUpLogin}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={loading || !validateEmail(loginCredentials.username) || loginCredentials.password === ''}
|
||||
style={{marginTop: 20}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={handleClickLogin}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Connexion
|
||||
</Typography>
|
||||
</Button>
|
||||
<ResetPassword />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor='register-email'>E-mail</InputLabel>
|
||||
<Input
|
||||
autoComplete='email'
|
||||
value={registerCredentials.email}
|
||||
name='register-email'
|
||||
type='email'
|
||||
id='register-email'
|
||||
onChange={event => handleRegisterUpdate({email: event.target.value})}
|
||||
onKeyUp={handleKeyUpRegister}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='register-username'>Nom d’utilisateur</InputLabel>
|
||||
<Input
|
||||
autoComplete='username'
|
||||
value={registerCredentials.username}
|
||||
name='register-username'
|
||||
type='text'
|
||||
id='register-username'
|
||||
onChange={event => handleRegisterUpdate({username: event.target.value})}
|
||||
onKeyUp={handleKeyUpRegister}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
|
||||
<Input
|
||||
autoComplete='new-password' // Disable auto complete
|
||||
value={registerCredentials.password}
|
||||
name='register-password'
|
||||
type={showRegisterPassword ? 'text' : 'password'}
|
||||
id='register-password'
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
aria-label='password visibility'
|
||||
size='large'
|
||||
onClick={handleClickShowRegisterPassword}
|
||||
onMouseDown={handleMouseDownRegisterPassword}
|
||||
>
|
||||
{showRegisterPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => handleRegisterUpdate({password: event.target.value})}
|
||||
onKeyUp={handleKeyUpRegister}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||||
<InputLabel htmlFor='password'>Vérification du mot de passe</InputLabel>
|
||||
<Input
|
||||
value={passwordVerification}
|
||||
name='verification-password'
|
||||
type={showVerificationPassword ? 'text' : 'password'}
|
||||
id='verification-password'
|
||||
error={registerCredentials.password !== passwordVerification}
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
aria-label='password visibility'
|
||||
size='large'
|
||||
onClick={handleClickShowVerificationPassword}
|
||||
onMouseDown={handleMouseDownVerificationPassword}
|
||||
>
|
||||
{showVerificationPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => setPasswordVerification(event.target.value)}
|
||||
onKeyUp={handleKeyUpRegister}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={loading || !validateEmail(registerCredentials.email) || registerCredentials.username === '' || registerCredentials.password === ''}
|
||||
style={{marginTop: 20}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={handleClickRegister}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Inscription
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
style={{marginTop: 20}}
|
||||
variant='outlined'
|
||||
color='warning'
|
||||
onClick={() => setOpenDialog(true)}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Renvoyer l’e-mail de confirmation
|
||||
</Typography>
|
||||
</Button>
|
||||
</TabPanel>
|
||||
</Box>
|
||||
<ResetDialog
|
||||
activation
|
||||
lyen='send-email-confirmation'
|
||||
title='Envoi de l’e-mail de confirmation'
|
||||
content='Si vous n’avez pas reçu l’e-mail de confirmation, renseignez le champ et validez le formulaire.'
|
||||
open={openDialog}
|
||||
setOpen={setOpenDialog}
|
||||
setLoading={setLoading}
|
||||
setError={setError}
|
||||
setSuccess={setSuccess}
|
||||
/>
|
||||
|
||||
{loading && <LinearProgress size={24} style={{width: '100%'}} />}
|
||||
|
||||
{error && (
|
||||
<Snackbar
|
||||
open={open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='error' onClose={handleClose}><strong>{error}</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
|
||||
{success && (
|
||||
<Snackbar
|
||||
open={success}
|
||||
autoHideDuration={15_000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert severity='success' onClose={handleClose}><strong>Veuillez confirmer votre adresse e-mail via le lien qui vous a été envoyé.</strong></Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
Koneksyon.propTypes = {
|
||||
chimen: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default Koneksyon
|
||||
@@ -1,38 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
import {signIn} from 'next-auth/react'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
export default function LoginProvider({id, title, width, height, callbackUrl}) {
|
||||
const hanleClick = event => {
|
||||
event.preventDefault()
|
||||
signIn(id, {
|
||||
callbackUrl
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Link passHref href='/api/auth/signin'>
|
||||
<Button variant='outlined' color='info' startIcon={
|
||||
<Image
|
||||
width={width}
|
||||
height={height}
|
||||
alt={title}
|
||||
src={`/images/${id === 'twitter' ? 'x' : id}.svg`}
|
||||
/>
|
||||
} onClick={hanleClick}
|
||||
>
|
||||
{title}
|
||||
</Button>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
LoginProvider.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
callbackUrl: PropTypes.string.isRequired
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
import {useState} from 'react'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
import {MenuItem, Menu, Button} from '@mui/material'
|
||||
import {uniq} from 'lodash'
|
||||
|
||||
import OtomatikSwitch from './otomatik-switch'
|
||||
|
||||
const PREFIX = 'AjouteTradiksyon'
|
||||
|
||||
const classes = {
|
||||
paper: `${PREFIX}-paper`,
|
||||
root: `${PREFIX}-root`
|
||||
}
|
||||
|
||||
const Root = styled('div')((
|
||||
{
|
||||
theme
|
||||
}
|
||||
) => ({
|
||||
[`& .${classes.paper}`]: {
|
||||
border: '1px solid #d3d4d5'
|
||||
},
|
||||
|
||||
[`& .${classes.root}`]: {
|
||||
'&:focus': {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
'& .MuiListItemIcon-root, & .MuiListItemText-primary': {
|
||||
color: theme.palette.common.white
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
function StyledMenu(props) {
|
||||
return (
|
||||
<Menu
|
||||
elevation={0}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'center'
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'center'
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const StyledMenuItem = MenuItem
|
||||
|
||||
function AjouteTradiksyon({showSwitch, disableSwitch, tradiksyonOtomatik, setTradiksyonOtomatik, chwaLang, setChwaLang}) {
|
||||
const [anchorElement, setAnchorElement] = useState(null)
|
||||
|
||||
const handleClick = event => {
|
||||
setAnchorElement(event.currentTarget)
|
||||
}
|
||||
|
||||
const handleClose = event => {
|
||||
setAnchorElement(null)
|
||||
const chwaInik = uniq([...chwaLang, event.currentTarget.id])
|
||||
setChwaLang(chwaInik.filter(c => c !== ''))
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showSwitch && (
|
||||
<OtomatikSwitch tradiksyonOtomatik={tradiksyonOtomatik} setTradiksyonOtomatik={setTradiksyonOtomatik} disabled={disableSwitch} />
|
||||
)}
|
||||
<Root style={{textAlign: 'center', marginTop: 20}}>
|
||||
<Button
|
||||
aria-controls='lang-menu'
|
||||
variant='outlined'
|
||||
aria-haspopup='true'
|
||||
onClick={handleClick}
|
||||
>
|
||||
Ajouter une traduction <br /> 🇺🇸 🇫🇷 🇪🇸 🇩🇪 🇮🇹 🇧🇷 🇯🇵 🇰🇷
|
||||
</Button>
|
||||
<StyledMenu
|
||||
keepMounted
|
||||
id='lang-menu'
|
||||
anchorEl={anchorElement}
|
||||
open={Boolean(anchorElement)}
|
||||
classes={{
|
||||
paper: classes.paper
|
||||
}}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<StyledMenuItem
|
||||
id='en'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇺🇸 Anglais (US)</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='fr'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇫🇷 Français</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='es'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇪🇸 Espagnol</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='de'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇩🇪 Allemand</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='it'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇮🇹 Italien</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='pt'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇧🇷 Portugais</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='ja'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇯🇵 Japonais</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
id='ko'
|
||||
classes={{
|
||||
root: classes.root
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>🇰🇷 Coréen</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
</Root>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AjouteTradiksyon.propTypes = {
|
||||
showSwitch: PropTypes.bool.isRequired,
|
||||
disableSwitch: PropTypes.bool.isRequired,
|
||||
tradiksyonOtomatik: PropTypes.bool.isRequired,
|
||||
setTradiksyonOtomatik: PropTypes.func.isRequired,
|
||||
chwaLang: PropTypes.array.isRequired,
|
||||
setChwaLang: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default AjouteTradiksyon
|
||||
@@ -1,109 +0,0 @@
|
||||
import {useState} from 'react'
|
||||
import {useSession} from 'next-auth/react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Button from '@mui/material/Button'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import List from '@mui/material/List'
|
||||
import ListItem from '@mui/material/ListItem'
|
||||
import ListItemAvatar from '@mui/material/ListItemAvatar'
|
||||
import ListItemText from '@mui/material/ListItemText'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import {green} from '@mui/material/colors'
|
||||
import Container from '@mui/material/Container'
|
||||
import CircularProgress from '@mui/material/CircularProgress'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import AudiotrackIcon from '@mui/icons-material/Audiotrack'
|
||||
|
||||
import {jwennUserEpiToken} from '../../lib/oki-api'
|
||||
|
||||
function Chwa(props) {
|
||||
const {onClose, teksLis, selectedTeks, loading, open} = props
|
||||
|
||||
const handleClose = () => {
|
||||
onClose(selectedTeks)
|
||||
}
|
||||
|
||||
const handleListItemClick = value => {
|
||||
onClose(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={handleClose}>
|
||||
<DialogTitle>Choisir la parole à modifier</DialogTitle>
|
||||
{loading ? (
|
||||
<Container sx={{textAlign: 'center', marginBottom: 1}}>
|
||||
<CircularProgress size={20} sx={{color: '#29d'}} />
|
||||
</Container>
|
||||
) : (
|
||||
<List sx={{pt: 0}}>
|
||||
{teksLis.length > 0 ? teksLis.map(({id, titre, artistes}) => (
|
||||
<ListItem key={id} button onClick={() => handleListItemClick(id)}>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{bgcolor: green[100], color: green[600]}}>
|
||||
<AudiotrackIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={`${new Intl.ListFormat('fr').format(artistes.map(({alias}) => alias))} - ${titre}`} />
|
||||
</ListItem>
|
||||
)) : (
|
||||
<Typography sx={{textAlign: 'center'}} variant='button' component='div'>Aucun texte</Typography>
|
||||
)}
|
||||
</List>
|
||||
)}
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
Chwa.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
teksLis: PropTypes.array.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
selectedTeks: PropTypes.object,
|
||||
}
|
||||
|
||||
export default function ChwaTeks({selectedTeks, setSelectedTeks}) {
|
||||
const {data: session} = useSession()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [teksLis, setTeksLis] = useState([])
|
||||
|
||||
const handleClickOpen = async () => {
|
||||
setOpen(true)
|
||||
setLoading(true)
|
||||
|
||||
const user = await jwennUserEpiToken(session?.jwt)
|
||||
const {paroles} = user
|
||||
const parolesList = paroles && paroles.length > 0 ? paroles : []
|
||||
|
||||
setTeksLis(parolesList)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleClose = value => {
|
||||
const teks = teksLis.find(({id}) => id === value)
|
||||
setSelectedTeks(teks)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container sx={{textAlign: 'center', marginBottom: 1}} maxWidth='sm'>
|
||||
<Button variant='outlined' onClick={handleClickOpen}>
|
||||
Modifier mes paroles
|
||||
</Button>
|
||||
<Chwa
|
||||
selectedTeks={selectedTeks}
|
||||
teksLis={teksLis}
|
||||
open={open}
|
||||
loading={loading}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
ChwaTeks.propTypes = {
|
||||
selectedTeks: PropTypes.object,
|
||||
setSelectedTeks: PropTypes.func.isRequired,
|
||||
}
|
||||
@@ -1,469 +0,0 @@
|
||||
import {useCallback, useEffect, forwardRef, useState} from 'react'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
import axios from 'axios'
|
||||
import {useSession} from 'next-auth/react'
|
||||
import Box from '@mui/material/Box'
|
||||
import Button from '@mui/material/Button'
|
||||
import Container from '@mui/material/Container'
|
||||
import FormControl from '@mui/material/FormControl'
|
||||
import FormHelperText from '@mui/material/FormHelperText'
|
||||
import Grid from '@mui/material/Grid'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import InputAdornment from '@mui/material/InputAdornment'
|
||||
import InputLabel from '@mui/material/InputLabel'
|
||||
import LinearProgress from '@mui/material/LinearProgress'
|
||||
import OutlinedInput from '@mui/material/OutlinedInput'
|
||||
import Snackbar from '@mui/material/Snackbar'
|
||||
import TextField from '@mui/material/TextField'
|
||||
import Tooltip from '@mui/material/Tooltip'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
import MuiAlert from '@mui/material/Alert'
|
||||
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
|
||||
|
||||
import {jwennAnTeks} from '../../lib/oki-api'
|
||||
|
||||
import AjouteTradiksyon from './ajoute-tradiksyon'
|
||||
|
||||
const PREFIX = 'EkriTeks'
|
||||
|
||||
const classes = {
|
||||
tooltip: `${PREFIX}-tooltip`
|
||||
}
|
||||
|
||||
const StyledContainer = styled(Container)(() => ({
|
||||
[`& .${classes.tooltip}`]: {
|
||||
fontSize: 18
|
||||
}
|
||||
}))
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
|
||||
|
||||
const textLabels = {
|
||||
fr: {
|
||||
title: 'Traduction',
|
||||
help: 'Traduction des paroles',
|
||||
emoji: '🇫🇷'
|
||||
},
|
||||
en: {
|
||||
title: 'Translation',
|
||||
help: 'Translation of the lyrics',
|
||||
emoji: '🇬🇧'
|
||||
},
|
||||
es: {
|
||||
title: 'Traducción',
|
||||
help: 'Traducción de la letra',
|
||||
emoji: '🇪🇸'
|
||||
},
|
||||
de: {
|
||||
title: 'Übersetzung',
|
||||
help: 'Übersetzung von Liedtexten',
|
||||
emoji: '🇩🇪'
|
||||
},
|
||||
it: {
|
||||
title: 'Traduzione',
|
||||
help: 'Traduzione del testo',
|
||||
emoji: '🇮🇹'
|
||||
},
|
||||
pt: {
|
||||
title: 'Tradução',
|
||||
help: 'Tradução da letra',
|
||||
emoji: '🇧🇷'
|
||||
},
|
||||
ja: {
|
||||
title: '翻訳',
|
||||
help: '歌詞の翻訳',
|
||||
emoji: '🇯🇵'
|
||||
},
|
||||
ko: {
|
||||
title: '번역',
|
||||
help: '가사 번역',
|
||||
emoji: '🇰🇷'
|
||||
}
|
||||
}
|
||||
|
||||
const Alert = forwardRef(function Alert(props, ref) {
|
||||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||||
})
|
||||
|
||||
const RemoveTooltip = Tooltip
|
||||
|
||||
function EkriTeks({canAutoTranslate, selectedTeks, setSelectedTeks}) {
|
||||
const {data: session} = useSession()
|
||||
const {jwt, user} = session
|
||||
const [teksEkri, setTeksEkri] = useState({awtis: '', tit: '', transkripsyon: ''})
|
||||
const [tradiksyon, setTradiksyon] = useState({fr: '', en: '', es: '', de: '', it: '', pt: '', ja: '', ko: ''})
|
||||
const [kiChawLang, setKiChwalang] = useState(['fr'])
|
||||
const [error, setError] = useState('')
|
||||
const [success, setSuccess] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [currentTeksId, setCurrentTeksId] = useState(null)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [tradiksyonOtomatik, setTradiksyonOtomatik] = useState(false)
|
||||
|
||||
const handleUpdate = useCallback(update => {
|
||||
setTeksEkri({...teksEkri, ...update})
|
||||
}, [teksEkri])
|
||||
|
||||
const handleUpdateTradiksyon = useCallback(update => {
|
||||
setTradiksyon({...tradiksyon, ...update})
|
||||
}, [tradiksyon])
|
||||
|
||||
const handleRemoveTradiksyon = useCallback(idTradiksyon => {
|
||||
setKiChwalang(kiChawLang.filter(t => t !== idTradiksyon))
|
||||
}, [kiChawLang, setKiChwalang])
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
setSuccess('')
|
||||
setError('')
|
||||
}
|
||||
|
||||
const handleClick = async () => {
|
||||
setLoading(true)
|
||||
const {awtis, tit, transkripsyon} = teksEkri
|
||||
const {fr, en, es, de, it, pt, ja, ko} = tradiksyon
|
||||
|
||||
if (teksEkri.awtis === '' || teksEkri.tit === '' || teksEkri.transkripsyon === '') {
|
||||
setError({message: 'Certains champs sont obligatoires'})
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'content-type': 'application/json',
|
||||
Authorization: `Bearer ${jwt}`
|
||||
}
|
||||
|
||||
if (currentTeksId) {
|
||||
try {
|
||||
const teks = await jwennAnTeks(currentTeksId, jwt)
|
||||
const teksResponse = await axios.put(`${API_URL}/paroles/${currentTeksId}`, {
|
||||
data: {
|
||||
id: teks.id,
|
||||
titre: tit,
|
||||
transcription: transkripsyon,
|
||||
traductions: {
|
||||
francais: fr === '' ? null : fr,
|
||||
anglais: en === '' ? null : en,
|
||||
espagnol: es === '' ? null : es,
|
||||
allemand: de === '' ? null : de,
|
||||
italien: it === '' ? null : it,
|
||||
portugais: pt === '' ? null : pt,
|
||||
japonais: ja === '' ? null : ja,
|
||||
coreen: ko === '' ? null : ko
|
||||
},
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email
|
||||
},
|
||||
artistes: teks.artistes.map(({id}) => id),
|
||||
traductionAuto: tradiksyonOtomatik
|
||||
}
|
||||
}, {
|
||||
headers
|
||||
})
|
||||
|
||||
const {data} = teksResponse
|
||||
setSuccess(`Le morceau "${data.tit}" a été modifié avec succès. Il apparaîtra sur le site après validation.`)
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setError(error?.response?.data)
|
||||
setLoading(false)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const artiste = await axios.post(`${API_URL}/artistes`, {
|
||||
data: {
|
||||
alias: awtis,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email
|
||||
}
|
||||
}
|
||||
}, {
|
||||
headers
|
||||
})
|
||||
|
||||
const parole = await axios.post(`${API_URL}/paroles`, {
|
||||
data: {
|
||||
titre: tit,
|
||||
transcription: transkripsyon,
|
||||
traductions: {
|
||||
francais: fr === '' ? null : fr,
|
||||
anglais: en === '' ? null : en,
|
||||
espagnol: es === '' ? null : es,
|
||||
allemand: de === '' ? null : de,
|
||||
italien: it === '' ? null : it,
|
||||
portugais: pt === '' ? null : pt,
|
||||
japonais: ja === '' ? null : ja,
|
||||
coreen: ko === '' ? null : ko
|
||||
},
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email
|
||||
},
|
||||
artistes: [artiste.id],
|
||||
traductionAuto: tradiksyonOtomatik
|
||||
}
|
||||
}, {
|
||||
headers
|
||||
})
|
||||
|
||||
const {data} = parole
|
||||
|
||||
setSuccess(`Le texte "${data.titre}" a été soumis avec succès. Il apparaîtra sur le site après validation.`)
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setError(error?.response?.data)
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setTeksEkri({awtis: '', tit: '', transkripsyon: ''})
|
||||
setTradiksyon({fr: '', en: '', es: '', de: '', it: '', pt: '', ja: '', ko: ''})
|
||||
setKiChwalang(['fr'])
|
||||
setCurrentTeksId(null)
|
||||
setTradiksyonOtomatik(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (success) {
|
||||
setOpen(true)
|
||||
handleReset()
|
||||
}
|
||||
}, [success])
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
setOpen(true)
|
||||
}
|
||||
}, [error])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTeks) {
|
||||
setTradiksyonOtomatik(false)
|
||||
setCurrentTeksId(selectedTeks.id)
|
||||
setTeksEkri({
|
||||
awtis: new Intl.ListFormat('fr').format(selectedTeks.artistes.map(({alias}) => alias)),
|
||||
tit: selectedTeks.titre,
|
||||
transkripsyon: selectedTeks.transcription
|
||||
})
|
||||
setTradiksyon({
|
||||
fr: selectedTeks?.traductions?.francais || '',
|
||||
en: selectedTeks?.traductions?.anglais || '',
|
||||
es: selectedTeks?.traductions?.espagnol || '',
|
||||
de: selectedTeks?.traductions?.allemand || '',
|
||||
it: selectedTeks?.traductions?.italien || '',
|
||||
pt: selectedTeks?.traductions?.portugais || '',
|
||||
ja: selectedTeks?.traductions?.japonais || '',
|
||||
ko: selectedTeks?.traductions?.coreen || ''
|
||||
})
|
||||
|
||||
const jennLangId = () => {
|
||||
const ids = []
|
||||
|
||||
if (selectedTeks?.traductions?.francais) {
|
||||
ids.push('fr')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.anglais) {
|
||||
ids.push('en')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.espagnol) {
|
||||
ids.push('es')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.allemand) {
|
||||
ids.push('de')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.italien) {
|
||||
ids.push('it')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.portugais) {
|
||||
ids.push('pt')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.japonais) {
|
||||
ids.push('ja')
|
||||
}
|
||||
|
||||
if (selectedTeks?.traductions?.coreen) {
|
||||
ids.push('ko')
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
const langIds = jennLangId()
|
||||
|
||||
setKiChwalang(langIds)
|
||||
}
|
||||
|
||||
return () => {
|
||||
setSelectedTeks(null)
|
||||
}
|
||||
}, [teksEkri, selectedTeks, setSelectedTeks, kiChawLang])
|
||||
|
||||
return (
|
||||
<StyledContainer maxWidth='sm'>
|
||||
<Box sx={{textAlign: 'center', marginBottom: 2}}>
|
||||
<Typography display='inline' variant='h6' component='h1'>
|
||||
Proposer une parole
|
||||
</Typography>
|
||||
</Box>
|
||||
<form noValidate autoComplete='off'>
|
||||
<Grid container style={{textAlign: 'center'}} spacing={1}>
|
||||
<Grid xs='true'>
|
||||
<TextField
|
||||
required
|
||||
id='awtis'
|
||||
name='awtis'
|
||||
label='Artiste'
|
||||
value={teksEkri.awtis}
|
||||
disabled={Boolean(currentTeksId)}
|
||||
variant='outlined'
|
||||
helperText='Nom de l’artiste (obligatoire)'
|
||||
onChange={event => handleUpdate({awtis: event.target.value})}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid xs='true'>
|
||||
<TextField
|
||||
required
|
||||
id='tit'
|
||||
name='tit'
|
||||
label='Titre'
|
||||
value={selectedTeks?.tit || teksEkri.tit}
|
||||
variant='outlined'
|
||||
helperText='Titre de la musique (obligatoire)'
|
||||
onChange={event => handleUpdate({tit: event.target.value})}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
required
|
||||
helperText='Transcription des paroles (obligatoire)'
|
||||
style={{marginTop: '1em'}}
|
||||
id='transkripsyon'
|
||||
label='Transcription'
|
||||
value={teksEkri.transkripsyon}
|
||||
rows={8}
|
||||
variant='outlined'
|
||||
onChange={event => handleUpdate({transkripsyon: event.target.value})}
|
||||
/>
|
||||
{kiChawLang.length > 0 && kiChawLang.map(k => (
|
||||
<FormControl key={k} fullWidth style={{marginBlock: 10}}>
|
||||
<InputLabel htmlFor={`tradiksyon-${k}`}>
|
||||
<span dangerouslySetInnerHTML={{__html: textLabels[k].emoji}} /> {textLabels[k].title}
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
multiline
|
||||
style={{marginTop: '1em'}}
|
||||
id={`tradiksyon-${k}`}
|
||||
name={`tradiksyon-${k}`}
|
||||
label={`${textLabels[k].title}`}
|
||||
value={tradiksyon[k]}
|
||||
rows={8}
|
||||
endAdornment={
|
||||
<InputAdornment position='end'>
|
||||
<RemoveTooltip
|
||||
title='Cacher la fenêtre'
|
||||
placement='left'
|
||||
classes={{
|
||||
tooltip: classes.tooltip
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
style={{bottom: 75}}
|
||||
aria-label='remove-tradiksyon'
|
||||
edge='end'
|
||||
size='large'
|
||||
onClick={() => handleRemoveTradiksyon(k)}
|
||||
>
|
||||
<VisibilityOffIcon />
|
||||
</IconButton>
|
||||
</RemoveTooltip>
|
||||
</InputAdornment>
|
||||
}
|
||||
onChange={event => handleUpdateTradiksyon({[k]: event.target.value})}
|
||||
/>
|
||||
<FormHelperText id={`tradiksyon-${k}`}>{textLabels[k].help}</FormHelperText>
|
||||
</FormControl>
|
||||
))}
|
||||
</form>
|
||||
<AjouteTradiksyon
|
||||
showSwitch={Boolean(canAutoTranslate) && Boolean(!currentTeksId)}
|
||||
disableSwitch={tradiksyon.fr === '' || tradiksyon.en !== '' || tradiksyon.es !== '' || tradiksyon.de !== '' || tradiksyon.it !== '' || tradiksyon.pt !== '' || tradiksyon.ja !== '' || tradiksyon.ko !== ''}
|
||||
tradiksyonOtomatik={tradiksyonOtomatik}
|
||||
setTradiksyonOtomatik={setTradiksyonOtomatik}
|
||||
chwaLang={kiChawLang}
|
||||
setChwaLang={setKiChwalang}
|
||||
/>
|
||||
<div>
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={loading || teksEkri.awtis === '' || teksEkri.tit === '' || teksEkri.transkripsyon === ''}
|
||||
style={{marginTop: 20}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Valider
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
disabled={loading || (teksEkri.awtis === '' && teksEkri.tit === '' && teksEkri.transkripsyon === '')}
|
||||
style={{marginTop: 20}}
|
||||
variant='contained'
|
||||
color='error'
|
||||
onClick={handleReset}
|
||||
>
|
||||
<Typography style={{fontWeight: 'bold'}}>
|
||||
Tout effacer
|
||||
</Typography>
|
||||
</Button>
|
||||
{loading && <LinearProgress size={24} style={{width: '100%', marginBlock: '1em'}} />}
|
||||
</div>
|
||||
{success && (
|
||||
<Snackbar open={open} autoHideDuration={10_000} onClose={handleClose}>
|
||||
<Alert severity='success' onClose={handleClose}>
|
||||
<strong>{success}</strong>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
{error && (
|
||||
<Snackbar open={open} autoHideDuration={10_000} onClose={handleClose}>
|
||||
<Alert severity='error' onClose={handleClose}>
|
||||
<strong>Une erreur s’est produite</strong> : <i>{error?.error?.message}</i>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
)}
|
||||
</StyledContainer>
|
||||
)
|
||||
}
|
||||
|
||||
EkriTeks.propTypes = {
|
||||
canAutoTranslate: PropTypes.bool,
|
||||
selectedTeks: PropTypes.object,
|
||||
setSelectedTeks: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default EkriTeks
|
||||
@@ -1,26 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import FormGroup from '@mui/material/FormGroup'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import Switch from '@mui/material/Switch'
|
||||
|
||||
export default function OtomatikSwitch({tradiksyonOtomatik, setTradiksyonOtomatik, disabled}) {
|
||||
const handleChange = event => {
|
||||
setTradiksyonOtomatik(event.target.checked)
|
||||
}
|
||||
|
||||
return (
|
||||
<FormGroup sx={{marginTop: 1}}>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
OtomatikSwitch.propTypes = {
|
||||
tradiksyonOtomatik: PropTypes.bool.isRequired,
|
||||
setTradiksyonOtomatik: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool.isRequired
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import {styled} from '@mui/material/styles'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Box from '@mui/material/Box'
|
||||
import LinearProgress, {linearProgressClasses} from '@mui/material/LinearProgress'
|
||||
|
||||
const BorderLinearProgress = styled(LinearProgress)(({theme}) => ({
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: 200,
|
||||
...theme.applyStyles('dark', {
|
||||
backgroundColor: 800
|
||||
})
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 5,
|
||||
backgroundColor: '#1a90ff',
|
||||
...theme.applyStyles('dark', {
|
||||
backgroundColor: '#308fe8'
|
||||
})
|
||||
},
|
||||
}))
|
||||
|
||||
export default function BarStats({percent}) {
|
||||
return (
|
||||
<Box sx={{display: 'flex', alignItems: 'center'}}>
|
||||
<Box sx={{width: '100%'}}>
|
||||
<BorderLinearProgress variant='determinate' value={percent} />
|
||||
</Box>
|
||||
<Box sx={{minWidth: 35}}>
|
||||
<Typography textAlign='right' sx={{fontWeight: 'bold'}} variant='body2' color='text.secondary'>{`${Math.round(
|
||||
percent,
|
||||
)}%`}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
BarStats.propTypes = {
|
||||
percent: PropTypes.number.isRequired,
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
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/Grid'
|
||||
|
||||
import TraductionsStats from './traductions-stats'
|
||||
|
||||
export default function KatStats({emoji, value, total}) {
|
||||
return (
|
||||
<Grid size={{xs: 12, md: 2}}>
|
||||
<Card variant='outlined'>
|
||||
<CardContent>
|
||||
<Typography align='center' variant='h6'>
|
||||
<span dangerouslySetInnerHTML={{__html: emoji}} />
|
||||
</Typography>
|
||||
<TraductionsStats value={value} total={total} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
KatStats.propTypes = {
|
||||
emoji: PropTypes.string.isRequired,
|
||||
value: PropTypes.number.isRequired,
|
||||
total: PropTypes.number.isRequired
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Box from '@mui/material/Box'
|
||||
import Grid from '@mui/material/Grid'
|
||||
|
||||
import BarStats from './bar-stats'
|
||||
|
||||
export default function TraductionsStats({value, total}) {
|
||||
const translated = total - value
|
||||
const percent = (translated / total) * 100
|
||||
|
||||
return (
|
||||
<Box sx={{width: '100%'}}>
|
||||
<Grid container rowSpacing={3} columnSpacing={6} justifyContent='space-around'>
|
||||
<Grid size={{xs: 12, md: 6}}>
|
||||
<Typography style={{fontWeight: 'bold'}} align='center' variant='h6'>
|
||||
{translated}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<BarStats value={value} percent={percent} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
TraductionsStats.propTypes = {
|
||||
value: PropTypes.number.isRequired,
|
||||
total: PropTypes.number.isRequired
|
||||
}
|
||||
Reference in New Issue
Block a user