diff --git a/src/components/modal/BookingInfoModal.js b/src/components/modal/BookingInfoModal.js index d68d2af..78472fd 100644 --- a/src/components/modal/BookingInfoModal.js +++ b/src/components/modal/BookingInfoModal.js @@ -15,11 +15,17 @@ export const BookingInfoModalView = styled.div` box-shadow: 0 9px 26px 0 #170F490D; padding: 10px; width: fit-content; + height: fit-content; z-index: 3; ` export const BookingInfosModalView = styled(BookingInfoModalView)` - + max-height: 300px; + position: relative; + z-index: initial; + margin-left: 50px; + margin-top: initial; + overflow-y: scroll; ` export const BookingInfoText = styled.span` @@ -49,12 +55,12 @@ export function BookingInfoModal(props) { export function BookingInfosModal(props) { return ( - - {props.info.map((value, index) => + + {props.info && props.info.map((value, index) => <> - {value.start} ~ {value.end} + {value.startDateTime} ~ {value.endDateTime} {value.reservatorName} - {value.department} + {value.reservatorDepartment} {value.reservatorPhone} {index < props.info.length - 1 ? : null} diff --git a/src/components/officeBooking/BookingTimeBar.js b/src/components/officeBooking/BookingTimeBar.js index 6a7e882..192b133 100644 --- a/src/components/officeBooking/BookingTimeBar.js +++ b/src/components/officeBooking/BookingTimeBar.js @@ -21,7 +21,7 @@ let date = moment(new Date()).format("YYYY-MM-DD"); export const BookingContentContainer = styled.div` margin: 30px 0 30px 20px; display: flex; - align-items: baseline; + //align-items: baseline; ` export const BookingDateTextContainer = styled.div` diff --git a/src/components/resourceBooking/TimeSelector.js b/src/components/resourceBooking/TimeSelector.js index d6ec2f9..5785666 100644 --- a/src/components/resourceBooking/TimeSelector.js +++ b/src/components/resourceBooking/TimeSelector.js @@ -1,9 +1,10 @@ import styled from "styled-components" import React, {useEffect, useState} from "react"; -import {ResourceTimeList} from "../../constants/ToggleList"; +import {findTimeIndex, ResourceTimeList, TimeList} from "../../constants/ToggleList"; import {ResourcesAxios} from "../../api/AxiosApi"; import {getToken} from "../../utils/IsLoginUtil"; import {basicError} from "../../utils/ErrorHandlerUtil"; +import {BookingInfosModal} from "../modal/BookingInfoModal"; export const TimeContainer = styled.ul` margin-top: 10px; @@ -55,6 +56,8 @@ export function setDate(date) { export function TimeSelector(props) { const [bookedTimes, setBookedTimes] = useState([]); + const [bookingInfos, setBookingInfos] = useState(false) + const [isOpen, setIsOpen] = useState(false) useEffect(() => { getResourceBookedDates(currentDate, props.resourceId) @@ -72,6 +75,40 @@ export function TimeSelector(props) { return false } + // 시간에 마우스 오버 + const handleTimeMouseEnter = (time, date) => { + // ResourcesAxios.get(`/${props.resourceId}/booking?dateTime=${date} ${time.slice(0 ,2)}`, { + // headers: { + // Authorization: getToken() + // } + // }) + // .then((Response) => { + // const info = Response.data.data; + // if (info === undefined) { + // setBookingInfos(null) + // } else { + // setBookingInfos(Response.data.data) + // setIsOpen(true) + // } + // }) + // .catch((Error) => { + // basicError(Error) + // window.alert("예약 정보를 불러오는데 실패하였습니다.") + // }); + } + + const handleTimeMouseLeave = () => { + setIsOpen(false) + } + + const handleModalMouseEnter = () => { + setIsOpen(true) + } + + const handleModalMouseLeave = () => { + setIsOpen(false) + } + const getResourceBookedDates = (date, resourceId) => { const params = {date: date}; ResourcesAxios.get(`/${resourceId}/booking-time`, { @@ -98,12 +135,22 @@ export function TimeSelector(props) { { ResourceTimeList.map(function (time) { if (isTimeMatch(time)) - return ({time}) + return ( handleTimeMouseEnter(time, currentDate)} + onMouseOut={() => handleTimeMouseLeave()} + className={'disabled'}>{time}) else return ( clickHandler(time)}>{time}) }) } + {isOpen && ( + handleModalMouseEnter()} + onMouseOut={() => handleModalMouseLeave()}/> + )} - ) - ; + ); } \ No newline at end of file diff --git a/src/constants/ToggleList.js b/src/constants/ToggleList.js index 82fe921..f4bdea0 100644 --- a/src/constants/ToggleList.js +++ b/src/constants/ToggleList.js @@ -18,4 +18,8 @@ export const BookingCategoryList = [ export const AffiliationList = [ "플래디", "스튜디오아이", "피디룸" -] \ No newline at end of file +] + +export function findTimeIndex(time) { + return ResourceTimeList.indexOf(time) +} \ No newline at end of file diff --git a/src/pages/admin/car/CarManageAdd.js b/src/pages/admin/car/CarManageAdd.js index 7c15465..8b9a6e9 100644 --- a/src/pages/admin/car/CarManageAdd.js +++ b/src/pages/admin/car/CarManageAdd.js @@ -10,6 +10,7 @@ import EmptyImg from "assets/images/EmptyImg.svg" import {ExitBtn} from "components/modal/BigModal"; import axios from "axios"; import {useParams} from "react-router-dom"; +import {getImgKey} from "../../../utils/ImageUtil"; const MarginWhiteContainer = styled(WhiteContainer)` padding: 40px; @@ -291,7 +292,7 @@ function CarManageAdd(props) { manufacturer: manufacturer, location: place, name: name, - imgKey: imageFile === null ? imageUrl : `car/${imageUrl.imageKey}`, + imgKey: imageFile === null ? getImgKey(imageUrl) : `car/${imageUrl.imageKey}`, }, { headers: { diff --git a/src/pages/admin/resource/ResourceManageAdd.js b/src/pages/admin/resource/ResourceManageAdd.js index ded4caa..c42895a 100644 --- a/src/pages/admin/resource/ResourceManageAdd.js +++ b/src/pages/admin/resource/ResourceManageAdd.js @@ -10,6 +10,7 @@ import EmptyImg from "assets/images/EmptyImg.svg" import {ExitBtn} from "components/modal/BigModal"; import axios from "axios"; import {useParams} from "react-router-dom"; +import {getImgKey} from "../../../utils/ImageUtil"; const MarginWhiteContainer = styled(WhiteContainer)` padding: 40px; @@ -206,6 +207,7 @@ function ResourceManageAdd(props) { setIsUpload(false); imageInput.current.value = ""; setImgSrc(null) + setImgUrl(null) }; // 이미지 람다 호출 @@ -290,7 +292,7 @@ function ResourceManageAdd(props) { manufacturer: manufacturer, location: place, name: name, - imgKey: imageFile === null ? imageUrl : `resource/${imageUrl.imageKey}`, + imgKey: imageFile === null ? getImgKey(imageUrl) : `resource/${imageUrl.imageKey}`, }, { headers: { @@ -328,6 +330,7 @@ function ResourceManageAdd(props) { description: Response.data.data.description }); setImgUrl(Response.data.data.imgUrl); + setImgSrc(Response.data.data.imgUrl); }) .catch((Error) => { basicError(Error) diff --git a/src/pages/basic/booking/resource/ResourceBooking.js b/src/pages/basic/booking/resource/ResourceBooking.js index af91088..aa7d4db 100644 --- a/src/pages/basic/booking/resource/ResourceBooking.js +++ b/src/pages/basic/booking/resource/ResourceBooking.js @@ -3,7 +3,7 @@ import styled from "styled-components" import Calendar from 'react-calendar'; import 'react-calendar/dist/Calendar.css'; import moment from 'moment'; -import {OfficesAxios, ResourcesAxios} from 'api/AxiosApi'; +import {ResourcesAxios} from 'api/AxiosApi'; import {useParams} from 'react-router-dom'; import Capsule from 'components/capsule/Capsule'; import {DetailSubTitleText, NameSubTitleText} from 'components/officeBooking/SubTitleBar'; @@ -16,9 +16,8 @@ import SmallButton from 'components/button/SmallButton'; import {Bar} from 'pages/basic/myBookings/BookedList'; import {getToken} from 'utils/IsLoginUtil'; import ResourceDetailInfo from "components/card/ResourceDetailInfo"; -import {TimeList} from "constants/ToggleList"; -import {setDate, TimeSelector} from "../../../../components/resourceBooking/TimeSelector"; -import {BookingInfoModal, BookingInfosModal} from "../../../../components/modal/BookingInfoModal"; +import {setDate, TimeSelector} from "components/resourceBooking/TimeSelector"; +import {BookingInfosModal} from "components/modal/BookingInfoModal"; export const BookingDateTimeContainer = styled.div` margin-left: 10px; @@ -32,6 +31,7 @@ export const BookingDateText = styled.text` color: #575757; font-size: 22px; text-align: left; + line-height: 34px; ` export const PurposeTextarea = styled.textarea` @@ -56,9 +56,7 @@ export const DateContainer = styled.div` margin-left: 10px; ` -var currentMonth = moment(new Date()).format('YYYY-MM') -// var startTime = ""; -// var endTime = ""; +let currentMonth = moment(new Date()).format('YYYY-MM'); function ResourceBooking(props) { let {resourceId} = useParams(); @@ -74,27 +72,9 @@ function ResourceBooking(props) { const [changed, setCurrentMonth] = useState(); const [isOpen, setIsOpen] = useState(false) const [bookingInfos, setBookingInfos] = useState(false) - - // const handleMouseEnter = (index) => { - // OfficesAxios.get(`/${resourceId}/booking?date=${date}&time=${TimeList[index]}`, { - // headers: { - // Authorization: getToken() - // } - // }) - // .then((Response) => { - // const info = Response.data.data; - // if (info === undefined) { - // setBookingInfo(null) - // } else { - // setBookingInfo(Response.data.data) - // setIsOpen(true) - // } - // }) - // .catch((Error) => { - // basicError(Error) - // window.alert("예약 정보를 불러오는데 실패하였습니다.") - // }); - // } + const [x, setX] = useState(0); + const [y, setY] = useState(0); + const [clickedDate, setClickedDate] = useState(null); const getResourceInfo = () => { ResourcesAxios.get(`/${resourceId}`, { @@ -143,7 +123,6 @@ function ResourceBooking(props) { endDate.current = "" setStartTime("") setEndTime("") - // endTime = "" } else { endDate.current = dateFormat for (var i = 0; i < dates.length; i++) { @@ -164,31 +143,19 @@ function ResourceBooking(props) { if ((startDate !== "" && startTime === "") || (startDate !== "" && endDate.current === "")) { setStartTime(time) } else if (startDate !== "" && endDate.current !== "" && startTime !== "") { - // endTime = time setEndTime(time) - // console.log(startDate + " " + startTime) - // console.log(endDate.current + " " + endTime) - // if (new Date(startDate + " " + startTime) > new Date(endDate.current + " " + endTime)) { - // alert('시작일시보다 종료일시가 더 앞에 있습니다.') - // endTime = "" - // } - // for (var i = 0; i < dates.length; i++) { - // var temp = new Date(dates[i]) - // temp = moment(temp).format("YYYY-MM-DD") - // - // if (startDate <= temp && endDate >= temp) { - // alert('예약된 일자를 포함한 날짜는 선택할 수 없습니다.') - // startDate = ''; - // endDate = ''; - // setStartDate(startDate) - // setEndDate(endDate) - // window.location.reload() - // return - // } - // } + console.log(startDate + " " + startTime) + console.log(endDate.current + " " + endTime) } }; + useEffect(() => { + if (endTime !== "" && new Date(startDate + " " + startTime) > new Date(endDate.current + " " + endTime)) { + alert('시작일시보다 종료일시가 더 앞에 있습니다.') + setEndTime("") + } + }, [endTime]) + const onActiveStartDateChange = (e) => { if (e.activeStartDate !== null) { const changed = moment(e.activeStartDate).format("YYYY-MM") @@ -232,6 +199,46 @@ function ResourceBooking(props) { getBookedDates() }, []); + useEffect(() => { + if (clickedDate !== null) + handleDateMouseEnter(clickedDate) + }, [clickedDate]) + + function formatDate(dateString) { + // 한글 문자 제거 + const cleanedDateString = dateString.replace(/[년월일]/g, ''); + const originalDate = new Date(cleanedDateString); + + // 월과 일을 가져와서 두 자리로 포맷팅 + const month = ('0' + (originalDate.getMonth() + 1)).slice(-2); + const day = ('0' + originalDate.getDate()).slice(-2); + + // 년-월-일 형식으로 조합 + return `${originalDate.getFullYear()}-${month}-${day}`; + } + + // 일자에 마우스 오버 + const handleDateMouseEnter = (date) => { + ResourcesAxios.get(`/${resourceId}/booking-info?date=${date}`, { + headers: { + Authorization: getToken() + } + }) + .then((Response) => { + const info = Response.data.data; + if (info === undefined) { + setBookingInfos(null) + } else { + setBookingInfos(Response.data.data) + // setIsOpen(true) + } + }) + .catch((Error) => { + basicError(Error) + window.alert("예약 정보를 불러오는데 실패하였습니다.") + }); + } + const handleMouseLeave = () => { setIsOpen(false) } @@ -275,8 +282,11 @@ function ResourceBooking(props) { { - // console.log(event) if (event.target.classList.contains("react-calendar__month-view__days__day")) { + console.log(event) + setX(event.clientX) + setY(event.clientY) + setClickedDate(formatDate(event.target.children[0].ariaLabel)) } }} onMouseOut={(event) => { @@ -309,13 +319,12 @@ function ResourceBooking(props) { : null } - {/*{isOpen && (*/} - {/* handleModalMouseEnter()}*/} - {/* onMouseOut={() => handleModalMouseLeave()}/>*/} - {/*)}*/} + handleModalMouseEnter()} + onMouseOut={() => handleModalMouseLeave()}/> diff --git a/src/pages/basic/user/Login.js b/src/pages/basic/user/Login.js index 8533e4a..dcf7be1 100644 --- a/src/pages/basic/user/Login.js +++ b/src/pages/basic/user/Login.js @@ -6,7 +6,7 @@ import LogoImg from "assets/images/imgLogo.svg" import { UsersAxios } from 'api/AxiosApi'; import { setCookie } from 'utils/CookiesUtil' import { isLogin } from 'utils/IsLoginUtil'; -import { basicError } from 'utils/ErrorHandlerUtil'; +import {basicError, notLogInError} from 'utils/ErrorHandlerUtil'; const Container = styled.div` height: fit-content; @@ -90,7 +90,7 @@ function Login() { setCookie('Role', res.data.data.role) window.location.replace('/officeBooking') }).catch((error) => { - basicError(error) + notLogInError(error) }) } diff --git a/src/utils/ErrorHandlerUtil.js b/src/utils/ErrorHandlerUtil.js index 1ecf06c..b00533f 100644 --- a/src/utils/ErrorHandlerUtil.js +++ b/src/utils/ErrorHandlerUtil.js @@ -2,6 +2,31 @@ import { removeTokenAndNavigate, isLogin } from "utils/IsLoginUtil" // 일반 예외처리 export function basicError(error) { + try { + const errMsg = error.response.data.message; + if (errMsg !== undefined) { + // 토큰에러가 아닌 경우 일단 alert + if (!String(error.response.data.code).startsWith('T') && isLogin()) { + alert(errMsg) + } + + // 토큰에러인 경우 쿠키 삭제 (토큰 에러를 두번 alert 하지 않기 위해 토큰 존재 여부 판단) + if (String(error.response.data.code).startsWith('T')) { + alert(errMsg) + removeTokenAndNavigate() + } + } else { + console.log(error) + alert("서버 오류입니다.") + } + } catch (error) { + console.log(error) + alert("서버 오류입니다.") + } +} + +// 로그인하지 않은 상태일 때 예외처리 +export function notLogInError(error) { try { const errMsg = error.response.data.message; if (errMsg !== undefined) { @@ -17,8 +42,10 @@ export function basicError(error) { } } else { console.log(error) + alert("서버 오류입니다.") } } catch (error) { console.log(error) + alert("서버 오류입니다.") } } diff --git a/src/utils/ImageUtil.js b/src/utils/ImageUtil.js new file mode 100644 index 0000000..d327e6c --- /dev/null +++ b/src/utils/ImageUtil.js @@ -0,0 +1,5 @@ +export const getImgKey = (imgUrl) => { + if (imgUrl !== null) + return imgUrl.split('amazonaws.com/')[1] + else return null +} \ No newline at end of file