Initial Commit

This commit is contained in:
Eric Gullickson
2025-09-17 16:09:15 -05:00
parent 0cdb9803de
commit a052040e3a
373 changed files with 437090 additions and 6773 deletions

View File

@@ -0,0 +1,323 @@
import React, { useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard';
import { MobileContainer } from '../../../shared-minimal/components/mobile/MobileContainer';
import { useSettings } from '../hooks/useSettings';
interface ToggleSwitchProps {
enabled: boolean;
onChange: () => void;
label: string;
description?: string;
}
const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
enabled,
onChange,
label,
description
}) => (
<div className="flex items-center justify-between py-2">
<div>
<p className="font-medium text-slate-800">{label}</p>
{description && (
<p className="text-sm text-slate-500">{description}</p>
)}
</div>
<button
onClick={onChange}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
enabled ? 'bg-blue-600' : 'bg-gray-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
enabled ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
);
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
}
const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children }) => {
if (!isOpen) return null;
return (
<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-4">{title}</h3>
{children}
<div className="flex justify-end mt-4">
<button
onClick={onClose}
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg font-medium"
>
Close
</button>
</div>
</div>
</div>
);
};
export const MobileSettingsScreen: React.FC = () => {
const { user, logout } = useAuth0();
const { settings, updateSetting, isLoading, error } = useSettings();
const [showDataExport, setShowDataExport] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const handleLogout = () => {
logout({
logoutParams: {
returnTo: window.location.origin
}
});
};
const handleExportData = () => {
// TODO: Implement data export functionality
console.log('Exporting user data...');
setShowDataExport(false);
};
const handleDeleteAccount = () => {
// TODO: Implement account deletion
console.log('Deleting account...');
setShowDeleteConfirm(false);
};
// Loading state
if (isLoading) {
return (
<MobileContainer>
<div className="flex items-center justify-center min-h-[400px]">
<div className="text-center">
<div className="text-slate-500 mb-2">Loading settings...</div>
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
</div>
</div>
</MobileContainer>
);
}
// Error state
if (error) {
return (
<MobileContainer>
<div className="space-y-4 pb-20 p-4">
<GlassCard padding="md">
<div className="text-center py-8">
<p className="text-red-600 mb-4">Failed to load settings</p>
<p className="text-sm text-slate-600 mb-4">{error}</p>
<button
onClick={() => window.location.reload()}
className="px-4 py-2 bg-blue-600 text-white rounded-lg"
>
Retry
</button>
</div>
</GlassCard>
</div>
</MobileContainer>
);
}
return (
<MobileContainer>
<div className="space-y-4 pb-20 p-4">
{/* Header */}
<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>
{/* Account Section */}
<GlassCard padding="md">
<div>
<h2 className="text-lg font-semibold text-slate-800 mb-4">Account</h2>
<div className="flex items-center space-x-3">
{user?.picture && (
<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-3 mt-3 border-t border-slate-200">
<p className="text-sm text-slate-600">
Member since {user?.updated_at ? new Date(user.updated_at).toLocaleDateString() : 'Unknown'}
</p>
</div>
</div>
</GlassCard>
{/* Notifications Section */}
<GlassCard padding="md">
<div>
<h2 className="text-lg font-semibold text-slate-800 mb-4">Notifications</h2>
<div className="space-y-3">
<ToggleSwitch
enabled={settings.notifications.email}
onChange={() => updateSetting('notifications', {
...settings.notifications,
email: !settings.notifications.email
})}
label="Email Notifications"
description="Receive updates via email"
/>
<ToggleSwitch
enabled={settings.notifications.push}
onChange={() => updateSetting('notifications', {
...settings.notifications,
push: !settings.notifications.push
})}
label="Push Notifications"
description="Receive mobile push notifications"
/>
<ToggleSwitch
enabled={settings.notifications.maintenance}
onChange={() => updateSetting('notifications', {
...settings.notifications,
maintenance: !settings.notifications.maintenance
})}
label="Maintenance Reminders"
description="Get reminded about vehicle maintenance"
/>
</div>
</div>
</GlassCard>
{/* Appearance & Units Section */}
<GlassCard padding="md">
<div>
<h2 className="text-lg font-semibold text-slate-800 mb-4">Appearance & Units</h2>
<div className="space-y-4">
<ToggleSwitch
enabled={settings.darkMode}
onChange={() => updateSetting('darkMode', !settings.darkMode)}
label="Dark Mode"
description="Switch to dark theme"
/>
<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={() => updateSetting('unitSystem', settings.unitSystem === 'imperial' ? 'metric' : 'imperial')}
className="px-4 py-2 bg-blue-100 text-blue-700 rounded-lg text-sm font-medium hover:bg-blue-200 transition-colors"
>
{settings.unitSystem === 'imperial' ? 'Switch to Metric' : 'Switch to Imperial'}
</button>
</div>
</div>
</div>
</GlassCard>
{/* Data Management Section */}
<GlassCard padding="md">
<div>
<h2 className="text-lg font-semibold text-slate-800 mb-4">Data Management</h2>
<div className="space-y-3">
<button
onClick={() => setShowDataExport(true)}
className="w-full text-left p-3 bg-blue-50 text-blue-700 rounded-lg font-medium hover:bg-blue-100 transition-colors"
>
Export My Data
</button>
<p className="text-sm text-slate-500">
Download a copy of all your vehicle and fuel data
</p>
</div>
</div>
</GlassCard>
{/* Account Actions Section */}
<GlassCard padding="md">
<div>
<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>
</div>
</GlassCard>
{/* Data Export Modal */}
<Modal
isOpen={showDataExport}
onClose={() => setShowDataExport(false)}
title="Export Data"
>
<p className="text-slate-600 mb-4">
This will create a downloadable file containing all your vehicle data, fuel logs, and preferences.
</p>
<div className="flex space-x-3">
<button
onClick={() => setShowDataExport(false)}
className="flex-1 py-2 px-4 bg-gray-200 text-gray-700 rounded-lg font-medium"
>
Cancel
</button>
<button
onClick={handleExportData}
className="flex-1 py-2 px-4 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
Export
</button>
</div>
</Modal>
{/* Delete Account Confirmation */}
<Modal
isOpen={showDeleteConfirm}
onClose={() => setShowDeleteConfirm(false)}
title="Delete Account"
>
<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 hover:bg-red-700 transition-colors"
>
Delete
</button>
</div>
</Modal>
</div>
</MobileContainer>
);
};