Proyectos de Subversion LeadersLinked - SPA

Rev

Rev 623 | Rev 814 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
813 stevensc 1
import React, { useEffect, useRef, useState } from 'react'
2
import { axios } from '../../utils'
3
import { useForm } from 'react-hook-form'
4
import { connect } from 'react-redux'
5 stevensc 5
 
813 stevensc 6
import { updateFeed } from '../../redux/feed/feed.actions'
7
import { addNotification } from '../../redux/notification/notification.actions'
5 stevensc 8
 
813 stevensc 9
import LockClockIcon from '@mui/icons-material/LockClock'
10
import PublicIcon from '@mui/icons-material/Public'
5 stevensc 11
 
813 stevensc 12
import styles from './survey.module.scss'
13
import styled, { css } from 'styled-components'
5 stevensc 14
 
15
const RadioButton = styled.div`
16
  display: flex;
17
  align-items: center;
18
  gap: 0.5rem;
19
  padding: 0.5rem 1rem;
20
  border: 2px solid var(--border-primary);
21
  border-radius: 50px;
22
  cursor: pointer;
23
  transition: all 200ms ease;
24
  position: relative;
25
  overflow: hidden;
26
  margin-bottom: 0.5rem;
27
  input {
28
    margin: 0 !important;
29
  }
30
  label {
31
    color: var(--font-color);
32
    font-weight: 500;
33
  }
34
  &::before {
813 stevensc 35
    content: '';
5 stevensc 36
    position: absolute;
37
    left: 0;
38
    top: 0;
39
    height: 100%;
813 stevensc 40
    width: ${(props) => (props.porcentage ? `${props.porcentage}%` : '0%')};
5 stevensc 41
    background-color: #0002;
42
    z-index: 4;
43
  }
44
  &:hover {
45
    border-color: var(--font-color);
46
    text-shadow: 0 0 1px var(--font-color);
47
  }
48
  ${(props) =>
49
    props.disabled &&
50
    css`
51
      background-color: #9992;
52
      cursor: auto;
53
 
54
      label {
55
        color: gray;
56
      }
57
 
58
      &:hover {
59
        border-color: var(--border-primary);
60
        text-shadow: none;
61
      }
62
    `}
813 stevensc 63
`
5 stevensc 64
 
65
const VoteTag = styled.span`
66
  position: absolute;
67
  bottom: 1rem;
68
  right: 1rem;
69
  color: var(--font-color) !important;
70
  font-weight: 600;
813 stevensc 71
`
5 stevensc 72
 
