2020-08-03 12:04:07 +02:00
import { useState , useEffect , useContext , useRef , useCallback } from 'react'
import Link from 'next/link'
import { UserContext } from '../../contexts/UserContext'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTwitter } from '@fortawesome/free-brands-svg-icons'
import redirect from '../../utils/redirect'
import htmlParser from 'html-react-parser'
import Loader from '../../components/Loader'
import FunctionPage from '../../components/FunctionPage/FunctionPage'
import FunctionTabs from '../../components/FunctionPage/FunctionTabs'
import FunctionArticle from '../../components/FunctionPage/FunctionArticle'
import FunctionComments from '../../components/FunctionPage/FunctionComments/FunctionComments'
import api from '../../utils/api'
import copyToClipboard from '../../utils/copyToClipboard'
import 'notyf/notyf.min.css'
import '../../public/css/pages/FunctionComponent.css'
2020-04-22 20:44:06 +02:00
const GenerateQuote = ( ) => {
2020-08-03 12:04:07 +02:00
const [ quote , setQuote ] = useState ( { quote : '' , author : '' } )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
useEffect ( ( ) => {
getRandomQuote ( )
} , [ ] )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
const getRandomQuote = async ( ) => {
const { data } = await api . post ( '/functions/randomQuote' )
setQuote ( data )
}
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
const handleCopyQuote = ( ) => {
let Notyf
if ( typeof window !== 'undefined' ) {
Notyf = require ( 'notyf' )
2020-04-22 20:44:06 +02:00
}
2020-08-03 12:04:07 +02:00
const notyf = new Notyf . Notyf ( {
duration : 5000
} )
copyToClipboard ( ` " ${ quote ? . quote } " - ${ quote ? . author } ` )
notyf . success ( 'Citation copiée dans le presse-papier!' )
}
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
return (
< div className = 'container-fluid' >
< div className = 'row justify-content-center' >
< div className = 'col-24 text-center' >
< button onClick = { getRandomQuote } className = 'btn btn-dark' > Générer une nouvelle citation < / b u t t o n >
< button style = { { marginLeft : '15px' } } onClick = { handleCopyQuote } className = 'btn btn-dark' > Copier la citation < / b u t t o n >
< / d i v >
< / d i v >
< div style = { { marginTop : '20px' } } className = 'row justify-content-center' >
< div className = 'col-24 text-center' >
< p > " {quote?.quote} " < / p >
< p > - { quote ? . author } < / p >
2020-04-22 20:44:06 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< / d i v >
< div style = { { marginBottom : '20px' } } className = 'row justify-content-center' >
< a
target = '_blank'
rel = 'noopener noreferrer'
href = { ` https://twitter.com/intent/tweet?text=" ${ quote ? . quote } " - ${ quote ? . author } &via=Divlo_FR&hashtags=citation,FunctionProject&url=https://function.divlo.fr/functions/randomQuote ` }
className = 'btn btn-lg btn-primary'
>
< FontAwesomeIcon icon = { faTwitter } style = { { width : '1em' } } / > Twitter
< / a >
< / d i v >
< / d i v >
)
2020-04-22 20:44:06 +02:00
}
2020-08-03 12:04:07 +02:00
let pageQuotes = 1
2020-04-22 20:44:06 +02:00
const QuoteList = ( ) => {
2020-08-03 12:04:07 +02:00
const [ quotesData , setQuotesData ] = useState ( { hasMore : true , rows : [ ] , totalItems : 0 } )
const [ isLoadingQuotes , setLoadingQuotes ] = useState ( true )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
// Récupère les citations initiales
useEffect ( ( ) => {
getQuotesData ( ) . then ( ( data ) => setQuotesData ( data ) )
} , [ ] )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
const getQuotesData = async ( ) => {
setLoadingQuotes ( true )
const { data } = await api . get ( ` /quotes?page= ${ pageQuotes } &limit=20 ` )
setLoadingQuotes ( false )
return data
}
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
// Permet la pagination au scroll
const observer = useRef ( )
const lastQuoteRef = useCallback ( ( node ) => {
if ( isLoadingQuotes ) return
if ( observer . current ) observer . current . disconnect ( )
observer . current = new window . IntersectionObserver ( ( entries ) => {
if ( entries [ 0 ] . isIntersecting && quotesData . hasMore ) {
pageQuotes += 1
getQuotesData ( ) . then ( ( data ) => {
setQuotesData ( ( oldData ) => {
return {
hasMore : data . hasMore ,
rows : [ ... oldData . rows , ... data . rows ] ,
totalItems : data . totalItems
2020-04-22 20:44:06 +02:00
}
2020-08-03 12:04:07 +02:00
} )
} )
}
} , { threshold : 1 } )
if ( node ) observer . current . observe ( node )
} , [ isLoadingQuotes , quotesData . hasMore ] )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
return (
< div className = 'container-fluid' >
< div className = 'row justify-content-center' >
< div className = 'col-24 text-center' >
< h2 style = { { margin : 0 } } > Liste des citations : < / h 2 >
< p style = { { marginTop : '5px' } } > Total de { quotesData . totalItems } citations . < / p >
< / d i v >
< / d i v >
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
< div className = 'row' style = { { marginBottom : '30px' } } >
< div className = 'col-24 table-column' >
< table >
< thead >
< tr >
< th className = 'table-row' scope = 'col' > Citation / Proverbe < / t h >
< th className = 'table-row' scope = 'col' > Auteur < / t h >
< th className = 'table-row' scope = 'col' > Proposée par < / t h >
< / t r >
< / t h e a d >
< tbody >
{ quotesData . rows . map ( ( currentQuote , index ) => {
const quoteJSX = (
< >
< td className = 'table-row text-center' > { currentQuote . quote } < / t d >
< td className = 'table-row text-center' > { currentQuote . author } < / t d >
< td className = 'table-row text-center' >
< Link href = '/users/[name]' as = { ` /users/ ${ currentQuote . user . name } ` } >
< a > { currentQuote . user . name } < / a >
< / L i n k >
< / t d >
< / >
)
// Si c'est le dernier élément
if ( quotesData . rows . length === index + 1 ) {
return < tr key = { index } ref = { lastQuoteRef } > { quoteJSX } < / t r >
}
return < tr key = { index } > { quoteJSX } < / t r >
} ) }
< / t b o d y >
< / t a b l e >
2020-04-22 20:44:06 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< / d i v >
< / d i v >
)
2020-04-22 20:44:06 +02:00
}
const SuggestQuote = ( ) => {
2020-08-03 12:04:07 +02:00
const { isAuth , user } = useContext ( UserContext )
const [ inputState , setInputState ] = useState ( { quote : '' , author : '' } )
const [ message , setMessage ] = useState ( '' )
const [ isLoading , setIsLoading ] = useState ( false )
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
const handleChange = ( event ) => {
const inputStateNew = { ... inputState }
inputStateNew [ event . target . name ] = event . target . value
setInputState ( inputStateNew )
}
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
const handleSubmit = ( event ) => {
setIsLoading ( true )
event . preventDefault ( )
const token = user . token
if ( isAuth && token != null ) {
api . post ( '/quotes' , inputState , { headers : { Authorization : token } } )
. then ( ( { data } ) => {
setInputState ( { quote : '' , author : '' } )
setMessage ( ` <p class="form-success"><b>Succès:</b> ${ data . message } </p> ` )
setIsLoading ( false )
} )
. catch ( ( error ) => {
setMessage ( ` <p class="form-error"><b>Erreur:</b> ${ error . response . data . message } </p> ` )
setIsLoading ( false )
} )
2020-04-24 14:43:52 +02:00
}
2020-08-03 12:04:07 +02:00
}
2020-04-24 14:43:52 +02:00
2020-08-03 12:04:07 +02:00
if ( ! isAuth ) {
2020-04-22 20:44:06 +02:00
return (
2020-08-03 12:04:07 +02:00
< p className = 'text-center' >
Vous devez être < Link href = '/users/login' > < a > connecté < / a > < / L i n k > p o u r p r o p o s e r u n e c i t a t i o n .
< / p >
)
}
return (
< div className = 'container-fluid' >
< div className = 'row justify-content-center' >
< div className = 'col-24 text-center' >
< h2 style = { { margin : 0 } } > Proposer une citation : < / h 2 >
< p style = { { marginTop : '5px' } } > Vous pouvez proposer des citations , et une fois validé elles seront rajoutés à la liste des citations . < / p >
< / d i v >
< / d i v >
< div style = { { marginBottom : '40px' } } className = 'row' >
< div className = 'col-24' >
< form onSubmit = { handleSubmit } >
< div className = 'form-group' >
< label htmlFor = 'quote' className = 'form-label' > Citation : < / l a b e l >
< textarea value = { inputState . quote } onChange = { handleChange } style = { { height : 'auto' } } id = 'quote' name = 'quote' type = 'text' className = 'form-control' rows = '4' placeholder = 'La citation...' / >
2020-04-24 14:43:52 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< div className = 'form-group' >
< label htmlFor = 'author' className = 'form-label' > Auteur : < / l a b e l >
< input value = { inputState . author } onChange = { handleChange } name = 'author' id = 'author' type = 'text' className = 'form-control' placeholder = "L'auteur de la citation..." / >
2020-04-24 14:43:52 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< div className = 'form-group text-center' >
< button type = 'submit' className = 'btn btn-dark' > Envoyer < / b u t t o n >
2020-04-24 14:43:52 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< / f o r m >
2020-04-22 20:44:06 +02:00
< / d i v >
2020-08-03 12:04:07 +02:00
< / d i v >
< div className = 'form-result text-center' >
{
( isLoading )
? < Loader / >
: htmlParser ( message )
}
< / d i v >
< / d i v >
)
2020-04-22 20:44:06 +02:00
}
const FunctionTabManager = ( props ) => {
2020-08-03 12:04:07 +02:00
return (
< FunctionTabs setSlideIndex = { props . setSlideIndex } slideIndex = { props . slideIndex } >
< div className = 'FunctionComponent__slide' >
< GenerateQuote / >
< / d i v >
< div className = 'FunctionComponent__slide' >
< QuoteList / >
< / d i v >
< div className = 'FunctionComponent__slide' >
< SuggestQuote / >
< / d i v >
< div className = 'FunctionComponent__slide' >
< FunctionArticle article = { props . article } / >
< / d i v >
< div className = 'FunctionComponent__slide' >
< FunctionComments functionId = { props . id } / >
< / d i v >
< / F u n c t i o n T a b s >
)
2020-04-22 20:44:06 +02:00
}
2020-04-23 16:58:12 +02:00
const randomQuote = ( props ) => (
2020-08-03 12:04:07 +02:00
< FunctionPage
FunctionTabManager = { FunctionTabManager }
{ ... props }
tabNames = { [ '⚙️ Utilisation' , '📜 Liste' , '✒️ Proposer' , '📝 Article' , '📬 Commentaires' ] }
/ >
)
2020-04-22 20:44:06 +02:00
2020-08-03 12:04:07 +02:00
export async function getServerSideProps ( context ) {
return api . get ( '/functions/randomQuote' )
. then ( ( response ) => ( { props : response . data } ) )
. catch ( ( ) => redirect ( context , '/404' ) )
2020-04-22 20:44:06 +02:00
}
2020-08-03 12:04:07 +02:00
export default randomQuote