feat: user export service. bug and UX fixes. Complete minus outstanding email template fixes.
This commit is contained in:
@@ -4,6 +4,7 @@ import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard';
|
||||
import { MobileContainer } from '../../../shared-minimal/components/mobile/MobileContainer';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
import { useProfile, useUpdateProfile } from '../hooks/useProfile';
|
||||
import { useExportUserData } from '../hooks/useExportUserData';
|
||||
import { useAdminAccess } from '../../../core/auth/useAdminAccess';
|
||||
import { useNavigationStore } from '../../../core/store';
|
||||
import { DeleteAccountModal } from './DeleteAccountModal';
|
||||
@@ -32,7 +33,7 @@ const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
|
||||
<button
|
||||
onClick={onChange}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
|
||||
enabled ? 'bg-blue-600' : 'bg-gray-200'
|
||||
enabled ? 'bg-primary-500 dark:bg-primary-600' : 'bg-gray-200 dark:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
@@ -78,6 +79,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
const { settings, updateSetting, isLoading, error } = useSettings();
|
||||
const { data: profile, isLoading: profileLoading } = useProfile();
|
||||
const updateProfileMutation = useUpdateProfile();
|
||||
const exportMutation = useExportUserData();
|
||||
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
||||
const [showDataExport, setShowDataExport] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
@@ -102,9 +104,8 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleExportData = () => {
|
||||
// TODO: Implement data export functionality
|
||||
console.log('Exporting user data...');
|
||||
setShowDataExport(false);
|
||||
exportMutation.mutate();
|
||||
};
|
||||
|
||||
|
||||
@@ -149,7 +150,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</MobileContainer>
|
||||
@@ -167,7 +168,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<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"
|
||||
className="px-4 py-2 bg-primary-500 hover:bg-primary-600 text-white rounded-lg dark:bg-primary-600 dark:hover:bg-primary-700"
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
@@ -198,7 +199,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
{!isEditingProfile && !profileLoading && (
|
||||
<button
|
||||
onClick={handleEditProfile}
|
||||
className="px-3 py-1.5 bg-blue-100 text-blue-700 rounded-lg text-sm font-medium hover:bg-blue-200 transition-colors"
|
||||
className="px-3 py-1.5 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200 transition-colors dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
|
||||
style={{ minHeight: '44px', minWidth: '44px' }}
|
||||
>
|
||||
Edit
|
||||
@@ -208,7 +209,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
|
||||
{profileLoading ? (
|
||||
<div className="flex justify-center py-8">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-500"></div>
|
||||
</div>
|
||||
) : isEditingProfile ? (
|
||||
<div className="space-y-4">
|
||||
@@ -235,7 +236,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
value={editedDisplayName}
|
||||
onChange={(e) => setEditedDisplayName(e.target.value)}
|
||||
placeholder="Enter your display name"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 dark:bg-nero dark:border-silverstone dark:text-avus"
|
||||
style={{ fontSize: '16px', minHeight: '44px' }}
|
||||
/>
|
||||
</div>
|
||||
@@ -249,7 +250,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
value={editedNotificationEmail}
|
||||
onChange={(e) => setEditedNotificationEmail(e.target.value)}
|
||||
placeholder="Leave blank to use your primary email"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 dark:bg-nero dark:border-silverstone dark:text-avus"
|
||||
style={{ fontSize: '16px', minHeight: '44px' }}
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-1">Optional: Use a different email for notifications</p>
|
||||
@@ -267,7 +268,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<button
|
||||
onClick={handleSaveProfile}
|
||||
disabled={updateProfileMutation.isPending}
|
||||
className="flex-1 py-2.5 px-4 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors disabled:opacity-50 flex items-center justify-center"
|
||||
className="flex-1 py-2.5 px-4 bg-primary-500 text-white rounded-lg font-medium hover:bg-primary-600 transition-colors disabled:opacity-50 flex items-center justify-center dark:bg-primary-600 dark:hover:bg-primary-700"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
{updateProfileMutation.isPending ? (
|
||||
@@ -288,7 +289,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
className="w-12 h-12 rounded-full"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-12 h-12 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold">
|
||||
<div className="w-12 h-12 rounded-full bg-primary-500 flex items-center justify-center text-white font-semibold">
|
||||
{profile?.displayName?.charAt(0) || user?.name?.charAt(0) || user?.email?.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
@@ -372,7 +373,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
</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"
|
||||
className="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200 transition-colors dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
|
||||
>
|
||||
{settings.unitSystem === 'imperial' ? 'Switch to Metric' : 'Switch to Imperial'}
|
||||
</button>
|
||||
@@ -388,7 +389,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<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"
|
||||
className="w-full text-left p-3 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
>
|
||||
Export My Data
|
||||
</button>
|
||||
@@ -399,43 +400,60 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
{/* Security & Privacy Section */}
|
||||
<GlassCard padding="md">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-slate-800 dark:text-white mb-4">Security & Privacy</h2>
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
onClick={() => navigateToScreen('Security')}
|
||||
className="w-full text-left p-4 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors active:bg-primary-200 dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">Security Settings</div>
|
||||
<div className="text-sm text-primary-500 mt-1 dark:text-primary-400">Password, passkeys, verification</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
{/* Admin Console Section */}
|
||||
{!adminLoading && isAdmin && (
|
||||
<GlassCard padding="md">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-blue-600 mb-4">Admin Console</h2>
|
||||
<h2 className="text-lg font-semibold text-primary-500 mb-4">Admin Console</h2>
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
onClick={() => navigateToScreen('AdminUsers')}
|
||||
className="w-full text-left p-4 bg-blue-50 text-blue-700 rounded-lg font-medium hover:bg-blue-100 transition-colors active:bg-blue-200"
|
||||
className="w-full text-left p-4 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors active:bg-primary-200 dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">User Management</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Manage admin users and permissions</div>
|
||||
<div className="text-sm text-primary-500 mt-1 dark:text-primary-400">Manage admin users and permissions</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigateToScreen('AdminCatalog')}
|
||||
className="w-full text-left p-4 bg-blue-50 text-blue-700 rounded-lg font-medium hover:bg-blue-100 transition-colors active:bg-blue-200"
|
||||
className="w-full text-left p-4 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors active:bg-primary-200 dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">Vehicle Catalog</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Manage makes, models, and engines</div>
|
||||
<div className="text-sm text-primary-500 mt-1 dark:text-primary-400">Manage makes, models, and engines</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigateToScreen('AdminEmailTemplates')}
|
||||
className="w-full text-left p-4 bg-blue-50 text-blue-700 rounded-lg font-medium hover:bg-blue-100 transition-colors active:bg-blue-200"
|
||||
className="w-full text-left p-4 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors active:bg-primary-200 dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">Email Templates</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Manage notification email templates</div>
|
||||
<div className="text-sm text-primary-500 mt-1 dark:text-primary-400">Manage notification email templates</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigateToScreen('AdminBackup')}
|
||||
className="w-full text-left p-4 bg-blue-50 text-blue-700 rounded-lg font-medium hover:bg-blue-100 transition-colors active:bg-blue-200"
|
||||
className="w-full text-left p-4 bg-primary-50 text-primary-700 rounded-lg font-medium hover:bg-primary-100 transition-colors active:bg-primary-200 dark:bg-primary-900/20 dark:text-primary-300 dark:hover:bg-primary-900/30"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">Backup & Restore</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Create backups and restore data</div>
|
||||
<div className="text-sm text-primary-500 mt-1 dark:text-primary-400">Create backups and restore data</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -481,9 +499,10 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
</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"
|
||||
disabled={exportMutation.isPending}
|
||||
className="flex-1 py-2 px-4 bg-primary-500 text-white rounded-lg font-medium hover:bg-primary-600 transition-colors disabled:opacity-50 dark:bg-primary-600 dark:hover:bg-primary-700"
|
||||
>
|
||||
Export
|
||||
{exportMutation.isPending ? 'Exporting...' : 'Export'}
|
||||
</button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user