73
const SurveyForm = ({
74
  question,
75
  answers = [],
76
  votes,
77
  active = false,
78
  time,
79
  resultType,
80
  voteUrl,
81
  addNotification, // Redux action
813 stevensc 82
  updateFeed // Redux action
5 stevensc 83
}) => {
813 stevensc 84
  const [remainingTime, setRemainingTime] = useState('00:00:00')
85
  const [isActive, setIsActive] = useState(true)
86
  const [totalVotes, setTotalVotes] = useState(0)
87
  const timeRef = useRef(time)
88
  const { register, handleSubmit } = useForm()
5 stevensc 89
 
90
  const sendVote = handleSubmit(({ vote }) => {
813 stevensc 91
    setIsActive(false)
5 stevensc 92
 
813 stevensc 93
    const formData = new FormData()
94
    formData.append('vote', vote)
5 stevensc 95
 
96
    axios
97
      .post(voteUrl, formData)
98
      .then(({ data: response }) => {
813 stevensc 99
        const { success, data } = response
100
 
5 stevensc 101
        if (!success) {
813 stevensc 102
          addNotification({ style: 'danger', msg: `Error: ${data}` })
103
          setIsActive(true)
5 stevensc 104
        }
105
 
813 stevensc 106
        updateFeed({ feed: data, uuid: data.feed_uuid })
107
        addNotification({ style: 'success', msg: 'Voto emitido con exito' })
5 stevensc 108
      })
109
      .catch((err) => {
813 stevensc 110
        addNotification({ style: 'danger', msg: `Error: ${err}` })
111
        setIsActive(true)
112
        throw new Error(err)
113
      })
114
  })
5 stevensc 115
 
116
  function getTimeDiff(segundos) {
117
    // Obtener la fecha y hora actual
813 stevensc 118
    const currentDate = new Date()
5 stevensc 119
 
120
    // Calcular la fecha y hora futura sumando los segundos proporcionados
813 stevensc 121
    const futureDate = new Date(currentDate.getTime() + segundos * 1000)
5 stevensc 122
 
123
    // Calcular la diferencia entre la fecha futura y la fecha actual
813 stevensc 124
    const diff = futureDate - currentDate
5 stevensc 125
 
126
    // Calcular los componentes de la diferencia de tiempo
813 stevensc 127
    const days = Math.floor(diff / (1000 * 60 * 60 * 24))
128
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
129
    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
5 stevensc 130
 
131
    // Devolver el resultado
813 stevensc 132
    return `${addZero(days)}d ${addZero(hours)}h ${addZero(minutes)}m`
5 stevensc 133
  }
134
 
135
  function addZero(unit) {
813 stevensc 136
    return String(unit).padStart(2, '0')
5 stevensc 137
  }
138
 
139
  function getPorcentage(n, total) {
813 stevensc 140
    return (n / total) * 100
5 stevensc 141
  }
142
 
143
  useEffect(() => {
813 stevensc 144
    setRemainingTime(getTimeDiff(time))
5 stevensc 145
 
813 stevensc 146
    if (!time) return
5 stevensc 147
 
148
    const interval = setInterval(() => {
149
      if (!timeRef.current) {
813 stevensc 150
        setRemainingTime(() => getTimeDiff(0))
151
        setIsActive(false)
152
        return
5 stevensc 153
      }
154
 
155
      if (!timeRef.current <= 60) {
813 stevensc 156
        timeRef.current -= 1
157
        setRemainingTime(() => getTimeDiff(timeRef.current))
158
        return
5 stevensc 159
      }
160
 
813 stevensc 161
      timeRef.current -= 60
162
      setRemainingTime(() => getTimeDiff(timeRef.current))
163
    }, 60000)
5 stevensc 164
 
165
    return () => {
813 stevensc 166
      clearInterval(interval)
167
    }
168
  }, [])
5 stevensc 169
 
170
  useEffect(() => {
813 stevensc 171
    if (!votes) return
172
    const total = votes.reduce((acum, current) => acum + Number(current), 0)
173
    setTotalVotes(total)
174
  }, [votes])
5 stevensc 175
 
176
  useEffect(() => {
813 stevensc 177
    setIsActive(Boolean(active))
178
  }, [active])
5 stevensc 179
 
180
  return (
181
    <form onChange={sendVote} className={styles.survey_form}>
182
      <h3>{question}</h3>
813 stevensc 183
      {resultType === 'pu' && (
5 stevensc 184
        <span
813 stevensc 185
          className='mb-2'
186
          title='El número de votos es visible para todos los usuarios'
5 stevensc 187
        >
188
          <PublicIcon /> Público
189
        </span>
190
      )}
813 stevensc 191
      {resultType === 'pr' && (
5 stevensc 192
        <span
813 stevensc 193
          className='mb-2'
194
          title='Los resultados de la votación son privados'
5 stevensc 195
        >
196
          <LockClockIcon /> Privado
197
        </span>
198
      )}
199
      {answers.map(
200
        (option, index) =>
201
          option && (
202
            <RadioButton
203
              disabled={!isActive}
204
              porcentage={
205
                !!totalVotes && getPorcentage(votes[index], totalVotes)
206
              }
207
              key={index}
208
            >
209
              <input
813 stevensc 210
                type='radio'
211
                name='vote'
5 stevensc 212
                id={`vote-${index + 1}`}
213
                disabled={!isActive}
214
                ref={register({ required: true })}
215
                value={index + 1}
216
              />
217
              <label htmlFor={`vote-${index + 1}`}>{option}</label>
218
              {!!totalVotes && (
813 stevensc 219
                <span className='mb-0'>
5 stevensc 220
                  {getPorcentage(votes[index], totalVotes)}%
221
                </span>
222
              )}
223
            </RadioButton>
224
          )
225
      )}
226
      <span>Tiempo restante: {remainingTime}</span>
227
      {!isActive && <VoteTag>Tu voto ya fue emitido</VoteTag>}
228
    </form>
813 stevensc 229
  )
230
}
5 stevensc 231
 
232
const mapDispatchToProps = {
233
  addNotification: (notification) => addNotification(notification),
813 stevensc 234
  updateFeed: (payload) => updateFeed(payload)
235
}
5 stevensc 236
 
813 stevensc 237
export default connect(null, mapDispatchToProps)(SurveyForm)