2020-04-22 20:44:06 +02:00
import { Fragment , 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' ;
2020-04-23 16:58:12 +02:00
import FunctionPage from '../../components/FunctionPage/FunctionPage' ;
import FunctionTabs from '../../components/FunctionPage/FunctionTabs' ;
2020-04-23 17:31:36 +02:00
import FunctionArticle from '../../components/FunctionPage/FunctionArticle' ;
import FunctionComments from '../../components/FunctionPage/FunctionComments/FunctionComments' ;
2020-04-22 20:44:06 +02:00
import api from '../../utils/api' ;
import copyToClipboard from '../../utils/copyToClipboard' ;
2020-04-23 16:58:12 +02:00
import 'notyf/notyf.min.css' ;
2020-04-22 20:44:06 +02:00
import '../../public/css/pages/FunctionComponent.css' ;
const GenerateQuote = ( ) => {
const [ quote , setQuote ] = useState ( { quote : "" , author : "" } ) ;
useEffect ( ( ) => {
getRandomQuote ( ) ;
} , [ ] ) ;
const getRandomQuote = async ( ) => {
const { data } = await api . post ( "/functions/randomQuote" ) ;
setQuote ( data ) ;
}
const handleCopyQuote = ( ) => {
let Notyf ;
if ( typeof window != 'undefined' ) {
Notyf = require ( 'notyf' ) ;
}
const notyf = new Notyf . Notyf ( {
duration : 5000
} ) ;
copyToClipboard ( ` " ${ quote . quote } " - ${ quote . author } ` ) ;
notyf . success ( 'Citation copiée dans le presse-papier!' ) ;
}
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 >
< / d i v >
< / 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 >
) ;
}
const QuoteList = ( ) => {
const [ quotesData , setQuotesData ] = useState ( { hasMore : true , rows : [ ] , totalItems : 0 } ) ;
const [ isLoadingQuotes , setLoadingQuotes ] = useState ( true ) ;
const [ pageQuotes , setPageQuotes ] = useState ( 1 ) ;
// Récupère les citations si la page change
useEffect ( ( ) => {
getQuotesData ( ) ;
} , [ pageQuotes ] ) ;
const getQuotesData = async ( ) => {
setLoadingQuotes ( true ) ;
const { data } = await api . get ( ` /quotes?limit=20page= ${ pageQuotes } ` ) ;
setQuotesData ( {
hasMore : data . hasMore ,
rows : [ ... quotesData . rows , ... data . rows ] ,
totalItems : data . totalItems
} ) ;
setLoadingQuotes ( false ) ;
}
// Permet la pagination au scroll
const observer = useRef ( ) ;
const lastQuoteRef = useCallback ( ( node ) => {
if ( isLoadingQuotes ) return ;
if ( observer . current ) observer . current . disconnect ( ) ;
observer . current = new IntersectionObserver ( ( entries ) => {
if ( entries [ 0 ] . isIntersecting && quotesData . hasMore ) {
setPageQuotes ( pageQuotes + 1 ) ;
}
} , { threshold : 1 } ) ;
if ( node ) observer . current . observe ( node ) ;
} , [ isLoadingQuotes , quotesData . hasMore ] ) ;
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 >
< 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 = (
< Fragment >
< 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" >
2020-04-23 17:45:21 +02:00
< Link href = { "/users/[name]" } as = { ` /users/ ${ currentQuote . user . name } ` } >
2020-04-22 20:44:06 +02:00
< a > { currentQuote . user . name } < / a >
< / L i n k >
< / t d >
< / F r a g m e n t >
) ;
// 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 >
< / d i v >
< / d i v >
< / d i v >
) ;
}
const SuggestQuote = ( ) => {
const { isAuth , user } = useContext ( UserContext ) ;
const [ inputState , setInputState ] = useState ( { quote : "" , author : "" } ) ;
const [ message , setMessage ] = useState ( "" ) ;
const [ isLoading , setIsLoading ] = useState ( false ) ;
const handleChange = ( event ) => {
const inputStateNew = { ... inputState } ;
inputStateNew [ event . target . name ] = event . target . value ;
setInputState ( inputStateNew ) ;
}
const handleSubmit = ( event ) => {
setIsLoading ( true ) ;
event . preventDefault ( ) ;
const token = user . token ;
if ( isAuth && token != undefined ) {
api . post ( '/quotes' , inputState , { headers : { 'Authorization' : token } } )
2020-04-24 14:43:52 +02:00
. then ( ( { data } ) => {
2020-04-22 20:44:06 +02:00
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
if ( ! isAuth ) {
return (
< 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 >
) ;
}
2020-04-22 20:44:06 +02:00
return (
2020-04-24 14:43:52 +02:00
< 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-22 20:44:06 +02:00
< / d i v >
2020-04-24 14:43:52 +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-22 20:44:06 +02:00
< / d i v >
2020-04-24 14:43:52 +02:00
< div className = "form-group text-center" >
< button type = "submit" className = "btn btn-dark" > Envoyer < / b u t t o n >
2020-04-22 20:44:06 +02:00
< / d i v >
2020-04-24 14:43:52 +02:00
< / f o r m >
< / d i v >
< / d i v >
< div className = "form-result text-center" >
{
( isLoading ) ?
< Loader / >
:
htmlParser ( message )
}
< / d i v >
2020-04-22 20:44:06 +02:00
< / d i v >
) ;
}
const FunctionTabManager = ( props ) => {
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-23 16:58:12 +02:00
const randomQuote = ( props ) => (
< FunctionPage
FunctionTabManager = { FunctionTabManager }
{ ... props }
tabNames = { [ "⚙️ Utilisation" , "📜 Liste" , "✒️ Proposer" , "📝 Article" , "📬 Commentaires" ] }
/ >
) ;
2020-04-22 20:44:06 +02:00
export async function getServerSideProps ( context ) {
return api . get ( ` /functions/randomQuote ` )
. then ( ( response ) => ( { props : response . data } ) )
. catch ( ( ) => redirect ( context , '/404' ) ) ;
}
export default randomQuote ;