mirror of
https://github.com/xlorepdarkhelm/numinar-coding-project.git
synced 2026-09-10 10:03:26 -04:00
106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
// Utility/helper imports
|
|
import { logger } from "../utils/logger";
|
|
|
|
// External imports
|
|
import React from "react";
|
|
|
|
// MUI imports
|
|
import { List, ListItemButton, Typography } from "@mui/material";
|
|
import "../styles/BookingList.css";
|
|
|
|
// Internal helper imports
|
|
import {
|
|
formatBookingTime,
|
|
sortBookingsByStartTime,
|
|
} from "../helpers/bookingList";
|
|
|
|
// Type-only imports
|
|
import type { BookingListProps } from "../interfaces";
|
|
|
|
// Context hook imports
|
|
import { useUsers } from "../context/UserContext";
|
|
|
|
/**
|
|
* BookingList component
|
|
* Displays a list of bookings for a room or user, including times and invitees.
|
|
* Handles empty state and sorts bookings chronologically.
|
|
* @component
|
|
* @param {BookingListProps} props - Component props
|
|
* @returns {JSX.Element} Booking list UI
|
|
*/
|
|
const BookingList: React.FC<BookingListProps> = ({ bookings, onSelect }) => {
|
|
// Context hook for users (must be called at top level)
|
|
const { users } = useUsers();
|
|
|
|
React.useEffect(() => {
|
|
// [BookingList] Mounted log removed
|
|
return () => {
|
|
// [BookingList] Unmounted log removed
|
|
};
|
|
}, []);
|
|
|
|
React.useEffect(() => {
|
|
logger.debug("[BookingList] bookings updated", bookings);
|
|
}, [bookings]);
|
|
|
|
if (!bookings || bookings.length === 0) {
|
|
return (
|
|
<List className="booking-list">
|
|
<ListItemButton className="bookinglist-empty" disabled>
|
|
<Typography className="bookinglist-item-title">
|
|
No bookings found.
|
|
</Typography>
|
|
</ListItemButton>
|
|
</List>
|
|
);
|
|
}
|
|
const sortedBookings = sortBookingsByStartTime(bookings);
|
|
/**
|
|
* Maps invitee email to user name for display.
|
|
* Only shows invitee names (not emails).
|
|
* @param {string} email - Invitee email
|
|
* @returns {string} Display name
|
|
*/
|
|
const getInviteeDisplay = (email: string) => {
|
|
const user = users.find(
|
|
(u: import("../interfaces").User) => u.email === email
|
|
);
|
|
return user ? user.name : email;
|
|
};
|
|
return (
|
|
<List className="booking-list">
|
|
{sortedBookings.map((booking) => {
|
|
let inviteeNames: string[] = [];
|
|
if (Array.isArray(booking.invitees)) {
|
|
inviteeNames = booking.invitees.map(getInviteeDisplay);
|
|
}
|
|
const roomId = booking.room_id ? Number(booking.room_id) : 0;
|
|
const roomColorIdx = ((roomId - 1) % 20) + 1;
|
|
const roomColorClass = `room-color-${roomColorIdx}`;
|
|
return (
|
|
<ListItemButton
|
|
key={booking.id}
|
|
onClick={() => onSelect && onSelect(booking)}
|
|
className={`booking-list-item ${roomColorClass}`}
|
|
>
|
|
<span className="booking-list-time">
|
|
{booking.start_time && booking.end_time
|
|
? `${formatBookingTime(
|
|
booking.start_time
|
|
)} - ${formatBookingTime(booking.end_time)}`
|
|
: "Time not set"}
|
|
</span>
|
|
<span className="booking-list-invitees">
|
|
{inviteeNames.length > 0
|
|
? `Invitees: ${inviteeNames.join(", ")}`
|
|
: "No invitees"}
|
|
</span>
|
|
</ListItemButton>
|
|
);
|
|
})}
|
|
</List>
|
|
);
|
|
};
|
|
|
|
export default BookingList;
|