diff --git a/Dockerfile b/Dockerfile
index 1a50c20..76b0ebf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Buile Step
-FROM node:18.18-alpine AS builder
+FROM node:20.9-alpine AS builder
WORKDIR /usr/src/app
@@ -21,7 +21,7 @@ RUN npm run build
RUN npm prune --production
# Run Step
-FROM node:18.18-alpine AS runner
+FROM node:20.9-alpine AS runner
WORKDIR /usr/src/app
diff --git a/assets/owner.options.js b/assets/owner.options.js
index aecae60..7e503fc 100644
--- a/assets/owner.options.js
+++ b/assets/owner.options.js
@@ -1,7 +1,7 @@
export const OwnerOptions = [
- { key: "chonghak", text: "총학생회", value: "chonghak" },
{ key: "dongyeon", text: "동아리연합회", value: "dongyeon" },
{ key: "dormUnion", text: "생활관자치회", value: "dormUnion" },
+ { key: "chonghak", text: "총학생회", value: "chonghak" },
{ key: "saengna", text: "생각나눔", value: "saengna" },
{ key: "others", text: "그 외", value: "others" },
];
diff --git a/components/equipment/equipment.reservation.confirm.modal.jsx b/components/equipment/equipment.reservation.confirm.modal.jsx
index 1e6519d..841da17 100644
--- a/components/equipment/equipment.reservation.confirm.modal.jsx
+++ b/components/equipment/equipment.reservation.confirm.modal.jsx
@@ -18,9 +18,9 @@ const EquipmentReservationConfirmModal = (props) => {
{}, {withCredentials: true})
setOpen(false)
window.location.reload()
- } catch (e) {
- alert('예약 승인/거절에 실패했습니다.')
- console.log(e)
+ } catch (err) {
+ const errMsg = err.response.data.message;
+ alert(`예약 승인/거절에 실패했습니다.\n${errMsg}`);
}
}
diff --git a/components/equipment/equipment.reservation.table.jsx b/components/equipment/equipment.reservation.table.jsx
index 4740e81..ec7f254 100644
--- a/components/equipment/equipment.reservation.table.jsx
+++ b/components/equipment/equipment.reservation.table.jsx
@@ -4,72 +4,67 @@ import moment from 'moment'
import EquipmentReservationConfirmModal
from './equipment.reservation.confirm.modal'
-const EquipmentReservationTable = (props) => {
- const reservations = props.reservations
- const start_idx = props.startIdx
-
+const EquipmentReservationTable = ({ reservations, startIdx }) => {
return (
- <>
-
-
-
- idx.
- 장비 목록
- 사용자
- 예약 제목
- 예약 기간
- 상태
-
-
-
- {
- reservations.map((reservation, idx) =>
-
- {start_idx + idx + 1}
-
- {
- reservation.equipments.map(equipment => {
- return (
-
- )
- })
- }
-
- {reservation.booker.name}
- {reservation.title}
-
-
- {moment(reservation.date, 'YYYYMMDD').
- format('YYYY년 MM월 DD일')}
-
- {moment(reservation.start_time, 'HHmm').
- format('HH:mm')}
- ~
- {moment(reservation.end_time, 'HHmm').
- format('HH:mm')}
-
-
- {reservation.status}
-
- }
- />,
- )
- }
-
-
- >
+
+
+
+ idx.
+ 장비 목록
+ 사용자
+ 예약 제목
+ 예약 기간
+ 상태
+
+
+
+ {
+ reservations.map((reservation, idx) =>
+
+ {startIdx + idx + 1}
+
+ {
+ reservation.equipments.map(equipment => {
+ return (
+
+ )
+ })
+ }
+
+ {reservation.booker.name}
+ {reservation.title}
+
+
+ {moment(reservation.date, 'YYYYMMDD').
+ format('YYYY년 MM월 DD일')}
+
+ {moment(reservation.start_time, 'HHmm').
+ format('HH:mm')}
+ ~
+ {moment(reservation.end_time, 'HHmm').
+ format('HH:mm')}
+
+
+ {reservation.status}
+
+ }
+ />,
+ )
+ }
+
+
)
}
diff --git a/components/equipment/equipment.reservation.wait.table.jsx b/components/equipment/equipment.reservation.wait.table.jsx
new file mode 100644
index 0000000..90df58b
--- /dev/null
+++ b/components/equipment/equipment.reservation.wait.table.jsx
@@ -0,0 +1,82 @@
+import React from 'react'
+import { Label, Table } from 'semantic-ui-react'
+import moment from 'moment'
+import EquipmentReservationConfirmModal
+ from './equipment.reservation.confirm.modal'
+
+const EquipmentReservationWaitTable = ({ reservations, startIdx }) => {
+ return (
+
+
+
+ idx.
+ 장비 목록
+ 사용자
+ 예약 제목
+ 예약 기간
+ 상태
+
+
+
+ {
+ reservations.map((reservation, idx) => {
+
+ const start_datetime = moment(
+ `${reservation.date} ${reservation.start_time}`, 'YYYYMMDD HHmm')
+ const end_datetime = moment(
+ `${reservation.date} ${reservation.end_time}`, 'YYYYMMDD HHmm')
+
+ const isOutdated = moment() > end_datetime;
+ const isNow = start_datetime <= moment() && moment() <= end_datetime;
+
+ return (
+
+ {startIdx + idx + 1}
+
+ {
+ reservation.equipments.map(equipment => {
+ return (
+
+ )
+ })
+ }
+
+ {reservation.booker.name}
+ {reservation.title}
+
+
+ {moment(reservation.date, 'YYYYMMDD').
+ format('YYYY년 MM월 DD일')}
+
+ {moment(reservation.start_time, 'HHmm').
+ format('HH:mm')}
+ ~
+ {moment(reservation.end_time, 'HHmm').
+ format('HH:mm')}
+
+
+ {reservation.status}
+
+ }
+ />
+ )
+ })
+ }
+
+
+ )
+}
+
+export default EquipmentReservationWaitTable
\ No newline at end of file
diff --git a/components/place/place.reservation.confirm.modal.jsx b/components/place/place.reservation.confirm.modal.jsx
index ccbc248..cc36002 100644
--- a/components/place/place.reservation.confirm.modal.jsx
+++ b/components/place/place.reservation.confirm.modal.jsx
@@ -16,9 +16,9 @@ const PlaceReservationConfirmModal = ({trigger, reservation}) => {
{}, {withCredentials: true})
setOpen(false)
window.location.reload()
- } catch (e) {
- alert('예약 승인/거절에 실패했습니다.')
- console.log(e)
+ } catch (err) {
+ const errMsg = err.response.data.message;
+ alert(`예약 승인/거절에 실패했습니다.\n${errMsg}`);
}
}
diff --git a/components/place/place.reservation.wait.table.jsx b/components/place/place.reservation.wait.table.jsx
index b7a4377..2b10561 100644
--- a/components/place/place.reservation.wait.table.jsx
+++ b/components/place/place.reservation.wait.table.jsx
@@ -68,12 +68,16 @@ const PlaceReservationWaitTable = ({reservations}) => {
{
reservations.map((reservation, idx) => {
- const reservation_end_datetime = moment(
+ const start_datetime = moment(
+ `${reservation.date} ${reservation.start_time}`, 'YYYYMMDD HHmm')
+ const end_datetime = moment(
`${reservation.date} ${reservation.end_time}`, 'YYYYMMDD HHmm')
- const isOutdated = moment() > reservation_end_datetime
+
+ const isOutdated = moment() > end_datetime;
+ const isNow = start_datetime <= moment() && moment() <= end_datetime;
return (
-
+
{idx + 1}
{reservation.place.name}
{reservation.booker.name}
diff --git a/components/reservation/opening_hours.list.jsx b/components/reservation/opening_hours.list.jsx
new file mode 100644
index 0000000..75afafd
--- /dev/null
+++ b/components/reservation/opening_hours.list.jsx
@@ -0,0 +1,52 @@
+import { KoreanWeekday } from '@/utils/opening_hours'
+
+const OpeningHoursList = ({ openingHours }) => {
+ let isBriefCase;
+ if (openingHours['Everyday']) {
+ isBriefCase = false;
+ } else {
+ let cnt = 0;
+ for(const day of Object.keys(openingHours)) {
+ if(openingHours[day] === '00:00-24:00') {
+ cnt += 1;
+ }
+ }
+ isBriefCase = (cnt > 5);
+ }
+
+ return (
+
+ {
+ Object.keys(openingHours).map(day => {
+ if(isBriefCase && openingHours[day] === '00:00-24:00') {
+ return;
+ }
+
+ return (
+
+
+ {KoreanWeekday[day]}:
+
+
+ {openingHours[day]}
+
+
+ )
+ },
+ )
+ }
+ {
+ isBriefCase ? (
+
+
그외:
+
+ 00:00-24:00
+
+
+ ) : null
+ }
+
+ )
+}
+
+export default OpeningHoursList
diff --git a/components/reservation/reservation.datetime.picker.jsx b/components/reservation/reservation.datetime.picker.jsx
new file mode 100644
index 0000000..88d01e1
--- /dev/null
+++ b/components/reservation/reservation.datetime.picker.jsx
@@ -0,0 +1,82 @@
+import moment from 'moment'
+import React from 'react'
+import DatePicker from 'react-datepicker'
+import 'react-datepicker/dist/react-datepicker.css'
+import { roundUpByDuration } from '@/utils/time-date'
+
+const ReservationDatetimePicker = ({
+ date,
+ startTime,
+ endTime,
+ setDate,
+ setStartTime,
+ setEndTime,
+}) => {
+ const now = roundUpByDuration(moment(), 30);
+ const nowNext30Min = moment(now).add(30, 'minute');
+
+ return (
+ <>
+
+
+ e.preventDefault()}
+ dateFormat={'yyyy-MM-dd'}
+ minDate={now.toDate()}
+ // maxDate={now.add(30, 'day').toDate()}
+ selected={date.toDate()}
+ onChange={(date) => {
+ const targetDate = moment(date).format('YYYY-MM-DD')
+ const nowDate = now.format('YYYY-MM-DD');
+ if (targetDate === nowDate) {
+ setDate(now);
+ setStartTime(now);
+ setEndTime(nowNext30Min);
+ } else {
+ setDate(moment(targetDate + 'T00:00'));
+ setStartTime(moment(targetDate + 'T00:00'));
+ setEndTime(moment(targetDate + 'T00:30'));
+ }
+ }}
+ />
+
+
+
+
+ e.preventDefault()}
+ dateFormat={'hh:mm aa'}
+ selected={startTime.toDate()}
+ minTime={date.toDate()}
+ maxTime={moment(date.format('YYYY-MM-DD') + 'T23:59').toDate()}
+ onChange={(startTime) => {
+ const newStartTime = moment(startTime);
+ const newStartTimeNext30Min = moment(newStartTime).add(30, 'minute');
+ setStartTime(newStartTime);
+ setEndTime(newStartTimeNext30Min);
+ }}/>
+
+
+
+
+ e.preventDefault()}
+ dateFormat={'hh:mm aa'}
+ selected={endTime.toDate()}
+ minTime={
+ moment(startTime).add(30, 'minute').toDate()
+ }
+ maxTime={
+ (endTime.format('HHmm') === '0000') ?
+ moment(date.format('YYYY-MM-DD') + 'T00:00').toDate() // edge-case
+ : moment(date.format('YYYY-MM-DD') + 'T23:59').toDate()
+ }
+ onChange={(endTime) => {setEndTime(moment(endTime))}}/>
+
+ >
+ )
+}
+
+export default ReservationDatetimePicker;
\ No newline at end of file
diff --git a/components/reservation/reservation.menubar.jsx b/components/reservation/reservation.menubar.jsx
index bec8ea5..bdd48b4 100644
--- a/components/reservation/reservation.menubar.jsx
+++ b/components/reservation/reservation.menubar.jsx
@@ -6,6 +6,11 @@ export default class ReservationMenubar extends Component {
render() {
return (