#596 صلاحية الرئيس: حذف بحث الاجتماعات + زر الإعدادات
Two changes to artifacts/tx-os/src/pages/executive-meetings.tsx,
both gated on `isPresidentView` so non-president users are unaffected.
1. Schedule search hidden for the President
- Wrapped <SearchToggle> in ScheduleSection (L2945) in
{!isPresidentView && (...)}.
- Kept searchQuery state + meetingMatchesSearch wiring intact:
when query is "" the filter is a no-op, so the President sees
the full day's meetings, and the box reappears for anyone else.
2. Gear button so the President can reach Settings (font controls)
- Added an icon-only gear button (SettingsIcon, lucide-react —
already imported) in the header right-side block (L1113),
visible only when isPresidentView && section === "schedule".
data-testid="em-president-settings".
- Added an icon+label "back to schedule" button (ArrowRight for
RTL / ArrowLeft for LTR) shown when isPresidentView &&
section === "settings". data-testid="em-president-back-to-schedule".
- Relaxed the force-schedule effect (L966) so the President is
only redirected when section is neither "schedule" nor
"settings" — otherwise the gear tap would bounce back instantly.
- Sub-nav stays hidden (`!isPresidentView` on the SECTIONS map
is unchanged). Gear is the only entry point.
- No backend, no new i18n keys (reuses
executiveMeetings.nav.settings / .schedule).
- FontSettingsSection already renders for canRead users, and
canEditGlobalFontSettings stays as the API reports it — no
extra client-side gate.
`pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
This commit is contained in:
@@ -961,7 +961,12 @@ function ExecutiveMeetingsPageInner() {
|
||||
// their role flips on mid-session, so they never get stuck on a now-
|
||||
// hidden tab.
|
||||
useEffect(() => {
|
||||
if (isPresidentView && section !== "schedule") {
|
||||
// #596: President is normally pinned to "schedule", but we now
|
||||
// expose a gear-icon entry point to "settings" in the header so
|
||||
// they can edit their own font. Allow that one extra section here,
|
||||
// otherwise this effect would immediately bounce them back the
|
||||
// moment they tap the gear.
|
||||
if (isPresidentView && section !== "schedule" && section !== "settings") {
|
||||
setSection("schedule");
|
||||
}
|
||||
}, [isPresidentView, section]);
|
||||
@@ -1098,6 +1103,43 @@ function ExecutiveMeetingsPageInner() {
|
||||
<span className="hidden sm:inline">{t("executiveMeetings.exportPdf")}</span>
|
||||
</Button>
|
||||
)}
|
||||
{/* #596: President's only entry point to Settings (font
|
||||
family/size/etc). The full sub-nav stays hidden for
|
||||
them; a single gear button switches to the settings
|
||||
section, and a back arrow returns to the schedule. */}
|
||||
{isPresidentView && section === "schedule" && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-9 px-0"
|
||||
onClick={() => setSection("settings")}
|
||||
aria-label={t("executiveMeetings.nav.settings")}
|
||||
title={t("executiveMeetings.nav.settings")}
|
||||
data-testid="em-president-settings"
|
||||
>
|
||||
<SettingsIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
{isPresidentView && section === "settings" && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-1.5"
|
||||
onClick={() => setSection("schedule")}
|
||||
aria-label={t("executiveMeetings.nav.schedule")}
|
||||
title={t("executiveMeetings.nav.schedule")}
|
||||
data-testid="em-president-back-to-schedule"
|
||||
>
|
||||
{isRtl ? (
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
) : (
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
)}
|
||||
<span className="hidden sm:inline">
|
||||
{t("executiveMeetings.nav.schedule")}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2894,14 +2936,19 @@ function ScheduleSection({
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
<SearchToggle
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
placeholder={t("executiveMeetings.schedule.searchPlaceholder")}
|
||||
ariaLabel={t("executiveMeetings.schedule.searchAria")}
|
||||
clearLabel={t("executiveMeetings.schedule.searchClear")}
|
||||
isRtl={isRtl}
|
||||
/>
|
||||
{/* #596: President view hides the search box (presentation-
|
||||
style focus). The underlying searchQuery state stays "" so
|
||||
meetingMatchesSearch is a no-op and the full day shows. */}
|
||||
{!isPresidentView && (
|
||||
<SearchToggle
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
placeholder={t("executiveMeetings.schedule.searchPlaceholder")}
|
||||
ariaLabel={t("executiveMeetings.schedule.searchAria")}
|
||||
clearLabel={t("executiveMeetings.schedule.searchClear")}
|
||||
isRtl={isRtl}
|
||||
/>
|
||||
)}
|
||||
<label className="flex items-center gap-2 text-sm">
|
||||
<span className="text-muted-foreground">{t("executiveMeetings.date")}</span>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user