Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Rooms page #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/routes/rooms/category-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ router.get('/:category', async (req, res) => {
}
});

module.exports = router;
module.exports = router;
3,271 changes: 3,271 additions & 0 deletions backend/yarn.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Dashboard from "./pages/Dashboard";
import BookingsPage from "./pages/admin/BookingsPage";
import UsersPage from "./pages/admin/UsersPage";
import SettingsPage from "./pages/admin/SettingsPage";
import RoomsPage from "./pages/admin/RoomsPage";
import EventsPage from "./pages/EventsPage";
import VenueBookingPage from "./pages/VenueBookingPage";
import ProfilePage from "./pages/ProfilePage";
Expand Down Expand Up @@ -59,9 +60,9 @@ class App extends React.Component {
{token !== null && role === "Admin" && (
<Route path="/admin/settings" exact component={SettingsPage} />
)}
{/* {token !== null && role === "Admin" && (
{token !== null && role === "Admin" && (
<Route path="/admin/rooms" exact component={RoomsPage} />
)} */}
)}
{token !== null && (
<Route path="/profile" exact component={ProfilePage} />
)}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/DevelopmentView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// toggle this to switch between production and development
export const DEVELOPMENT_VIEW = false;
export const DEVELOPMENT_VIEW = true;
// toggle this to enable/disable console logging
export const CONSOLE_LOGGING = false;
export const CONSOLE_LOGGING = true;
14 changes: 7 additions & 7 deletions frontend/src/components/NavigationBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ class NavigationBar extends React.Component {
as={Link}
to="/admin/settings"
onClick={this.handleAdminItemClick}
/>,
<Dropdown.Item
name="rooms"
text="Rooms"
as={Link}
to="/admin/rooms"
onClick={this.handleAdminItemClick}
/>
// <Dropdown.Item
// name="rooms"
// text="Rooms"
// as={Link}
// to="/admin/rooms"
// onClick={this.handleAdminItemClick}
// />
];

return (
Expand Down
76 changes: 76 additions & 0 deletions frontend/src/components/admin/venue_booking/DeleteRoomButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, {useContext, useState} from 'react';
import axios from 'axios';
import {Context} from '../../../contexts/UserProvider';
import {Confirm, Button, Popup} from 'semantic-ui-react';
import {CONSOLE_LOGGING} from '../../../DevelopmentView';

function DeleteRoomButton(props) {
const {token, name, profilePic, role, setUser, resetUser} = useContext(
Context,
);

const [isOpen, setIsOpen] = useState(false);
const [confirming, setConfirming] = useState(false);

function deleteRoom() {
const data = {
roomId: props.id,
};
axios
.delete('../api/rooms', {
data: data,
headers: {Authorization: `Bearer ${token}`},
})
.then(response => {
CONSOLE_LOGGING && console.log('DELETE room', response);
if (response.status === 200) {
props.updateTable();
toggleConfirmation();
}
})
.catch(({response}) => {
CONSOLE_LOGGING && console.log('DELETE room error', response);
if (response.status === 401) {
alert('Your current session has expired. Please log in again.');
resetUser();
}
});
}

function togglePopup() {
setIsOpen(!isOpen);
}

function toggleConfirmation() {
setConfirming(!confirming);
}

return (
<div>
<Popup
trigger={<Button basic color="red" icon="close" />}
on="click"
content={
<Button
color="red"
content="Delete Room"
onClick={toggleConfirmation}
/>
}
position="bottom center"
open={isOpen}
onOpen={togglePopup}
onClose={togglePopup}
/>
<Confirm
open={confirming}
onCancel={toggleConfirmation}
onConfirm={deleteRoom}
content="Confirm Room Deletion?"
size="mini"
/>
</div>
);
}

export default DeleteRoomButton;
153 changes: 153 additions & 0 deletions frontend/src/components/admin/venue_booking/RoomConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React, {useState, useEffect, useContext} from 'react';
import axios from 'axios';
import {Context} from '../../../contexts/UserProvider';
import {Table, Segment, Button} from 'semantic-ui-react';
import DeleteRoomButton from './DeleteRoomButton';
import {CONSOLE_LOGGING} from '../../../DevelopmentView';
import '../../../styles/ScrollableTable.scss';

const OVERLAP_CONFLICT_MSG = 'This room is has been created already.';
const UNKNOWN_ERROR_MSG = 'An unknown error has occurred. Please try again.';

function RoomConfig(props) {
const {token, name, profilePic, role, setUser, resetUser} = useContext(
Context,
);
const [allCategories, setAllCategories] = useState([]);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
updateAllCategories();
}, []);

