diff --git a/src/components/dialog/content/SignInContent.vue b/src/components/dialog/content/SignInContent.vue index 35a72ac03..db701166e 100644 --- a/src/components/dialog/content/SignInContent.vue +++ b/src/components/dialog/content/SignInContent.vue @@ -19,7 +19,7 @@ - + @@ -87,46 +87,44 @@ import Divider from 'primevue/divider' import { ref } from 'vue' import { useI18n } from 'vue-i18n' -import { useErrorHandling } from '@/composables/useErrorHandling' import { SignInData, SignUpData } from '@/schemas/signInSchema' -import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' +import { useFirebaseAuthService } from '@/services/firebaseAuthService' import SignInForm from './signin/SignInForm.vue' import SignUpForm from './signin/SignUpForm.vue' -const { t } = useI18n() - const { onSuccess } = defineProps<{ onSuccess: () => void }>() -const firebaseAuthStore = useFirebaseAuthStore() -const { wrapWithErrorHandlingAsync } = useErrorHandling() - +const { t } = useI18n() +const authService = useFirebaseAuthService() const isSignIn = ref(true) const toggleState = () => { isSignIn.value = !isSignIn.value } -const signInWithGoogle = wrapWithErrorHandlingAsync(async () => { - await firebaseAuthStore.loginWithGoogle() - onSuccess() -}) - -const signInWithGithub = wrapWithErrorHandlingAsync(async () => { - await firebaseAuthStore.loginWithGithub() - onSuccess() -}) - -const signInWithEmail = wrapWithErrorHandlingAsync( - async (values: SignInData | SignUpData) => { - const { email, password } = values - if (isSignIn.value) { - await firebaseAuthStore.login(email, password) - } else { - await firebaseAuthStore.register(email, password) - } +const signInWithGoogle = async () => { + if (await authService.signInWithGoogle()) { onSuccess() } -) +} + +const signInWithGithub = async () => { + if (await authService.signInWithGithub()) { + onSuccess() + } +} + +const signInWithEmail = async (values: SignInData) => { + if (await authService.signInWithEmail(values.email, values.password)) { + onSuccess() + } +} + +const signUpWithEmail = async (values: SignUpData) => { + if (await authService.signUpWithEmail(values.email, values.password)) { + onSuccess() + } +} diff --git a/src/composables/useErrorHandling.ts b/src/composables/useErrorHandling.ts index ffeaa2998..623e6c5e0 100644 --- a/src/composables/useErrorHandling.ts +++ b/src/composables/useErrorHandling.ts @@ -3,13 +3,11 @@ import { useToastStore } from '@/stores/toastStore' export function useErrorHandling() { const toast = useToastStore() - - const toastErrorHandler = (error: any) => { - console.error(error) + const toastErrorHandler = (error: unknown) => { toast.add({ severity: 'error', summary: t('g.error'), - detail: error.message + detail: error instanceof Error ? error.message : t('g.unknownError') }) } @@ -45,5 +43,9 @@ export function useErrorHandling() { } } - return { wrapWithErrorHandling, wrapWithErrorHandlingAsync } + return { + wrapWithErrorHandling, + wrapWithErrorHandlingAsync, + toastErrorHandler + } } diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 95e2d3957..653c801e4 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -1085,7 +1085,8 @@ "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}" + "failedToPurchaseCredits": "Failed to purchase credits: {error}", + "unauthorizedDomain": "Your domain {domain} is not authorized to use this service. Please contact {email} to add your domain to the whitelist." }, "auth": { "login": { diff --git a/src/locales/es/main.json b/src/locales/es/main.json index baa387ef4..ea85f4224 100644 --- a/src/locales/es/main.json +++ b/src/locales/es/main.json @@ -1131,6 +1131,7 @@ "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", + "unauthorizedDomain": "Tu dominio {domain} no está autorizado para usar este servicio. Por favor, contacta a {email} para agregar tu dominio a la lista blanca.", "updateRequested": "Actualización solicitada", "userNotAuthenticated": "Usuario no autenticado" }, diff --git a/src/locales/fr/main.json b/src/locales/fr/main.json index 10f1207b5..489cfb408 100644 --- a/src/locales/fr/main.json +++ b/src/locales/fr/main.json @@ -1131,6 +1131,7 @@ "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", + "unauthorizedDomain": "Votre domaine {domain} n'est pas autorisé à utiliser ce service. Veuillez contacter {email} pour ajouter votre domaine à la liste blanche.", "updateRequested": "Mise à jour demandée", "userNotAuthenticated": "Utilisateur non authentifié" }, diff --git a/src/locales/ja/main.json b/src/locales/ja/main.json index c58a65458..bd7f41bc1 100644 --- a/src/locales/ja/main.json +++ b/src/locales/ja/main.json @@ -1131,6 +1131,7 @@ "pendingTasksDeleted": "保留中のタスクが削除されました", "pleaseSelectNodesToGroup": "グループを作成するためのノード(または他のグループ)を選択してください", "unableToGetModelFilePath": "モデルファイルのパスを取得できません", + "unauthorizedDomain": "あなたのドメイン {domain} はこのサービスを利用する権限がありません。ご利用のドメインをホワイトリストに追加するには、{email} までご連絡ください。", "updateRequested": "更新が要求されました", "userNotAuthenticated": "ユーザーが認証されていません" }, diff --git a/src/locales/ko/main.json b/src/locales/ko/main.json index 76075175d..2cb2f1d1a 100644 --- a/src/locales/ko/main.json +++ b/src/locales/ko/main.json @@ -1131,6 +1131,7 @@ "pendingTasksDeleted": "보류 중인 작업이 삭제되었습니다", "pleaseSelectNodesToGroup": "그룹을 만들기 위해 노드(또는 다른 그룹)를 선택해 주세요", "unableToGetModelFilePath": "모델 파일 경로를 가져올 수 없습니다", + "unauthorizedDomain": "귀하의 도메인 {domain}은(는) 이 서비스를 사용할 수 있는 권한이 없습니다. 도메인을 허용 목록에 추가하려면 {email}로 문의해 주세요.", "updateRequested": "업데이트 요청됨", "userNotAuthenticated": "사용자가 인증되지 않았습니다" }, diff --git a/src/locales/ru/main.json b/src/locales/ru/main.json index 717fbe622..f0df1621d 100644 --- a/src/locales/ru/main.json +++ b/src/locales/ru/main.json @@ -1131,6 +1131,7 @@ "pendingTasksDeleted": "Ожидающие задачи удалены", "pleaseSelectNodesToGroup": "Пожалуйста, выберите узлы (или другие группы) для создания группы", "unableToGetModelFilePath": "Не удалось получить путь к файлу модели", + "unauthorizedDomain": "Ваш домен {domain} не авторизован для использования этого сервиса. Пожалуйста, свяжитесь с {email}, чтобы добавить ваш домен в белый список.", "updateRequested": "Запрошено обновление", "userNotAuthenticated": "Пользователь не аутентифицирован" }, diff --git a/src/locales/zh/main.json b/src/locales/zh/main.json index 6f7dc95bf..9dba863ac 100644 --- a/src/locales/zh/main.json +++ b/src/locales/zh/main.json @@ -1131,6 +1131,7 @@ "pendingTasksDeleted": "待处理任务已删除", "pleaseSelectNodesToGroup": "请选取节点(或其他组)以创建分组", "unableToGetModelFilePath": "无法获取模型文件路径", + "unauthorizedDomain": "您的域名 {domain} 未被授权使用此服务。请联系 {email} 将您的域名添加到白名单。", "updateRequested": "已请求更新", "userNotAuthenticated": "用户未认证" }, diff --git a/src/services/firebaseAuthService.ts b/src/services/firebaseAuthService.ts index a63c52f15..d453a6fd5 100644 --- a/src/services/firebaseAuthService.ts +++ b/src/services/firebaseAuthService.ts @@ -1,3 +1,5 @@ +import { FirebaseError } from 'firebase/app' + import { useErrorHandling } from '@/composables/useErrorHandling' import { t } from '@/i18n' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' @@ -12,15 +14,29 @@ import { usdToMicros } from '@/utils/formatUtil' export const useFirebaseAuthService = () => { const authStore = useFirebaseAuthStore() const toastStore = useToastStore() - const { wrapWithErrorHandlingAsync } = useErrorHandling() + const { wrapWithErrorHandlingAsync, toastErrorHandler } = useErrorHandling() const reportError = (error: unknown) => { - toastStore.add({ - severity: 'error', - summary: t('g.error'), - detail: error instanceof Error ? error.message : t('g.unknownError'), - life: 5000 - }) + // Ref: https://firebase.google.com/docs/auth/admin/errors + if ( + error instanceof FirebaseError && + [ + 'auth/unauthorized-domain', + 'auth/invalid-dynamic-link-domain', + 'auth/unauthorized-continue-uri' + ].includes(error.code) + ) { + toastStore.add({ + severity: 'error', + summary: t('g.error'), + detail: t('toastMessages.unauthorizedDomain', { + domain: window.location.hostname, + email: 'support@comfy.org' + }) + }) + } else { + toastErrorHandler(error) + } } const logout = wrapWithErrorHandlingAsync(async () => { @@ -77,14 +93,40 @@ export const useFirebaseAuthService = () => { }, reportError) const fetchBalance = wrapWithErrorHandlingAsync(async () => { - await authStore.fetchBalance() + return await authStore.fetchBalance() }, reportError) + const signInWithGoogle = wrapWithErrorHandlingAsync(async () => { + return await authStore.loginWithGoogle() + }, reportError) + + const signInWithGithub = wrapWithErrorHandlingAsync(async () => { + return await authStore.loginWithGithub() + }, reportError) + + const signInWithEmail = wrapWithErrorHandlingAsync( + async (email: string, password: string) => { + return await authStore.login(email, password) + }, + reportError + ) + + const signUpWithEmail = wrapWithErrorHandlingAsync( + async (email: string, password: string) => { + return await authStore.register(email, password) + }, + reportError + ) + return { logout, sendPasswordReset, purchaseCredits, accessBillingPortal, - fetchBalance + fetchBalance, + signInWithGoogle, + signInWithGithub, + signInWithEmail, + signUpWithEmail } }