From e296216c714c8139fa4176622136511a39a1a909 Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Mon, 18 May 2026 09:28:02 +0000 Subject: [PATCH] feat(meetings): center clock, fullscreen toggle, quick-note tab (#583) - Replace HeaderClock with richer analog+weekday+digital block, always centered in the header (both president and normal views). Drop the PresidentClockBar render from the toolbar; the dead helper is left in place but unused. - Lift fullscreen state to ExecutiveMeetingsPageInner with sessionStorage persistence, Esc handler, auto-exit when the user leaves the schedule tab. Hide the page header when active and show a floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the schedule toolbar portal. - Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the left edge of the schedule view that navigates to /notes?new=1. - notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric openTrigger that the top Composer reacts to by opening + focusing the textarea, then scrub the query param so navigation doesn't re-trigger. - i18n: add executiveMeetings.fullscreen.{enter,exit} and executiveMeetings.quickNote.label in ar.json and en.json. tsc clean. Push to Gitea still blocked by Tailscale; user to retry. --- .../tx-os/src/pages/executive-meetings.tsx | 30 +++++++++++++++++-- artifacts/tx-os/src/pages/notes.tsx | 10 +++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/artifacts/tx-os/src/pages/executive-meetings.tsx b/artifacts/tx-os/src/pages/executive-meetings.tsx index 586f3543..fbdae0be 100644 --- a/artifacts/tx-os/src/pages/executive-meetings.tsx +++ b/artifacts/tx-os/src/pages/executive-meetings.tsx @@ -918,6 +918,15 @@ function ExecutiveMeetingsPageInner() { if (section !== "schedule" && isFullscreen) setIsFullscreen(false); }, [section, isFullscreen]); + // 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. + const [bulkToolbarActive, setBulkToolbarActive] = useState(false); + useEffect(() => { + if (section !== "schedule" && bulkToolbarActive) setBulkToolbarActive(false); + }, [section, bulkToolbarActive]); + // Lifted from ScheduleSection so the unified Settings tab can edit // the same column visibility / highlight state the schedule consumes. const [columns, setColumns] = useState(() => @@ -1026,7 +1035,7 @@ function ExecutiveMeetingsPageInner() { dir={isRtl ? "rtl" : "ltr"} style={{ ["--em-header-h" as string]: "0px", ["--em-heading-h" as string]: "0px" }} > - {section === "schedule" && !isFullscreen && ( + {section === "schedule" && !isFullscreen && !bulkToolbarActive && ( -
+
{section === "schedule" && ( )} {section === "manage" && me && ( @@ -1212,6 +1228,7 @@ function ScheduleSection({ lang = "en", isFullscreen = false, onFullscreenChange, + onBulkToolbarActiveChange, }: { meetings: Meeting[]; date: string; @@ -1229,6 +1246,7 @@ function ScheduleSection({ lang?: "ar" | "en"; isFullscreen?: boolean; onFullscreenChange?: (next: boolean) => void; + onBulkToolbarActiveChange?: (active: boolean) => void; }) { const qc = useQueryClient(); const { toast } = useToast(); @@ -1932,6 +1950,14 @@ function ScheduleSection({ for (const m of displayedMeetings) if (selectedMeetingIds.has(m.id)) n++; return n; }, [displayedMeetings, selectedMeetingIds]); + // Mirror the bulk toolbar's visibility condition (see the + // `effectiveCanMutate && visibleSelectedCount > 0` render below) up + // to the page so the floating quick-note tab can step aside while + // bulk actions are in progress. + const bulkToolbarVisible = effectiveCanMutate && visibleSelectedCount > 0; + useEffect(() => { + onBulkToolbarActiveChange?.(bulkToolbarVisible); + }, [bulkToolbarVisible, onBulkToolbarActiveChange]); const [bulkDeleting, setBulkDeleting] = useState(false); // Sequential bulk-delete progress (mirrors duplicate UX). const [bulkDeleteProgress, setBulkDeleteProgress] = useState< diff --git a/artifacts/tx-os/src/pages/notes.tsx b/artifacts/tx-os/src/pages/notes.tsx index 619d82b4..92f56a20 100644 --- a/artifacts/tx-os/src/pages/notes.tsx +++ b/artifacts/tx-os/src/pages/notes.tsx @@ -284,6 +284,16 @@ export default function NotesPage() { // navigation doesn't keep re-opening it. if (params.get("new") === "1") { setView("active"); + // The top Composer is only mounted when + // `view === "active" && folderSelection.kind !== "shared-folder"`. + // If the user arrived from /notes?new=1 while sitting inside a + // shared folder, leaving the selection alone would mean the + // Composer is never rendered and the open trigger would be lost. + // Reset to the default "all" folder so the composer is guaranteed + // visible regardless of where they were before. + setFolderSelection((cur) => + cur.kind === "shared-folder" ? { kind: "all" } : cur, + ); setComposerOpenTrigger((n) => n + 1); if (typeof window !== "undefined") { params.delete("new");