Update booking display with index numbers and structured details

Refactors the `ProtocolPage` component to include an index column for bookings and restructures the booking detail view into a fixed grid layout.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 9637de15-465f-4172-bea0-f0b45a37bd23
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/ychh3tH
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
Replit Agent
2026-07-08 12:19:27 +00:00
parent 1b263a9f05
commit 2ac960b69a
+67 -49
View File
@@ -787,10 +787,10 @@ export default function ProtocolPage() {
timeStyle: "short",
});
const renderBookingRow = (b: Booking) => {
const renderBookingRow = (b: Booking, index: number) => {
const expanded = expandedBookings.has(b.id);
const bookingIsToday = sameYmd(new Date(b.startsAt), now);
const detailColSpan = 7;
const detailColSpan = 8;
return (
<>
<TableRow
@@ -805,6 +805,11 @@ export default function ProtocolPage() {
)}
data-testid={`booking-row-${b.id}`}
>
<TableCell className="w-10 text-slate-500">
<span className="flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-xs font-semibold text-slate-600">
{index}
</span>
</TableCell>
<TableCell className="whitespace-nowrap font-semibold text-sky-700">
<span dir="ltr">{bookingNumber(b)}</span>
{bookingIsToday && (
@@ -945,52 +950,62 @@ export default function ProtocolPage() {
{expanded && (
<TableRow key={`${b.id}-details`} className="bg-slate-50/80">
<TableCell colSpan={detailColSpan} className="py-3">
<div className="space-y-0.5">
<div className="text-xs text-slate-500 font-medium">
<div className="space-y-1">
<div className="text-sm text-slate-700 font-semibold">
{b.title}
</div>
{b.bookingReference && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.reference")}:{" "}
<span dir="ltr">{b.bookingReference}</span>
</div>
)}
{b.department && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.department")}: {b.department}
</div>
)}
<div className="text-xs text-slate-400">
{t("protocol.bookings.meetingType")}:{" "}
{t(`protocol.bookings.meetingTypes.${b.meetingType}`)}
<div className="grid gap-x-6 gap-y-1 sm:grid-cols-2 lg:grid-cols-3 text-xs">
{(
[
[t("protocol.bookings.requester"), b.requesterName],
[t("protocol.bookings.department"), b.department],
[
t("protocol.bookings.meetingType"),
t(`protocol.bookings.meetingTypes.${b.meetingType}`),
],
...(b.meetingType === "external"
? [
[
t("protocol.bookings.entity"),
b.requesterOrg,
] as const,
]
: []),
[
t("protocol.bookings.phone"),
b.requesterPhone ? (
<span dir="ltr">{b.requesterPhone}</span>
) : null,
],
[
t("protocol.bookings.attendeeCount"),
b.attendeeCount != null ? b.attendeeCount : null,
],
[t("protocol.bookings.purpose"), b.purpose],
[
t("protocol.bookings.reference"),
b.bookingReference ? (
<span dir="ltr">{b.bookingReference}</span>
) : null,
],
] as Array<[string, React.ReactNode]>
).map(([label, value], i) => (
<div key={i} className="flex gap-1">
<span className="text-slate-400 shrink-0">
{label}:
</span>
<span className="text-slate-600 min-w-0 break-words">
{value != null && value !== "" ? value : "—"}
</span>
</div>
))}
</div>
{b.meetingType === "external" && b.requesterOrg && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.entity")}: {b.requesterOrg}
</div>
)}
{b.requesterPhone && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.phone")}:{" "}
<span dir="ltr">{b.requesterPhone}</span>
</div>
)}
{b.attendeeCount != null && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.attendeeCount")}: {b.attendeeCount}
</div>
)}
{b.purpose && (
<div className="text-xs text-slate-400">
{t("protocol.bookings.purpose")}: {b.purpose}
</div>
)}
{b.keyAttendees && b.keyAttendees.length > 0 && (
<div className="text-xs text-slate-400 mt-1">
<span className="font-medium">
{t("protocol.bookings.keyAttendees")}:
</span>
<ul className="mt-0.5 space-y-0.5">
<div className="text-xs">
<span className="text-slate-400 font-medium">
{t("protocol.bookings.keyAttendees")}:
</span>{" "}
{b.keyAttendees && b.keyAttendees.length > 0 ? (
<ul className="mt-0.5 space-y-0.5 text-slate-600">
{b.keyAttendees.map((a, i) => (
<li key={i}>
{a.name}
@@ -999,8 +1014,10 @@ export default function ProtocolPage() {
</li>
))}
</ul>
</div>
)}
) : (
<span className="text-slate-600"></span>
)}
</div>
{b.status === "rejected" && b.rejectionReason && (
<div className="text-xs text-rose-500">
{b.rejectionReason}
@@ -1019,6 +1036,7 @@ export default function ProtocolPage() {
<Table>
<TableHeader>
<TableRow className="bg-slate-100/80 hover:bg-slate-100/80">
<TableHead className="w-10 text-start">#</TableHead>
<TableHead className="text-start whitespace-nowrap">
{t("protocol.bookings.table.number")}
</TableHead>
@@ -1043,8 +1061,8 @@ export default function ProtocolPage() {
</TableRow>
</TableHeader>
<TableBody>
{list.map((b) => (
<Fragment key={b.id}>{renderBookingRow(b)}</Fragment>
{list.map((b, i) => (
<Fragment key={b.id}>{renderBookingRow(b, i + 1)}</Fragment>
))}
</TableBody>
</Table>