[feat] Add account deletion functionality to UserPanel component (#5216)

This commit is contained in:
Yoland Yan
2025-08-29 15:29:20 -07:00
committed by GitHub
parent 2bf92a0e57
commit 23d0362267
13 changed files with 141 additions and 10 deletions

View File

@@ -57,14 +57,23 @@
class="w-8 h-8 mt-4" class="w-8 h-8 mt-4"
style="--pc-spinner-color: #000" style="--pc-spinner-color: #000"
/> />
<Button <div v-else class="mt-4 flex flex-col gap-2">
v-else <Button
class="mt-4 w-32" class="w-32"
severity="secondary" severity="secondary"
:label="$t('auth.signOut.signOut')" :label="$t('auth.signOut.signOut')"
icon="pi pi-sign-out" icon="pi pi-sign-out"
@click="handleSignOut" @click="handleSignOut"
/> />
<Button
v-if="!isApiKeyLogin"
class="w-32"
severity="danger"
:label="$t('auth.deleteAccount.deleteAccount')"
icon="pi pi-trash"
@click="handleDeleteAccount"
/>
</div>
</div> </div>
<!-- Login Section --> <!-- Login Section -->
@@ -100,6 +109,7 @@ const dialogService = useDialogService()
const { const {
loading, loading,
isLoggedIn, isLoggedIn,
isApiKeyLogin,
isEmailProvider, isEmailProvider,
userDisplayName, userDisplayName,
userEmail, userEmail,
@@ -107,6 +117,7 @@ const {
providerName, providerName,
providerIcon, providerIcon,
handleSignOut, handleSignOut,
handleSignIn handleSignIn,
handleDeleteAccount
} = useCurrentUser() } = useCurrentUser()
</script> </script>

View File

@@ -1,5 +1,8 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { t } from '@/i18n'
import { useDialogService } from '@/services/dialogService'
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore' import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
import { useCommandStore } from '@/stores/commandStore' import { useCommandStore } from '@/stores/commandStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
@@ -8,6 +11,8 @@ export const useCurrentUser = () => {
const authStore = useFirebaseAuthStore() const authStore = useFirebaseAuthStore()
const commandStore = useCommandStore() const commandStore = useCommandStore()
const apiKeyStore = useApiKeyAuthStore() const apiKeyStore = useApiKeyAuthStore()
const dialogService = useDialogService()
const { deleteAccount } = useFirebaseAuthActions()
const firebaseUser = computed(() => authStore.currentUser) const firebaseUser = computed(() => authStore.currentUser)
const isApiKeyLogin = computed(() => apiKeyStore.isAuthenticated) const isApiKeyLogin = computed(() => apiKeyStore.isAuthenticated)
@@ -85,6 +90,18 @@ export const useCurrentUser = () => {
await commandStore.execute('Comfy.User.OpenSignInDialog') await commandStore.execute('Comfy.User.OpenSignInDialog')
} }
const handleDeleteAccount = async () => {
const confirmed = await dialogService.confirm({
title: t('auth.deleteAccount.confirmTitle'),
message: t('auth.deleteAccount.confirmMessage'),
type: 'delete'
})
if (confirmed) {
await deleteAccount()
}
}
return { return {
loading: authStore.loading, loading: authStore.loading,
isLoggedIn, isLoggedIn,
@@ -96,6 +113,7 @@ export const useCurrentUser = () => {
providerName, providerName,
providerIcon, providerIcon,
handleSignOut, handleSignOut,
handleSignIn handleSignIn,
handleDeleteAccount
} }
} }

View File

@@ -135,6 +135,16 @@ export const useFirebaseAuthActions = () => {
reportError reportError
) )
const deleteAccount = wrapWithErrorHandlingAsync(async () => {
await authStore.deleteAccount()
toastStore.add({
severity: 'success',
summary: t('auth.deleteAccount.success'),
detail: t('auth.deleteAccount.successDetail'),
life: 5000
})
}, reportError)
return { return {
logout, logout,
sendPasswordReset, sendPasswordReset,
@@ -146,6 +156,7 @@ export const useFirebaseAuthActions = () => {
signInWithEmail, signInWithEmail,
signUpWithEmail, signUpWithEmail,
updatePassword, updatePassword,
deleteAccount,
accessError accessError
} }
} }

View File

