Task #527: unify topbar into per-user Settings panel

Topbar right cluster collapses from 5–7 icons to exactly Bell -> Inbox
(conditional on canReceiveOrders) -> Settings (gear). Logout moved
inside the Settings panel; the second bell, globe, volume and clock
buttons are gone from the topbar.

New SettingsPanel renders as a Popover on md+ and a bottom Sheet on
<md (via new useMediaQuery hook). It composes existing controls
rather than re-implementing them:
- Language radio uses useUpdateLanguage + i18n.changeLanguage
- Notifications group renders extracted NotificationSettingsContent
- Sound group toggles notificationsMuted (same flag QuickMute used)
- Clock group renders extracted ClockStyleContent
All DB + localStorage persistence is preserved unchanged.

Refactors:
- notification-settings.tsx: extracted NotificationSettingsContent;
  NotificationSettingsPicker now wraps it (kept for any future caller).
- clock-style-picker.tsx: extracted ClockStyleContent; ClockStylePicker
  now wraps it; removed dead setOpen reference inside choose().
- home.tsx: removed Globe / QuickMute / NotificationSettingsPicker /
  ClockStylePicker / standalone LogOut from the cluster, dropped
  related imports + useUpdateLanguage, reordered to Bell -> Inbox ->
  Settings, and passes onLogout to SettingsPanel.

i18n: added settingsPanel.{title, section.*, lang.*, sound.master}
keys to ar.json and en.json.

Code review: PASS.
This commit is contained in:
Riyadh
2026-05-13 14:53:53 +00:00
parent f0d77c625c
commit baeec59f39
5 changed files with 279 additions and 449 deletions
+22 -27
View File
@@ -23,7 +23,6 @@ import { useIncomingNotePopup } from "@/contexts/IncomingNotePopupContext";
import {
Bell,
Inbox,
LogOut,
Grid2X2,
Coffee,
BellRing,
@@ -566,16 +565,29 @@ export default function HomePage() {
itself can scale at the `md:` breakpoint.
*/}
{/*
Task #527: the topbar's right-side cluster used to host five
icon buttons (clock-style, quick-mute, notification-settings,
language toggle, plus the inbox/notifications/logout below).
Per-user UI preferences (language, notification sound +
vibration, master sound, clock style/visibility/12-24h) now
live behind a single Settings (gear) entry that opens the
unified panel. The notification-center bell stays as a
navigation link — it's the only bell on the page now.
Task #527: the topbar's right-side cluster previously hosted
up to seven icon buttons (clock-style, quick-mute,
notification-settings, language toggle, inbox, notifications
bell, logout). Per-user UI preferences now live behind a
single Settings (gear) entry that opens the unified panel,
and logout has moved inside that panel. The cluster now
shows exactly Bell → Inbox → Settings (Inbox is conditional
on the user being able to receive incoming orders). The
notification-center bell is the only bell on the page.
*/}
<div className="flex items-center gap-1 md:gap-2 shrink basis-0 flex-1 justify-end">
<button
onClick={() => setLocation("/notifications")}
aria-label={t("notifications.title")}
className="relative p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
>
<Bell className="w-[18px] h-[18px] md:w-6 md:h-6" />
{unreadCount > 0 && (
<span aria-hidden="true" className="absolute -top-0.5 -right-0.5 bg-destructive text-destructive-foreground text-[10px] md:text-xs rounded-full min-w-[16px] md:min-w-[20px] h-4 md:h-5 px-1 flex items-center justify-center font-bold tabular-nums">
{unreadCount > 9 ? "9+" : unreadCount}
</span>
)}
</button>
{canReceiveOrders && (
<button
onClick={() => setLocation("/orders/incoming")}
@@ -590,24 +602,7 @@ export default function HomePage() {
)}
</button>
)}
<button
onClick={() => setLocation("/notifications")}
className="relative p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
>
<Bell className="w-[18px] h-[18px] md:w-6 md:h-6" />
{unreadCount > 0 && (
<span aria-hidden="true" className="absolute -top-0.5 -right-0.5 bg-destructive text-destructive-foreground text-[10px] md:text-xs rounded-full min-w-[16px] md:min-w-[20px] h-4 md:h-5 px-1 flex items-center justify-center font-bold tabular-nums">
{unreadCount > 9 ? "9+" : unreadCount}
</span>
)}
</button>
<SettingsPanel />
<button
onClick={handleLogout}
className="p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
>
<LogOut className="w-[18px] h-[18px] md:w-6 md:h-6" />
</button>
<SettingsPanel onLogout={handleLogout} />
</div>
</div>