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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user