Rev 5 | Rev 813 | 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 actionupdateFeed, // 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 actualconst currentDate = new Date();// Calcular la fecha y hora futura sumando los segundos proporcionadosconst futureDate = new Date(currentDate.getTime() + segundos * 1000);// Calcular la diferencia entre la fecha futura y la fecha actualconst diff = futureDate - currentDate;// Calcular los componentes de la diferencia de tiempoconst 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 resultadoreturn `${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" && (<spanclassName="mb-2"title="El número de votos es visible para todos los usuarios"><PublicIcon /> Público</span>)}{resultType === "pr" && (<spanclassName="mb-2"title="Los resultados de la votación son privados"><LockClockIcon /> Privado</span>)}{answers.map((option, index) =>option && (<RadioButtondisabled={!isActive}porcentage={!!totalVotes && getPorcentage(votes[index], totalVotes)}key={index}><inputtype="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);