Notification updates
This commit is contained in:
@@ -3,6 +3,7 @@ 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';
|
||||
import { useProfile, useUpdateProfile } from '../hooks/useProfile';
|
||||
import { useAdminAccess } from '../../../core/auth/useAdminAccess';
|
||||
import { useNavigationStore } from '../../../core/store';
|
||||
|
||||
@@ -73,9 +74,22 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
const { user, logout } = useAuth0();
|
||||
const { navigateToScreen } = useNavigationStore();
|
||||
const { settings, updateSetting, isLoading, error } = useSettings();
|
||||
const { data: profile, isLoading: profileLoading } = useProfile();
|
||||
const updateProfileMutation = useUpdateProfile();
|
||||
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
||||
const [showDataExport, setShowDataExport] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [isEditingProfile, setIsEditingProfile] = useState(false);
|
||||
const [editedDisplayName, setEditedDisplayName] = useState('');
|
||||
const [editedNotificationEmail, setEditedNotificationEmail] = useState('');
|
||||
|
||||
// Initialize edit form when profile loads or edit mode starts
|
||||
React.useEffect(() => {
|
||||
if (profile && isEditingProfile) {
|
||||
setEditedDisplayName(profile.displayName || '');
|
||||
setEditedNotificationEmail(profile.notificationEmail || '');
|
||||
}
|
||||
}, [profile, isEditingProfile]);
|
||||
|
||||
const handleLogout = () => {
|
||||
logout({
|
||||
@@ -97,6 +111,40 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
setShowDeleteConfirm(false);
|
||||
};
|
||||
|
||||
const handleEditProfile = () => {
|
||||
setIsEditingProfile(true);
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setIsEditingProfile(false);
|
||||
setEditedDisplayName(profile?.displayName || '');
|
||||
setEditedNotificationEmail(profile?.notificationEmail || '');
|
||||
};
|
||||
|
||||
const handleSaveProfile = async () => {
|
||||
const updates: { displayName?: string; notificationEmail?: string } = {};
|
||||
|
||||
if (editedDisplayName !== (profile?.displayName || '')) {
|
||||
updates.displayName = editedDisplayName;
|
||||
}
|
||||
|
||||
if (editedNotificationEmail !== (profile?.notificationEmail || '')) {
|
||||
updates.notificationEmail = editedNotificationEmail || undefined;
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
setIsEditingProfile(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await updateProfileMutation.mutateAsync(updates);
|
||||
setIsEditingProfile(false);
|
||||
} catch (error) {
|
||||
// Error is handled by the mutation hook
|
||||
}
|
||||
};
|
||||
|
||||
// Loading state
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -142,28 +190,128 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<p className="text-slate-500 mt-2">Manage your account and preferences</p>
|
||||
</div>
|
||||
|
||||
{/* Account Section */}
|
||||
{/* Profile 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 className="flex justify-between items-center mb-4">
|
||||
<h2 className="text-lg font-semibold text-slate-800">Profile</h2>
|
||||
{!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"
|
||||
style={{ minHeight: '44px', minWidth: '44px' }}
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium text-slate-800">{user?.name}</p>
|
||||
<p className="text-sm text-slate-500">{user?.email}</p>
|
||||
</div>
|
||||
|
||||
{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>
|
||||
</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>
|
||||
) : isEditingProfile ? (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={profile?.email || ''}
|
||||
disabled
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg bg-slate-100 text-slate-500"
|
||||
style={{ fontSize: '16px', minHeight: '44px' }}
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-1">Email is managed by your account provider</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||
Display Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
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"
|
||||
style={{ fontSize: '16px', minHeight: '44px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||
Notification Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
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"
|
||||
style={{ fontSize: '16px', minHeight: '44px' }}
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-1">Optional: Use a different email for notifications</p>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-3 pt-2">
|
||||
<button
|
||||
onClick={handleCancelEdit}
|
||||
disabled={updateProfileMutation.isPending}
|
||||
className="flex-1 py-2.5 px-4 bg-gray-200 text-gray-700 rounded-lg font-medium hover:bg-gray-300 transition-colors disabled:opacity-50"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<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"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
{updateProfileMutation.isPending ? (
|
||||
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
|
||||
) : (
|
||||
'Save'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className="flex items-center space-x-3 mb-4">
|
||||
{user?.picture ? (
|
||||
<img
|
||||
src={user.picture}
|
||||
alt="Profile"
|
||||
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">
|
||||
{profile?.displayName?.charAt(0) || user?.name?.charAt(0) || user?.email?.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium text-slate-800">
|
||||
{profile?.displayName || user?.name || 'User'}
|
||||
</p>
|
||||
<p className="text-sm text-slate-500">{profile?.email || user?.email}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 pt-3 border-t border-slate-200">
|
||||
<div>
|
||||
<p className="text-xs font-medium text-slate-500 uppercase">Display Name</p>
|
||||
<p className="text-sm text-slate-800">{profile?.displayName || 'Not set'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs font-medium text-slate-500 uppercase">Notification Email</p>
|
||||
<p className="text-sm text-slate-800">{profile?.notificationEmail || 'Using primary email'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
@@ -281,6 +429,14 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<div className="font-semibold">Station Management</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Manage gas station data and locations</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"
|
||||
style={{ minHeight: '44px' }}
|
||||
>
|
||||
<div className="font-semibold">Email Templates</div>
|
||||
<div className="text-sm text-blue-600 mt-1">Manage notification email templates</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
Reference in New Issue
Block a user