Rev 5 | Rev 814 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
import React, { useEffect, useRef, useState } from "react";
import { axios } from "../../utils";
import { useForm } from "react-hook-form";
import { connect } from "react-redux";
import { updateFeed } from "../../redux/feed/feed.actions";
import { addNotification } from "../../redux/notification/notification.actions";
import LockClockIcon from "@mui/icons-material/LockClock";
import PublicIcon from "@mui/icons-material/Public";
import styles from "./survey.module.scss";
import styled, { css } from "styled-components";
const RadioButton = styled.div`
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border: 2px solid var(--border-primary);
border-radius: 50px;
cursor: pointer;
transition: all 200ms ease;
position: relative;
overflow: hidden;
margin-bottom: 0.5rem;
input {
margin: 0 !important;
}
label {
color: var(--font-color);
font-weight: 500;
}
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
height: 100%;
width: ${(props) => (props.porcentage ? `${props.porcentage}%` : "0%")};
background-color: #0002;
z-index: 4;
}
&:hover {
border-color: var(--font-color);
text-shadow: 0 0 1px var(--font-color);
}
${(props) =>
props.disabled &&
css`
background-color: #9992;
cursor: auto;
label {
color: gray;
}
&:hover {
border-color: var(--border-primary);
text-shadow: none;
}
`}
`;
const VoteTag = styled.span`
position: absolute;
bottom: 1rem;
right: 1rem;
color: var(--font-color) !important;
font-weight: 600;
`;
const SurveyForm = ({
question,
answers = [],
votes,
active = false,
time,
resultType,
voteUrl,
addNotification, // Redux action
updateFeed, // Redux action
}) => {
const [remainingTime, setRemainingTime] = useState("00:00:00");
const [isActive, setIsActive] = useState();
const [totalVotes, setTotalVotes] = useState(0);
const timeRef = useRef(time);
const { register, handleSubmit } = useForm();
const sendVote = handleSubmit(({ vote }) => {
setIsActive(false);
const formData = new FormData();
formData.append("vote", vote);
axios
.post(voteUrl, formData)
.then(({ data: response }) => {
const { success, data } = response;
if (!success) {
addNotification({ style: "danger", msg: `Error: ${data}` });
setIsActive(true);
}
updateFeed({ feed: data, uuid: data.feed_uuid });
addNotification({ style: "success", msg: "Voto emitido con exito" });
})
.catch((err) => {
addNotification({ style: "danger", msg: `Error: ${err}` });
setIsActive(true);
throw new Error(err);
});
});
function getTimeDiff(segundos) {
// Obtener la fecha y hora actual
const currentDate = new Date();
// Calcular la fecha y hora futura sumando los segundos proporcionados
const futureDate = new Date(currentDate.getTime() + segundos * 1000);
// Calcular la diferencia entre la fecha futura y la fecha actual
const diff = futureDate - currentDate;
// Calcular los componentes de la diferencia de tiempo
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
// Devolver el resultado
return `${addZero(days)}d ${addZero(hours)}h ${addZero(minutes)}m`;
}
function addZero(unit) {
return String(unit).padStart(2, "0");
}
function getPorcentage(n, total) {
return (n / total) * 100;
}
useEffect(() => {
setRemainingTime(getTimeDiff(time));
if (!time) return;
const interval = setInterval(() => {
if (!timeRef.current) {
setRemainingTime(() => getTimeDiff(0));
setIsActive(false);
return;
}
if (!timeRef.current <= 60) {
timeRef.current -= 1;
setRemainingTime(() => getTimeDiff(timeRef.current));
return;
}
timeRef.current -= 60;
setRemainingTime(() => getTimeDiff(timeRef.current));
}, 60000);
return () => {
clearInterval(interval);
};
}, []);
useEffect(() => {
if (!votes) return;
const total = votes.reduce((acum, current) => acum + Number(current), 0);
setTotalVotes(total);
}, [votes]);
useEffect(() => {
active ?? setIsActive(Boolean(active));
}, [active]);
return (
<form onChange={sendVote} className={styles.survey_form}>
<h3>{question}</h3>
{resultType === "pu" && (
<span
className="mb-2"
title="El número de votos es visible para todos los usuarios"
>
<PublicIcon /> Público
</span>
)}
{resultType === "pr" && (
<span
className="mb-2"
title="Los resultados de la votación son privados"
>
<LockClockIcon /> Privado
</span>
)}
{answers.map(
(option, index) =>
option && (
<RadioButton
disabled={!isActive}
porcentage={
!!totalVotes && getPorcentage(votes[index], totalVotes)
}
key={index}
>
<input
type="radio"
name="vote"
id={`vote-${index + 1}`}
disabled={!isActive}
ref={register({ required: true })}
value={index + 1}
/>
<label htmlFor={`vote-${index + 1}`}>{option}</label>
{!!totalVotes && (
<span className="mb-0">
{getPorcentage(votes[index], totalVotes)}%
</span>
)}
</RadioButton>
)
)}
<span>Tiempo restante: {remainingTime}</span>
{!isActive && <VoteTag>Tu voto ya fue emitido</VoteTag>}
</form>
);
};
const mapDispatchToProps = {
addNotification: (notification) => addNotification(notification),
updateFeed: (payload) => updateFeed(payload),
};
export default connect(null, mapDispatchToProps)(SurveyForm);