mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-07 00:20:07 +00:00
[fix] Improve cloud onboarding UX with email verification polling and signup flow (#6030)
## Summary Improve cloud onboarding flow by adding email verification polling and fixing signup auto-logout issue. ## Changes - **What**: - Add polling mechanism to automatically check email verification status every 5 seconds on the verify email page - Fix auto-logout issue after signup by redirecting to root instead of login page - Remove automatic logout on login page mount to preserve user session after signup - **Breaking**: None - **Dependencies**: None ## Review Focus - Email verification polling implementation uses Firebase Auth's `reload()` method to refresh user state - Polling stops after 5 minutes to prevent indefinite resource usage - Proper cleanup of intervals/timeouts in `onUnmounted` hook to prevent memory leaks - Signup flow now maintains user session instead of forcing re-login ## User Experience Improvements 1. **Before**: Users had to manually refresh the page after clicking email verification link **After**: Page automatically detects verification and proceeds to next step 2. **Before**: After signup, users were redirected to login page and automatically logged out, requiring them to sign in again **After**: Users stay logged in after signup and are redirected to root, maintaining their session ## Testing - Tested email verification polling with both verified and unverified states - Verified that invite codes are preserved throughout the flow - Confirmed no memory leaks from polling intervals - Tested signup flow with email/password authentication ## Related Issues - Resolves user complaints about having to sign in twice during signup flow - Addresses email verification page not auto-advancing after verification ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6030-fix-Improve-cloud-onboarding-UX-with-email-verification-polling-and-signup-flow-28a6d73d365081be8020caee6337c3e7) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -104,7 +104,7 @@
|
||||
import Button from 'primevue/button'
|
||||
import Divider from 'primevue/divider'
|
||||
import Message from 'primevue/message'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
@@ -179,8 +179,4 @@ const signInWithEmail = async (values: SignInData) => {
|
||||
await onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await authActions.logout()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -117,7 +117,8 @@ const navigateToLogin = () => {
|
||||
}
|
||||
|
||||
const onSuccess = async () => {
|
||||
await router.push({ name: 'cloud-login', query: route.query })
|
||||
// The invite code will be handled after the user is logged in
|
||||
await router.push({ path: '/', query: route.query })
|
||||
}
|
||||
|
||||
// Custom error handler for inline display
|
||||
|
||||
@@ -35,19 +35,54 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useFirebaseAuth } from 'vuefire'
|
||||
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const auth = useFirebaseAuth()!
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { t } = useI18n()
|
||||
|
||||
let intervalId: number | null = null
|
||||
let timeoutId: number | null = null
|
||||
const redirectInProgress = ref(false)
|
||||
|
||||
function clearPolling(): void {
|
||||
if (intervalId !== null) {
|
||||
clearInterval(intervalId)
|
||||
intervalId = null
|
||||
}
|
||||
if (timeoutId !== null) {
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = null
|
||||
}
|
||||
}
|
||||
|
||||
async function redirectToNextStep(): Promise<void> {
|
||||
if (redirectInProgress.value) return
|
||||
|
||||
redirectInProgress.value = true
|
||||
clearPolling()
|
||||
|
||||
const inviteCode = route.query.inviteCode as string | undefined
|
||||
|
||||
if (inviteCode) {
|
||||
await router.push({
|
||||
name: 'cloud-invite-check',
|
||||
query: { inviteCode }
|
||||
})
|
||||
} else {
|
||||
await router.push({ name: 'cloud-user-check' })
|
||||
}
|
||||
}
|
||||
|
||||
const goBack = async () => {
|
||||
const inviteCode = route.query.inviteCode as string | undefined
|
||||
const authStore = useFirebaseAuthStore()
|
||||
@@ -86,23 +121,35 @@ async function onSend() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// When this screen loads via invite flow,
|
||||
// ensure the invite code stays in the URL for the next step.
|
||||
const inviteCode = route.query.inviteCode as string | undefined
|
||||
|
||||
// If the user is already verified (email link already clicked),
|
||||
// continue to the next step automatically.
|
||||
if (authStore.isEmailVerified) {
|
||||
if (inviteCode) {
|
||||
await router.push({
|
||||
name: 'cloud-invite-check',
|
||||
query: inviteCode ? { inviteCode } : {}
|
||||
})
|
||||
} else {
|
||||
await router.push({ name: 'cloud-user-check' })
|
||||
}
|
||||
} else {
|
||||
await onSend()
|
||||
return redirectToNextStep()
|
||||
}
|
||||
|
||||
// Send initial verification email
|
||||
await onSend()
|
||||
|
||||
// Start polling to check email verification status
|
||||
intervalId = window.setInterval(async () => {
|
||||
if (auth.currentUser && !redirectInProgress.value) {
|
||||
await auth.currentUser.reload()
|
||||
if (auth.currentUser?.emailVerified) {
|
||||
void redirectToNextStep()
|
||||
}
|
||||
}
|
||||
}, 5000) // Check every 5 seconds
|
||||
|
||||
// Stop polling after 5 minutes
|
||||
timeoutId = window.setTimeout(
|
||||
() => {
|
||||
clearPolling()
|
||||
},
|
||||
5 * 60 * 1000
|
||||
)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearPolling()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user