@@ -27,6 +27,15 @@
"title": "مفتاح API", "title": "مفتاح API",
"whitelistInfo": "حول المواقع غير المدرجة في القائمة البيضاء" "whitelistInfo": "حول المواقع غير المدرجة في القائمة البيضاء"
}, },
"deleteAccount": {
"cancel": "إلغاء",
"confirm": "حذف الحساب",
"confirmMessage": "هل أنت متأكد أنك تريد حذف حسابك؟ لا يمكن التراجع عن هذا الإجراء وسيتم حذف جميع بياناتك نهائيًا.",
"confirmTitle": "حذف الحساب",
"deleteAccount": "حذف الحساب",
"success": "تم حذف الحساب",
"successDetail": "تم حذف حسابك بنجاح."
},
"login": { "login": {
"andText": "و", "andText": "و",
"confirmPasswordLabel": "تأكيد كلمة المرور", "confirmPasswordLabel": "تأكيد كلمة المرور",

View File

@@ -1601,6 +1601,15 @@
"passwordUpdate": { "passwordUpdate": {
"success": "Password Updated", "success": "Password Updated",
"successDetail": "Your password has been updated successfully" "successDetail": "Your password has been updated successfully"
},
"deleteAccount": {
"deleteAccount": "Delete Account",
"confirmTitle": "Delete Account",
"confirmMessage": "Are you sure you want to delete your account? This action cannot be undone and will permanently remove all your data.",
"confirm": "Delete Account",
"cancel": "Cancel",
"success": "Account Deleted",
"successDetail": "Your account has been successfully deleted."
} }
}, },
"validation": { "validation": {

View File

@@ -27,6 +27,15 @@
"title": "Clave API", "title": "Clave API",
"whitelistInfo": "Acerca de los sitios no incluidos en la lista blanca" "whitelistInfo": "Acerca de los sitios no incluidos en la lista blanca"
}, },
"deleteAccount": {
"cancel": "Cancelar",
"confirm": "Eliminar cuenta",
"confirmMessage": "¿Estás seguro de que deseas eliminar tu cuenta? Esta acción no se puede deshacer y eliminará permanentemente todos tus datos.",
"confirmTitle": "Eliminar cuenta",
"deleteAccount": "Eliminar cuenta",
"success": "Cuenta eliminada",
"successDetail": "Tu cuenta ha sido eliminada exitosamente."
},
"login": { "login": {
"andText": "y", "andText": "y",
"confirmPasswordLabel": "Confirmar contraseña", "confirmPasswordLabel": "Confirmar contraseña",

View File

@@ -27,6 +27,15 @@
"title": "Clé API", "title": "Clé API",
"whitelistInfo": "À propos des sites non autorisés" "whitelistInfo": "À propos des sites non autorisés"
}, },
"deleteAccount": {
"cancel": "Annuler",
"confirm": "Supprimer le compte",
"confirmMessage": "Êtes-vous sûr de vouloir supprimer votre compte ? Cette action est irréversible et supprimera définitivement toutes vos données.",
"confirmTitle": "Supprimer le compte",
"deleteAccount": "Supprimer le compte",
"success": "Compte supprimé",
"successDetail": "Votre compte a été supprimé avec succès."
},
"login": { "login": {
"andText": "et", "andText": "et",
"confirmPasswordLabel": "Confirmer le mot de passe", "confirmPasswordLabel": "Confirmer le mot de passe",

View File

@@ -27,6 +27,15 @@
"title": "APIキー", "title": "APIキー",
"whitelistInfo": "ホワイトリストに登録されていないサイトについて" "whitelistInfo": "ホワイトリストに登録されていないサイトについて"
}, },
"deleteAccount": {
"cancel": "キャンセル",
"confirm": "アカウントを削除",
"confirmMessage": "本当にアカウントを削除しますか?この操作は元に戻せず、すべてのデータが完全に削除されます。",
"confirmTitle": "アカウントを削除",
"deleteAccount": "アカウントを削除",
"success": "アカウントが削除されました",
"successDetail": "アカウントは正常に削除されました。"
},
"login": { "login": {
"andText": "および", "andText": "および",
"confirmPasswordLabel": "パスワードの確認", "confirmPasswordLabel": "パスワードの確認",

View File

@@ -27,6 +27,15 @@
"title": "API 키", "title": "API 키",
"whitelistInfo": "비허용 사이트에 대하여" "whitelistInfo": "비허용 사이트에 대하여"
}, },
"deleteAccount": {
"cancel": "취소",
"confirm": "계정 삭제",
"confirmMessage": "정말로 계정을 삭제하시겠습니까? 이 작업은 되돌릴 수 없으며 모든 데이터가 영구적으로 삭제됩니다.",
"confirmTitle": "계정 삭제",
"deleteAccount": "계정 삭제",
"success": "계정이 삭제되었습니다",
"successDetail": "계정이 성공적으로 삭제되었습니다."
},
"login": { "login": {
"andText": "및", "andText": "및",
"confirmPasswordLabel": "비밀번호 확인", "confirmPasswordLabel": "비밀번호 확인",

View File

@@ -27,6 +27,15 @@
"title": "API-ключ", "title": "API-ключ",
"whitelistInfo": "О не включённых в белый список сайтах" "whitelistInfo": "О не включённых в белый список сайтах"
}, },
"deleteAccount": {
"cancel": "Отмена",
"confirm": "Удалить аккаунт",
"confirmMessage": "Вы уверены, что хотите удалить свой аккаунт? Это действие необратимо и приведёт к безвозвратному удалению всех ваших данных.",
"confirmTitle": "Удалить аккаунт",
"deleteAccount": "Удалить аккаунт",
"success": "Аккаунт удалён",
"successDetail": "Ваш аккаунт был успешно удалён."
},
"login": { "login": {
"andText": "и", "andText": "и",
"confirmPasswordLabel": "Подтвердите пароль", "confirmPasswordLabel": "Подтвердите пароль",

View File

@@ -27,6 +27,15 @@
"title": "API 金鑰", "title": "API 金鑰",
"whitelistInfo": "關於未列入白名單的網站" "whitelistInfo": "關於未列入白名單的網站"
}, },
"deleteAccount": {
"cancel": "取消",
"confirm": "刪除帳號",
"confirmMessage": "您確定要刪除您的帳號嗎?此操作無法復原,且將永久移除您所有的資料。",
"confirmTitle": "刪除帳號",
"deleteAccount": "刪除帳號",
"success": "帳號已刪除",
"successDetail": "您的帳號已成功刪除。"
},
"login": { "login": {
"andText": "以及", "andText": "以及",
"confirmPasswordLabel": "確認密碼", "confirmPasswordLabel": "確認密碼",

View File

@@ -27,6 +27,15 @@
"title": "API 密钥", "title": "API 密钥",
"whitelistInfo": "关于非白名单网站" "whitelistInfo": "关于非白名单网站"
}, },
"deleteAccount": {
"cancel": "取消",
"confirm": "删除账户",
"confirmMessage": "您确定要删除您的账户吗?此操作无法撤销,并且会永久删除您的所有数据。",
"confirmTitle": "删除账户",
"deleteAccount": "删除账户",
"success": "账户已删除",
"successDetail": "您的账户已成功删除。"
},
"login": { "login": {
"andText": "和", "andText": "和",
"confirmPasswordLabel": "确认密码", "confirmPasswordLabel": "确认密码",

View File

@@ -8,6 +8,7 @@ import {
type UserCredential, type UserCredential,
browserLocalPersistence, browserLocalPersistence,
createUserWithEmailAndPassword, createUserWithEmailAndPassword,
deleteUser,
onAuthStateChanged, onAuthStateChanged,
sendPasswordResetEmail, sendPasswordResetEmail,
setPersistence, setPersistence,
@@ -287,6 +288,14 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
await updatePassword(currentUser.value, newPassword) await updatePassword(currentUser.value, newPassword)
} }
/** Delete the current user account */
const _deleteAccount = async (): Promise<void> => {
if (!currentUser.value) {
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
}
await deleteUser(currentUser.value)
}
const addCredits = async ( const addCredits = async (
requestBodyContent: CreditPurchasePayload requestBodyContent: CreditPurchasePayload
): Promise<CreditPurchaseResponse> => { ): Promise<CreditPurchaseResponse> => {
@@ -385,6 +394,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
accessBillingPortal, accessBillingPortal,
sendPasswordReset, sendPasswordReset,
updatePassword: _updatePassword, updatePassword: _updatePassword,
deleteAccount: _deleteAccount,
getAuthHeader getAuthHeader
} }
}) })