Skip to content
Snippets Groups Projects
Select Git revision
  • 2a16f88fd5e57e943cf7ccf78ffb60dba208cc7f
  • master default protected
2 results

data.js

Blame
  • ResultMakeForm.js 8.87 KiB
    import React, { useState, useEffect } from "react";
    import CalendarWeek from "./CalendarWeek";
    import PasswordModal from "./PasswordModal";
    import { useNavigate, useParams } from "react-router-dom";
    import axios from "axios";
    import "../styles/ResultMake.css";
    
    function ResultMakeForm() {
      const [meetingData, setMeetingData] = useState(null);
      const { meeting_id } = useParams();
      const navigate = useNavigate();
      const [timeLeft, setTimeLeft] = useState("");
      const [hoveredInfo, setHoveredInfo] = useState(null);
      const [isLoading, setIsLoading] = useState(true);
      const [isModalOpen, setIsModalOpen] = useState(false);
      const [mostAvailableDates, setMostAvailableDates] = useState([]);
      const [topAvailableDates, setTopAvailableDates] = useState([]);
    
      useEffect(() => {
        if (meetingData && meetingData.participants) {
          calculateTopAvailableDates();
        }
      }, [meetingData]);
    
      const calculateTopAvailableDates = () => {
        let dateAvailability = {};
    
        meetingData.participants.forEach((participant) => {
          participant.availableSchedules.forEach((schedule) => {
            if (!dateAvailability[schedule.availableDate]) {
              dateAvailability[schedule.availableDate] = {};
            }
            schedule.availableTimes.forEach((time) => {
              if (!dateAvailability[schedule.availableDate][time]) {
                dateAvailability[schedule.availableDate][time] = 0;
              }
              dateAvailability[schedule.availableDate][time]++;
            });
          });
        });
    
        let dateCounts = Object.entries(dateAvailability).map(([date, times]) => {
          let maxCount = Math.max(...Object.values(times));
          let count = Object.values(times).filter((val) => val === maxCount).length;
          return { date, count, maxCount };
        });
    
        dateCounts.sort((a, b) => b.maxCount - a.maxCount || b.count - a.count);
    
        setTopAvailableDates(dateCounts.slice(0, 5));
      };
    
      useEffect(() => {
        if (meetingData && meetingData.participants) {
          calculateMostAvailableDates();
        }
      }, [meetingData]);
    
      const calculateMostAvailableDates = () => {
        let dateAvailabilityCount = {};
    
        meetingData.participants.forEach((participant) => {
          participant.availableSchedules.forEach((schedule) => {
            if (!dateAvailabilityCount[schedule.availableDate]) {
              dateAvailabilityCount[schedule.availableDate] = new Set();
            }
            schedule.availableTimes.forEach((time) => {
              dateAvailabilityCount[schedule.availableDate].add(time);
            });
          });
        });
    
        const sortedDates = Object.entries(dateAvailabilityCount)
          .map(([date, times]) => ({ date, count: times.size }))
          .sort((a, b) => b.count - a.count)
          .slice(0, 5);
    
        setMostAvailableDates(sortedDates);
      };
      useEffect(() => {
        const fetchMeetingData = async () => {
          setIsLoading(true);
          try {
            const response = await axios.get(`/meetings/${meeting_id}/details`, {
              withCredentials: true,
            });
            setMeetingData(response.data);
            setIsLoading(false);
          } catch (error) {
            console.error("데이터 로딩 에러:", error);
            setIsLoading(false);
          }
        };
    
        fetchMeetingData();
      }, [meeting_id]);
    
      useEffect(() => {
        const calculateTimeLeft = () => {
          if (!meetingData || !meetingData.voteExpiresAt) {
            return { days: 0, hours: 0, minutes: 0, seconds: 0 };
          }
    
          // 서버의 voteExpiresAt 값을 한국 시간대로 가정하여 파싱
          const voteExpiresKST = new Date(meetingData.voteExpiresAt);
    
          // 현재 로컬 시간 (브라우저 시간대를 한국 시간대로 조정)
          const now = new Date();
          const nowKST = new Date(now.getTime() + 9 * 60 * 60 * 1000); // UTC 시간에 9시간을 더해 KST로 조정
    
          // 남은 시간 계산
          const difference = voteExpiresKST - nowKST;
    
          if (difference > 0) {
            return {
              days: Math.floor(difference / (1000 * 60 * 60 * 24)),
              hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
              minutes: Math.floor((difference / 1000 / 60) % 60),
              seconds: Math.floor((difference / 1000) % 60),
            };
          } else {
            return { days: 0, hours: 0, minutes: 0, seconds: 0 };
          }
        };
    
        const updateTimer = () => {
          const newTimeLeft = calculateTimeLeft();
          const formattedTime = `${
            newTimeLeft.days ? newTimeLeft.days + "일 " : ""
          }${newTimeLeft.hours ? newTimeLeft.hours + "시간 " : ""}${
            newTimeLeft.minutes ? newTimeLeft.minutes + "분 " : ""
          }${newTimeLeft.seconds ? newTimeLeft.seconds + "초" : ""}`;
          setTimeLeft(formattedTime);
        };
    
        const timerId = setInterval(updateTimer, 1000);
        return () => clearInterval(timerId);
      }, [meetingData]);
    
      const handleEdit = async () => {
        try {
          const response = await axios.get(`/meetings/${meeting_id}/`);
          const {
            startDate,
            endDate,
            availableVotingStartTime,
            availableVotingEndTime,
          } = response.data;
    
          try {
            const scheduleResponse = await axios.get(
              `/meetings/${meeting_id}/my/schedules`
            );
            navigate(`/homeparticipate/${meeting_id}/usertimeinfo/`, {
              state: {
                id: meeting_id,
                startTime: availableVotingStartTime,
                endTime: availableVotingEndTime,
                startDate,
                endDate,
                schedules: scheduleResponse.data.schedules,
              },
            });
          } catch (error) {
            console.error(error);
          }
        } catch (error) {
          console.error(error);
        }
      };
    
      const closeMeeting = () => {
        setIsModalOpen(true);
      };
    
      const handleModalClose = () => {
        setIsModalOpen(false);
      };
    
      const handlePasswordSubmit = async (password) => {
        setIsModalOpen(false);
        try {
          await axios.patch(`/meetings/${meeting_id}/close`, {
            adminPassword: password,
          });
          navigate(`/resultend/${meeting_id}`);
        } catch (error) {
          if (error.response && error.response.status === 401) {
            alert("비밀번호가 틀렸습니다.");
          } else if (error.response && error.response.status === 409) {
            alert("이미 종료된 투표입니다.");
          } else {
            console.error("오류 발생:", error);
          }
        }
      };
    
      return (
        <>
          {isLoading ? (
            <div>Loading...</div>
          ) : (
            <div className="column-container">
              <h1 className="title-box">{meetingData?.title}</h1>
              {meetingData.maxParticipants && (
                <div>
                  현재 완료한 인원수 : {meetingData?.currentParticipants} /{" "}
                  {meetingData?.maxParticipants}
                </div>
              )}
              {!meetingData.maxParticipants && (
                <div>현재 완료한 인원수 : {meetingData?.currentParticipants}</div>
              )}
    
              <div>종료까지 남은 시간 : {timeLeft}</div>
              <button onClick={handleEdit}>수정하기</button>
              <button onClick={closeMeeting}>투표 종료하기</button>
            </div>
          )}
          {meetingData && (
            <div className="flex-row">
              <CalendarWeek
                participants={meetingData.participants}
                startDate={meetingData.startDate}
                endDate={meetingData.endDate}
                currentParticipants={meetingData.currentParticipants}
                maxParticipants={meetingData.maxParticipants}
                hoveredInfo={hoveredInfo}
                setHoveredInfo={setHoveredInfo}
                availableVotingStartTime={meetingData.availableVotingStartTime}
                availableVotingEndTime={meetingData.availableVotingEndTime}
              />
            </div>
          )}
          <PasswordModal
            isOpen={isModalOpen}
            onRequestClose={handleModalClose}
            onSubmit={handlePasswordSubmit}
          />
          <div className="flex-bottom-container">
            <span className="mostTime">
              <strong style={{ textAlign: "center" }}>
                가장 많은 사람들이 가능한 일정
              </strong>
              <ol>
                {topAvailableDates.map((dateInfo, index) => (
                  <li key={index}>
                    {dateInfo.date} ({dateInfo.maxCount}명이 가능한 시간대:{" "}
                    {dateInfo.count}개 )
                  </li>
                ))}
              </ol>
            </span>
            <span className="possible">
              {!hoveredInfo && (
                <div>
                  <strong>가능한 사람들이 표시됩니다.</strong>
                  <p>마우스를 달력 위에 올려보세요!</p>
                </div>
              )}
    
              {hoveredInfo && (
                <div style={{ textAlign: "center" }}>
                  <strong>
                    {hoveredInfo.date} {hoveredInfo.time}에 가능한 사람:
                  </strong>
                  <ul>
                    {hoveredInfo.participants.map((name) => (
                      <li key={name}>{name}</li>
                    ))}
                  </ul>
                </div>
              )}
            </span>
          </div>
        </>
      );
    }
    
    export default ResultMakeForm;