14 KiB
Mobile Settings Implementation Guide
Overview
Complete implementation guide for creating a full-featured mobile settings screen that matches desktop functionality. This addresses the critical gap where desktop has comprehensive settings but mobile only has a placeholder.
Current State Analysis
Desktop Settings (Full Implementation)
File: /home/egullickson/motovaultpro/frontend/src/pages/SettingsPage.tsx
Features:
- Account management section
- Notifications settings
- Appearance & Units (dark mode, metric/imperial)
- Data export and management
- Account actions (logout, delete account)
Mobile Settings (Placeholder Only)
File: frontend/src/App.tsx (lines 113-122)
Current Implementation:
const SettingsScreen = () => (
<div className="space-y-4">
<GlassCard>
<div className="text-center py-12">
<h2 className="text-lg font-semibold text-slate-800 mb-2">Settings</h2>
<p className="text-slate-500">Coming soon - App settings and preferences</p>
</div>
</GlassCard>
</div>
);
Implementation Strategy
Step 1: Create Mobile Settings Directory Structure
Create dedicated mobile settings components following existing patterns:
frontend/src/features/settings/
├── mobile/
│ ├── MobileSettingsScreen.tsx # Main settings screen
│ ├── AccountSection.tsx # Account management
│ ├── NotificationsSection.tsx # Notification preferences
│ ├── AppearanceSection.tsx # Dark mode & units
│ ├── DataSection.tsx # Export & data management
│ └── AccountActionsSection.tsx # Logout & delete account
└── hooks/
├── useSettings.ts # Settings state management
└── useSettingsPersistence.ts # Settings persistence
Step 2: Implement Mobile Settings Screen Component
File: frontend/src/features/settings/mobile/MobileSettingsScreen.tsx
import React from 'react';
import { GlassCard, MobileContainer } from '../../../shared-minimal/components/mobile';
import { AccountSection } from './AccountSection';
import { NotificationsSection } from './NotificationsSection';
import { AppearanceSection } from './AppearanceSection';
import { DataSection } from './DataSection';
import { AccountActionsSection } from './AccountActionsSection';
export const MobileSettingsScreen: React.FC = () => {
return (
<MobileContainer>
<div className="space-y-4 pb-20"> {/* Bottom padding for nav */}
<div className="text-center mb-6">
<h1 className="text-2xl font-bold text-slate-800">Settings</h1>
<p className="text-slate-500 mt-2">Manage your account and preferences</p>
</div>
<AccountSection />
<NotificationsSection />
<AppearanceSection />
<DataSection />
<AccountActionsSection />
</div>
</MobileContainer>
);
};
Step 3: Implement Settings Sections
Account Section Component
File: frontend/src/features/settings/mobile/AccountSection.tsx
import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { GlassCard } from '../../../shared-minimal/components/mobile';
export const AccountSection: React.FC = () => {
const { user } = useAuth0();
return (
<GlassCard>
<div className="p-4">
<h2 className="text-lg font-semibold text-slate-800 mb-4">Account</h2>
<div className="space-y-3">
<div className="flex items-center space-x-3">
<img
src={user?.picture}
alt="Profile"
className="w-12 h-12 rounded-full"
/>
<div>
<p className="font-medium text-slate-800">{user?.name}</p>
<p className="text-sm text-slate-500">{user?.email}</p>
</div>
</div>
<div className="pt-2 border-t border-slate-200">
<p className="text-sm text-slate-600">
Member since {new Date(user?.updated_at || '').toLocaleDateString()}
</p>
</div>
</div>
</div>
</GlassCard>
);
};
Appearance Section Component
File: frontend/src/features/settings/mobile/AppearanceSection.tsx
import React from 'react';
import { GlassCard } from '../../../shared-minimal/components/mobile';
import { useSettings } from '../hooks/useSettings';
export const AppearanceSection: React.FC = () => {
const { settings, updateSetting } = useSettings();
const toggleDarkMode = () => {
updateSetting('darkMode', !settings.darkMode);
};
const toggleUnitSystem = () => {
updateSetting('unitSystem', settings.unitSystem === 'imperial' ? 'metric' : 'imperial');
};
return (
<GlassCard>
<div className="p-4">
<h2 className="text-lg font-semibold text-slate-800 mb-4">Appearance & Units</h2>
<div className="space-y-4">
{/* Dark Mode Toggle */}
<div className="flex items-center justify-between">
<div>
<p className="font-medium text-slate-800">Dark Mode</p>
<p className="text-sm text-slate-500">Switch to dark theme</p>
</div>
<button
onClick={toggleDarkMode}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
settings.darkMode ? 'bg-blue-600' : 'bg-gray-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
settings.darkMode ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
{/* Unit System Toggle */}
<div className="flex items-center justify-between">
<div>
<p className="font-medium text-slate-800">Unit System</p>
<p className="text-sm text-slate-500">
Currently using {settings.unitSystem === 'imperial' ? 'Miles & Gallons' : 'Kilometers & Liters'}
</p>
</div>
<button
onClick={toggleUnitSystem}
className="px-4 py-2 bg-blue-100 text-blue-700 rounded-lg text-sm font-medium"
>
{settings.unitSystem === 'imperial' ? 'Switch to Metric' : 'Switch to Imperial'}
</button>
</div>
</div>
</div>
</GlassCard>
);
};
Account Actions Section Component
File: frontend/src/features/settings/mobile/AccountActionsSection.tsx
import React, { useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { GlassCard } from '../../../shared-minimal/components/mobile';
export const AccountActionsSection: React.FC = () => {
const { logout } = useAuth0();
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const handleLogout = () => {
logout({
logoutParams: {
returnTo: window.location.origin
}
});
};
const handleDeleteAccount = () => {
// Implementation for account deletion
setShowDeleteConfirm(false);
// Navigate to account deletion flow
};
return (
<GlassCard>
<div className="p-4">
<h2 className="text-lg font-semibold text-slate-800 mb-4">Account Actions</h2>
<div className="space-y-3">
<button
onClick={handleLogout}
className="w-full py-3 px-4 bg-gray-100 text-gray-700 rounded-lg text-left font-medium hover:bg-gray-200 transition-colors"
>
Sign Out
</button>
<button
onClick={() => setShowDeleteConfirm(true)}
className="w-full py-3 px-4 bg-red-50 text-red-600 rounded-lg text-left font-medium hover:bg-red-100 transition-colors"
>
Delete Account
</button>
</div>
{/* Delete Confirmation Modal */}
{showDeleteConfirm && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg p-6 max-w-sm w-full">
<h3 className="text-lg font-semibold text-slate-800 mb-2">Delete Account</h3>
<p className="text-slate-600 mb-4">
This action cannot be undone. All your data will be permanently deleted.
</p>
<div className="flex space-x-3">
<button
onClick={() => setShowDeleteConfirm(false)}
className="flex-1 py-2 px-4 bg-gray-200 text-gray-700 rounded-lg font-medium"
>
Cancel
</button>
<button
onClick={handleDeleteAccount}
className="flex-1 py-2 px-4 bg-red-600 text-white rounded-lg font-medium"
>
Delete
</button>
</div>
</div>
</div>
)}
</div>
</GlassCard>
);
};
Step 4: Implement Settings State Management
Settings Hook
File: frontend/src/features/settings/hooks/useSettings.ts
import { useState, useEffect } from 'react';
import { useSettingsPersistence } from './useSettingsPersistence';
export interface SettingsState {
darkMode: boolean;
unitSystem: 'imperial' | 'metric';
notifications: {
email: boolean;
push: boolean;
maintenance: boolean;
};
}
const defaultSettings: SettingsState = {
darkMode: false,
unitSystem: 'imperial',
notifications: {
email: true,
push: true,
maintenance: true,
},
};
export const useSettings = () => {
const { loadSettings, saveSettings } = useSettingsPersistence();
const [settings, setSettings] = useState<SettingsState>(defaultSettings);
useEffect(() => {
const savedSettings = loadSettings();
if (savedSettings) {
setSettings(savedSettings);
}
}, [loadSettings]);
const updateSetting = <K extends keyof SettingsState>(
key: K,
value: SettingsState[K]
) => {
const newSettings = { ...settings, [key]: value };
setSettings(newSettings);
saveSettings(newSettings);
};
return {
settings,
updateSetting,
};
};
Settings Persistence Hook
File: frontend/src/features/settings/hooks/useSettingsPersistence.ts
import { useCallback } from 'react';
import { SettingsState } from './useSettings';
const SETTINGS_STORAGE_KEY = 'motovaultpro-mobile-settings';
export const useSettingsPersistence = () => {
const loadSettings = useCallback((): SettingsState | null => {
try {
const stored = localStorage.getItem(SETTINGS_STORAGE_KEY);
return stored ? JSON.parse(stored) : null;
} catch (error) {
console.error('Error loading settings:', error);
return null;
}
}, []);
const saveSettings = useCallback((settings: SettingsState) => {
try {
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
} catch (error) {
console.error('Error saving settings:', error);
}
}, []);
return {
loadSettings,
saveSettings,
};
};
Step 5: Update App.tsx Integration
File: frontend/src/App.tsx
Replace the existing placeholder SettingsScreen with:
// Import the new component
import { MobileSettingsScreen } from './features/settings/mobile/MobileSettingsScreen';
// Replace the existing SettingsScreen component (around line 113)
const SettingsScreen = MobileSettingsScreen;
Step 6: Integration with Existing Systems
Unit System Integration
Ensure mobile settings integrate with existing unit system:
File: frontend/src/shared-minimal/utils/units.ts
The mobile settings should use the existing unit conversion utilities and persist to the same storage key (motovaultpro-unit-system).
Zustand Store Integration
File: frontend/src/core/store/index.ts
Extend the existing store to include settings state if needed for cross-component access.
Testing Requirements
Mobile Testing Checklist
- ✅ Settings screen renders correctly on mobile devices
- ✅ All sections (Account, Notifications, Appearance, Data, Actions) function properly
- ✅ Dark mode toggle works and persists
- ✅ Unit system changes work and persist
- ✅ Logout functionality works correctly
- ✅ Account deletion flow works (with confirmation)
- ✅ Settings persist across app restarts
- ✅ Navigation to/from settings maintains context
Desktop Compatibility Testing
- ✅ Changes don't break existing desktop settings
- ✅ Settings synchronize between mobile and desktop views
- ✅ Unit system changes reflect in both interfaces
- ✅ Authentication flows remain consistent
Integration Testing
- ✅ Settings integrate properly with existing Auth0 authentication
- ✅ Unit preferences work across all features (vehicles, fuel logs, etc.)
- ✅ Settings state management doesn't conflict with existing Zustand store
- ✅ localStorage persistence works correctly
Migration Strategy
Phase 1: Component Creation
- Create the mobile settings directory structure
- Implement individual settings section components
- Create settings hooks for state management
Phase 2: Integration
- Replace placeholder in App.tsx
- Test mobile settings functionality
- Verify persistence and state management
Phase 3: Enhancement
- Add any missing features from desktop version
- Implement mobile-specific optimizations
- Ensure full feature parity
Success Criteria
Upon completion, the mobile settings should:
- Feature Parity: Match all desktop settings functionality
- Mobile-Optimized: Use appropriate mobile UI patterns and components
- Persistent: All settings persist across app restarts
- Integrated: Work seamlessly with existing authentication and state management
- Tested: Pass all mobile and desktop compatibility tests
This implementation will eliminate the critical mobile settings gap and provide a comprehensive settings experience across all platforms.