Skip to content

Commit

Permalink
Improve UX of bookings page (#35)
Browse files Browse the repository at this point in the history
* Freeze action column and remove heading

* Change dropdown arrow to view booking details and add tooltip

* Allow expand details when clicking on row

* Fix double loading bug when clicking expand icon

* Update booking table columns

* Change to pointer cursor for booking table hover

* Update booking-details-view.tsx

Add row in booking details tab to show Booking ID

* Adjust admin and user booking table columns

* Remove comment

---------

Co-authored-by: Jonathan Loh <[email protected]>
  • Loading branch information
lynnetteeee and jloh02 authored Mar 29, 2024
1 parent 1fab392 commit 40457f2
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 72 deletions.
55 changes: 33 additions & 22 deletions frontend/src/components/booking-admin-table/booking-admin-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import {
BOOKER,
CREATED_AT,
CREATED_AT_STRING,
DATE_FORMAT,
EMAIL,
END_DATE_TIME,
END_DATE_TIME_STRING,
EVENT_DATE,
EVENT_TIME_RANGE,
ID,
NAME,
START_DATE_TIME,
START_DATE_TIME_STRING,
STATUS,
TITLE,
VENUE,
} from "../../constants";
import useTableState, {
Expand All @@ -24,7 +24,7 @@ import {
selectAllBookings,
selectBookingsLoadingState,
} from "../../redux/slices/bookings-slice";
import { displayDateTime } from "../../utils/transform-utils";
import { displayDateTime, displayTimeRange } from "../../utils/transform-utils";
import BookingBaseTable, { BookingViewProps } from "../booking-base-table";
import PlaceholderWrapper from "../placeholder-wrapper";
import SearchBar from "../search-bar";
Expand All @@ -40,9 +40,9 @@ const BOOKING_ADMIN_TABLE_STATE_OPTIONS: TableStateOptions = {
ID,
BOOKER_NAME,
BOOKER_EMAIL,
EVENT_DATE,
EVENT_TIME_RANGE,
VENUE_NAME,
START_DATE_TIME_STRING,
END_DATE_TIME_STRING,
CREATED_AT_STRING,
STATUS,
],
Expand All @@ -56,8 +56,11 @@ function BookingAdminTable() {
() =>
allBookings.map((booking) => ({
...booking,
[START_DATE_TIME_STRING]: displayDateTime(booking.startDateTime),
[END_DATE_TIME_STRING]: displayDateTime(booking.endDateTime),
[EVENT_DATE]: displayDateTime(booking.startDateTime, DATE_FORMAT),
[EVENT_TIME_RANGE]: displayTimeRange(
booking.startDateTime,
booking.endDateTime,
),
[CREATED_AT_STRING]: displayDateTime(booking.createdAt),
children: [{ [ID]: `${booking.id}-details`, booking }],
})),
Expand Down Expand Up @@ -100,16 +103,24 @@ function BookingAdminTable() {
key={ID}
dataKey={ID}
title="ID"
width={60}
width={70}
resizable
sortable
align="center"
/>
<Column<BookingViewProps>
key={TITLE}
dataKey={TITLE}
title="Booking Title"
width={210}
resizable
sortable
/>
<Column<BookingViewProps>
key={BOOKER_NAME}
dataKey={BOOKER}
title="Name"
width={150}
width={90}
resizable
sortable
cellRenderer={UserNameRenderer}
Expand All @@ -118,7 +129,7 @@ function BookingAdminTable() {
key={BOOKER_EMAIL}
dataKey={BOOKER}
title="Email"
width={180}
width={130}
resizable
sortable
cellRenderer={UserEmailRenderer}
Expand All @@ -127,31 +138,31 @@ function BookingAdminTable() {
key={VENUE_NAME}
dataKey={VENUE_NAME}
title="Venue"
width={180}
width={190}
resizable
sortable
/>
<Column<BookingViewProps>
key={START_DATE_TIME}
dataKey={START_DATE_TIME_STRING}
title="Start"
width={160}
key={EVENT_DATE}
dataKey={EVENT_DATE}
title="Date"
width={100}
resizable
sortable
/>
<Column<BookingViewProps>
key={END_DATE_TIME}
dataKey={END_DATE_TIME_STRING}
title="End"
width={160}
key={EVENT_TIME_RANGE}
dataKey={EVENT_TIME_RANGE}
title="Time"
width={150}
resizable
sortable
/>
<Column<BookingViewProps>
key={CREATED_AT}
dataKey={CREATED_AT_STRING}
title="Created at"
width={160}
width={165}
resizable
sortable
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

.bookingBaseTable {
@include base.table;
cursor: pointer;

div {
box-shadow: none;
}

.extraContentContainer {
width: 100%;
Expand Down
46 changes: 32 additions & 14 deletions frontend/src/components/booking-base-table/booking-base-table.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useCallback } from "react";
import { AutoResizer, Column, ColumnShape } from "react-base-table";
import { useCallback, useState } from "react";
import { AutoResizer, Column, ColumnShape, RowKey } from "react-base-table";
import { Segment } from "semantic-ui-react";

import {
ACTION,
CREATED_AT_STRING,
END_DATE_TIME_STRING,
EVENT_DATE,
EVENT_TIME_RANGE,
ID,
START_DATE_TIME_STRING,
STATUS,
} from "../../constants";
import { useGetSingleBooking } from "../../custom-hooks/api/bookings-api";
Expand All @@ -20,11 +20,11 @@ import Table, { TableProps } from "../table";
import styles from "./booking-base-table.module.scss";

export type BookingViewProps = BookingData & {
[START_DATE_TIME_STRING]: string;
[END_DATE_TIME_STRING]: string;
[EVENT_DATE]: string;
[EVENT_TIME_RANGE]: string;
[CREATED_AT_STRING]: string;
booking?: BookingData;
children: [{ [ID]: string; booking: BookingData }];
children: { [ID]: string; booking: BookingData }[];
};

type Props = Partial<TableProps<BookingViewProps>> & {
Expand All @@ -34,12 +34,17 @@ type Props = Partial<TableProps<BookingViewProps>> & {
};

const RowRenderer: TableProps<BookingViewProps>["rowRenderer"] = ({
// eslint-disable-next-line react/prop-types
rowData: { booking },
// eslint-disable-next-line react/prop-types
cells,
columns,
}: {
rowData: BookingViewProps;
cells: React.ReactNode[];
columns: ColumnShape<BookingViewProps>;
}) =>
booking ? (
// Only render details if there are booking details
// and the column is not the frozen column
booking && columns.length > 1 ? (
<Segment className={styles.extraContentContainer} basic>
<BookingDetailsView
className={styles.detailsContainer}
Expand Down Expand Up @@ -75,16 +80,15 @@ function BookingBaseTable({
[adminView],
);

const [expandedRowKeys, setExpandedRowKeys] = useState<RowKey[]>([]);
const onRowExpand: TableProps<BookingViewProps>["onRowExpand"] = async ({
expanded,
rowData: { id, formResponseData },
}) => {
if (!expanded || formResponseData) {
return;
}

const booking = await getSingleBooking(id);

if (booking) {
dispatch(updateBookingsAction({ bookings: [booking] }));
}
Expand All @@ -102,6 +106,20 @@ function BookingBaseTable({
fixed
expandColumnKey={ACTION}
onRowExpand={onRowExpand}
expandedRowKeys={expandedRowKeys}
rowEventHandlers={{
onClick: async ({ rowData, rowKey, rowIndex }) => {
if (!rowData.children || rowData.children.length === 0) return;
if (expandedRowKeys.includes(rowKey))
setExpandedRowKeys(
expandedRowKeys.filter((x) => x !== rowKey),
);
else {
setExpandedRowKeys([...expandedRowKeys, rowKey]);
onRowExpand({ expanded: true, rowData, rowIndex, rowKey });
}
},
}}
{...props}
>
{children}
Expand All @@ -116,10 +134,10 @@ function BookingBaseTable({
/>
<Column<BookingViewProps>
key={ACTION}
title="Action"
title=""
width={defaultActionColumnWidth}
align="center"
resizable
frozen="right"
/>
</Table>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ type Props = {

function BookingDetailsView({
className,
booking: { title, formResponseData },
booking: { id, title, formResponseData },
}: Props) {
return (
<LinkifyTextViewer>
<Grid className={className} padded="horizontally">
<Grid.Row>
<Grid.Column width="4">
<strong>Booking ID:</strong>
</Grid.Column>
<Grid.Column width="12">{id}</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width="4">
<strong>Booking title:</strong>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.userTableCell,
.userTableHeader {
padding-left: 24px;
}
57 changes: 33 additions & 24 deletions frontend/src/components/booking-user-table/booking-user-table.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useMemo } from "react";
import { Column } from "react-base-table";
import { Segment } from "semantic-ui-react";
import styles from "./booking-user-table.module.scss";

import {
CREATED_AT,
CREATED_AT_STRING,
END_DATE_TIME,
END_DATE_TIME_STRING,
DATE_FORMAT,
EVENT_DATE,
EVENT_TIME_RANGE,
ID,
NAME,
START_DATE_TIME,
START_DATE_TIME_STRING,
STATUS,
TITLE,
VENUE,
} from "../../constants";
import useTableState, {
Expand All @@ -23,7 +24,7 @@ import {
selectBookingsLoadingState,
} from "../../redux/slices/bookings-slice";
import { selectCurrentUserDisplayInfo } from "../../redux/slices/current-user-slice";
import { displayDateTime } from "../../utils/transform-utils";
import { displayDateTime, displayTimeRange } from "../../utils/transform-utils";
import BookingBaseTable, { BookingViewProps } from "../booking-base-table";
import PlaceholderWrapper from "../placeholder-wrapper";
import SearchBar from "../search-bar";
Expand All @@ -34,8 +35,8 @@ const BOOKING_ADMIN_TABLE_STATE_OPTIONS: TableStateOptions = {
searchKeys: [
ID,
VENUE_NAME,
START_DATE_TIME_STRING,
END_DATE_TIME_STRING,
EVENT_DATE,
EVENT_TIME_RANGE,
CREATED_AT_STRING,
STATUS,
],
Expand All @@ -53,8 +54,11 @@ function BookingUserTable() {
() =>
userBookings.map((booking) => ({
...booking,
[START_DATE_TIME_STRING]: displayDateTime(booking.startDateTime),
[END_DATE_TIME_STRING]: displayDateTime(booking.endDateTime),
[EVENT_DATE]: displayDateTime(booking.startDateTime, DATE_FORMAT),
[EVENT_TIME_RANGE]: displayTimeRange(
booking.startDateTime,
booking.endDateTime,
),
[CREATED_AT_STRING]: displayDateTime(booking.createdAt),
children: [{ [ID]: `${booking.id}-details`, booking }],
})),
Expand Down Expand Up @@ -91,16 +95,21 @@ function BookingUserTable() {
sortBy={sortBy}
setSortBy={setSortBy}
defaultStatusColumnWidth={110}
defaultActionColumnWidth={150}
defaultActionColumnWidth={50}
>
<Column<BookingViewProps>
key={ID}
dataKey={ID}
title="ID"
width={80}
key={TITLE}
dataKey={TITLE}
title="Booking Title"
width={330}
resizable
sortable
align="center"
cellRenderer={({ cellData }) => (
<div className={styles.userTableCell}>{cellData}</div>
)}
headerRenderer={({ column }) => (
<div className={styles.userTableHeader}>{column.title}</div>
)}
/>
<Column<BookingViewProps>
key={VENUE_NAME}
Expand All @@ -111,26 +120,26 @@ function BookingUserTable() {
sortable
/>
<Column<BookingViewProps>
key={START_DATE_TIME}
dataKey={START_DATE_TIME_STRING}
title="Start"
width={230}
key={EVENT_DATE}
dataKey={EVENT_DATE}
title="Date"
width={150}
resizable
sortable
/>
<Column<BookingViewProps>
key={END_DATE_TIME}
dataKey={END_DATE_TIME_STRING}
title="End"
width={230}
key={EVENT_TIME_RANGE}
dataKey={EVENT_TIME_RANGE}
title="Time"
width={190}
resizable
sortable
/>
<Column<BookingViewProps>
key={CREATED_AT}
dataKey={CREATED_AT_STRING}
title="Created at"
width={230}
width={210}
resizable
sortable
/>
Expand Down
Loading

0 comments on commit 40457f2

Please sign in to comment.