From 2d911a7355524ab3bb32ce71cff1ea365fbb3bc9 Mon Sep 17 00:00:00 2001 From: Brandon Satrom Date: Tue, 14 Apr 2026 17:23:42 -0700 Subject: [PATCH] fix(dashboard): extract duplicated constants into shared utility and config modules Co-Authored-By: Claude Sonnet 4.6 --- songbird-dashboard/src/api/alerts.ts | 8 +-- .../src/components/layout/MobileNav.tsx | 41 ++----------- .../src/components/layout/Sidebar.tsx | 60 +++---------------- .../src/components/maps/FleetMap.tsx | 36 ++--------- .../src/components/maps/LocationTrail.tsx | 12 +--- .../src/components/maps/VisitedCitiesMap.tsx | 12 +--- .../src/components/settings/FleetDefaults.tsx | 12 ++-- songbird-dashboard/src/config/mapConfig.ts | 10 ++++ songbird-dashboard/src/config/navigation.ts | 40 +++++++++++++ songbird-dashboard/src/config/preferences.ts | 13 ++++ .../src/contexts/PreferencesContext.tsx | 9 +-- .../src/hooks/useUserProfile.ts | 9 +-- songbird-dashboard/src/pages/DeviceDetail.tsx | 22 +------ songbird-dashboard/src/utils/formatters.ts | 7 +++ .../src/utils/locationSource.ts | 29 +++++++++ 15 files changed, 132 insertions(+), 188 deletions(-) create mode 100644 songbird-dashboard/src/config/mapConfig.ts create mode 100644 songbird-dashboard/src/config/navigation.ts create mode 100644 songbird-dashboard/src/config/preferences.ts create mode 100644 songbird-dashboard/src/utils/locationSource.ts diff --git a/songbird-dashboard/src/api/alerts.ts b/songbird-dashboard/src/api/alerts.ts index e5ca114..deb8365 100644 --- a/songbird-dashboard/src/api/alerts.ts +++ b/songbird-dashboard/src/api/alerts.ts @@ -19,13 +19,7 @@ export async function getAlerts(params?: { acknowledged?: boolean; limit?: number; }): Promise { - const searchParams = new URLSearchParams(); - if (params?.serial_number) searchParams.set('serial_number', params.serial_number); - if (params?.acknowledged !== undefined) searchParams.set('acknowledged', String(params.acknowledged)); - if (params?.limit) searchParams.set('limit', String(params.limit)); - - const query = searchParams.toString(); - return apiGet(`/v1/alerts${query ? `?${query}` : ''}`); + return apiGet('/v1/alerts', params as Record); } /** diff --git a/songbird-dashboard/src/components/layout/MobileNav.tsx b/songbird-dashboard/src/components/layout/MobileNav.tsx index 71a25a1..40fd17e 100644 --- a/songbird-dashboard/src/components/layout/MobileNav.tsx +++ b/songbird-dashboard/src/components/layout/MobileNav.tsx @@ -1,7 +1,6 @@ import { useState, useMemo } from 'react'; import { NavLink } from 'react-router-dom'; import { Menu } from 'lucide-react'; -import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Sheet, @@ -9,40 +8,15 @@ import { SheetHeader, SheetTitle, } from '@/components/ui/sheet'; -import { - LayoutDashboard, - Cpu, - AlertTriangle, - Settings, - Map, - Terminal, - Sparkles, -} from 'lucide-react'; -import { useFeatureFlags, type FeatureFlagKey } from '@/hooks/useFeatureFlags'; - -interface NavItem { - to: string; - icon: typeof LayoutDashboard; - label: string; - featureFlag?: FeatureFlagKey; -} - -const navItems: NavItem[] = [ - { to: '/', icon: LayoutDashboard, label: 'Dashboard' }, - { to: '/devices', icon: Cpu, label: 'Devices' }, - { to: '/map', icon: Map, label: 'Fleet Map' }, - { to: '/alerts', icon: AlertTriangle, label: 'Alerts' }, - { to: '/commands', icon: Terminal, label: 'Commands' }, - { to: '/analytics', icon: Sparkles, label: 'Analytics', featureFlag: 'analytics' }, - { to: '/settings', icon: Settings, label: 'Settings' }, -]; +import { useFeatureFlags } from '@/hooks/useFeatureFlags'; +import { NAV_ITEMS, navLinkClass } from '@/config/navigation'; export function MobileNav() { const [open, setOpen] = useState(false); const flags = useFeatureFlags(); const visibleNavItems = useMemo(() => { - return navItems.filter(item => { + return NAV_ITEMS.filter(item => { if (!item.featureFlag) return true; return flags[item.featureFlag]; }); @@ -72,14 +46,7 @@ export function MobileNav() { key={item.to} to={item.to} onClick={() => setOpen(false)} - className={({ isActive }) => - cn( - 'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors', - isActive - ? 'bg-primary text-primary-foreground' - : 'text-muted-foreground hover:bg-muted hover:text-foreground' - ) - } + className={({ isActive }) => navLinkClass(isActive)} > {item.label} diff --git a/songbird-dashboard/src/components/layout/Sidebar.tsx b/songbird-dashboard/src/components/layout/Sidebar.tsx index 989c3ec..3f4f176 100644 --- a/songbird-dashboard/src/components/layout/Sidebar.tsx +++ b/songbird-dashboard/src/components/layout/Sidebar.tsx @@ -1,42 +1,16 @@ -import { useMemo } from 'react'; +import { useMemo, Fragment } from 'react'; import { NavLink } from 'react-router-dom'; -import { cn } from '@/lib/utils'; -import { - LayoutDashboard, - Cpu, - AlertTriangle, - Settings, - Map, - Terminal, - Sparkles, - Radio, -} from 'lucide-react'; -import { useFeatureFlags, type FeatureFlagKey } from '@/hooks/useFeatureFlags'; +import { Radio } from 'lucide-react'; +import { useFeatureFlags } from '@/hooks/useFeatureFlags'; import { useMyDevice } from '@/hooks/useMyDevice'; - -interface NavItem { - to: string; - icon: typeof LayoutDashboard; - label: string; - featureFlag?: FeatureFlagKey; -} - -const navItems: NavItem[] = [ - { to: '/', icon: LayoutDashboard, label: 'Dashboard' }, - { to: '/devices', icon: Cpu, label: 'Devices' }, - { to: '/map', icon: Map, label: 'Fleet Map' }, - { to: '/alerts', icon: AlertTriangle, label: 'Alerts' }, - { to: '/commands', icon: Terminal, label: 'Commands' }, - { to: '/analytics', icon: Sparkles, label: 'Analytics', featureFlag: 'analytics' }, - { to: '/settings', icon: Settings, label: 'Settings' }, -]; +import { NAV_ITEMS, navLinkClass } from '@/config/navigation'; export function Sidebar() { const flags = useFeatureFlags(); const { serialNumber: myDeviceSerial } = useMyDevice(); const visibleNavItems = useMemo(() => { - return navItems.filter(item => { + return NAV_ITEMS.filter(item => { if (!item.featureFlag) return true; return flags[item.featureFlag]; }); @@ -48,41 +22,25 @@ export function Sidebar() {