#600: move quick-note entry from floating side tab into meetings header

User reported the yellow vertical "اكتب ملاحظة…" tab pinned to the page
edge (left-0 top-[40vh]) felt out of place and asked for it to live
inside the Executive Meetings header in a clear spot.

Changes (artifacts/tx-os/src/pages/executive-meetings.tsx):
- Added an amber-tinted Button in the header action cluster, placed
  before the Export PDF button so it reads first in RTL. Uses
  bg-amber-100 / border-amber-300 to keep the original yellow visual
  identity while matching the other header buttons' shape and size.
  Reuses the existing `executiveMeetings.quickNote.label` i18n key —
  no new translations. testid: `em-quick-note-header`.
- Same gating as the old floating tab: section === "schedule" &&
  !isFullscreen && !bulkToolbarActive && !quickNoteOpen, so the button
  hides while the composer is open, in fullscreen, during bulk
  selection, and on non-schedule sub-pages.
- Removed the `<MeetingsQuickNoteTab />` mount and the component
  definition itself. Updated the stale comment on `bulkToolbarActive`
  to refer to the header button.

Verified:
- `rg em-quick-note-tab|MeetingsQuickNoteTab` clean across repo (no
  tests referenced the old testid).
- `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.

No deviation from the plan.
This commit is contained in:
riyadhafraa
2026-05-18 12:58:30 +00:00
parent 6dda7d7120
commit 504a8d4a64
@@ -816,35 +816,6 @@ function HeaderClock({ lang, date }: { lang: "ar" | "en"; date: string }) {
);
}
function MeetingsQuickNoteTab({
lang,
onClick,
}: {
lang: "ar" | "en";
onClick: () => void;
}) {
const { t } = useTranslation();
const label = t("executiveMeetings.quickNote.label", lang === "ar" ? "اكتب ملاحظة…" : "Take a note…");
// Tab sits on the page edge that is visually "left" in LTR and "right"
// in RTL — but the spec calls for "left of meetings page", so we pin
// to physical left in both directions. Hidden in print.
return (
<button
type="button"
onClick={onClick}
aria-label={label}
title={label}
data-testid="em-quick-note-tab"
className="flex fixed left-0 top-[40vh] z-30 flex-col items-center justify-center gap-2 w-7 py-3 rounded-r-lg bg-amber-200 hover:bg-amber-300 border border-amber-300 border-l-0 text-[#0B1E3F] shadow-sm transition-all duration-150 hover:translate-x-0.5 print:hidden"
style={{ writingMode: "vertical-rl" as const }}
>
<Plus className="w-4 h-4 rotate-90" aria-hidden="true" />
<span className="text-xs font-medium tracking-wide select-none">{label}</span>
</button>
);
}
function ExecutiveMeetingsPageInner() {
const { t, i18n } = useTranslation();
const [, setLocation] = useLocation();
@@ -911,8 +882,8 @@ function ExecutiveMeetingsPageInner() {
// The schedule section publishes whether its bulk-action toolbar is
// currently visible (≥1 row selected in edit mode) so the page-level
// MeetingsQuickNoteTab can step out of the way while the user works
// with destructive bulk actions.
// quick-note header button can step out of the way while the user
// works with destructive bulk actions.
const [bulkToolbarActive, setBulkToolbarActive] = useState(false);
useEffect(() => {
if (section !== "schedule" && bulkToolbarActive) setBulkToolbarActive(false);
@@ -1031,15 +1002,8 @@ function ExecutiveMeetingsPageInner() {
dir={isRtl ? "rtl" : "ltr"}
style={{ ["--em-header-h" as string]: "0px", ["--em-heading-h" as string]: "0px" }}
>
{section === "schedule" && !isFullscreen && !bulkToolbarActive && !quickNoteOpen && (
<MeetingsQuickNoteTab
lang={lang}
onClick={() => {
setQuickNoteOpen(true);
setQuickNoteTrigger((n) => n + 1);
}}
/>
)}
{/* #600: yellow floating side tab removed entry point is now
the amber "Take a note" button in the header action cluster. */}
{isFullscreen && (
<button
type="button"
@@ -1098,6 +1062,27 @@ function ExecutiveMeetingsPageInner() {
</div>
<div className="flex items-center gap-2">
{/* #600: quick-note entry point moved off the page edge
into the header. Same gating as the old floating tab. */}
{section === "schedule" && !isFullscreen && !bulkToolbarActive && !quickNoteOpen && (
<Button
variant="outline"
size="sm"
className="gap-1.5 bg-amber-100 hover:bg-amber-200 border-amber-300 text-[#0B1E3F]"
onClick={() => {
setQuickNoteOpen(true);
setQuickNoteTrigger((n) => n + 1);
}}
aria-label={t("executiveMeetings.quickNote.label", lang === "ar" ? "اكتب ملاحظة…" : "Take a note…")}
title={t("executiveMeetings.quickNote.label", lang === "ar" ? "اكتب ملاحظة…" : "Take a note…")}
data-testid="em-quick-note-header"
>
<Plus className="w-4 h-4" />
<span className="hidden sm:inline">
{t("executiveMeetings.quickNote.label", lang === "ar" ? "اكتب ملاحظة…" : "Take a note…")}
</span>
</Button>
)}
{!isPresidentView && (
<Button
variant="outline"