fix(executive-meetings): quick-actions UX + reschedule/cancel polish (Task #563)

User-reported polish on the executive-meetings quick-actions flow on
iPad/mobile. Six fixes, all client-side:

1. Quick-actions surface now opens from ANY click on a meeting row
   (was: only the attendees cell). Root cause: handleRowClick guard
   skipped any `em-edit-*`, `em-merge-edit-*`, and `em-time-*`
   descendants. Those affordances only do anything in edit mode, but
   handleRowClick already early-returns when edit mode is on, so the
   testid guard was always over-aggressive. Dropped those guards plus
   the `[role='button']` rule from the interactive selector, kept the
   real `button`/`input`/`textarea`/`a`/`menuitem`/`checkbox`/etc.
   guards and the `em-row-actions-*` / `em-row-select-*` testid
   guards (those affordances are visible outside edit mode and must
   not trigger the surface).
   File: artifacts/tx-os/src/pages/executive-meetings.tsx (~L4350).

2. Originating row is now unmistakable on iPad: quickOpenShadow is
   `inset 0 0 0 4px highlight, 0 0 0 2px highlight` (was a single
   3px inset) and the row background tints to
   `rgba(highlight, 0.08)` while quick-actions is open.
   File: artifacts/tx-os/src/pages/executive-meetings.tsx
   (~L4287, L4344).

3. Postpone dialog header was overlapping the Radix close X in RTL.
   Added `pr-8` on the DialogHeader (same pattern already used for
   the row-quick mini-dialog).
   File: artifacts/tx-os/src/components/executive-meetings/
   upcoming-meeting-alert.tsx (~L1447).

4. Reschedule tab: date / start / end inputs collided on iPad
   portrait. Grid is now `grid-cols-1 md:grid-cols-3` (single column
   through iPad portrait, three across on landscape/desktop), with
   `min-w-0` on each cell and `w-full` on every Input so Safari's
   native date/time pickers stop overflowing.
   Same file (~L1761).

5. Cancel tab X overlap is resolved by the same DialogHeader fix in
   step 3 (one Dialog wraps all three tabs).

6. Removed the `cancelHint` paragraph + the `cancelHint` translation
   keys in ar.json (L1252) and en.json (L1164) — fully unused now.

NOT pushed to Gitea (Tailscale to desktop-11cj93j still flaky).
Pending pushes: #560 (VAPID), #561 (CEO roles), #563 (this).
This commit is contained in:
riyadhafraa
2026-05-17 10:18:13 +00:00
parent 5834036707
commit 620ab284e2
4 changed files with 57 additions and 37 deletions
@@ -1436,7 +1436,12 @@ function PostponeDialog({
data-testid="postpone-dialog"
className="sm:max-w-2xl"
>
<DialogHeader className="space-y-1">
{/* #563: reserve pr-8 (~2rem) so the Radix close button
(positioned right-4 top-4 inside DialogContent) never
overlaps the title/description. Physical right padding is
correct for BOTH AR (RTL) and LTR because Radix uses CSS
physical positioning for the close. */}
<DialogHeader className="space-y-1 pr-8">
<DialogTitle className="text-base">
{t("executiveMeetings.alert.postponeTitle")}
</DialogTitle>
@@ -1741,11 +1746,17 @@ function PostponeDialog({
onBack={() => setCascadePrompt(null)}
/>
) : null}
{/* Responsive grid: 1 col on narrow / 2 cols on sm /
3 cols on md+. Prevents horizontal overflow inside the
dialog on phones and split panes. */}
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3">
<div className="space-y-1">
{/* #563: responsive grid — single column on phones AND
iPad portrait (`md` and below), then 3 columns in a
single row on iPad landscape / desktop. The previous
`sm:grid-cols-2` packed date + time-start onto one row
on iPad portrait where Safari's native date/time
pickers carry wide internal icons + Arabic labels and
visibly collided. `min-w-0` lets each column shrink
inside the grid track so inputs respect their cell,
and `w-full` on the Input ensures it fills the cell. */}
<div className="grid grid-cols-1 gap-3 md:grid-cols-3">
<div className="space-y-1 min-w-0">
<Label className="text-xs">
{t("executiveMeetings.alert.rescheduleDate")}
</Label>
@@ -1755,9 +1766,10 @@ function PostponeDialog({
onChange={(e) => setResDate(e.target.value)}
disabled={busy !== null}
data-testid="reschedule-date"
className="w-full"
/>
</div>
<div className="space-y-1">
<div className="space-y-1 min-w-0">
<Label className="text-xs">
{t("executiveMeetings.alert.rescheduleStart")}
</Label>
@@ -1767,9 +1779,10 @@ function PostponeDialog({
onChange={(e) => setResStart(e.target.value)}
disabled={busy !== null}
data-testid="reschedule-start"
className="w-full"
/>
</div>
<div className="space-y-1">
<div className="space-y-1 min-w-0">
<Label className="text-xs">
{t("executiveMeetings.alert.rescheduleEnd")}
</Label>
@@ -1779,6 +1792,7 @@ function PostponeDialog({
onChange={(e) => setResEnd(e.target.value)}
disabled={busy !== null}
data-testid="reschedule-end"
className="w-full"
/>
</div>
</div>
@@ -1811,9 +1825,9 @@ function PostponeDialog({
className="space-y-2 focus:outline-none"
data-testid="postpone-cancel-panel"
>
<p className="text-xs text-muted-foreground">
{t("executiveMeetings.alert.cancelHint")}
</p>
{/* #563: cancelHint paragraph removed per user request —
the destructive button + confirm prompt convey intent
without the long disclaimer. */}
{!confirmCancel ? (
<Button
type="button"