function updateAllCategories() {
axios
.all([getAllCategories()])
.then(
axios.spread(categoriesArr => {
const newAllCategories = [];
axios.all([getRoomsData(categoriesArr, newAllCategories)]).then(
axios.spread(res => {
newAllCategories.sort((first, second) => {
if (first.category > second.category) {
return 1;
} else if (first.category < second.category) {
return -1;
} else if (first.name > second.name) {
return 1;
} else {
return -1;
}
});
setAllCategories(newAllCategories);
setIsLoading(false);
}),
);
}),
)
.catch(err => {
const response = err.response;
CONSOLE_LOGGING && console.log('POST form submission error:', response);
let msg;
switch (response.status) {
case 400:
alert(OVERLAP_CONFLICT_MSG);
break;
case 401:
alert('Your current session has expired. Please log in again.');
resetUser();
break;
default:
alert(UNKNOWN_ERROR_MSG);
}
});
}

function getAllCategories() {
return axios
.get('../api/rooms/categories', {
headers: {Authorization: `Bearer ${token}`},
})
.then(res => {
CONSOLE_LOGGING &&
console.log(`GET request to /api/rooms/categories:`, res);
return res.data.categories;
})
.catch(err => console.log(err));
}

function getRoomsData(categoriesArr, resArr) {
const promiseArr = [];
categoriesArr.forEach(cat => {
promiseArr.push(
axios
.get(`../api/rooms/categories/${cat}`, {
headers: {Authorization: `Bearer ${token}`},
})
.then(rooms => {
CONSOLE_LOGGING &&
console.log(
`GET request to /api/rooms/categories/${cat}:`,
rooms,
);
const roomsData = rooms.data;
roomsData.map(room => {
const {roomId, name, recommendedCapacity, contactEmail} = room;
resArr.push({
category: cat,
roomId,
name,
recommendedCapacity,
contactEmail,
});
});
}),
);
});
return Promise.all(promiseArr);
}

function renderBodyRow(data, index) {
const {category, roomId, name, recommendedCapacity, contactEmail} = data;

const row = (
<Table.Row>
<Table.Cell>{category}</Table.Cell>
<Table.Cell>{name}</Table.Cell>
<Table.Cell>{recommendedCapacity}</Table.Cell>
<Table.Cell>{contactEmail}</Table.Cell>
<Table.Cell>
<DeleteRoomButton id={roomId} updateTable={updateAllCategories} />
</Table.Cell>
</Table.Row>
);
return row;
}

return (
<div className="scrollable-table" style={{maxHeight: '44em'}}>
{allCategories.length > 0 ? (
<Table
selectable
headerRow={
<Table.Row>
<Table.HeaderCell>Category</Table.HeaderCell>
<Table.HeaderCell>Room Name</Table.HeaderCell>
<Table.HeaderCell>Recommended Capacity</Table.HeaderCell>
<Table.HeaderCell>Contact Email</Table.HeaderCell>
<Table.HeaderCell>Actions</Table.HeaderCell>
</Table.Row>
}
tableData={allCategories}
renderBodyRow={renderBodyRow}
/>
) : (
<Segment placeholder textAlign="center" size="huge" loading={isLoading}>
There are currently no rooms configured
</Segment>
)}
</div>
);
}

export default RoomConfig;
Loading