Skip to content

Commit 693fbbd

Browse files
DrJKLviva-jinyiactions-user
authored
Mainification: Bring Onboarding in from rh-test (#6564)
## Summary Migrate the onboarding / login / sign-up / survey pieces from `rh-test` to `main`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6564-WIP-Bring-Onboarding-in-from-rh-test-2a16d73d365081318483f993e3ca0f89) by [Unito](https://www.unito.io) --------- Co-authored-by: Jin Yi <[email protected]> Co-authored-by: GitHub Action <[email protected]>
1 parent 47688fe commit 693fbbd

30 files changed

+2296
-38
lines changed

public/assets/images/comfy-cloud-logo.svg

Lines changed: 4 additions & 0 deletions
Loading

src/composables/auth/useFirebaseAuthActions.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { FirebaseError } from 'firebase/app'
22
import { AuthErrorCodes } from 'firebase/auth'
33
import { ref } from 'vue'
4-
import { useRouter } from 'vue-router'
54

65
import { useErrorHandling } from '@/composables/useErrorHandling'
76
import type { ErrorRecoveryStrategy } from '@/composables/useErrorHandling'
@@ -61,8 +60,7 @@ export const useFirebaseAuthActions = () => {
6160

6261
if (isCloud) {
6362
try {
64-
const router = useRouter()
65-
await router.push({ name: 'cloud-login' })
63+
window.location.href = '/cloud/login'
6664
} catch (error) {
6765
// needed for local development until we bring in cloud login pages.
6866
window.location.reload()

src/locales/en/main.json

Lines changed: 456 additions & 17 deletions
Large diffs are not rendered by default.

src/locales/en/nodeDefs.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4640,7 +4640,10 @@
46404640
},
46414641
"height": {
46424642
"name": "height"
4643-
}
4643+
},
4644+
"clear": {},
4645+
"upload 3d model": {},
4646+
"upload extra resources": {}
46444647
},
46454648
"outputs": {
46464649
"0": {
@@ -8802,6 +8805,9 @@
88028805
},
88038806
"camera_info": {
88048807
"name": "camera_info"
8808+
},
8809+
"image": {
8810+
"name": "image"
88058811
}
88068812
}
88078813
},
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<template>
2+
<div class="flex h-full items-center justify-center p-6">
3+
<div class="max-w-[100vw] text-center lg:w-[500px]">
4+
<h2 class="mb-3 text-xl text-text-primary">
5+
{{ $t('cloudOnboarding.authTimeout.title') }}
6+
</h2>
7+
<p class="mb-5 text-muted">
8+
{{ $t('cloudOnboarding.authTimeout.message') }}
9+
</p>
10+
11+
<!-- Troubleshooting Section -->
12+
<div
13+
class="mb-4 rounded bg-surface-700 px-3 py-2 text-left dark-theme:bg-surface-800"
14+
>
15+
<h3 class="mb-2 text-sm font-semibold text-text-primary">
16+
{{ $t('cloudOnboarding.authTimeout.troubleshooting') }}
17+
</h3>
18+
<ul class="space-y-1.5 text-sm text-muted">
19+
<li
20+
v-for="(cause, index) in $tm('cloudOnboarding.authTimeout.causes')"
21+
:key="index"
22+
class="flex gap-2"
23+
>
24+
<span>•</span>
25+
<span>{{ cause }}</span>
26+
</li>
27+
</ul>
28+
</div>
29+
30+
<!-- Technical Details (Collapsible) -->
31+
<div v-if="errorMessage" class="mb-4 text-left">
32+
<button
33+
class="flex w-full items-center justify-between rounded bg-surface-600 px-4 py-2 text-sm text-muted transition-colors hover:bg-surface-500 dark-theme:bg-surface-700 dark-theme:hover:bg-surface-600"
34+
@click="showTechnicalDetails = !showTechnicalDetails"
35+
>
36+
<span>{{ $t('cloudOnboarding.authTimeout.technicalDetails') }}</span>
37+
<i
38+
:class="[
39+
'pi',
40+
showTechnicalDetails ? 'pi-chevron-up' : 'pi-chevron-down'
41+
]"
42+
></i>
43+
</button>
44+
<div
45+
v-if="showTechnicalDetails"
46+
class="mt-2 rounded bg-surface-800 p-4 font-mono text-xs text-muted break-all dark-theme:bg-surface-900"
47+
>
48+
{{ errorMessage }}
49+
</div>
50+
</div>
51+
52+
<!-- Helpful Links -->
53+
<p class="mb-5 text-center text-sm text-gray-600">
54+
{{ $t('cloudOnboarding.authTimeout.helpText') }}
55+
<a
56+
href="https://support.comfy.org"
57+
class="cursor-pointer text-blue-400 no-underline"
58+
target="_blank"
59+
rel="noopener noreferrer"
60+
>
61+
{{ $t('cloudOnboarding.authTimeout.supportLink') }}</a
62+
>.
63+
</p>
64+
65+
<div class="flex flex-col gap-3">
66+
<Button
67+
:label="$t('cloudOnboarding.authTimeout.restart')"
68+
class="w-full"
69+
@click="handleRestart"
70+
/>
71+
</div>
72+
</div>
73+
</div>
74+
</template>
75+
76+
<script setup lang="ts">
77+
import Button from 'primevue/button'
78+
import { ref } from 'vue'
79+
import { useRouter } from 'vue-router'
80+
81+
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
82+
83+
interface Props {
84+
errorMessage?: string
85+
}
86+
87+
defineProps<Props>()
88+
89+
const router = useRouter()
90+
const { logout } = useFirebaseAuthActions()
91+
const showTechnicalDetails = ref(false)
92+
93+
const handleRestart = async () => {
94+
await logout()
95+
await router.replace({ name: 'cloud-login' })
96+
}
97+
</script>
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<template>
2+
<div class="flex h-full items-center justify-center p-8">
3+
<div class="max-w-[100vw] p-2 lg:w-96">
4+
<!-- Header -->
5+
<div class="mb-8 flex flex-col gap-4">
6+
<h1 class="my-0 text-xl leading-normal font-medium">
7+
{{ t('cloudForgotPassword_title') }}
8+
</h1>
9+
<p class="my-0 text-base text-muted">
10+
{{ t('cloudForgotPassword_instructions') }}
11+
</p>
12+
</div>
13+
14+
<!-- Form -->
15+
<form class="flex flex-col gap-6" @submit.prevent="handleSubmit">
16+
<div class="flex flex-col gap-2">
17+
<label
18+
class="mb-2 text-base font-medium opacity-80"
19+
for="reset-email"
20+
>
21+
{{ t('cloudForgotPassword_emailLabel') }}
22+
</label>
23+
<InputText
24+
id="reset-email"
25+
v-model="email"
26+
type="email"
27+
:placeholder="t('cloudForgotPassword_emailPlaceholder')"
28+
class="h-10"
29+
:invalid="!!errorMessage && !email"
30+
autocomplete="email"
31+
required
32+
/>
33+
<small v-if="errorMessage" class="text-red-500">
34+
{{ errorMessage }}
35+
</small>
36+
</div>
37+
38+
<Message v-if="successMessage" severity="success">
39+
{{ successMessage }}
40+
</Message>
41+
42+
<div class="flex flex-col gap-4">
43+
<Button
44+
type="submit"
45+
:label="t('cloudForgotPassword_sendResetLink')"
46+
:loading="loading"
47+
:disabled="!email || loading"
48+
class="h-10 font-medium text-white"
49+
/>
50+
51+
<Button
52+
type="button"
53+
:label="t('cloudForgotPassword_backToLogin')"
54+
severity="secondary"
55+
class="h-10 bg-[#2d2e32]"
56+
@click="navigateToLogin"
57+
/>
58+
</div>
59+
</form>
60+
61+
<!-- Help text -->
62+
<p class="mt-5 text-sm text-gray-600">
63+
{{ t('cloudForgotPassword_didntReceiveEmail') }}
64+
</p>
65+
</div>
66+
</div>
67+
</template>
68+
69+
<script setup lang="ts">
70+
import Button from 'primevue/button'
71+
import InputText from 'primevue/inputtext'
72+
import Message from 'primevue/message'
73+
import { ref } from 'vue'
74+
import { useI18n } from 'vue-i18n'
75+
import { useRouter } from 'vue-router'
76+
77+
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
78+
79+
const { t } = useI18n()
80+
const router = useRouter()
81+
const authActions = useFirebaseAuthActions()
82+
83+
const email = ref('')
84+
const loading = ref(false)
85+
const errorMessage = ref('')
86+
const successMessage = ref('')
87+
88+
const navigateToLogin = () => {
89+
void router.push({ name: 'cloud-login' })
90+
}
91+
92+
const handleSubmit = async () => {
93+
if (!email.value) {
94+
errorMessage.value = t('cloudForgotPassword_emailRequired')
95+
return
96+
}
97+
98+
loading.value = true
99+
errorMessage.value = ''
100+
successMessage.value = ''
101+
102+
try {
103+
// sendPasswordReset is already wrapped and returns a promise
104+
await authActions.sendPasswordReset(email.value)
105+
106+
successMessage.value = t('cloudForgotPassword_passwordResetSent')
107+
108+
// Optionally redirect to login after a delay
109+
setTimeout(() => {
110+
navigateToLogin()
111+
}, 3000)
112+
} catch (error) {
113+
console.error('Password reset error:', error)
114+
errorMessage.value = t('cloudForgotPassword_passwordResetError')
115+
} finally {
116+
loading.value = false
117+
}
118+
}
119+
</script>
120+
<style scoped>
121+
:deep(.p-inputtext) {
122+
border: none !important;
123+
box-shadow: none !important;
124+
background: #2d2e32 !important;
125+
}
126+
</style>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<template>
2+
<div class="flex h-full items-center justify-center p-8">
3+
<div class="max-w-screen p-2 lg:w-96">
4+
<!-- Header -->
5+
<div class="mt-6 mb-8 flex flex-col gap-4">
6+
<h1 class="my-0 text-xl leading-normal font-medium">
7+
{{ t('auth.login.title') }}
8+
</h1>
9+
<p class="my-0 text-base">
10+
<span class="text-muted">{{ t('auth.login.newUser') }}</span>
11+
<span
12+
class="ml-1 cursor-pointer text-blue-500"
13+
@click="navigateToSignup"
14+
>{{ t('auth.login.signUp') }}</span
15+
>
16+
</p>
17+
</div>
18+
19+
<Message v-if="!isSecureContext" severity="warn" class="mb-4">
20+
{{ t('auth.login.insecureContextWarning') }}
21+
</Message>
22+
23+
<!-- Form -->
24+
<CloudSignInForm :auth-error="authError" @submit="signInWithEmail" />
25+
26+
<!-- Divider -->
27+
<Divider align="center" layout="horizontal" class="my-8">
28+
<span class="text-muted">{{ t('auth.login.orContinueWith') }}</span>
29+
</Divider>
30+
31+
<!-- Social Login Buttons -->
32+
<div class="flex flex-col gap-6">
33+
<Button
34+
type="button"
35+
class="h-10 bg-[#2d2e32]"
36+
severity="secondary"
37+
@click="signInWithGoogle"
38+
>
39+
<i class="pi pi-google mr-2"></i>
40+
{{ t('auth.login.loginWithGoogle') }}
41+
</Button>
42+
43+
<Button
44+
type="button"
45+
class="h-10 bg-[#2d2e32]"
46+
severity="secondary"
47+
@click="signInWithGithub"
48+
>
49+
<i class="pi pi-github mr-2"></i>
50+
{{ t('auth.login.loginWithGithub') }}
51+
</Button>
52+
</div>
53+
54+
<!-- Terms & Contact -->
55+
<p class="mt-5 text-sm text-gray-600">
56+
{{ t('auth.login.termsText') }}
57+
<a
58+
href="https://www.comfy.org/terms-of-service"
59+
target="_blank"
60+
class="cursor-pointer text-blue-400 no-underline"
61+
>
62+
{{ t('auth.login.termsLink') }}
63+
</a>
64+
{{ t('auth.login.andText') }}
65+
<a
66+
href="https://www.comfy.org/privacy-policy"
67+
target="_blank"
68+
class="cursor-pointer text-blue-400 no-underline"
69+
>
70+
{{ t('auth.login.privacyLink') }} </a
71+
>.
72+
</p>
73+
</div>
74+
</div>
75+
</template>
76+
77+
<script setup lang="ts">
78+
import Button from 'primevue/button'
79+
import Divider from 'primevue/divider'
80+
import Message from 'primevue/message'
81+
import { ref } from 'vue'
82+
import { useI18n } from 'vue-i18n'
83+
import { useRoute, useRouter } from 'vue-router'
84+
85+
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
86+
import CloudSignInForm from '@/platform/cloud/onboarding/components/CloudSignInForm.vue'
87+
import { useToastStore } from '@/platform/updates/common/toastStore'
88+
import type { SignInData } from '@/schemas/signInSchema'
89+
90+
const { t } = useI18n()
91+
const router = useRouter()
92+
const route = useRoute()
93+
const authActions = useFirebaseAuthActions()
94+
const isSecureContext = window.isSecureContext
95+
const authError = ref('')
96+
const toastStore = useToastStore()
97+
98+
const navigateToSignup = () => {
99+
void router.push({ name: 'cloud-signup', query: route.query })
100+
}
101+
102+
const onSuccess = async () => {
103+
toastStore.add({
104+
severity: 'success',
105+
summary: 'Login Completed',
106+
life: 2000
107+
})
108+
await router.push({ name: 'cloud-user-check' })
109+
}
110+
111+
const signInWithGoogle = async () => {
112+
authError.value = ''
113+
if (await authActions.signInWithGoogle()) {
114+
await onSuccess()
115+
}
116+
}
117+
118+
const signInWithGithub = async () => {
119+
authError.value = ''
120+
if (await authActions.signInWithGithub()) {
121+
await onSuccess()
122+
}
123+
}
124+
125+
const signInWithEmail = async (values: SignInData) => {
126+
authError.value = ''
127+
if (await authActions.signInWithEmail(values.email, values.password)) {
128+
await onSuccess()
129+
}
130+
}
131+
</script>

0 commit comments

Comments
 (0)