Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/contexts/AuthContext.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { account, databases } from '../appwriteClient';
import { userRecipeService } from '../services/userRecipeService';
import { Query } from 'appwrite';
import { mealLoggingService } from '../services/mealLoggingService';
import { validatePassword } from '../utils/validation';
Expand Down Expand Up @@ -277,6 +278,75 @@ export const AuthProvider = ({ children }) => {
throw error;
}
};

const deleteAccount = async () => {
try {
if (!user) return;
const userId = user.$id;

// Best-effort cleanup of user data
try {
await userRecipeService.clearMealLogs(userId);
} catch (e) {
console.warn('Failed to clear meal logs during account deletion:', e);
}
try {
await userRecipeService.clearFavorites(userId);
} catch (e) {
console.warn('Failed to clear favorites during account deletion:', e);
}
try {
await deleteProfile();
} catch (e) {
console.warn('Failed to delete profile during account deletion:', e);
}

// End sessions and reset local state
try {
await account.deleteSessions();
} catch (e) {
console.warn('Failed to delete all sessions, continuing:', e);
}
try {
await account.deleteSession('current');
} catch (e) {
console.warn('Failed to delete current session, continuing:', e);
}

setUser(null);
setUserProfile(null);
mealLoggingService.setCurrentUser(null);
navigate('/');
} catch (error) {
console.error('Delete account flow failed:', error);
throw error;
}
};
const refreshUserSession = async () => {
try {
console.log('Refreshing user session...');
const currentUser = await account.get();
console.log('Session refreshed, user:', currentUser);
setUser(currentUser);
mealLoggingService.setCurrentUser(currentUser);
setError(null);

// Try to get user profile
try {
await getUserProfile(currentUser.$id);
} catch (profileError) {
console.warn('Failed to load profile after session refresh:', profileError);
}

return currentUser;
} catch (error) {
console.error('Failed to refresh user session:', error);
setUser(null);
setError(null);
throw error;
}
};

const guestLogin = async () => {
try {
setError(null);
Expand Down Expand Up @@ -324,9 +394,11 @@ export const AuthProvider = ({ children }) => {
logout,
signup,
guestLogin,
refreshUserSession,
updateProfile,
getUserProfile,
deleteProfile,
deleteAccount,
loading,
error,
isAuthenticated: !!user,
Expand Down
13 changes: 10 additions & 3 deletions src/pages/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { useAuth } from '../contexts/AuthContext';
import { Link } from 'react-router-dom';
const Settings = () => {
const { user, userProfile, updateProfile, logout } = useAuth();
const { user, userProfile, updateProfile, logout, deleteAccount } = useAuth();
const [activeTab, setActiveTab] = useState('profile');
const [isLoading, setIsLoading] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
Expand Down Expand Up @@ -208,7 +208,6 @@ const Settings = () => {
{activeTab === 'account' && (
<div className="space-y-6">
<h2 className="text-2xl font-bold text-[hsl(var(--card-foreground))] mb-6">Account Settings</h2>
<h2 className="text-2xl font-bold text-[hsl(var(--card-foreground))] mb-6">Account Settings</h2>
<div className="space-y-4">
<div className="bg-[hsl(var(--card))]/50 backdrop-blur-sm rounded-xl p-4 border border-[hsl(var(--border))]">
<h3 className="font-semibold text-[hsl(var(--card-foreground))] mb-2">Account Information</h3>
Expand Down Expand Up @@ -251,8 +250,16 @@ const Settings = () => {
Cancel
</button>
<button
onClick={() => {
onClick={async () => {
setShowDeleteConfirm(false);
setIsLoading(true);
try {
await deleteAccount();
} catch (e) {
alert('Failed to delete account. Please try again.');
} finally {
setIsLoading(false);
}
}}
className="flex-1 px-4 py-2 bg-[hsl(var(--destructive))] text-[hsl(var(--destructive-foreground))] rounded-lg hover:brightness-95"
>
Expand Down
20 changes: 20 additions & 0 deletions src/services/userRecipeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,26 @@ class UserRecipeService {
}
}

async clearFavorites(userId) {
try {
const response = await databases.listDocuments(
this.databaseId,
this.favoritesCollectionId,
[Query.equal('userId', userId)]
);

const deletePromises = response.documents.map(doc =>
databases.deleteDocument(this.databaseId, this.favoritesCollectionId, doc.$id)
);

await Promise.all(deletePromises);
console.log('🗑️ All favorites cleared from database');
} catch (error) {
console.error('Error clearing favorites from database:', error);
throw error;
}
}

// Helper methods
extractIngredientsText(recipe) {
if (recipe.ingredients && Array.isArray(recipe.ingredients)) {
Expand Down