Task #694: Booking details dialog from calendar day-grid
- BookingDayGrid (artifacts/tx-os/src/pages/protocol.tsx): booking blocks are
now <button type="button"> with onClick -> new optional onSelect prop,
hover/focus-visible styles, aria-label (title/room/time) and
data-testid="calendar-booking-{id}".
- ProtocolPage: new detailsBooking state; day grid passes onSelect; new
read-only details Dialog (before AppDock) with:
header = booking title + status pill + public-request badge;
summary card = date, time range (LTR), duration, room, reference,
meeting type; requester section = name, phone (LTR), entity (external
only), department, attendee count; meeting section = purpose + key
attendees with side badges; notes; rejection-reason box when rejected.
Empty/null fields hidden via DetailRow helper.
- New helpers: DetailRow component, formatDuration(start,end,t) using
pluralized i18n keys.
- i18n: protocol.bookings.details.* added to ar.json (full Arabic plural
forms for hours/minutes) and en.json.
- View-only per task scope (no edit/approve/cancel in dialog).
- tsc --noEmit clean; both locale JSONs valid; architect review PASS.
- Added explicit 'Request source' row (internal/public) in summary card per review; keys protocol.bookings.details.source/sources.* in ar/en.
This commit is contained in:
@@ -1796,6 +1796,11 @@
|
|||||||
"meetingSection": "تفاصيل الاجتماع",
|
"meetingSection": "تفاصيل الاجتماع",
|
||||||
"notes": "ملاحظات",
|
"notes": "ملاحظات",
|
||||||
"rejectionReason": "سبب الرفض",
|
"rejectionReason": "سبب الرفض",
|
||||||
|
"source": "مصدر الطلب",
|
||||||
|
"sources": {
|
||||||
|
"internal": "داخلي",
|
||||||
|
"public": "طلب عام"
|
||||||
|
},
|
||||||
"durationHours_zero": "{{count}} ساعة",
|
"durationHours_zero": "{{count}} ساعة",
|
||||||
"durationHours_one": "ساعة واحدة",
|
"durationHours_one": "ساعة واحدة",
|
||||||
"durationHours_two": "ساعتان",
|
"durationHours_two": "ساعتان",
|
||||||
|
|||||||
@@ -1657,6 +1657,11 @@
|
|||||||
"meetingSection": "Meeting details",
|
"meetingSection": "Meeting details",
|
||||||
"notes": "Notes",
|
"notes": "Notes",
|
||||||
"rejectionReason": "Rejection reason",
|
"rejectionReason": "Rejection reason",
|
||||||
|
"source": "Request source",
|
||||||
|
"sources": {
|
||||||
|
"internal": "Internal",
|
||||||
|
"public": "Public request"
|
||||||
|
},
|
||||||
"durationHours_one": "1 hour",
|
"durationHours_one": "1 hour",
|
||||||
"durationHours_other": "{{count}} hours",
|
"durationHours_other": "{{count}} hours",
|
||||||
"durationMinutes_one": "1 minute",
|
"durationMinutes_one": "1 minute",
|
||||||
|
|||||||
@@ -2085,6 +2085,12 @@ export default function ProtocolPage() {
|
|||||||
`protocol.bookings.meetingTypes.${detailsBooking.meetingType}`,
|
`protocol.bookings.meetingTypes.${detailsBooking.meetingType}`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<DetailRow
|
||||||
|
label={t("protocol.bookings.details.source")}
|
||||||
|
value={t(
|
||||||
|
`protocol.bookings.details.sources.${detailsBooking.source}`,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user