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:55:53 +00:00
parent baeec59f39
commit d0221e6ca2
@@ -7,7 +7,6 @@ import {
} from "@workspace/api-client-react";
import {
Settings as SettingsIcon,
BellOff,
Volume2,
VolumeX,
LogOut,
@@ -235,7 +234,6 @@ export function SettingsPanel({ onLogout }: { onLogout: () => void }) {
const { user } = useAuth();
const isDesktop = useMediaQuery("(min-width: 768px)");
if (!user) return null;
const muted = user.notificationsMuted;
const trigger = (
<button
@@ -243,15 +241,9 @@ export function SettingsPanel({ onLogout }: { onLogout: () => void }) {
aria-label={t("settingsPanel.title")}
aria-haspopup="dialog"
data-testid="topbar-settings-button"
className="text-muted-foreground hover:text-foreground transition-colors p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 relative"
className="text-muted-foreground hover:text-foreground transition-colors p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5"
>
<SettingsIcon className="w-[18px] h-[18px] md:w-6 md:h-6" />
{muted && (
<BellOff
aria-hidden="true"
className="absolute -top-0.5 -right-0.5 w-3 h-3 text-destructive bg-background rounded-full p-px"
/>
)}
</button>
);
@@ -287,15 +279,9 @@ export function SettingsPanel({ onLogout }: { onLogout: () => void }) {
aria-label={t("settingsPanel.title")}
aria-haspopup="dialog"
data-testid="topbar-settings-button"
className="text-muted-foreground hover:text-foreground transition-colors p-1.5 rounded-lg hover:bg-foreground/5 relative"
className="text-muted-foreground hover:text-foreground transition-colors p-1.5 rounded-lg hover:bg-foreground/5"
>
<SettingsIcon className="w-[18px] h-[18px]" />
{muted && (
<BellOff
aria-hidden="true"
className="absolute -top-0.5 -right-0.5 w-3 h-3 text-destructive bg-background rounded-full p-px"
/>
)}
</button>
<SheetContent
side="bottom"