mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
[Refactor] Split authStore into authStore and authService (#3612)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -69,7 +69,7 @@ import { computed, watch } from 'vue'
|
||||
import SearchBox from '@/components/common/SearchBox.vue'
|
||||
import { useSettingSearch } from '@/composables/setting/useSettingSearch'
|
||||
import { useSettingUI } from '@/composables/setting/useSettingUI'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
|
||||
import { SettingTreeNode } from '@/stores/settingStore'
|
||||
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
|
||||
import { flattenTree } from '@/utils/treeUtil'
|
||||
@@ -107,7 +107,7 @@ const {
|
||||
getSearchResults
|
||||
} = useSettingSearch()
|
||||
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const authService = useFirebaseAuthService()
|
||||
|
||||
// Sort groups for a category
|
||||
const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
|
||||
@@ -140,7 +140,7 @@ watch(activeCategory, (_, oldValue) => {
|
||||
activeCategory.value = oldValue
|
||||
}
|
||||
if (activeCategory.value?.key === 'credits') {
|
||||
void authStore.fetchBalance()
|
||||
void authService.fetchBalance()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -109,8 +109,9 @@ import ProgressSpinner from 'primevue/progressspinner'
|
||||
import Tag from 'primevue/tag'
|
||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { formatMetronomeCurrency, usdToMicros } from '@/utils/formatUtil'
|
||||
import { formatMetronomeCurrency } from '@/utils/formatUtil'
|
||||
|
||||
const {
|
||||
isInsufficientCredits = false,
|
||||
@@ -123,6 +124,7 @@ const {
|
||||
}>()
|
||||
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const authService = useFirebaseAuthService()
|
||||
const customAmount = ref<number>(100)
|
||||
const didClickBuyNow = ref(false)
|
||||
const loading = computed(() => authStore.loading)
|
||||
@@ -133,29 +135,18 @@ const formattedBalance = computed(() => {
|
||||
})
|
||||
|
||||
const handleSeeDetails = async () => {
|
||||
const response = await authStore.accessBillingPortal()
|
||||
if (!response?.billing_portal_url) return
|
||||
window.open(response.billing_portal_url, '_blank')
|
||||
await authService.accessBillingPortal()
|
||||
}
|
||||
|
||||
const handleBuyNow = async (amount: number) => {
|
||||
const response = await authStore.initiateCreditPurchase({
|
||||
amount_micros: usdToMicros(amount),
|
||||
currency: 'usd'
|
||||
})
|
||||
|
||||
if (!response?.checkout_url) return
|
||||
|
||||
await authService.purchaseCredits(amount)
|
||||
didClickBuyNow.value = true
|
||||
|
||||
// Go to Stripe checkout page
|
||||
window.open(response.checkout_url, '_blank')
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (didClickBuyNow.value) {
|
||||
// If clicked buy now, then returned back to the dialog and closed, fetch the balance
|
||||
void authStore.fetchBalance()
|
||||
void authService.fetchBalance()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
text
|
||||
size="small"
|
||||
severity="secondary"
|
||||
@click="() => authStore.fetchBalance()"
|
||||
@click="() => authService.fetchBalance()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,6 +128,7 @@ import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { formatMetronomeCurrency } from '@/utils/formatUtil'
|
||||
|
||||
@@ -141,6 +142,7 @@ interface CreditHistoryItemData {
|
||||
const { t } = useI18n()
|
||||
const dialogService = useDialogService()
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const authService = useFirebaseAuthService()
|
||||
const loading = computed(() => authStore.loading)
|
||||
const balanceLoading = computed(() => authStore.isFetchingBalance)
|
||||
const formattedBalance = computed(() => {
|
||||
@@ -159,13 +161,7 @@ const handlePurchaseCreditsClick = () => {
|
||||
}
|
||||
|
||||
const handleCreditsHistoryClick = async () => {
|
||||
const response = await authStore.accessBillingPortal()
|
||||
if (!response) return
|
||||
|
||||
const { billing_portal_url } = response
|
||||
if (billing_portal_url) {
|
||||
window.open(billing_portal_url, '_blank')
|
||||
}
|
||||
await authService.accessBillingPortal()
|
||||
}
|
||||
|
||||
const handleMessageSupport = () => {
|
||||
|
||||
@@ -81,14 +81,14 @@ import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { type SignInData, signInSchema } from '@/schemas/signInSchema'
|
||||
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const firebaseAuthService = useFirebaseAuthService()
|
||||
const loading = computed(() => authStore.loading)
|
||||
|
||||
const { t } = useI18n()
|
||||
const toast = useToastStore()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: SignInData]
|
||||
@@ -102,19 +102,6 @@ const onSubmit = (event: FormSubmitEvent) => {
|
||||
|
||||
const handleForgotPassword = async (email: string) => {
|
||||
if (!email) return
|
||||
await authStore.sendPasswordReset(email)
|
||||
if (authStore.error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('auth.login.forgotPasswordError'),
|
||||
detail: authStore.error
|
||||
})
|
||||
} else {
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: t('auth.login.passwordResetSent'),
|
||||
detail: t('auth.login.passwordResetSentDetail')
|
||||
})
|
||||
}
|
||||
await firebaseAuthService.sendPasswordReset(email)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -13,10 +13,10 @@ import { t } from '@/i18n'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
|
||||
import { useLitegraphService } from '@/services/litegraphService'
|
||||
import { useWorkflowService } from '@/services/workflowService'
|
||||
import type { ComfyCommand } from '@/stores/commandStore'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { useTitleEditorStore } from '@/stores/graphStore'
|
||||
import { useQueueSettingsStore, useQueueStore } from '@/stores/queueStore'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
@@ -32,7 +32,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const dialogService = useDialogService()
|
||||
const colorPaletteStore = useColorPaletteStore()
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const firebaseAuthService = useFirebaseAuthService()
|
||||
const toastStore = useToastStore()
|
||||
const getTracker = () => workflowStore.activeWorkflow?.changeTracker
|
||||
|
||||
@@ -649,17 +649,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
label: 'Sign Out',
|
||||
versionAdded: '1.18.1',
|
||||
function: async () => {
|
||||
await authStore.logout()
|
||||
if (authStore.error) {
|
||||
toastStore.addAlert(authStore.error)
|
||||
} else {
|
||||
toastStore.add({
|
||||
severity: 'success',
|
||||
summary: t('auth.signOut.success'),
|
||||
detail: t('auth.signOut.successDetail'),
|
||||
life: 5000
|
||||
})
|
||||
}
|
||||
await firebaseAuthService.logout()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"updateAvailable": "Update Available",
|
||||
"login": "Login",
|
||||
"learnMore": "Learn more",
|
||||
"amount": "Amount"
|
||||
"amount": "Amount",
|
||||
"unknownError": "Unknown error"
|
||||
},
|
||||
"manager": {
|
||||
"title": "Custom Nodes Manager",
|
||||
@@ -1077,7 +1078,14 @@
|
||||
"errorCopyImage": "Error copying image: {error}",
|
||||
"noTemplatesToExport": "No templates to export",
|
||||
"failedToFetchLogs": "Failed to fetch server logs",
|
||||
"migrateToLitegraphReroute": "Reroute nodes will be removed in future versions. Click to migrate to litegraph-native reroute."
|
||||
"migrateToLitegraphReroute": "Reroute nodes will be removed in future versions. Click to migrate to litegraph-native reroute.",
|
||||
"userNotAuthenticated": "User not authenticated",
|
||||
"firebaseAuthNotInitialized": "Firebase Auth not initialized",
|
||||
"failedToFetchBalance": "Failed to fetch balance: {error}",
|
||||
"failedToCreateCustomer": "Failed to create customer: {error}",
|
||||
"failedToInitiateCreditPurchase": "Failed to initiate credit purchase: {error}",
|
||||
"failedToAccessBillingPortal": "Failed to access billing portal: {error}",
|
||||
"failedToPurchaseCredits": "Failed to purchase credits: {error}"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
@@ -1104,8 +1112,7 @@
|
||||
"andText": "and",
|
||||
"privacyLink": "Privacy Policy",
|
||||
"success": "Login successful",
|
||||
"failed": "Login failed",
|
||||
"genericErrorMessage": "Sorry, we've encountered an error. Please contact {supportEmail}."
|
||||
"failed": "Login failed"
|
||||
},
|
||||
"signup": {
|
||||
"title": "Create an account",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "Inicio de sesión fallido",
|
||||
"forgotPassword": "¿Olvidaste tu contraseña?",
|
||||
"forgotPasswordError": "No se pudo enviar el correo electrónico para restablecer la contraseña",
|
||||
"genericErrorMessage": "Lo sentimos, hemos encontrado un error. Por favor, contacta con {supportEmail}.",
|
||||
"loginButton": "Iniciar sesión",
|
||||
"loginWithGithub": "Iniciar sesión con Github",
|
||||
"loginWithGoogle": "Iniciar sesión con Google",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "Éxito",
|
||||
"systemInfo": "Información del sistema",
|
||||
"terminal": "Terminal",
|
||||
"unknownError": "Error desconocido",
|
||||
"update": "Actualizar",
|
||||
"updateAvailable": "Actualización Disponible",
|
||||
"updated": "Actualizado",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "Error al copiar la imagen: {error}",
|
||||
"errorLoadingModel": "Error al cargar el modelo",
|
||||
"errorSaveSetting": "Error al guardar la configuración {id}: {err}",
|
||||
"failedToAccessBillingPortal": "No se pudo acceder al portal de facturación: {error}",
|
||||
"failedToApplyTexture": "Error al aplicar textura",
|
||||
"failedToCreateCustomer": "No se pudo crear el cliente: {error}",
|
||||
"failedToDownloadFile": "Error al descargar el archivo",
|
||||
"failedToExportModel": "Error al exportar modelo como {format}",
|
||||
"failedToFetchBalance": "No se pudo obtener el saldo: {error}",
|
||||
"failedToFetchLogs": "Error al obtener los registros del servidor",
|
||||
"failedToInitiateCreditPurchase": "No se pudo iniciar la compra de créditos: {error}",
|
||||
"failedToPurchaseCredits": "No se pudo comprar créditos: {error}",
|
||||
"fileLoadError": "No se puede encontrar el flujo de trabajo en {fileName}",
|
||||
"fileUploadFailed": "Error al subir el archivo",
|
||||
"firebaseAuthNotInitialized": "Firebase Auth no está inicializado",
|
||||
"interrupted": "La ejecución ha sido interrumpida",
|
||||
"migrateToLitegraphReroute": "Los nodos de reroute se eliminarán en futuras versiones. Haz clic para migrar a reroute nativo de litegraph.",
|
||||
"no3dScene": "No hay escena 3D para aplicar textura",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "Tareas pendientes eliminadas",
|
||||
"pleaseSelectNodesToGroup": "Por favor, seleccione los nodos (u otros grupos) para crear un grupo para",
|
||||
"unableToGetModelFilePath": "No se puede obtener la ruta del archivo del modelo",
|
||||
"updateRequested": "Actualización solicitada"
|
||||
"updateRequested": "Actualización solicitada",
|
||||
"userNotAuthenticated": "Usuario no autenticado"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "Introduce un nombre de usuario",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "Échec de la connexion",
|
||||
"forgotPassword": "Mot de passe oublié?",
|
||||
"forgotPasswordError": "Échec de l'envoi de l'e-mail de réinitialisation du mot de passe",
|
||||
"genericErrorMessage": "Désolé, une erreur s'est produite. Veuillez contacter {supportEmail}.",
|
||||
"loginButton": "Se connecter",
|
||||
"loginWithGithub": "Se connecter avec Github",
|
||||
"loginWithGoogle": "Se connecter avec Google",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "Succès",
|
||||
"systemInfo": "Informations système",
|
||||
"terminal": "Terminal",
|
||||
"unknownError": "Erreur inconnue",
|
||||
"update": "Mettre à jour",
|
||||
"updateAvailable": "Mise à jour disponible",
|
||||
"updated": "Mis à jour",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "Erreur lors de la copie de l'image: {error}",
|
||||
"errorLoadingModel": "Erreur lors du chargement du modèle",
|
||||
"errorSaveSetting": "Erreur lors de l'enregistrement du paramètre {id}: {err}",
|
||||
"failedToAccessBillingPortal": "Échec de l'accès au portail de facturation : {error}",
|
||||
"failedToApplyTexture": "Échec de l'application de la texture",
|
||||
"failedToCreateCustomer": "Échec de la création du client : {error}",
|
||||
"failedToDownloadFile": "Échec du téléchargement du fichier",
|
||||
"failedToExportModel": "Échec de l'exportation du modèle en {format}",
|
||||
"failedToFetchBalance": "Échec de la récupération du solde : {error}",
|
||||
"failedToFetchLogs": "Échec de la récupération des journaux du serveur",
|
||||
"failedToInitiateCreditPurchase": "Échec de l'initiation de l'achat de crédits : {error}",
|
||||
"failedToPurchaseCredits": "Échec de l'achat de crédits : {error}",
|
||||
"fileLoadError": "Impossible de trouver le flux de travail dans {fileName}",
|
||||
"fileUploadFailed": "Échec du téléchargement du fichier",
|
||||
"firebaseAuthNotInitialized": "Authentification Firebase non initialisée",
|
||||
"interrupted": "L'exécution a été interrompue",
|
||||
"migrateToLitegraphReroute": "Les nœuds de reroute seront supprimés dans les futures versions. Cliquez pour migrer vers le reroute natif de litegraph.",
|
||||
"no3dScene": "Aucune scène 3D pour appliquer la texture",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "Tâches en attente supprimées",
|
||||
"pleaseSelectNodesToGroup": "Veuillez sélectionner les nœuds (ou autres groupes) pour créer un groupe pour",
|
||||
"unableToGetModelFilePath": "Impossible d'obtenir le chemin du fichier modèle",
|
||||
"updateRequested": "Mise à jour demandée"
|
||||
"updateRequested": "Mise à jour demandée",
|
||||
"userNotAuthenticated": "Utilisateur non authentifié"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "Entrez un nom d'utilisateur",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "ログイン失敗",
|
||||
"forgotPassword": "パスワードを忘れましたか?",
|
||||
"forgotPasswordError": "パスワードリセット用メールの送信に失敗しました",
|
||||
"genericErrorMessage": "申し訳ありませんが、エラーが発生しました。{supportEmail} までご連絡ください。",
|
||||
"loginButton": "ログイン",
|
||||
"loginWithGithub": "Githubでログイン",
|
||||
"loginWithGoogle": "Googleでログイン",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "成功",
|
||||
"systemInfo": "システム情報",
|
||||
"terminal": "ターミナル",
|
||||
"unknownError": "不明なエラー",
|
||||
"update": "更新",
|
||||
"updateAvailable": "更新が利用可能",
|
||||
"updated": "更新済み",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "画像のコピーにエラーが発生しました: {error}",
|
||||
"errorLoadingModel": "モデルの読み込みエラー",
|
||||
"errorSaveSetting": "設定{id}の保存エラー: {err}",
|
||||
"failedToAccessBillingPortal": "請求ポータルへのアクセスに失敗しました: {error}",
|
||||
"failedToApplyTexture": "テクスチャの適用に失敗しました",
|
||||
"failedToCreateCustomer": "顧客の作成に失敗しました: {error}",
|
||||
"failedToDownloadFile": "ファイルのダウンロードに失敗しました",
|
||||
"failedToExportModel": "{format}としてモデルのエクスポートに失敗しました",
|
||||
"failedToFetchBalance": "残高の取得に失敗しました: {error}",
|
||||
"failedToFetchLogs": "サーバーログの取得に失敗しました",
|
||||
"failedToInitiateCreditPurchase": "クレジット購入の開始に失敗しました: {error}",
|
||||
"failedToPurchaseCredits": "クレジットの購入に失敗しました: {error}",
|
||||
"fileLoadError": "{fileName}でワークフローが見つかりません",
|
||||
"fileUploadFailed": "ファイルのアップロードに失敗しました",
|
||||
"firebaseAuthNotInitialized": "Firebase認証が初期化されていません",
|
||||
"interrupted": "実行が中断されました",
|
||||
"migrateToLitegraphReroute": "将来のバージョンではRerouteノードが削除されます。litegraph-native rerouteに移行するにはクリックしてください。",
|
||||
"no3dScene": "テクスチャを適用する3Dシーンがありません",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "保留中のタスクが削除されました",
|
||||
"pleaseSelectNodesToGroup": "グループを作成するためのノード(または他のグループ)を選択してください",
|
||||
"unableToGetModelFilePath": "モデルファイルのパスを取得できません",
|
||||
"updateRequested": "更新が要求されました"
|
||||
"updateRequested": "更新が要求されました",
|
||||
"userNotAuthenticated": "ユーザーが認証されていません"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "ユーザー名を入力してください",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "로그인 실패",
|
||||
"forgotPassword": "비밀번호를 잊으셨나요?",
|
||||
"forgotPasswordError": "비밀번호 재설정 이메일 전송에 실패했습니다",
|
||||
"genericErrorMessage": "죄송합니다. 오류가 발생했습니다. {supportEmail}로 문의해 주세요.",
|
||||
"loginButton": "로그인",
|
||||
"loginWithGithub": "Github로 로그인",
|
||||
"loginWithGoogle": "구글로 로그인",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "성공",
|
||||
"systemInfo": "시스템 정보",
|
||||
"terminal": "터미널",
|
||||
"unknownError": "알 수 없는 오류",
|
||||
"update": "업데이트",
|
||||
"updateAvailable": "업데이트 가능",
|
||||
"updated": "업데이트 됨",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "이미지 복사 오류: {error}",
|
||||
"errorLoadingModel": "모델 로딩 오류",
|
||||
"errorSaveSetting": "설정 {id} 저장 오류: {err}",
|
||||
"failedToAccessBillingPortal": "결제 포털에 접근하지 못했습니다: {error}",
|
||||
"failedToApplyTexture": "텍스처 적용에 실패했습니다",
|
||||
"failedToCreateCustomer": "고객 생성에 실패했습니다: {error}",
|
||||
"failedToDownloadFile": "파일 다운로드에 실패했습니다",
|
||||
"failedToExportModel": "{format} 형식으로 모델 내보내기에 실패했습니다",
|
||||
"failedToFetchBalance": "잔액을 가져오지 못했습니다: {error}",
|
||||
"failedToFetchLogs": "서버 로그를 가져오는 데 실패했습니다",
|
||||
"failedToInitiateCreditPurchase": "크레딧 구매를 시작하지 못했습니다: {error}",
|
||||
"failedToPurchaseCredits": "크레딧 구매에 실패했습니다: {error}",
|
||||
"fileLoadError": "{fileName}에서 워크플로우를 찾을 수 없습니다",
|
||||
"fileUploadFailed": "파일 업로드에 실패했습니다",
|
||||
"firebaseAuthNotInitialized": "Firebase 인증이 초기화되지 않았습니다",
|
||||
"interrupted": "실행이 중단되었습니다",
|
||||
"migrateToLitegraphReroute": "향후 버전에서는 Reroute 노드가 제거됩니다. LiteGraph 에서 자체 제공하는 경유점으로 변환하려면 클릭하세요.",
|
||||
"no3dScene": "텍스처를 적용할 3D 장면이 없습니다",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "보류 중인 작업이 삭제되었습니다",
|
||||
"pleaseSelectNodesToGroup": "그룹을 만들기 위해 노드(또는 다른 그룹)를 선택해 주세요",
|
||||
"unableToGetModelFilePath": "모델 파일 경로를 가져올 수 없습니다",
|
||||
"updateRequested": "업데이트 요청됨"
|
||||
"updateRequested": "업데이트 요청됨",
|
||||
"userNotAuthenticated": "사용자가 인증되지 않았습니다"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "사용자 이름 입력",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "Вход не удался",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"forgotPasswordError": "Не удалось отправить письмо для сброса пароля",
|
||||
"genericErrorMessage": "Извините, произошла ошибка. Пожалуйста, свяжитесь с {supportEmail}.",
|
||||
"loginButton": "Войти",
|
||||
"loginWithGithub": "Войти через Github",
|
||||
"loginWithGoogle": "Войти через Google",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "Успех",
|
||||
"systemInfo": "Информация о системе",
|
||||
"terminal": "Терминал",
|
||||
"unknownError": "Неизвестная ошибка",
|
||||
"update": "Обновить",
|
||||
"updateAvailable": "Доступно обновление",
|
||||
"updated": "Обновлено",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "Ошибка копирования изображения: {error}",
|
||||
"errorLoadingModel": "Ошибка загрузки модели",
|
||||
"errorSaveSetting": "Ошибка сохранения настройки {id}: {err}",
|
||||
"failedToAccessBillingPortal": "Не удалось получить доступ к биллинговому порталу: {error}",
|
||||
"failedToApplyTexture": "Не удалось применить текстуру",
|
||||
"failedToCreateCustomer": "Не удалось создать клиента: {error}",
|
||||
"failedToDownloadFile": "Не удалось скачать файл",
|
||||
"failedToExportModel": "Не удалось экспортировать модель как {format}",
|
||||
"failedToFetchBalance": "Не удалось получить баланс: {error}",
|
||||
"failedToFetchLogs": "Не удалось получить серверные логи",
|
||||
"failedToInitiateCreditPurchase": "Не удалось начать покупку кредитов: {error}",
|
||||
"failedToPurchaseCredits": "Не удалось купить кредиты: {error}",
|
||||
"fileLoadError": "Не удалось найти рабочий процесс в {fileName}",
|
||||
"fileUploadFailed": "Не удалось загрузить файл",
|
||||
"firebaseAuthNotInitialized": "Firebase Auth не инициализирован",
|
||||
"interrupted": "Выполнение было прервано",
|
||||
"migrateToLitegraphReroute": "Узлы перенаправления будут удалены в будущих версиях. Нажмите, чтобы перейти на litegraph-native reroute.",
|
||||
"no3dScene": "Нет 3D сцены для применения текстуры",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "Ожидающие задачи удалены",
|
||||
"pleaseSelectNodesToGroup": "Пожалуйста, выберите узлы (или другие группы) для создания группы",
|
||||
"unableToGetModelFilePath": "Не удалось получить путь к файлу модели",
|
||||
"updateRequested": "Запрошено обновление"
|
||||
"updateRequested": "Запрошено обновление",
|
||||
"userNotAuthenticated": "Пользователь не аутентифицирован"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "Введите имя пользователя",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"failed": "登录失败",
|
||||
"forgotPassword": "忘记密码?",
|
||||
"forgotPasswordError": "发送重置密码邮件失败",
|
||||
"genericErrorMessage": "抱歉,我们遇到了一些错误。请联系 {supportEmail}。",
|
||||
"loginButton": "登录",
|
||||
"loginWithGithub": "使用Github登录",
|
||||
"loginWithGoogle": "使用Google登录",
|
||||
@@ -297,6 +296,7 @@
|
||||
"success": "成功",
|
||||
"systemInfo": "系统信息",
|
||||
"terminal": "终端",
|
||||
"unknownError": "未知错误",
|
||||
"update": "更新",
|
||||
"updateAvailable": "有更新可用",
|
||||
"updated": "已更新",
|
||||
@@ -1108,12 +1108,18 @@
|
||||
"errorCopyImage": "复制图片出错:{error}",
|
||||
"errorLoadingModel": "加载模型出错",
|
||||
"errorSaveSetting": "保存设置 {id} 出错:{err}",
|
||||
"failedToAccessBillingPortal": "访问账单门户失败:{error}",
|
||||
"failedToApplyTexture": "应用纹理失败",
|
||||
"failedToCreateCustomer": "创建客户失败:{error}",
|
||||
"failedToDownloadFile": "文件下载失败",
|
||||
"failedToExportModel": "无法将模型导出为 {format}",
|
||||
"failedToFetchBalance": "获取余额失败:{error}",
|
||||
"failedToFetchLogs": "无法获取服务器日志",
|
||||
"failedToInitiateCreditPurchase": "发起积分购买失败:{error}",
|
||||
"failedToPurchaseCredits": "购买积分失败:{error}",
|
||||
"fileLoadError": "无法在 {fileName} 中找到工作流",
|
||||
"fileUploadFailed": "文件上传失败",
|
||||
"firebaseAuthNotInitialized": "Firebase 认证未初始化",
|
||||
"interrupted": "执行已被中断",
|
||||
"migrateToLitegraphReroute": "将来的版本中将删除重定向节点。点击以迁移到litegraph-native重定向。",
|
||||
"no3dScene": "没有3D场景可以应用纹理",
|
||||
@@ -1124,7 +1130,8 @@
|
||||
"pendingTasksDeleted": "待处理任务已删除",
|
||||
"pleaseSelectNodesToGroup": "请选取节点(或其他组)以创建分组",
|
||||
"unableToGetModelFilePath": "无法获取模型文件路径",
|
||||
"updateRequested": "已请求更新"
|
||||
"updateRequested": "已请求更新",
|
||||
"userNotAuthenticated": "用户未认证"
|
||||
},
|
||||
"userSelect": {
|
||||
"enterUsername": "输入用户名",
|
||||
|
||||
90
src/services/firebaseAuthService.ts
Normal file
90
src/services/firebaseAuthService.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useErrorHandling } from '@/composables/useErrorHandling'
|
||||
import { t } from '@/i18n'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import { usdToMicros } from '@/utils/formatUtil'
|
||||
|
||||
/**
|
||||
* Service for Firebase Auth actions.
|
||||
* All actions are wrapped with error handling.
|
||||
* @returns {Object} - Object containing all Firebase Auth actions
|
||||
*/
|
||||
export const useFirebaseAuthService = () => {
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const toastStore = useToastStore()
|
||||
const { wrapWithErrorHandlingAsync } = useErrorHandling()
|
||||
|
||||
const reportError = (error: unknown) => {
|
||||
toastStore.add({
|
||||
severity: 'error',
|
||||
summary: t('g.error'),
|
||||
detail: error instanceof Error ? error.message : t('g.unknownError'),
|
||||
life: 5000
|
||||
})
|
||||
}
|
||||
|
||||
const logout = wrapWithErrorHandlingAsync(async () => {
|
||||
await authStore.logout()
|
||||
toastStore.add({
|
||||
severity: 'success',
|
||||
summary: t('auth.signOut.success'),
|
||||
detail: t('auth.signOut.successDetail'),
|
||||
life: 5000
|
||||
})
|
||||
}, reportError)
|
||||
|
||||
const sendPasswordReset = wrapWithErrorHandlingAsync(
|
||||
async (email: string) => {
|
||||
await authStore.sendPasswordReset(email)
|
||||
toastStore.add({
|
||||
severity: 'success',
|
||||
summary: t('auth.login.passwordResetSent'),
|
||||
detail: t('auth.login.passwordResetSentDetail'),
|
||||
life: 5000
|
||||
})
|
||||
},
|
||||
reportError
|
||||
)
|
||||
|
||||
const purchaseCredits = wrapWithErrorHandlingAsync(async (amount: number) => {
|
||||
const response = await authStore.initiateCreditPurchase({
|
||||
amount_micros: usdToMicros(amount),
|
||||
currency: 'usd'
|
||||
})
|
||||
|
||||
if (!response.checkout_url) {
|
||||
throw new Error(
|
||||
t('toastMessages.failedToPurchaseCredits', {
|
||||
error: 'No checkout URL returned'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Go to Stripe checkout page
|
||||
window.open(response.checkout_url, '_blank')
|
||||
}, reportError)
|
||||
|
||||
const accessBillingPortal = wrapWithErrorHandlingAsync(async () => {
|
||||
const response = await authStore.accessBillingPortal()
|
||||
if (!response.billing_portal_url) {
|
||||
throw new Error(
|
||||
t('toastMessages.failedToAccessBillingPortal', {
|
||||
error: 'No billing portal URL returned'
|
||||
})
|
||||
)
|
||||
}
|
||||
window.open(response.billing_portal_url, '_blank')
|
||||
}, reportError)
|
||||
|
||||
const fetchBalance = wrapWithErrorHandlingAsync(async () => {
|
||||
await authStore.fetchBalance()
|
||||
}, reportError)
|
||||
|
||||
return {
|
||||
logout,
|
||||
sendPasswordReset,
|
||||
purchaseCredits,
|
||||
accessBillingPortal,
|
||||
fetchBalance
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,6 @@ import { COMFY_API_BASE_URL } from '@/config/comfyApi'
|
||||
import { t } from '@/i18n'
|
||||
import { operations } from '@/types/comfyRegistryTypes'
|
||||
|
||||
import { useToastStore } from './toastStore'
|
||||
|
||||
type CreditPurchaseResponse =
|
||||
operations['InitiateCreditPurchase']['responses']['201']['content']['application/json']
|
||||
type CreditPurchasePayload =
|
||||
@@ -36,10 +34,16 @@ type AccessBillingPortalResponse =
|
||||
type AccessBillingPortalReqBody =
|
||||
operations['AccessBillingPortal']['requestBody']
|
||||
|
||||
export class FirebaseAuthStoreError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message)
|
||||
this.name = 'FirebaseAuthStoreError'
|
||||
}
|
||||
}
|
||||
|
||||
export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
// State
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const currentUser = ref<User | null>(null)
|
||||
const isInitialized = ref(false)
|
||||
const customerCreated = ref(false)
|
||||
@@ -75,16 +79,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
lastBalanceUpdateTime.value = null
|
||||
})
|
||||
|
||||
const showAuthErrorToast = () => {
|
||||
useToastStore().add({
|
||||
summary: t('g.error'),
|
||||
detail: t('auth.login.genericErrorMessage', {
|
||||
supportEmail: 'support@comfy.org'
|
||||
}),
|
||||
severity: 'error'
|
||||
})
|
||||
}
|
||||
|
||||
const getIdToken = async (): Promise<string | null> => {
|
||||
if (currentUser.value) {
|
||||
return currentUser.value.getIdToken()
|
||||
@@ -97,9 +91,10 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
try {
|
||||
const token = await getIdToken()
|
||||
if (!token) {
|
||||
error.value = 'Cannot fetch balance: User not authenticated'
|
||||
isFetchingBalance.value = false
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.userNotAuthenticated')
|
||||
)
|
||||
}
|
||||
|
||||
const response = await fetch(`${COMFY_API_BASE_URL}/customers/balance`, {
|
||||
@@ -114,8 +109,11 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
return null
|
||||
}
|
||||
const errorData = await response.json()
|
||||
error.value = `Failed to fetch balance: ${errorData.message}`
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.failedToFetchBalance', {
|
||||
error: errorData.message
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const balanceData = await response.json()
|
||||
@@ -123,9 +121,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
lastBalanceUpdateTime.value = new Date()
|
||||
balance.value = balanceData
|
||||
return balanceData
|
||||
} catch (e) {
|
||||
error.value = `Failed to fetch balance: ${e}`
|
||||
return null
|
||||
} finally {
|
||||
isFetchingBalance.value = false
|
||||
}
|
||||
@@ -142,15 +137,21 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
})
|
||||
if (!createCustomerRes.ok) {
|
||||
throw new Error(
|
||||
`Failed to create customer: ${createCustomerRes.statusText}`
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.failedToCreateCustomer', {
|
||||
error: createCustomerRes.statusText
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const createCustomerResJson: CreateCustomerResponse =
|
||||
await createCustomerRes.json()
|
||||
if (!createCustomerResJson?.id) {
|
||||
throw new Error('Failed to create customer: No customer ID returned')
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.failedToCreateCustomer', {
|
||||
error: 'No customer ID returned'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return createCustomerResJson
|
||||
@@ -162,10 +163,12 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
createCustomer?: boolean
|
||||
} = {}
|
||||
): Promise<T> => {
|
||||
if (!auth) throw new Error('Firebase Auth not initialized')
|
||||
if (!auth)
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.firebaseAuthNotInitialized')
|
||||
)
|
||||
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const result = await action(auth)
|
||||
@@ -180,10 +183,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
|
||||
return result
|
||||
} catch (e: unknown) {
|
||||
error.value = e instanceof Error ? e.message : 'Unknown error'
|
||||
showAuthErrorToast()
|
||||
throw e
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -232,11 +231,10 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
|
||||
const addCredits = async (
|
||||
requestBodyContent: CreditPurchasePayload
|
||||
): Promise<CreditPurchaseResponse | null> => {
|
||||
): Promise<CreditPurchaseResponse> => {
|
||||
const token = await getIdToken()
|
||||
if (!token) {
|
||||
error.value = 'Cannot add credits: User not authenticated'
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
|
||||
}
|
||||
|
||||
// Ensure customer was created during login/registration
|
||||
@@ -256,9 +254,11 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
error.value = `Failed to initiate credit purchase: ${errorData.message}`
|
||||
showAuthErrorToast()
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.failedToInitiateCreditPurchase', {
|
||||
error: errorData.message
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
@@ -266,16 +266,15 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
|
||||
const initiateCreditPurchase = async (
|
||||
requestBodyContent: CreditPurchasePayload
|
||||
): Promise<CreditPurchaseResponse | null> =>
|
||||
): Promise<CreditPurchaseResponse> =>
|
||||
executeAuthAction((_) => addCredits(requestBodyContent))
|
||||
|
||||
const accessBillingPortal = async (
|
||||
requestBody?: AccessBillingPortalReqBody
|
||||
): Promise<AccessBillingPortalResponse | null> => {
|
||||
): Promise<AccessBillingPortalResponse> => {
|
||||
const token = await getIdToken()
|
||||
if (!token) {
|
||||
error.value = 'Cannot access billing portal: User not authenticated'
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
|
||||
}
|
||||
|
||||
const response = await fetch(`${COMFY_API_BASE_URL}/customers/billing`, {
|
||||
@@ -291,9 +290,11 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
error.value = `Failed to access billing portal: ${errorData.message}`
|
||||
showAuthErrorToast()
|
||||
return null
|
||||
throw new FirebaseAuthStoreError(
|
||||
t('toastMessages.failedToAccessBillingPortal', {
|
||||
error: errorData.message
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
@@ -302,7 +303,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
return {
|
||||
// State
|
||||
loading,
|
||||
error,
|
||||
currentUser,
|
||||
isInitialized,
|
||||
balance,
|
||||
|
||||
@@ -135,7 +135,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
expect(store.userEmail).toBe('test@example.com')
|
||||
expect(store.userId).toBe('test-user-id')
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
it('should set persistence to local storage on initialization', () => {
|
||||
@@ -158,17 +157,12 @@ describe('useFirebaseAuthStore', () => {
|
||||
// Error expected
|
||||
}
|
||||
|
||||
expect(store.error).toBe('Invalid password')
|
||||
|
||||
// Now, succeed on next attempt
|
||||
vi.mocked(firebaseAuth.signInWithEmailAndPassword).mockResolvedValueOnce({
|
||||
user: mockUser
|
||||
} as any)
|
||||
|
||||
await store.login('test@example.com', 'correct-password')
|
||||
|
||||
// Error should be cleared
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
describe('login', () => {
|
||||
@@ -187,7 +181,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
)
|
||||
expect(result).toEqual(mockUserCredential)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
it('should handle login errors', async () => {
|
||||
@@ -206,7 +199,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
'wrong-password'
|
||||
)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe('Invalid password')
|
||||
})
|
||||
|
||||
it('should handle concurrent login attempts correctly', async () => {
|
||||
@@ -243,7 +235,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
)
|
||||
expect(result).toEqual(mockUserCredential)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
it('should handle registration errors', async () => {
|
||||
@@ -262,7 +253,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
'password'
|
||||
)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe('Email already in use')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -282,7 +272,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
await expect(store.logout()).rejects.toThrow('Network error')
|
||||
|
||||
expect(firebaseAuth.signOut).toHaveBeenCalledWith(mockAuth)
|
||||
expect(store.error).toBe('Network error')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -356,7 +345,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
)
|
||||
expect(result).toEqual(mockUserCredential)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
it('should handle Google sign in errors', async () => {
|
||||
@@ -372,7 +360,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
expect.any(firebaseAuth.GoogleAuthProvider)
|
||||
)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe('Google authentication failed')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -391,7 +378,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
)
|
||||
expect(result).toEqual(mockUserCredential)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe(null)
|
||||
})
|
||||
|
||||
it('should handle Github sign in errors', async () => {
|
||||
@@ -407,7 +393,6 @@ describe('useFirebaseAuthStore', () => {
|
||||
expect.any(firebaseAuth.GithubAuthProvider)
|
||||
)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(store.error).toBe('Github authentication failed')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user