Skip to content
Snippets Groups Projects
Commit 63a30796 authored by 준현 강's avatar 준현 강
Browse files

[EDIT] 관리자 버튼, 달력 현재 참여자 기준으로 hover수정

parent a8690d92
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@
"react": "^18.2.0",
"react-calendar": "^4.6.1",
"react-dom": "^18.2.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.18.0",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4"
......@@ -8115,6 +8116,11 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/exenv": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
"integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw=="
},
"node_modules/exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
......@@ -14949,6 +14955,29 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-modal": {
"version": "3.16.1",
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz",
"integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==",
"dependencies": {
"exenv": "^1.2.0",
"prop-types": "^15.7.2",
"react-lifecycles-compat": "^3.0.0",
"warning": "^4.0.3"
},
"engines": {
"node": ">=8"
},
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18",
"react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18"
}
},
"node_modules/react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
......@@ -17254,6 +17283,14 @@
"makeerror": "1.0.12"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
......
......@@ -13,6 +13,7 @@
"react": "^18.2.0",
"react-calendar": "^4.6.1",
"react-dom": "^18.2.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.18.0",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4"
......
import React, { useState } from "react";
import Modal from "react-modal";
Modal.setAppElement("#root");
function PasswordModal({ isOpen, onRequestClose, onSubmit }) {
const [password, setPassword] = useState("");
const handleSubmit = () => {
onSubmit(password);
setPassword("");
};
const customStyles = {
content: {
width: "400px", // 모달의 너비
height: "200px", // 모달의 높이
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
},
};
return (
<Modal
isOpen={isOpen}
onRequestClose={onRequestClose}
contentLabel="비밀번호 입력"
style={customStyles}
>
<h2>관리자 비밀번호를 입력하세요</h2>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="비밀번호"
/>
<button onClick={handleSubmit}>확인</button>
<button onClick={onRequestClose}>취소</button>
</Modal>
);
}
export default PasswordModal;
// import React, { useState, useEffect } from "react";
// import CalendarWeek from "./CalendarWeek";
// 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 { currentParticipants, maxParticipants } = meetingData || {};
// const navigate = useNavigate();
// const [timeLeft, setTimeLeft] = useState("");
// const [hoveredInfo, setHoveredInfo] = useState(null);
// const [isLoading, setIsLoading] = useState(true); // 로딩 상태 관리
// const [isModalOpen, setIsModalOpen] = useState(false);
// useEffect(() => {
// // 서버에서 미팅 데이터를 가져오는 함수
// const fetchMeetingData = async () => {
// setIsLoading(true);
// try {
// const response = await axios.get(
// `http://localhost:3000/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) {
// // meetingData나 voteExpiresAt이 없는 경우 기본값을 반환
// return {
// days: 0,
// hours: 0,
// minutes: 0,
// seconds: 0,
// };
// }
// const now = new Date();
// const voteExpires = new Date(meetingData.voteExpiresAt);
// const difference = voteExpires - now;
// 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() || {}; // newTimeLeft가 undefined인 경우를 대비해 기본 객체 할당
// const formattedTime = `${
// newTimeLeft.days ? newTimeLeft.days + "일 " : ""
// }${newTimeLeft.hours ? newTimeLeft.hours + "시간 " : ""}${
// newTimeLeft.minutes ? newTimeLeft.minutes + "분 " : ""
// }${newTimeLeft.seconds ? newTimeLeft.seconds + "초" : ""}`;
// setTimeLeft(formattedTime);
// };
// updateTimer();
// const timerId = setInterval(updateTimer, 1000);
// return () => clearInterval(timerId);
// }, [meetingData]);
// const handleEdit = async () => {
// try {
// const response = await axios.get(
// `http://localhost:3000/meetings/${meeting_id}/`
// );
// const {
// startDate,
// endDate,
// availableVotingStartTime,
// availableVotingEndTime,
// } = response.data;
// try {
// const scheduleResponse = await axios.get(
// `http://localhost:3000/meetings/${meeting_id}/my/schedules`
// );
// navigate("/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 = async () => {
// const adminPassword = prompt("관리자 비밀번호를 입력하세요:");
// if (adminPassword) {
// try {
// await axios.post(`http://localhost:3000/meetings/${meeting_id}/close`, {
// adminPassword,
// });
// navigate(`/resultend/${meeting_id}`);
// } catch (error) {
// if (error.response && error.response.status === 401) {
// alert("비밀번호가 틀렸습니다.");
// } else {
// console.error("오류 발생:", error);
// }
// }
// }
// };
// const handleModalClose = () => {
// setIsModalOpen(false);
// };
// const handlePasswordConfirm = async (password) => {
// setIsModalOpen(false);
// try {
// await axios.post(`http://localhost:3000/meetings/${meeting_id}/close`, {
// adminPassword: password,
// });
// navigate(`/resultend/${meeting_id}`);
// } catch (error) {
// if (error.response && error.response.status === 401) {
// alert("비밀번호가 틀렸습니다.");
// } else {
// console.error("오류 발생:", error);
// }
// }
// };
// return (
// <>
// {isLoading ? (
// <div>Loading...</div>
// ) : (
// <div className="column-container">
// <h1 className="title-box">{meetingData?.title}</h1>
// <div>
// 현재 완료한 인원수 {currentParticipants}
// {maxParticipants != null && ` / ${maxParticipants}`}
// </div>
// <div>종료까지 남은 시간 {timeLeft}</div>
// <button onClick={handleEdit}>수정하기</button>
// <button onClick={closeMeeting}>투표 종료하기</button>
// </div>
// )}
// {meetingData && (
// <span className="flex-row">
// <div className="calander-container">
// <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>
// <span className="mostTime">
// <div style={{ textAlign: "center" }}>
// 가장 많은 사람들이 가능한 일정
// </div>
// <ol>//일정 5개 나열</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>
// </span>
// )}
// </>
// );
// }
// export default ResultMakeForm;
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 { currentParticipants, maxParticipants } = meetingData || {};
const navigate = useNavigate();
const [timeLeft, setTimeLeft] = useState("");
const [hoveredInfo, setHoveredInfo] = useState(null);
const [isLoading, setIsLoading] = useState(true); // 로딩 상태 관리
const [isLoading, setIsLoading] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
useEffect(() => {
// 서버에서 미팅 데이터를 가져오는 함수
const fetchMeetingData = async () => {
setIsLoading(true);
try {
const response = await axios.get(
`http://localhost:3000/meetings/${meeting_id}/details`,
{
withCredentials: true,
}
{ withCredentials: true }
);
setMeetingData(response.data);
setIsLoading(false);
......@@ -35,17 +263,10 @@ function ResultMakeForm() {
fetchMeetingData();
}, [meeting_id]);
// 타이머를 시작하고 관리하는 로직
useEffect(() => {
const calculateTimeLeft = () => {
if (!meetingData || !meetingData.voteExpiresAt) {
// meetingData나 voteExpiresAt이 없는 경우 기본값을 반환
return {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};
return { days: 0, hours: 0, minutes: 0, seconds: 0 };
}
const now = new Date();
const voteExpires = new Date(meetingData.voteExpiresAt);
......@@ -59,18 +280,12 @@ function ResultMakeForm() {
seconds: Math.floor((difference / 1000) % 60),
};
} else {
// 시간이 이미 지난 경우 기본값을 반환
return {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};
return { days: 0, hours: 0, minutes: 0, seconds: 0 };
}
};
const updateTimer = () => {
const newTimeLeft = calculateTimeLeft() || {}; // newTimeLeft가 undefined인 경우를 대비해 기본 객체 할당
const newTimeLeft = calculateTimeLeft();
const formattedTime = `${
newTimeLeft.days ? newTimeLeft.days + "" : ""
}${newTimeLeft.hours ? newTimeLeft.hours + "시간 " : ""}${
......@@ -79,14 +294,65 @@ function ResultMakeForm() {
setTimeLeft(formattedTime);
};
updateTimer();
const timerId = setInterval(updateTimer, 1000);
return () => clearInterval(timerId);
}, [meetingData]);
const handleEdit = async () => {
try {
const response = await axios.get(
`http://localhost:3000/meetings/${meeting_id}/`
);
const {
startDate,
endDate,
availableVotingStartTime,
availableVotingEndTime,
} = response.data;
try {
const scheduleResponse = await axios.get(
`http://localhost:3000/meetings/${meeting_id}/my/schedules`
);
navigate("/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 handleEdit = () => {
navigate("/meetinginfo/linkpage");
const handleModalClose = () => {
setIsModalOpen(false);
};
const handlePasswordSubmit = async (password) => {
setIsModalOpen(false);
try {
await axios.post(`http://localhost:3000/meetings/${meeting_id}/close`, {
adminPassword: password,
});
navigate(`/resultend/${meeting_id}`);
} catch (error) {
if (error.response && error.response.status === 401) {
alert("비밀번호가 틀렸습니다.");
} else {
console.error("오류 발생:", error);
}
}
};
return (
......@@ -96,65 +362,64 @@ function ResultMakeForm() {
) : (
<div className="column-container">
<h1 className="title-box">{meetingData?.title}</h1>
<div>
현재 완료한 인원수 {currentParticipants}
{maxParticipants != null && ` / ${maxParticipants}`}
현재 완료한 인원수 {meetingData?.currentParticipants} /{" "}
{meetingData?.maxParticipants}
</div>
<div>종료까지 남은 시간 {timeLeft}</div>
<button onClick={handleEdit}>수정하기</button>
<button onClick={() => navigate(`/resultend/${meeting_id}`)}>
투표 종료하기
</button>
<button onClick={closeMeeting}>투표 종료하기</button>
</div>
)}
{meetingData && (
<span className="flex-row">
<div className="calander-container">
<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 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}
/>
<span className="mostTime">
<div style={{ textAlign: "center" }}>
가장 많은 사람들이 가능한 일정
</div>
<ol>//일정 5개 나열</ol>
</span>
<span className="possible">
{!hoveredInfo && (
<div>
<strong>가능한 사람들이 표시됩니다.</strong>
<p>마우스를 달력 위에 올려보세요!</p>
</div>
)}
<span className="mostTime">
<div style={{ textAlign: "center" }}>
가장 많은 사람들이 가능한 일정
</div>
<ol>//일정 5개 나열</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>
</span>
)}
{hoveredInfo && (
<div style={{ textAlign: "center" }}>
<strong>
{hoveredInfo.date} {hoveredInfo.time} 가능한 사람:
</strong>
<ul>
{hoveredInfo.participants.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</div>
)}
</span>
</>
);
}
export default ResultMakeForm;
......@@ -19,6 +19,7 @@ table {
width: 100%;
border-collapse: collapse;
text-align: center;
margin-bottom: 4%;
}
th,
......
.title-box {
width: 30%;
margin: 0 auto;
text-align: center;
}
.form-container {
......@@ -24,6 +23,7 @@
width: 20%;
border: 1px solid black;
padding: 20px;
margin-right: 2%;
}
.row {
......
.title-box {
width: 30%;
margin: 0 auto;
width: 80%;
text-align: center;
}
.column-container {
display: flex;
flex-direction: column;
align-items: center;
}
.flex-row {
......@@ -22,4 +22,5 @@
width: 20%;
border: 1px solid black;
padding: 20px;
margin-right: 2%;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment