Making thngs cleaner.

Signed-off-by: Cliff Hill <xlorep@darkhelm.org>
This commit is contained in:
2025-10-09 09:39:14 -04:00
parent 5735a2d2cd
commit e0fe5c2241
4 changed files with 96 additions and 39 deletions

View File

@@ -14,6 +14,7 @@ import React, { useState, useMemo, useCallback } from "react";
import {
Box,
ListSubheader,
Button,
Chip,
Dialog,
@@ -88,7 +89,7 @@ const BookingForm: React.FC<BookingFormProps> = ({
const bookingsContext = useBookings();
const roomsContext = useRooms();
const usersContext = useUsers();
const bookings = useMemo(
const bookings: Booking[] = useMemo(
() => bookingsContext.bookings ?? [],
[bookingsContext.bookings]
);
@@ -530,35 +531,53 @@ const BookingForm: React.FC<BookingFormProps> = ({
</Box>
)}
disabled={isViewMode}
MenuProps={{
PaperProps: {
style: { maxHeight: 400 },
},
// Add a custom footer with a Done button
MenuListProps: {
"aria-label": "invitee-list",
},
}}
>
<MenuItem
disabled
className={
remainingSlots < 0
? "bookingform-invitee-over"
: "bookingform-invitee-remaining"
}
<ListSubheader
disableSticky={false}
className="bookingform-invitee-header"
>
{remainingSlots >= 0
? `${remainingSlots} invitee slot${
remainingSlots === 1 ? "" : "s"
} left`
: `${Math.abs(remainingSlots)} over room capacity`}
</MenuItem>
<span
className={
"bookingform-invitee-header-label" +
(remainingSlots < 0 ? " over" : "")
}
>
{remainingSlots >= 0
? `${remainingSlots} invitee slot${
remainingSlots === 1 ? "" : "s"
} left`
: `${Math.abs(remainingSlots)} over room capacity`}
</span>
</ListSubheader>
{users.map((user: import("../interfaces").User) => {
const email = user.email ?? user.name;
const isSelected = invitees.includes(email);
// User unavailable if booked for another event at this time
const unavailable = bookings.some((b: Booking) => {
if (isEdit && b.id === editBooking?.id) {
const unavailable = (bookings as unknown as Booking[]).some(
(b) => {
if (typeof b === "object" && b !== null && "id" in b) {
const booking = b as Booking;
if (isEdit && booking.id === editBooking?.id) {
return false;
}
return (
booking.invitees?.includes(email) &&
new Date(start) < new Date(booking.end_time) &&
new Date(end) > new Date(booking.start_time)
);
}
return false;
}
return (
b.invitees?.includes(email) &&
new Date(start) < new Date(b.end_time) &&
new Date(end) > new Date(b.start_time)
);
});
);
const disableUnselected =
!isSelected &&
(unavailable || invitees.length >= roomCapacity);

View File

@@ -28,6 +28,7 @@ import { getRooms } from "../apis/rooms";
// Context imports
import { useBookings } from "../context/BookingContext";
import { useUsers } from "../context/UserContext";
// Utility/helper imports
@@ -46,6 +47,7 @@ const ConfirmationPage: React.FC = () => {
const location = useLocation();
// Always call hooks at the top level
const { bookings, refreshBookings } = useBookings();
const { users } = useUsers();
// booking is passed from BookingForm or BookingPage
/**
@@ -93,7 +95,7 @@ const ConfirmationPage: React.FC = () => {
return () => {
es.close();
};
}, [bookings, location.state, booking?.id, navigate]);
}, [bookings, location.state, booking?.id, navigate, booking]);
/**
* Subscribe to SSE for live booking status updates.
*/
@@ -125,7 +127,7 @@ const ConfirmationPage: React.FC = () => {
return () => {
es.close();
};
}, [bookings, location.state, booking?.id]);
}, [bookings, location.state, booking?.id, booking]);
/**
* Editing state for toggling between confirmation and edit form.
*/
@@ -164,8 +166,19 @@ const ConfirmationPage: React.FC = () => {
}
};
// Enrich booking with room details if missing
// Enrich booking with room details and invitee names if missing
let enrichedBooking = booking;
if (
enrichedBooking &&
Array.isArray(users) &&
Array.isArray(enrichedBooking.invitees)
) {
const inviteeNames = enrichedBooking.invitees.map((email) => {
const user = users.find((u) => u.email === email);
return user ? user.name : email;
});
enrichedBooking = { ...enrichedBooking, invitees: inviteeNames };
}
if (
enrichedBooking &&
!enrichedBooking.room &&

View File

@@ -117,3 +117,27 @@
flex-wrap: wrap;
gap: 0.5em;
}
/* Sticky header for invitee selection */
.bookingform-invitee-header {
display: flex;
align-items: center;
padding-left: 16px;
padding-right: 16px;
padding-top: 8px;
padding-bottom: 8px;
position: sticky;
top: 0;
z-index: 1;
background-color: var(--mui-palette-background-paper, #fff);
border-bottom: 1px solid var(--color-horizontal-rule, #eee);
}
.bookingform-invitee-header-label {
flex: 1;
font-weight: 500;
}
.bookingform-invitee-header-label.over {
color: var(--color-error, #d32f2f);
}

View File

@@ -15,6 +15,7 @@
/* Text & Foreground Colors */
--color-text-primary: #23272f; /* Main text */
--color-horizontal-rule: #eee; /* Horizontal rules */
--color-text-secondary: #555; /* Secondary text */
--color-text-muted: #444; /* Muted/disabled text */
--color-text-disabled: #222; /* Disabled/very muted text */
@@ -27,24 +28,24 @@
--room-icon: rgba(0, 0, 0, 0.54); /* Room icon color */
/* Room color variables: Color Universal Design (CUD) palette, color-blind friendly */
--room-color-1: #e69f00; /* orange */
--room-color-2: #56b4e9; /* sky blue */
--room-color-3: #009e73; /* bluish green */
--room-color-4: #f0e442; /* yellow */
--room-color-5: #0072b2; /* blue */
--room-color-6: #d55e00; /* vermillion */
--room-color-7: #cc79a7; /* reddish purple */
--room-color-8: #000000; /* black */
--room-color-9: #999933; /* olive */
--room-color-10: #882255; /* wine */
--room-color-11: #44aa99; /* teal */
--room-color-12: #117733; /* green */
--room-color-1: #0072b2; /* blue */
--room-color-2: #117733; /* green */
--room-color-3: #aa3377; /* magenta */
--room-color-4: #e69f00; /* orange */
--room-color-5: #56b4e9; /* sky blue */
--room-color-6: #009e73; /* bluish green */
--room-color-7: #f0e442; /* yellow */
--room-color-8: #d55e00; /* vermillion */
--room-color-9: #cc79a7; /* reddish purple */
--room-color-10: #999933; /* olive */
--room-color-11: #882255; /* wine */
--room-color-12: #44aa99; /* teal */
--room-color-13: #aa4499; /* purple */
--room-color-14: #332288; /* navy */
--room-color-15: #ddcc77; /* sand */
--room-color-16: #661100; /* brown */
--room-color-17: #6699cc; /* steel blue */
--room-color-18: #888888; /* gray */
--room-color-19: #aa3377; /* magenta */
--room-color-20: #44bb99; /* turquoise */
--room-color-19: #44bb99; /* turquoise */
--room-color-20: #000000; /* black */
}