Proyectos de Subversion LeadersLinked - SPA

Rev

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

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