Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 7147 | | Comparar con el anterior | Ultima modificación | Ver Log |

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