chore: UX design audit cleanup #162
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Clean up findings from a comprehensive UX design audit of MotoVaultPro. The audit identified 20 issues across 4 severity levels covering mobile navigation bugs, content display issues, layout improvements, and UI polish items.
Severity Breakdown
Sub-Issues (ordered by priority)
Critical
High
Medium
Minor
Acceptance Criteria
Plan: UX Design Audit Cleanup (#162)
Phase: Planning | Agent: Orchestrator | Status: AWAITING_REVIEW
Codebase Analysis Summary
Thorough exploration of all affected frontend areas completed. Key architectural findings:
App.tsx,BottomNavigation.tsx,HamburgerDrawer.tsx,navigation.tsDashboardScreen.tsx,SummaryCards.tsx,QuickActions.tsx,useDashboardData.tsVehicleCard.tsx,VehicleMobileCard.tsx,SettingsPage.tsx,vehicleLabel.tsFuelLogsPage.tsx,FuelLogForm.tsx,FuelLogsList.tsxMaintenancePage.tsx,MaintenanceSchedulesList.tsxDocumentsPage.tsx,DocumentForm.tsx,DocumentCardMetadata.tsxLayout.tsx,NotificationBell.tsxuser?.name || user?.email. Bell IS fully functional with popover + API.Layout.tsxKey Decisions (No Decision Critic Needed)
activeScreenon mount/URL change. No architecture rewrite needed.useDashboardDatahook data (fuel logs + maintenance). Minimal new API work.user.namemay not be populated. Useuser.given_nameor parse first name fromuser.name.getVehicleLabel()fromdocuments/utils/tocore/utils/and use across all 10+ locations.Milestones (1:1 with Sub-Issues)
Phase 1: Foundation (shared utilities and critical fixes)
Milestone 1 -- #165: Fix null model display on Settings vehicle list
getVehicleLabel()fromfrontend/src/features/documents/utils/vehicleLabel.tstofrontend/src/core/utils/vehicleDisplay.tsgetVehicleSubtitle()helper for Year Make Model formatting with null safety${year} ${make} ${model}concatenation in:SettingsPage.tsx:378(desktop)MobileSettingsScreen.tsx:376(mobile)VehicleAttention.tsx:107(dashboard)VehicleDetailPage.tsx:376(detail page)core/utils/vehicleDisplay.ts(new),SettingsPage.tsx,MobileSettingsScreen.tsx,VehicleAttention.tsx,VehicleDetailPage.tsxnulltext visible anywhere. Consistent "Unknown Model" fallback.Milestone 2 -- #163: Fix mobile routing
App.tsx, adduseEffectthat reads current browser URL path on mount and maps it to the correctMobileScreenvalue in Zustand store/garage/dashboard->Dashboard,/garage/vehicles->Vehicles,/garage/fuel-logs->Log Fuel,/garage/maintenance->Maintenance,/garage/documents->Documents,/garage/stations->Stations,/garage/settings->Settingswindow.history.replaceState()for bookmark supportApp.tsx,core/store/navigation.tsMilestone 3 -- #164: Add Maintenance to mobile More menu
{ screen: 'Maintenance', label: 'Maintenance', icon: <BuildRoundedIcon /> }tomenuItemsarray inHamburgerDrawer.tsxHamburgerDrawer.tsxPhase 2: Navigation cleanup
Milestone 4 -- #173: Remove redundant Stations from More menu
{ screen: 'Stations', label: 'Stations', icon: <LocalGasStationRoundedIcon /> }frommenuItemsinHamburgerDrawer.tsxHamburgerDrawer.tsxMilestone 5 -- #181: Differentiate Stations icon from Fuel Logs
LocalGasStationRoundedIcontoPlaceRoundedIcon(map pin) inBottomNavigation.tsxrightNavItemsHamburgerDrawer.tsxif Stations entry remains after Milestone 4 (it won't)BottomNavigation.tsxMilestone 6 -- #170: Fix FAB overlap with content and bottom nav
bottomposition inBottomNavigation.tsxfromcalc(64px + env(...) - 26px)tocalc(64px + env(...) + 4px)to raise above nav labelspb-24(6rem) to mobile content container inLayout.tsx(currentlypb-20) to ensure content clears both bottom nav and FABBottomNavigation.tsx,Layout.tsxPhase 3: Vehicle display consistency
Milestone 7 -- #167: Vehicle cards show Year Make Model and hide empty VIN
VehicleCard.tsx: Add Year Make Model subtitle line below display name usinggetVehicleSubtitle(). Conditionally render VIN only when non-empty.VehicleMobileCard.tsx: Same treatment -- subtitle and conditional VIN.VehicleCard.tsx,VehicleMobileCard.tsxMilestone 8 -- #171: Standardize empty field display across all views
VehicleDetailPage.tsx)VehicleCard.tsxVIN display: wrap in conditional{vehicle.vin && <Typography>VIN: {vehicle.vin}</Typography>}VehicleCard.tsx,VehicleMobileCard.tsx,VehicleDetailPage.tsx(verify),SettingsPage.tsx,MobileSettingsScreen.tsxPhase 4: Dashboard improvements
Milestone 9 -- #178: Remove dashboard auto-refresh footer text
DashboardScreen.tsxcontaining "Dashboard updates every 2 minutes"DashboardScreen.tsxMilestone 10 -- #179: Add CTA links in zero-state stats cards
SummaryCards.tsx: When card value is 0, show a subtle link below the count/garage/maintenance/garage/fuel-logs/garage/vehiclesonNavigateprop to trigger Zustand screen change instead of router linkSummaryCards.tsxMilestone 11 -- #166: Enrich Dashboard with meaningful content
DashboardScreen.tsxRecentActivity.tsxcomponent that combines latest fuel logs and maintenance records into a chronological feed (last 7 items)useDashboardDatahook (vehicles, fuelLogs, maintenance schedules)DashboardScreen.tsx,features/dashboard/components/RecentActivity.tsx(new)Phase 5: Fuel Logs restructure
Milestone 12 -- #168: Fuel Logs default to list view
FuelLogsPage.tsxlayout:FuelStatsCardat top, thenFuelLogsListas main contentFuelLogFormin aDialog(modal)AddFuelLogDialog.tsxwrapping existingFuelLogFormin MUIDialog(similar toAddDocumentDialog.tsxpattern)FuelLogsPage.tsx,features/fuel-logs/components/AddFuelLogDialog.tsx(new),FuelLogForm.tsx(minor: add onSuccess callback for dialog close)Phase 6: Maintenance fixes
Milestone 13 -- #169: Add Maintenance page title and remove duplicate dropdown
<Typography variant="h5" fontWeight={600}>Maintenance</Typography>at top ofMaintenancePage.tsxbefore vehicle selector (consistent with Documents page pattern)FormControl/Selectfrom insideMaintenanceRecordForm.tsxandMaintenanceScheduleForm.tsxselectedVehicleIdas prop from page-level selector to formsMaintenanceMobileScreen.tsxMaintenancePage.tsx,MaintenanceMobileScreen.tsx,MaintenanceRecordForm.tsx,MaintenanceScheduleForm.tsxMilestone 14 -- #174: Differentiate maintenance schedule names
MaintenanceSchedulesList.tsx, change primary display fromgetCategoryDisplayName(schedule.category)to show the service type prominently{serviceType} - {category}(e.g., "Fluid-Differential - Routine Maintenance")MaintenanceSchedulesList.tsxPhase 7: Document improvements
Milestone 15 -- #175: Remove Insurance default bias from Add Document modal
DocumentForm.tsx, change initial state fromdocumentType: 'insurance'todocumentType: ''(empty)documentType === 'insurance'DocumentForm.tsxMilestone 16 -- #172: Improve document card with upload date and file type icon
DocumentCardMetadata.tsx: AddcreatedAtdisplay as "Uploaded {relative date}" (e.g., "Uploaded 3 days ago")contentTypefield: PDF icon forapplication/pdf, Image icon forimage/*, Generic file icon for othersPictureAsPdfRoundedIcon,ImageRoundedIcon,InsertDriveFileRoundedIconDocumentCardMetadata.tsx,DocumentsPage.tsx(card rendering),DocumentsMobileScreen.tsxPhase 8: Header and minor polish
Milestone 17 -- #177: Header greeting use display name
Layout.tsx, change greeting logic fromuser?.name || user?.emailto:Layout.tsxMilestone 18 -- #180: Hide notification bell if non-functional
NotificationBell.tsx, ensure empty state shows "No notifications" message in popoverNotificationBell.tsxMilestone 19 -- #176: Add desktop sidebar collapse to icon-only mode
Layout.tsx, add three sidebar states:expanded(256px),collapsed(64px),hidden(0px)Tooltipon each icon in collapsed mode for discoverabilitylocalStoragefor session persistenceLayout.tsxExecution Order Rationale
Branch Strategy
issue-162-ux-design-audit-cleanupchore: {summary} (refs #{sub-issue-number})Risk Notes
Verdict: AWAITING_REVIEW | Next: Plan review cycle (QR plan-completeness -> TW plan-scrub -> QR plan-code -> QR plan-docs)
Plan Revision: Addressing TW Plan-Scrub Findings
Phase: Plan-Review | Agent: Orchestrator | Status: REVISED
Review Results
Blocking Fixes Applied
Fix 1 -- Milestone 11 (#166):
useDashboardDatadoes not expose individual recordsThe
useDashboardData()hook'squeryFnfetches fuel logs and maintenance data but only returnssummary(counts) andvehiclesNeedingAttention. The rawfuelLogsandallSchedulesArraysare local variables not exposed to consumers.Revised Milestone 11: Extend
useDashboardDatato include arecentActivityfield in the returnedDashboardDatainterface:Inside the
queryFn, after calculating existing data, buildrecentActivityfrom the already-fetchedfuelLogsandflatSchedules:{ type: 'fuel', vehicleId, vehicleName, description, timestamp }maintenanceApi.getRecordsByVehicle()calls alongside existing schedule fetchesRecentActivityItemtype infrontend/src/features/dashboard/types/index.tsFiles:
frontend/src/features/dashboard/hooks/useDashboardData.ts,frontend/src/features/dashboard/types/index.ts,frontend/src/features/dashboard/components/RecentActivity.tsx(new),frontend/src/features/dashboard/components/DashboardScreen.tsxFix 2 -- Milestone 19 (#176): Resolve sidebar state ambiguity
Decision: Two-state toggle (expanded 256px <-> collapsed 64px). No hidden state. Rationale:
Fix 3 -- Add explicit mobile+desktop test criteria to ALL milestones
Every milestone now includes: "Verify on mobile (320px, 768px) and desktop (1920px) viewports" in its test section. For mobile-only milestones (#170, #181), test at 320px and 768px only. For desktop-only milestones (#176), test at 1024px and 1920px.
Secondary Fixes Applied
S1 -- Full file paths in "Files:" sections (relative to
frontend/src/):core/utils/vehicleDisplay.ts(new),pages/SettingsPage.tsx,features/settings/mobile/MobileSettingsScreen.tsx,features/dashboard/components/VehicleAttention.tsx,features/vehicles/pages/VehicleDetailPage.tsx(lines 228 AND 376)features/vehicles/components/VehicleCard.tsx,features/vehicles/mobile/VehicleMobileCard.tsxfeatures/vehicles/components/VehicleCard.tsx,features/vehicles/mobile/VehicleMobileCard.tsx,features/vehicles/pages/VehicleDetailPage.tsx,pages/SettingsPage.tsx,features/settings/mobile/MobileSettingsScreen.tsx,features/dashboard/components/VehicleAttention.tsxfeatures/fuel-logs/pages/FuelLogsPage.tsx,features/fuel-logs/components/AddFuelLogDialog.tsx(new, coexists with existingFuelLogEditDialog.tsxfor editing),features/fuel-logs/components/FuelLogForm.tsxfeatures/maintenance/pages/MaintenancePage.tsx,features/maintenance/mobile/MaintenanceMobileScreen.tsx,features/maintenance/components/MaintenanceRecordForm.tsx,features/maintenance/components/MaintenanceScheduleForm.tsxfeatures/documents/components/DocumentCardMetadata.tsx,features/documents/pages/DocumentsPage.tsx(card grid),features/documents/mobile/DocumentsMobileScreen.tsx(same card rendering pattern)S2 -- Fix commit type convention: Use appropriate type per sub-issue:
fix:for #163, #164, #165, fix: FAB button overlaps content and bottom nav on mobile (#162) (#170)feat:for #166, #176, chore: add call-to-action links in zero-state stats cards (#162) (#179)chore:for #167, #168, #169, #171, #172, #173, #174, #175, #177, #178, #180, chore: differentiate Stations icon from Fuel Logs in bottom nav (#162) (#181)S3 -- Remove Milestone 5 contradiction: Deleted "Also update HamburgerDrawer.tsx if Stations entry remains after Milestone 4 (it won't)". Milestone 5 only touches
shared-minimal/components/mobile/BottomNavigation.tsx.S4 -- Add VehicleDetailPage.tsx line 228 to Milestone 1: Both line 228 (filter(Boolean) pattern in displayName) and line 376 (direct concatenation in subtitle) need updating.
S5 -- Clarify Milestone 6 CSS: The exact current value in
BottomNavigation.tsxisbottom: 'calc(64px + env(safe-area-inset-bottom, 0px) - 26px)'. Raise FAB by changing-26pxto+4px. Content padding inLayout.tsxuses Tailwindpb-20class on the mobile content div -- change topb-24.S6 -- Milestone 8 audit scoped: Replaced "Audit all card views" with explicit file list (see S1 above).
S7 -- Milestone 12 FuelLogEditDialog:
AddFuelLogDialog.tsxis a NEW creation dialog that coexists with the existingFuelLogEditDialog.tsx(used for editing). They serve different purposes and both remain.S8 -- Milestone 10 onNavigate prop:
SummaryCards.tsxcurrently receivessummarydata only. Add optionalonNavigate?: (screen: MobileScreen) => voidprop. When provided (mobile), CTA links callonNavigate; when absent (desktop), CTA links use<Link>from React Router. Parent (DashboardScreen.tsx) passes the prop in mobile mode.Verdict: REVISED | Next: QR plan-code review
All blocking and secondary TW issues addressed. Plan is ready for QR plan-code and QR plan-docs reviews.
Plan Revision 2: Addressing QR Plan-Code + QR Plan-Docs Findings
Phase: Plan-Review | Agent: Orchestrator | Status: REVISED
Review Results
QR Plan-Code Blocking Fixes
Fix 1 -- Milestone 1 (#165): Define utility signatures and directory creation
The
frontend/src/core/utils/directory does not exist. Plan must explicitly create it.Existing
getVehicleLabel()infrontend/src/features/documents/utils/vehicleLabel.tshas this signature:New utility file
frontend/src/core/utils/vehicleDisplay.ts:Action: Create
frontend/src/core/utils/directory, createvehicleDisplay.ts, then deletefrontend/src/features/documents/utils/vehicleLabel.tsand update all imports.Fix 2 -- Milestone 7 (#167): Correct VIN hiding scope
Reviewed actual files:
VehicleCard.tsx(desktop): Shows VIN unconditionally at line 54:VIN: {vehicle.vin}-- NEEDS conditional hideVehicleMobileCard.tsx(mobile): Does NOT show VIN at all -- NO change neededRevised Milestone 7:
VehicleCard.tsxONLY: Add Year Make Model subtitle usinggetVehicleSubtitle(). Wrap VIN in conditional:{vehicle.vin && <Typography>VIN: {vehicle.vin}</Typography>}VehicleMobileCard.tsx: Add Year Make Model subtitle usinggetVehicleSubtitle()below display name (if nickname is primary). No VIN changes needed.features/vehicles/components/VehicleCard.tsx,features/vehicles/mobile/VehicleMobileCard.tsxFix 3 -- Milestone 11 (#166): Define RecentActivityItem type and hook extension
Current
DashboardDatainterface (fromfrontend/src/features/dashboard/types/index.ts):Add to
frontend/src/features/dashboard/types/index.ts:In
useDashboardData.ts, thequeryFnalready fetches fuel logs and maintenance data internally but only returns summary counts. Extend it to also buildrecentActivity:{ type: 'fuel', vehicleId, vehicleName, description: "Filled {gallons} gal at ${pricePerGallon}/gal", timestamp }{ type: 'maintenance', vehicleId, vehicleName, description: "{serviceType} completed", timestamp }maintenanceApi.getRecordsByVehicle()) since the hook currently only fetches schedulesFix 4 -- Milestone 12 (#168): Clarify AddFuelLogDialog relationship
AddFuelLogDialog.tsxis a NEW wrapper component:FuelLogForm.tsxinside a MUI<Dialog>componentFuelLogForm.tsxremains as-is (standalone form component, reused by both dialog and edit flow)FuelLogEditDialog.tsx(which wraps the form for editing)Fix 5 -- Milestone 19 (#176): Define sidebar collapse implementation
Current state:
useAppStore()exposessidebarOpen: boolean,toggleSidebar(),setSidebarOpen(). The sidebar slides fully off-screen when closed.Implementation approach:
useAppStore:sidebarCollapsed: boolean(default:false)toggleSidebarCollapse()sidebarCollapsedin localStorage (not Zustand persist -- simpleuseEffectwithlocalStorage.getItem/setItem)sidebarOpen=true, sidebarCollapsed=false-> Expanded (256px, icons + labels)sidebarOpen=true, sidebarCollapsed=true-> Collapsed (64px, icons only)sidebarOpen=false-> Hidden (0px, off-screen)width 200ms ease-in-outon the sidebar, matchingmargin-lefttransition on content area<Tooltip title="Page Name" placement="right">. Active indicator remains.margin-left:sidebarCollapsed ? '64px' : '256px'(whensidebarOpen)Files:
frontend/src/core/store/appStore.ts(add state),frontend/src/components/Layout.tsx(sidebar rendering + toggle logic)QR Plan-Code Minor Fixes
M2 (#163): URL vs Zustand conflict resolution
URL takes precedence on initial load. On mount,
useEffectreadswindow.location.pathname, maps toMobileScreen, and callsnavigateToScreen(). RemoveactiveScreenfrom Zustandpartializepersist config to avoid stale localStorage overriding URLs.M5 (#181): Missing import
Add
import PlaceRoundedIcon from '@mui/icons-material/PlaceRounded';toBottomNavigation.tsx.M6 (#170): Mobile-only scope
Padding change from
pb-20topb-24applies to the mobile content div inLayout.tsxline 89 ONLY. Desktop layout uses different padding at line 237.M8 (#171): Exhaustive audit scope
Fields to audit for empty state handling:
VehicleCard.tsx:54VehicleCard.tsx:57-61VehicleMobileCard.tsx:43-46VehicleDetailPage.tsx:288-350SettingsPage.tsx:378getVehicleSubtitle()MobileSettingsScreen.tsx:376getVehicleSubtitle()M10 (#179): Complete CTA prop interface
Card-to-route mapping:
/garage/vehicles/ screenVehicles/garage/maintenance/ screenMaintenance/garage/fuel-logs/ screenLog FuelDesktop: Use React Router
<Link>. Mobile: CallonNavigate(screen).M13 (#169): Heading placement and text
Add
<Typography variant="h5" fontWeight={600}>Maintenance</Typography>as first child of the page container, BEFORE the vehicle selector dropdown. Consistent with Documents page pattern (DocumentsPage.tsxline 89:<Typography variant="h5" fontWeight={600}>Documents</Typography>).M14 (#174): Service type display format
Display as text prefix in the schedule card title. Current: "Routine Maintenance" -> Revised: "Fluid-Differential -- Routine Maintenance". Use an em-dash separator. If
serviceTypeis empty, show category name alone (no change from current).M16 (#172): Upload date field
DocumentRecordtype hascreatedAt: string(line 22 ofdocuments.types.ts). Use this as the upload date. Format:"Uploaded {relativeTime}"usingdate-fns/formatDistanceToNowor similar. NouploadedAtfield exists --createdAtis the correct field.M18 (#180): Notification bell assessment
NotificationBell.tsxalready has an empty state at lines 132-135:"No notifications"in a centered box. The bell IS functional with popover, API calls, and mark-as-read.Revised Milestone 18: Investigate whether the popover actually opens on click. If it does and shows "No notifications", this issue may be a false positive from the UX audit. During implementation: test bell click, verify popover opens, confirm empty state displays. If working correctly, mark #180 as resolved with "verified functional" note. If popover fails to open, debug the click handler and Popover anchor logic.
QR Plan-Docs Blocking Fixes
Doc Fix 1 -- Create
frontend/src/features/dashboard/CLAUDE.mdAdd as a documentation task after Milestone 11 completes. Content:
Doc Fix 2 -- Document vehicleDisplay.ts in frontend/README.md
After Milestone 1, add to
frontend/README.mdStructure section:Doc Fix 3 (Recommended) -- Update fuel-logs/CLAUDE.md
After Milestone 12, add
AddFuelLogDialog.tsxentry to the components table infrontend/src/features/fuel-logs/CLAUDE.md.Updated Review Status
Verdict: APPROVED | Next: Implementation on branch
issue-162-ux-design-audit-cleanup