,
+ optimisticNextStatus: BookingStatusLabel,
+ confirmation?: boolean
+ ) => (
);
- if (loading) {
+ if (uiLoading) {
return (
@@ -50,39 +73,87 @@ export default function BookingActions({ status, calendarEventId }: Props) {
);
}
- const paBtns = (
- <>
- {status !== BookingStatusLabel.CHECKED_IN &&
- ActionButton('Check In', () =>
- serverFunctions.checkin(calendarEventId)
- )}
- {status !== BookingStatusLabel.NO_SHOW &&
- ActionButton('No Show', () => serverFunctions.noShow(calendarEventId))}
- >
- );
+ if (isUserView) {
+ if (status === BookingStatusLabel.CANCELED) {
+ return | | ;
+ }
+ return (
+
+
+ {ActionButton(
+ 'Cancel',
+ () => serverFunctions.cancel(calendarEventId),
+ BookingStatusLabel.CANCELED,
+ true
+ )}
+
+ |
+ );
+ }
- if (!isAdminPage) {
+ const paBtns = () => {
+ const checkInBtn = ActionButton(
+ 'Check In',
+ () => serverFunctions.checkin(calendarEventId),
+ BookingStatusLabel.CHECKED_IN
+ );
+ const noShowBtn = ActionButton(
+ 'No Show',
+ () => serverFunctions.noShow(calendarEventId),
+ BookingStatusLabel.NO_SHOW
+ );
+
+ if (status === BookingStatusLabel.APPROVED) {
+ return (
+ <>
+ {checkInBtn}
+ {noShowBtn}
+ >
+ );
+ } else if (status === BookingStatusLabel.CHECKED_IN) {
+ return noShowBtn;
+ } else if (status === BookingStatusLabel.NO_SHOW) {
+ return checkInBtn;
+ }
+ };
+
+ if (!isAdminView) {
return (
- {paBtns}
+ {paBtns()}
|
);
}
+ if (
+ status === BookingStatusLabel.CANCELED ||
+ status === BookingStatusLabel.REJECTED
+ ) {
+ return | ;
+ }
+
return (
-
+ |
{status === BookingStatusLabel.PRE_APPROVED &&
- ActionButton('2nd Approve', () =>
- serverFunctions.approveBooking(calendarEventId)
+ ActionButton(
+ '2nd Approve',
+ () => serverFunctions.approveBooking(calendarEventId),
+ BookingStatusLabel.APPROVED
)}
{status === BookingStatusLabel.REQUESTED &&
- ActionButton('1st Approve', () =>
- serverFunctions.approveBooking(calendarEventId)
+ ActionButton(
+ '1st Approve',
+ () => serverFunctions.approveBooking(calendarEventId),
+ BookingStatusLabel.PRE_APPROVED
)}
- {ActionButton('Reject', () => serverFunctions.reject(calendarEventId))}
- {ActionButton('Cancel', () => serverFunctions.cancel(calendarEventId))}
- {paBtns}
+ {ActionButton(
+ 'Reject',
+ () => serverFunctions.reject(calendarEventId),
+ BookingStatusLabel.REJECTED,
+ true
+ )}
+ {paBtns()}
|
);
diff --git a/media_commons_booking_app/src/client/routes/admin/components/BookingTableRow.tsx b/media_commons_booking_app/src/client/routes/admin/components/BookingTableRow.tsx
new file mode 100644
index 00000000..31611e0d
--- /dev/null
+++ b/media_commons_booking_app/src/client/routes/admin/components/BookingTableRow.tsx
@@ -0,0 +1,101 @@
+import { Booking, BookingStatusLabel } from '../../../../types';
+import React, { useContext, useState } from 'react';
+
+import BookingActions from './BookingActions';
+import { DatabaseContext } from '../../components/Provider';
+import { formatDate } from '../../../utils/date';
+import getBookingStatus from '../hooks/getBookingStatus';
+
+interface Props {
+ booking: Booking;
+ isAdminView: boolean;
+ isUserView: boolean;
+}
+
+export default function BookingTableRow({
+ booking,
+ isAdminView,
+ isUserView,
+}: Props) {
+ const { bookingStatuses } = useContext(DatabaseContext);
+ const status = getBookingStatus(booking, bookingStatuses);
+
+ const [optimisticStatus, setOptimisticStatus] =
+ useState();
+
+ return (
+
+
+ {optimisticStatus ?? status} |
+ {booking.roomId} |
+
+
+
+
+ {booking.firstName} {booking.lastName}
+
+ {booking.email}
+
+ {booking.phoneNumber}
+
+
+
+ |
+
+
+ {formatDate(booking.startDate)}
+
+ |
+
+
+ {formatDate(booking.endDate)}
+
+ |
+ {booking.secondaryName} |
+ {isAdminView && {booking.nNumber} | }
+ {booking.netId} |
+ {booking.department} |
+ {booking.role} |
+
+ {booking.sponsorFirstName} {booking.sponsorLastName}
+ |
+ {booking.sponsorEmail} |
+ {booking.title} |
+ {booking.description} |
+ {booking.expectedAttendance} |
+ {booking.attendeeAffiliation} |
+
+ {booking.roomSetup}
+ {booking.setupDetails && (
+ <>
+
+ Details
+
+ {booking.setupDetails}
+ >
+ )}
+ |
+ {booking.chartFieldForRoomSetup} |
+
+ {booking.mediaServices}
+ {booking.mediaServicesDetails && (
+ <>
+
+ Details
+
+ {booking.mediaServicesDetails}
+ >
+ )}
+ |
+ {booking.catering} |
+ {booking.cateringService} |
+ {booking.chartFieldForCatering} |
+ {booking.hireSecurity} |
+ {booking.chartFieldForSecurity} |
+
+ );
+}
diff --git a/media_commons_booking_app/src/client/routes/admin/components/Bookings.tsx b/media_commons_booking_app/src/client/routes/admin/components/Bookings.tsx
index c3c90347..f5806c05 100644
--- a/media_commons_booking_app/src/client/routes/admin/components/Bookings.tsx
+++ b/media_commons_booking_app/src/client/routes/admin/components/Bookings.tsx
@@ -1,12 +1,13 @@
-import React, { useContext, useMemo } from 'react';
+import React, { useContext, useEffect, useMemo } from 'react';
-import BookingActions from './BookingActions';
+import { BookingStatusLabel } from '../../../../types';
+import BookingTableRow from './BookingTableRow';
import { DatabaseContext } from '../../components/Provider';
-import { formatDate } from '../../../utils/date';
import getBookingStatus from '../hooks/getBookingStatus';
interface BookingsProps {
- showNnumber: boolean;
+ isAdminView?: boolean;
+ isPaView?: boolean;
isUserView?: boolean;
}
@@ -17,14 +18,35 @@ const TableHeader = (text: string) => (
);
export const Bookings: React.FC = ({
- showNnumber = false,
+ isAdminView = false,
+ isPaView = false,
isUserView = false,
}) => {
- const { bookings, bookingStatuses, userEmail } = useContext(DatabaseContext);
+ const {
+ bookings,
+ bookingStatuses,
+ userEmail,
+ reloadBookings,
+ reloadBookingStatuses,
+ } = useContext(DatabaseContext);
+
+ useEffect(() => {
+ reloadBookingStatuses();
+ reloadBookings();
+ }, []);
const filteredBookings = useMemo(() => {
+ const paViewStatuses = [
+ BookingStatusLabel.APPROVED,
+ BookingStatusLabel.CHECKED_IN,
+ BookingStatusLabel.NO_SHOW,
+ ];
if (isUserView)
return bookings.filter((booking) => booking.email === userEmail);
+ if (isPaView)
+ return bookings.filter((booking) =>
+ paViewStatuses.includes(getBookingStatus(booking, bookingStatuses))
+ );
return bookings;
}, [isUserView, bookings]);
@@ -34,16 +56,15 @@ export const Bookings: React.FC = ({
- {!isUserView && TableHeader('Action')}
+ {TableHeader('Action')}
{TableHeader('Status')}
{TableHeader('Room ID')}
{TableHeader('Contact')}
{TableHeader('Booking Start')}
{TableHeader('Booking End')}
{TableHeader('Secondary Name')}
- {showNnumber && TableHeader('N Number')}
+ {isAdminView && TableHeader('N Number')}
{TableHeader('Net ID')}
- {/* {TableHeader('Phone Number')} */}
{TableHeader('Department')}
{TableHeader('Role')}
{TableHeader('Sponsor Name')}
@@ -63,105 +84,12 @@ export const Bookings: React.FC = ({
- {filteredBookings.map((booking, index) => {
- const status = getBookingStatus(booking, bookingStatuses);
- return (
-
- {!isUserView && (
-
- )}
- {status} |
- {booking.roomId} |
-
-
-
-
- {booking.firstName} {booking.lastName}
-
-
- {booking.email}
-
-
- {booking.phoneNumber}
-
-
-
- |
-
-
- {formatDate(booking.startDate)}
-
- |
-
-
- {formatDate(booking.endDate)}
-
- |
- {booking.secondaryName} |
- {showNnumber && (
- {booking.nNumber} |
- )}
- {booking.netId} |
- {/* {booking.phoneNumber} | */}
- {booking.department} |
- {booking.role} |
-
- {booking.sponsorFirstName} {booking.sponsorLastName}
- |
- {booking.sponsorEmail} |
- {booking.title} |
-
- {booking.description}
- |
-
- {booking.expectedAttendance}
- |
-
- {booking.attendeeAffiliation}
- |
-
- {booking.roomSetup}
- {booking.setupDetails && (
- <>
-
- Details
-
- {booking.setupDetails}
- >
- )}
- |
-
- {booking.chartFieldForRoomSetup}
- |
-
- {booking.mediaServices}
- {booking.mediaServicesDetails && (
- <>
-
- Details
-
- {booking.mediaServicesDetails}
- >
- )}
- |
- {booking.catering} |
- {booking.cateringService} |
-
- {booking.chartFieldForCatering}
- |
- {booking.hireSecurity} |
-
- {booking.chartFieldForSecurity}
- |
-
- );
- })}
+ {filteredBookings.map((booking, index) => (
+
+ ))}
diff --git a/media_commons_booking_app/src/client/routes/admin/hooks/getBookingStatus.ts b/media_commons_booking_app/src/client/routes/admin/hooks/getBookingStatus.ts
index fe7fb9e6..a004686b 100644
--- a/media_commons_booking_app/src/client/routes/admin/hooks/getBookingStatus.ts
+++ b/media_commons_booking_app/src/client/routes/admin/hooks/getBookingStatus.ts
@@ -8,14 +8,38 @@ export default function getBookingStatus(
const bookingStatusMatch = bookingStatuses.filter(
(row) => row.calendarEventId === booking.calendarEventId
)[0];
+
if (bookingStatusMatch === undefined) return BookingStatusLabel.UNKNOWN;
- if (bookingStatusMatch.checkedInAt !== '') {
- return BookingStatusLabel.CHECKED_IN;
- } else if (bookingStatusMatch.noShowedAt !== '') {
- return BookingStatusLabel.NO_SHOW;
- } else if (bookingStatusMatch.canceledAt !== '') {
- return BookingStatusLabel.CANCELED;
- } else if (bookingStatusMatch.rejectedAt !== '') {
+
+ const timeStringtoDate = (time: string) =>
+ time.length > 0 ? new Date(time) : new Date(0);
+
+ const checkedInTimestamp = timeStringtoDate(bookingStatusMatch.checkedInAt);
+ const noShowTimestamp = timeStringtoDate(bookingStatusMatch.noShowedAt);
+ const canceledTimestamp = timeStringtoDate(bookingStatusMatch.canceledAt);
+
+ // if any of checkedInAt, noShowedAt, canceledAt have a date, return the most recent
+ if (
+ checkedInTimestamp.getTime() !== 0 ||
+ noShowTimestamp.getTime() !== 0 ||
+ canceledTimestamp.getTime() !== 0
+ ) {
+ let mostRecentTimestamp: Date = checkedInTimestamp;
+ let label = BookingStatusLabel.CHECKED_IN;
+
+ if (noShowTimestamp > mostRecentTimestamp) {
+ mostRecentTimestamp = noShowTimestamp;
+ label = BookingStatusLabel.NO_SHOW;
+ }
+
+ if (canceledTimestamp > mostRecentTimestamp) {
+ mostRecentTimestamp = canceledTimestamp;
+ label = BookingStatusLabel.CANCELED;
+ }
+ return label;
+ }
+
+ if (bookingStatusMatch.rejectedAt !== '') {
return BookingStatusLabel.REJECTED;
} else if (bookingStatusMatch.secondApprovedAt !== '') {
return BookingStatusLabel.APPROVED;
diff --git a/media_commons_booking_app/src/client/routes/booking/components/Calendars.tsx b/media_commons_booking_app/src/client/routes/booking/components/Calendars.tsx
index db872a36..e2029ea1 100644
--- a/media_commons_booking_app/src/client/routes/booking/components/Calendars.tsx
+++ b/media_commons_booking_app/src/client/routes/booking/components/Calendars.tsx
@@ -5,6 +5,7 @@ import { DateSelectArg } from '@fullcalendar/core';
import { RoomCalendar } from './RoomCalendar';
import { RoomSetting } from '../../../../types';
import { formatDate } from '../../../utils/date';
+import { HIDING_STATUS } from '../../../../policy';
type CalendarProps = {
allRooms: RoomSetting[];
@@ -29,6 +30,9 @@ export const Calendars = ({
const allEvents = calendarApi.getEvents();
return allEvents.some((event) => {
if (event.title.includes(TITLE_TAG)) return false;
+ if (HIDING_STATUS.some((status) => event.title.includes(status)))
+ return false;
+
return (
(event.start >= info.start && event.start < info.end) ||
(event.end > info.start && event.end <= info.end) ||
diff --git a/media_commons_booking_app/src/client/routes/booking/components/FormInput.tsx b/media_commons_booking_app/src/client/routes/booking/components/FormInput.tsx
index 47febc80..a6aa8892 100644
--- a/media_commons_booking_app/src/client/routes/booking/components/FormInput.tsx
+++ b/media_commons_booking_app/src/client/routes/booking/components/FormInput.tsx
@@ -518,14 +518,18 @@ const FormInput = ({ handleParentSubmit }) => {
)}
-
+ {roomNumber.some((room) =>
+ [103, 220, 221, 222, 223, 224, 230, 233, 260].includes(Number(room))
+ ) && (
+
+ )}
{roomNumber.includes('103') && (
)}
- {roomNumber.includes('202') ||
- (roomNumber.includes('1201') && (
-
- ))}
+ {roomNumber.some((room) => [202, 1201].includes(Number(room))) && (
+
+ )}
{watch('mediaServices') !== undefined &&
diff --git a/media_commons_booking_app/src/client/routes/booking/components/RoomCalendar.tsx b/media_commons_booking_app/src/client/routes/booking/components/RoomCalendar.tsx
index 35a57f6f..f8d69851 100644
--- a/media_commons_booking_app/src/client/routes/booking/components/RoomCalendar.tsx
+++ b/media_commons_booking_app/src/client/routes/booking/components/RoomCalendar.tsx
@@ -12,6 +12,7 @@ import googleCalendarPlugin from '@fullcalendar/google-calendar';
import interactionPlugin from '@fullcalendar/interaction'; // for selectable
import { serverFunctions } from '../../../utils/serverFunctions';
import timeGridPlugin from '@fullcalendar/timegrid'; // a plugin!
+import { HIDING_STATUS } from '../../../../policy';
const TITLE_TAG = '[Click to Delete]';
@@ -47,9 +48,49 @@ export const RoomCalendar = ({
);
}, []);
+ function renderEventContent(eventInfo) {
+ const match = eventInfo.event.title.match(/\[(.*?)\]/);
+ const title = match ? match[1] : eventInfo.event.title;
+
+ const startTime = new Intl.DateTimeFormat('en-US', {
+ hour: '2-digit',
+ minute: '2-digit',
+ }).format(eventInfo.event.start);
+ const endTime = new Intl.DateTimeFormat('en-US', {
+ hour: '2-digit',
+ minute: '2-digit',
+ }).format(eventInfo.event.end);
+
+ let backgroundColor = '';
+ // Change the background color of the event depending on its title
+ if (eventInfo.event.title.includes(BookingStatusLabel.REQUESTED)) {
+ backgroundColor = '#d60000';
+ } else if (
+ eventInfo.event.title.includes(BookingStatusLabel.PRE_APPROVED)
+ ) {
+ backgroundColor = '#f6c026';
+ } else if (eventInfo.event.title.includes(BookingStatusLabel.APPROVED)) {
+ backgroundColor = '#33b679';
+ }
+ return (
+
+ {title}
+
+ );
+ }
+
const fetchCalendarEvents = async (calendarId) => {
serverFunctions.getCalendarEvents(calendarId).then((rows) => {
- setEvents(rows);
+ const filteredEvents = rows.filter((row) => {
+ return !HIDING_STATUS.some((status) => row.title.includes(status));
+ });
+ setEvents(filteredEvents);
});
};
@@ -142,32 +183,7 @@ export const RoomCalendar = ({
right: '',
}}
themeSystem="bootstrap5"
- eventDidMount={function (info) {
- // Change the title status only
- const match = info.event.title.match(/\[(.*?)\]/);
- if (match) {
- let el = info.el.querySelector('.fc-event-title');
- if (el != null) {
- el.textContent = match[1];
- }
- }
- // Change the background color of the event depending on its title
- if (info.event.title.includes(BookingStatusLabel.REQUESTED)) {
- info.el.style.backgroundColor = '#d60000';
- } else if (
- info.event.title.includes(BookingStatusLabel.PRE_APPROVED)
- ) {
- info.el.style.backgroundColor = '#f6c026';
- } else if (info.event.title.includes(BookingStatusLabel.APPROVED)) {
- info.el.style.backgroundColor = '#33b679';
- } else if (info.event.title.includes(BookingStatusLabel.REJECTED)) {
- info.el.style.display = 'none';
- } else if (info.event.title.includes(BookingStatusLabel.CANCELED)) {
- info.el.style.display = 'none';
- } else if (info.event.title.includes(BookingStatusLabel.NO_SHOW)) {
- info.el.style.display = 'none';
- }
- }}
+ eventContent={renderEventContent}
editable={true}
initialView={selectedRooms.length > 1 ? 'timeGridDay' : 'timeGridDay'}
navLinks={true}
diff --git a/media_commons_booking_app/src/client/routes/components/AddEmail.tsx b/media_commons_booking_app/src/client/routes/components/AddEmail.tsx
index c8e8697e..03e08f99 100644
--- a/media_commons_booking_app/src/client/routes/components/AddEmail.tsx
+++ b/media_commons_booking_app/src/client/routes/components/AddEmail.tsx
@@ -19,7 +19,7 @@ export default function AddEmail({
userList,
userListRefresh,
}: Props) {
- const [emailToAdd, setEmailToAdd] = useState();
+ const [emailToAdd, setEmailToAdd] = useState('');
const [loading, setLoading] = useState(false);
const userEmails = useMemo(
@@ -28,7 +28,7 @@ export default function AddEmail({
);
const addUser = async () => {
- if (!emailToAdd) return;
+ if (!emailToAdd || emailToAdd.length === 0) return;
if (userEmails.includes(emailToAdd)) {
alert('This user is already registered');
diff --git a/media_commons_booking_app/src/client/routes/components/EmailListTable.tsx b/media_commons_booking_app/src/client/routes/components/EmailListTable.tsx
index 12e5d5a2..8d8fa440 100644
--- a/media_commons_booking_app/src/client/routes/components/EmailListTable.tsx
+++ b/media_commons_booking_app/src/client/routes/components/EmailListTable.tsx
@@ -1,6 +1,6 @@
-import React, { useMemo, useState } from 'react';
+import React, { useMemo } from 'react';
-import Loading from '../../utils/Loading';
+import EmailListTableRow from './EmailListTableRow';
import { TableNames } from '../../../policy';
// This is a wrapper for google.script.run that lets us use promises.
import { serverFunctions } from '../../utils/serverFunctions';
@@ -20,8 +20,6 @@ export default function EmailListTable(props: Props) {
const refresh = props.userListRefresh;
const columnFormatters = props.columnFormatters || {};
- const [loading, setLoading] = useState(false);
-
const columnNames = useMemo(() => {
if (props.userList.length === 0) {
return [];
@@ -29,23 +27,6 @@ export default function EmailListTable(props: Props) {
return Object.keys(props.userList[0]) as Array as string[];
}, [props.userList]);
- const onRemove = async (user: T) => {
- setLoading(true);
- try {
- await serverFunctions.removeFromListByEmail(props.tableName, user.email);
- await refresh();
- } catch (ex) {
- console.error(ex);
- alert('Failed to remove user');
- } finally {
- setLoading(false);
- }
- };
-
- if (loading) {
- return ;
- }
-
if (props.userList.length === 0) {
return No results
;
}
@@ -68,31 +49,18 @@ export default function EmailListTable(props: Props) {
- {props.userList.map((user, index: number) => {
- return (
-
- {/* all column values */}
- {columnNames.map((columnName, idx) => (
-
- {columnFormatters[columnName]
- ? columnFormatters[columnName](user[columnName])
- : user[columnName]}
- |
- ))}
-
-
- |
-
- );
- })}
+ {props.userList.map((user, index: number) => (
+
+ serverFunctions.removeFromListByEmail(
+ props.tableName,
+ user.email
+ )
+ }
+ {...{ columnNames, columnFormatters, index, user, refresh }}
+ />
+ ))}
diff --git a/media_commons_booking_app/src/client/routes/components/EmailListTableRow.tsx b/media_commons_booking_app/src/client/routes/components/EmailListTableRow.tsx
new file mode 100644
index 00000000..f2368ec1
--- /dev/null
+++ b/media_commons_booking_app/src/client/routes/components/EmailListTableRow.tsx
@@ -0,0 +1,88 @@
+import React, { useMemo, useState } from 'react';
+
+import Loading from '../../utils/Loading';
+import { TableNames } from '../../../policy';
+// This is a wrapper for google.script.run that lets us use promises.
+import { serverFunctions } from '../../utils/serverFunctions';
+
+interface EmailField {
+ email: string;
+}
+
+interface Props {
+ columnFormatters?: { [key: string]: (value: string) => string };
+ columnNames: string[];
+ index: number;
+ refresh: () => Promise;
+ removeUser: () => Promise;
+ user: T;
+}
+
+export default function EmailListTableRow(
+ props: Props
+) {
+ const { columnFormatters, columnNames, index, refresh, removeUser, user } =
+ props;
+ const [uiLoading, setUiLoading] = useState(false);
+ const [isRemoved, setIsRemoved] = useState(false);
+
+ const onError = () => {
+ alert('Failed to remove user: ' + user.email);
+ };
+
+ /**
+ * Google Sheets API writes are slow.
+ * To avoid UI lag, assume write will succeed and optimistically remove UI element before response completes.
+ * If write fails, alert the user and restore UI.
+ * Only devs should see this error behavior unless something is very broken
+ */
+ const onRemove = async () => {
+ setUiLoading(true);
+ setIsRemoved(true); // optimistically hide component
+ try {
+ removeUser()
+ .catch(() => {
+ onError();
+ setIsRemoved(false);
+ })
+ .finally(refresh);
+ } catch (ex) {
+ console.error(ex);
+ onError();
+ } finally {
+ setUiLoading(false);
+ }
+ };
+
+ if (uiLoading) {
+ return ;
+ }
+
+ if (isRemoved) {
+ return null;
+ }
+
+ return (
+
+ {/* all column values */}
+ {columnNames.map((columnName, idx) => (
+
+ {columnFormatters[columnName]
+ ? columnFormatters[columnName](user[columnName])
+ : user[columnName]}
+ |
+ ))}
+
+
+ |
+
+ );
+}
diff --git a/media_commons_booking_app/src/client/routes/components/Provider.tsx b/media_commons_booking_app/src/client/routes/components/Provider.tsx
index 62e011d4..363d8346 100644
--- a/media_commons_booking_app/src/client/routes/components/Provider.tsx
+++ b/media_commons_booking_app/src/client/routes/components/Provider.tsx
@@ -94,6 +94,13 @@ export const DatabaseProvider = ({ children }) => {
fetchLiaisonUsers();
fetchRoomSettings();
});
+
+ // refresh booking data every 10s;
+ setInterval(() => {
+ console.log('UPDATING');
+ fetchBookings();
+ fetchBookingStatuses();
+ }, 10000);
}, []);
const fetchActiveUserEmail = () => {
diff --git a/media_commons_booking_app/src/client/routes/myBookings/myBookingsPage.tsx b/media_commons_booking_app/src/client/routes/myBookings/myBookingsPage.tsx
index 5c2d7962..d1e1346d 100644
--- a/media_commons_booking_app/src/client/routes/myBookings/myBookingsPage.tsx
+++ b/media_commons_booking_app/src/client/routes/myBookings/myBookingsPage.tsx
@@ -2,5 +2,5 @@ import { Bookings } from '../admin/components/Bookings';
import React from 'react';
export default function MyBookingsPage() {
- return ;
+ return ;
}
diff --git a/media_commons_booking_app/src/client/routes/pa/PAPage.tsx b/media_commons_booking_app/src/client/routes/pa/PAPage.tsx
index 32c83d07..d47eb072 100644
--- a/media_commons_booking_app/src/client/routes/pa/PAPage.tsx
+++ b/media_commons_booking_app/src/client/routes/pa/PAPage.tsx
@@ -59,7 +59,7 @@ const PAPage = () => {
{tab === 'safety_training' && }
- {tab === 'bookings' && }
+ {tab === 'bookings' && }
)}
diff --git a/media_commons_booking_app/src/policy.ts b/media_commons_booking_app/src/policy.ts
index e00c26e3..044575f1 100644
--- a/media_commons_booking_app/src/policy.ts
+++ b/media_commons_booking_app/src/policy.ts
@@ -1,6 +1,6 @@
/********** GOOGLE SHEETS ************/
-import { DevBranch } from './types';
+import { BookingStatusLabel, DevBranch } from './types';
/** ACTIVE master Google Sheet */
export const ACTIVE_SHEET_ID = '1MnWbn6bvNyMiawddtYYx0tRW4NMgvugl0I8zBO3sy68';
@@ -79,3 +79,9 @@ export const SAFETY_TRAINING_REQUIRED_ROOM = [
];
export const INSTANT_APPROVAL_ROOMS = ['221', '222', '223', '224', '233'];
+
+export const HIDING_STATUS = [
+ BookingStatusLabel.NO_SHOW,
+ BookingStatusLabel.CANCELED,
+ BookingStatusLabel.REJECTED,
+];
diff --git a/media_commons_booking_app/src/server/emails.ts b/media_commons_booking_app/src/server/emails.ts
index af8169b5..31d37d4f 100644
--- a/media_commons_booking_app/src/server/emails.ts
+++ b/media_commons_booking_app/src/server/emails.ts
@@ -7,7 +7,10 @@ export const sendTextEmail = (
body: string
) => {
const subj = `${status}: Media Commons request for \"${eventTitle}\"`;
- GmailApp.sendEmail(targetEmail, subj, body);
+ const options = {
+ replyTo: 'mediacommons.reservations@nyu.edu',
+ };
+ GmailApp.sendEmail(targetEmail, subj, body, options);
};
const getEmailBranchTag = () => {
@@ -29,7 +32,6 @@ export const sendHTMLEmail = (
eventTitle: string,
body
) => {
- console.log('contents', contents);
const subj = `${getEmailBranchTag()}${status}: Media Commons request for \"${eventTitle}\"`;
const htmlTemplate = HtmlService.createTemplateFromFile(templateName);
for (const key in contents) {
@@ -38,6 +40,7 @@ export const sendHTMLEmail = (
const htmlBody = htmlTemplate.evaluate().getContent();
const options = {
htmlBody,
+ replyTo: 'mediacommons.reservations@nyu.edu',
};
GmailApp.sendEmail(targetEmail, subj, body, options);
};