@ -1,14 +1,14 @@
import React , { Component } from 'react' ;
import React , { Component } from "react" ;
import { Redirect } from 'react-router-dom' ;
import { Redirect } from "react-router-dom" ;
import { withTranslation } from 'react-i18next' ;
import { withTranslation } from "react-i18next" ;
import { Button , Col , Container , Row } from 'reactstrap' ;
import { Button , Col , Container , Row } from "reactstrap" ;
import { toast , ToastContainer } from 'react-toastify' ;
import { toast , ToastContainer } from "react-toastify" ;
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
import { faCheck } from '@fortawesome/free-solid-svg-icons' ;
import { faCheck } from "@fortawesome/free-solid-svg-icons" ;
import { resolve } from 'url' ;
import { resolve } from "url" ;
import { i18nGrades } from '../../Util' ;
import { i18nGrades } from "../../Util" ;
import { AppContext } from '../../AppContext' ;
import { AppContext } from "../../AppContext" ;
import { errorMessage } from '../../Errors' ;
import { errorMessage } from "../../Errors" ;
const shuffle = array => array . sort ( ( ) => Math . random ( ) - 0.5 ) ;
const shuffle = array => array . sort ( ( ) => Math . random ( ) - 0.5 ) ;
@ -29,7 +29,7 @@ class Vote extends Component {
colSizeGradeXs : 1 ,
colSizeGradeXs : 1 ,
redirectTo : null ,
redirectTo : null ,
electionGrades : i18nGrades ( ) ,
electionGrades : i18nGrades ( ) ,
errorMsg : "" ,
errorMsg : ""
} ;
} ;
}
}
@ -37,9 +37,9 @@ class Vote extends Component {
if ( ! response . ok ) {
if ( ! response . ok ) {
response . json ( ) . then ( response => {
response . json ( ) . then ( response => {
console . log ( response ) ;
console . log ( response ) ;
const { t } = this . props ;
const { t } = this . props ;
this . setState ( state => ( {
this . setState ( state => ( {
errorMsg : errorMessage ( response , t )
errorMsg : errorMessage ( response , t )
} ) ) ;
} ) ) ;
} ) ;
} ) ;
throw Error ( response ) ;
throw Error ( response ) ;
@ -51,18 +51,18 @@ class Vote extends Component {
const numGrades = response . num _grades ;
const numGrades = response . num _grades ;
const candidates = response . candidates . map ( ( c , i ) => ( {
const candidates = response . candidates . map ( ( c , i ) => ( {
id : i ,
id : i ,
label : c ,
label : c
} ) ) ;
} ) ) ;
shuffle ( candidates ) ;
shuffle ( candidates ) ;
const colSizeGradeLg = Math . floor (
const colSizeGradeLg = Math . floor (
( 12 - this . state . colSizeCandidateLg ) / numGrades ,
( 12 - this . state . colSizeCandidateLg ) / numGrades
) ;
) ;
const colSizeGradeMd = Math . floor (
const colSizeGradeMd = Math . floor (
( 12 - this . state . colSizeCandidateMd ) / numGrades ,
( 12 - this . state . colSizeCandidateMd ) / numGrades
) ;
) ;
const colSizeGradeXs = Math . floor (
const colSizeGradeXs = Math . floor (
( 12 - this . state . colSizeCandidateXs ) / numGrades ,
( 12 - this . state . colSizeCandidateXs ) / numGrades
) ;
) ;
this . setState ( state => ( {
this . setState ( state => ( {
@ -83,7 +83,7 @@ class Vote extends Component {
colSizeCandidateXs :
colSizeCandidateXs :
12 - colSizeGradeXs * numGrades > 0
12 - colSizeGradeXs * numGrades > 0
? 12 - colSizeGradeXs * numGrades
? 12 - colSizeGradeXs * numGrades
: 12 ,
: 12
} ) ) ;
} ) ) ;
return response ;
return response ;
} ;
} ;
@ -94,9 +94,9 @@ class Vote extends Component {
const detailsEndpoint = resolve (
const detailsEndpoint = resolve (
this . context . urlServer ,
this . context . urlServer ,
this . context . routesServer . getElection . replace (
this . context . routesServer . getElection . replace (
new RegExp ( ':slug' , 'g' ) ,
new RegExp ( ":slug" , "g" ) ,
electionSlug ,
electionSlug
) ,
)
) ;
) ;
fetch ( detailsEndpoint )
fetch ( detailsEndpoint )
. then ( this . handleErrors )
. then ( this . handleErrors )
@ -107,33 +107,33 @@ class Vote extends Component {
handleGradeClick = event => {
handleGradeClick = event => {
let data = {
let data = {
id : parseInt ( event . currentTarget . getAttribute ( 'data-id' ) ) ,
id : parseInt ( event . currentTarget . getAttribute ( "data-id" ) ) ,
value : parseInt ( event . currentTarget . value ) ,
value : parseInt ( event . currentTarget . value )
} ;
} ;
/ / r e m o v e c a n d i d a t e
/ / r e m o v e c a n d i d a t e
let ratedCandidates = this . state . ratedCandidates . filter (
let ratedCandidates = this . state . ratedCandidates . filter (
ratedCandidate => ratedCandidate . id !== data . id ,
ratedCandidate => ratedCandidate . id !== data . id
) ;
) ;
ratedCandidates . push ( data ) ;
ratedCandidates . push ( data ) ;
this . setState ( { ratedCandidates } ) ;
this . setState ( { ratedCandidates } ) ;
} ;
} ;
handleSubmitWithoutAllRate = ( ) => {
handleSubmitWithoutAllRate = ( ) => {
const { t } = this . props ;
const { t } = this . props ;
toast . error ( t ( 'You have to judge every candidate/proposal!' ) , {
toast . error ( t ( "You have to judge every candidate/proposal!" ) , {
position : toast . POSITION . TOP _CENTER ,
position : toast . POSITION . TOP _CENTER
} ) ;
} ) ;
} ;
} ;
handleSubmit = event => {
handleSubmit = event => {
event . preventDefault ( ) ;
event . preventDefault ( ) ;
const { ratedCandidates } = this . state ;
const { ratedCandidates } = this . state ;
const electionSlug = this . props . match . params . slug ;
const electionSlug = this . props . match . params . slug ;
const token = this . props . location . search . substr ( 7 ) ;
const token = this . props . location . search . substr ( 7 ) ;
const endpoint = resolve (
const endpoint = resolve (
this . context . urlServer ,
this . context . urlServer ,
this . context . routesServer . voteElection ,
this . context . routesServer . voteElection
) ;
) ;
const gradesById = { } ;
const gradesById = { } ;
@ -147,29 +147,29 @@ class Vote extends Component {
const payload = {
const payload = {
election : electionSlug ,
election : electionSlug ,
grades _by _candidate : gradesByCandidate ,
grades _by _candidate : gradesByCandidate
} ;
} ;
if ( token !== '' ) {
if ( token !== "" ) {
payload [ 'token' ] = token ;
payload [ "token" ] = token ;
}
}
fetch ( endpoint , {
fetch ( endpoint , {
method : 'POST' ,
method : "POST" ,
headers : { 'Content-Type' : 'application/json' } ,
headers : { "Content-Type" : "application/json" } ,
body : JSON . stringify ( payload ) ,
body : JSON . stringify ( payload )
} )
} )
. then ( this . handleErrors )
. then ( this . handleErrors )
. then ( result =>
. then ( result =>
this . setState ( { redirectTo : '/vote-success/' + electionSlug } ) ,
this . setState ( { redirectTo : "/vote-success/" + electionSlug } )
)
)
. catch ( error => error ) ;
. catch ( error => error ) ;
} ;
} ;
render ( ) {
render ( ) {
const { t } = this . props ;
const { t } = this . props ;
const { candidates , errorMsg , redirectTo } = this . state ;
const { candidates , errorMsg , redirectTo } = this . state ;
const grades = i18nGrades ( ) ;
const grades = i18nGrades ( ) ;
const offsetGrade = grades . length - this . state . numGrades ;
const offsetGrade = grades . length - this . state . numGrades ;
const electionGrades = grades . slice ( 0 , this . state . numGrades ) ;
const electionGrades = grades . slice ( 0 , this . state . numGrades ) ;
if ( redirectTo ) {
if ( redirectTo ) {
@ -177,15 +177,15 @@ class Vote extends Component {
}
}
if ( errorMsg !== "" ) {
if ( errorMsg !== "" ) {
return (
return (
< Container >
< Container >
< Row >
< Row >
< Col >
< Col >
< h3 > { errorMsg } < / h3 >
< h3 > { errorMsg } < / h3 >
< / Col >
< / Col >
< / Row >
< / Row >
< / Container >
< / Container >
) ;
) ;
}
}
return (
return (
@ -201,7 +201,8 @@ class Vote extends Component {
< Col
< Col
xs = { this . state . colSizeCandidateXs }
xs = { this . state . colSizeCandidateXs }
md = { this . state . colSizeCandidateMd }
md = { this . state . colSizeCandidateMd }
lg = { this . state . colSizeCandidateLg } >
lg = { this . state . colSizeCandidateLg }
>
< h5 > & nbsp ; < / h5 >
< h5 > & nbsp ; < / h5 >
< / Col >
< / Col >
{ electionGrades . map ( ( grade , gradeId ) => {
{ electionGrades . map ( ( grade , gradeId ) => {
@ -212,10 +213,12 @@ class Vote extends Component {
lg = { this . state . colSizeGradeLg }
lg = { this . state . colSizeGradeLg }
key = { gradeId }
key = { gradeId }
className = "text-center p-0"
className = "text-center p-0"
style = { { lineHeight : 2 } } >
style = { { lineHeight : 2 } }
>
< small
< small
className = "nowrap bold badge"
className = "nowrap bold badge"
style = { { backgroundColor : grade . color , color : '#fff' } } >
style = { { backgroundColor : grade . color , color : "#fff" } }
>
{ grade . label }
{ grade . label }
< / small >
< / small >
< / Col >
< / Col >
@ -229,81 +232,95 @@ class Vote extends Component {
< Col
< Col
xs = { this . state . colSizeCandidateXs }
xs = { this . state . colSizeCandidateXs }
md = { this . state . colSizeCandidateMd }
md = { this . state . colSizeCandidateMd }
lg = { this . state . colSizeCandidateLg } >
lg = { this . state . colSizeCandidateLg }
>
< h5 className = "m-0" > { candidate . label } < / h5 >
< h5 className = "m-0" > { candidate . label } < / h5 >
< hr className = "d-lg-none" / >
< hr className = "d-lg-none" / >
< / Col >
< / Col >
{ electionGrades . map ( ( grade , gradeId ) => {
{ electionGrades . map ( ( grade , gradeId ) => {
console . assert ( gradeId < this . state . numGrades )
console . assert ( gradeId < this . state . numGrades ) ;
const gradeValue = grade . value - offsetGrade ;
const gradeValue = grade . value - offsetGrade ;
return (
return (
< Col
< Col
xs = { this . state . colSizeGradeXs }
xs = { this . state . colSizeGradeXs }
md = { this . state . colSizeGradeMd }
md = { this . state . colSizeGradeMd }
lg = { this . state . colSizeGradeLg }
lg = { this . state . colSizeGradeLg }
key = { gradeId }
key = { gradeId }
className = "text-lg-center" >
className = "text-lg-center"
>
< label
< label
htmlFor = { 'candidateGrade' + candidateId + '-' + gradeValue }
htmlFor = {
className = "check" >
"candidateGrade" + candidateId + "-" + gradeValue
}
className = "check"
>
< small
< small
className = "nowrap d-lg-none ml-2 bold badge"
className = "nowrap d-lg-none ml-2 bold badge"
style = {
style = {
this . state . ratedCandidates . find ( function (
this . state . ratedCandidates . find ( function (
ratedCandidat ,
ratedCandidat
) {
) {
return (
return (
JSON . stringify ( ratedCandidat ) ===
JSON . stringify ( ratedCandidat ) ===
JSON . stringify ( { id : candidate . id , value : gradeValue } )
JSON . stringify ( {
id : candidate . id ,
value : gradeValue
} )
) ;
) ;
} )
} )
? { backgroundColor : grade . color , color : '#fff' }
? { backgroundColor : grade . color , color : "#fff" }
: {
: {
backgroundColor : 'transparent' ,
backgroundColor : "transparent" ,
color : '#000' ,
color : "#000"
}
}
} >
}
>
{ grade . label }
{ grade . label }
< / small >
< / small >
< input
< input
type = "radio"
type = "radio"
name = { 'candidate' + candidateId }
name = { "candidate" + candidateId }
id = { 'candidateGrade' + candidateId + '-' + gradeValue }
id = { "candidateGrade" + candidateId + "-" + gradeValue }
data - index = { candidateId }
data - index = { candidateId }
data - id = { candidate . id }
data - id = { candidate . id }
value = { grade . value - offsetGrade }
value = { grade . value - offsetGrade }
onClick = { this . handleGradeClick }
onClick = { this . handleGradeClick }
defaultChecked = { this . state . ratedCandidates . find (
defaultChecked = { this . state . ratedCandidates . find (
function ( element ) {
function ( element ) {
return (
return (
JSON . stringify ( element ) ===
JSON . stringify ( element ) ===
JSON . stringify ( { id : candidate . id , value : gradeValue } )
JSON . stringify ( {
id : candidate . id ,
value : gradeValue
} )
) ;
) ;
} ,
}
) }
) }
/ >
/ >
< span
< span
className = "checkmark"
className = "checkmark"
style = {
style = {
this . state . ratedCandidates . find ( function (
this . state . ratedCandidates . find ( function (
ratedCandidat ,
ratedCandidat
) {
) {
return (
return (
JSON . stringify ( ratedCandidat ) ===
JSON . stringify ( ratedCandidat ) ===
JSON . stringify ( { id : candidate . id , value : gradeValue } )
JSON . stringify ( {
id : candidate . id ,
value : gradeValue
} )
) ;
) ;
} )
} )
? { backgroundColor : grade . color , color : '#fff' }
? { backgroundColor : grade . color , color : "#fff" }
: {
: {
backgroundColor : 'transparent' ,
backgroundColor : "transparent" ,
color : '#000' ,
color : "#000"
}
}
}
}
/ >
/ >
< / label >
< / label >
< / Col >
< / Col >
) ;
)
} ) }
} ) }
< / Row >
< / Row >
) ;
) ;
@ -316,14 +333,15 @@ class Vote extends Component {
< Button
< Button
type = "button"
type = "button"
onClick = { this . handleSubmitWithoutAllRate }
onClick = { this . handleSubmitWithoutAllRate }
className = "btn btn-dark " >
className = "btn btn-dark "
>
< FontAwesomeIcon icon = { faCheck } className = "mr-2" / >
< FontAwesomeIcon icon = { faCheck } className = "mr-2" / >
{ t ( 'Validate' ) }
{ t ( "Validate" ) }
< / Button >
< / Button >
) : (
) : (
< Button type = "submit" className = "btn btn-success " >
< Button type = "submit" className = "btn btn-success " >
< FontAwesomeIcon icon = { faCheck } className = "mr-2" / >
< FontAwesomeIcon icon = { faCheck } className = "mr-2" / >
{ t ( 'Validate' ) }
{ t ( "Validate" ) }
< / Button >
< / Button >
) }
) }
< / Col >
< / Col >