delete profile & login redirect fixes

This commit is contained in:
2025-10-12 00:05:21 -04:00
parent 056841dc5e
commit c4674a4c85
4 changed files with 116 additions and 5 deletions

View File

@@ -20,7 +20,7 @@
</button>
<NuxtLink
v-else
to="/login"
:to="`/login?redirect=${encodeURIComponent(route.fullPath)}`"
class="px-4 py-2 text-sm font-medium text-green-700 bg-green-50 rounded-md hover:bg-green-100 whitespace-nowrap"
>
Log In
@@ -72,7 +72,7 @@
</button>
<NuxtLink
v-else
to="/login"
:to="`/login?redirect=${encodeURIComponent(route.fullPath)}`"
class="px-4 py-2 text-sm font-medium text-green-700 bg-green-50 rounded-md hover:bg-green-100 whitespace-nowrap"
>
Log In
@@ -204,7 +204,7 @@
<h3 class="text-lg font-medium text-gray-900 mb-2">Want to take notes?</h3>
<p class="text-gray-600 mb-4">Log in or create an account to save your sermon notes!</p>
<NuxtLink
to="/login"
:to="`/login?redirect=${encodeURIComponent(route.fullPath)}`"
class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 font-medium"
>
Log In

View File

@@ -222,7 +222,10 @@ async function handleLogin() {
})
if (response.success) {
await navigateTo('/')
// Check if there's a redirect parameter
const route = useRoute()
const redirect = route.query.redirect as string
await navigateTo(redirect || '/')
}
} catch (e: any) {
error.value = e.data?.message || 'Invalid credentials'
@@ -261,7 +264,10 @@ async function handleRegister() {
})
if (response.success) {
await navigateTo('/')
// Check if there's a redirect parameter
const route = useRoute()
const redirect = route.query.redirect as string
await navigateTo(redirect || '/')
}
} catch (e: any) {
error.value = e.data?.message || 'Registration failed'

View File

@@ -191,6 +191,58 @@
</NuxtLink>
</div>
</form>
<!-- Delete Profile Section -->
<div class="px-6 py-4 border-t border-gray-200 bg-red-50">
<h3 class="text-lg font-medium text-red-900 mb-2">Delete Profile</h3>
<p class="text-sm text-red-700 mb-4">
Warning: Deleting your profile will permanently remove your account and all sermon notes that you haven't emailed or downloaded. This action cannot be undone.
</p>
<button
@click="showDeleteConfirmation = true"
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
>
Delete My Profile
</button>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div
v-if="showDeleteConfirmation"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
@click.self="showDeleteConfirmation = false"
>
<div class="bg-white rounded-lg shadow-xl max-w-md w-full p-6">
<h3 class="text-xl font-bold text-gray-900 mb-4">Confirm Profile Deletion</h3>
<p class="text-gray-700 mb-4">
Are you absolutely sure you want to delete your profile? This will:
</p>
<ul class="list-disc list-inside text-gray-700 mb-6 space-y-2">
<li>Permanently delete your account</li>
<li>Remove all your sermon notes</li>
<li>Cannot be undone</li>
</ul>
<p class="text-sm text-red-600 font-semibold mb-6">
Make sure you have emailed or downloaded any notes you want to keep!
</p>
<div class="flex gap-4">
<button
@click="handleDeleteProfile"
:disabled="deleteLoading"
class="flex-1 px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 disabled:opacity-50"
>
{{ deleteLoading ? 'Deleting...' : 'Yes, Delete My Profile' }}
</button>
<button
@click="showDeleteConfirmation = false"
:disabled="deleteLoading"
class="flex-1 px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 disabled:opacity-50"
>
Cancel
</button>
</div>
</div>
</div>
</main>
@@ -219,6 +271,8 @@ const passwords = ref({
const error = ref('')
const success = ref('')
const loading = ref(false)
const showDeleteConfirmation = ref(false)
const deleteLoading = ref(false)
const passwordRequirements = computed(() => ({
minLength: passwords.value.new.length >= 8,
@@ -312,6 +366,24 @@ async function handleLogout() {
await navigateTo('/login')
}
async function handleDeleteProfile() {
deleteLoading.value = true
try {
await $fetch('/api/profile/delete', {
method: 'DELETE'
})
// Redirect to home page after successful deletion
await navigateTo('/')
} catch (e: any) {
error.value = e.data?.message || 'Failed to delete profile'
showDeleteConfirmation.value = false
} finally {
deleteLoading.value = false
}
}
onMounted(() => {
loadProfile()
})

View File

@@ -0,0 +1,33 @@
import { getDb } from '~/server/utils/database'
import { requireAuth } from '~/server/utils/auth'
export default defineEventHandler(async (event) => {
const user = await requireAuth(event)
const db = getDb()
try {
// Delete user's notes first (foreign key constraint)
db.prepare('DELETE FROM notes WHERE user_id = ?').run(user.id)
// Delete user's sessions
db.prepare('DELETE FROM sessions WHERE username = ?').run(user.username)
// Delete the user
db.prepare('DELETE FROM users WHERE id = ?').run(user.id)
// Clear the auth cookie
deleteCookie(event, 'session_token')
return {
success: true,
message: 'Profile deleted successfully'
}
} catch (error) {
console.error('Error deleting profile:', error)
throw createError({
statusCode: 500,
message: 'Failed to delete profile'
})
}
})