Skip to content

Commit 7e1e8e3

Browse files
subscription page (#6064)
Summary Implements cloud subscription management UI and flow for ComfyUI Cloud users. Core Features: - Subscription Status Tracking: Global reactive state management for subscription status across all components using shared subscriptionStatus ref - Subscribe to Run Button: Replaces the Run button in the actionbar with a "Subscribe to Run" button for users without active subscriptions - Subscription Required Dialog: Modal dialog with subscription benefits, pricing, and checkout flow with video background - Subscription Settings Panel: New settings panel showing subscription status, renewal date, and quick access to billing management - Auto-detection & Polling: Automatically polls subscription status after checkout completion and syncs state across the application https://github.com/user-attachments/assets/f41b8e6a-5845-48a7-8169-3a6fc0d2e5c8 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6064-subscription-page-28d6d73d36508135a2a0fe7c94b40852) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <[email protected]>
1 parent d83e34d commit 7e1e8e3

File tree

22 files changed

+1232
-14
lines changed

22 files changed

+1232
-14
lines changed
64.8 KB
Binary file not shown.

src/components/actionbar/ComfyActionbar.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
)
3535
"
3636
/>
37-
<ComfyQueueButton />
37+
38+
<ComfyRunButton />
3839
</div>
3940
</Panel>
4041
</div>
@@ -55,7 +56,7 @@ import { t } from '@/i18n'
5556
import { useSettingStore } from '@/platform/settings/settingStore'
5657
import { cn } from '@/utils/tailwindUtil'
5758
58-
import ComfyQueueButton from './ComfyQueueButton.vue'
59+
import ComfyRunButton from './ComfyRunButton'
5960
6061
const settingsStore = useSettingStore()
6162
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<component
3+
:is="currentButton"
4+
:key="isActiveSubscription ? 'queue' : 'subscribe'"
5+
/>
6+
</template>
7+
<script setup lang="ts">
8+
import { computed } from 'vue'
9+
10+
import ComfyQueueButton from '@/components/actionbar/ComfyRunButton/ComfyQueueButton.vue'
11+
import SubscribeToRunButton from '@/platform/cloud/subscription/components/SubscribeToRun.vue'
12+
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
13+
14+
const { isActiveSubscription } = useSubscription()
15+
16+
const currentButton = computed(() =>
17+
isActiveSubscription.value ? ComfyQueueButton : SubscribeToRunButton
18+
)
19+
</script>

src/components/actionbar/ComfyQueueButton.vue renamed to src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ import {
9393
} from '@/stores/queueStore'
9494
import { useWorkspaceStore } from '@/stores/workspaceStore'
9595
96-
import BatchCountEdit from './BatchCountEdit.vue'
96+
import BatchCountEdit from '../BatchCountEdit.vue'
9797
9898
const workspaceStore = useWorkspaceStore()
9999
const queueCountStore = storeToRefs(useQueuePendingTaskCountStore())
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineAsyncComponent } from 'vue'
2+
3+
import { isCloud } from '@/platform/distribution/types'
4+
5+
export default isCloud
6+
? defineAsyncComponent(() => import('./CloudRunButtonWrapper.vue'))
7+
: defineAsyncComponent(() => import('./ComfyQueueButton.vue'))
Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
11
<template>
2-
<div class="flex items-center gap-2 bg-comfy-menu-secondary px-3">
2+
<div
3+
class="flex items-center gap-2 bg-comfy-menu-secondary"
4+
:class="[{ 'flex-row-reverse': reverseOrder }, noPadding ? '' : 'px-3']"
5+
>
36
<div
47
v-if="badge.label"
58
class="rounded-full bg-white px-1.5 py-0.5 text-xxxs font-semibold text-black"
9+
:class="labelClass"
610
>
711
{{ badge.label }}
812
</div>
9-
<div class="font-inter text-sm font-extrabold text-slate-100">
13+
<div
14+
class="font-inter text-sm font-extrabold text-slate-100"
15+
:class="textClass"
16+
>
1017
{{ badge.text }}
1118
</div>
1219
</div>
1320
</template>
1421
<script setup lang="ts">
1522
import type { TopbarBadge } from '@/types/comfy'
1623
17-
defineProps<{
18-
badge: TopbarBadge
19-
}>()
24+
withDefaults(
25+
defineProps<{
26+
badge: TopbarBadge
27+
reverseOrder?: boolean
28+
noPadding?: boolean
29+
labelClass?: string
30+
textClass?: string
31+
}>(),
32+
{
33+
reverseOrder: false,
34+
noPadding: false,
35+
labelClass: '',
36+
textClass: ''
37+
}
38+
)
2039
</script>

src/components/topbar/TopbarBadges.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
v-for="badge in topbarBadgeStore.badges"
55
:key="badge.text"
66
:badge
7+
:reverse-order="reverseOrder"
8+
:no-padding="noPadding"
9+
:label-class="labelClass"
10+
:text-class="textClass"
711
/>
812
</div>
913
</template>
@@ -13,5 +17,20 @@ import { useTopbarBadgeStore } from '@/stores/topbarBadgeStore'
1317
1418
import TopbarBadge from './TopbarBadge.vue'
1519
20+
withDefaults(
21+
defineProps<{
22+
reverseOrder?: boolean
23+
noPadding?: boolean
24+
labelClass?: string
25+
textClass?: string
26+
}>(),
27+
{
28+
reverseOrder: false,
29+
noPadding: false,
30+
labelClass: '',
31+
textClass: ''
32+
}
33+
)
34+
1635
const topbarBadgeStore = useTopbarBadgeStore()
1736
</script>

src/composables/auth/useFirebaseAuthActions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ export const useFirebaseAuthActions = () => {
208208
signUpWithEmail,
209209
updatePassword,
210210
deleteAccount,
211-
accessError
211+
accessError,
212+
reportError
212213
}
213214
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MONTHLY_SUBSCRIPTION_PRICE = 20
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { watch } from 'vue'
2+
3+
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
4+
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
5+
import { useExtensionService } from '@/services/extensionService'
6+
7+
useExtensionService().registerExtension({
8+
name: 'Comfy.CloudSubscription',
9+
10+
setup: async () => {
11+
const { isLoggedIn } = useCurrentUser()
12+
const { requireActiveSubscription } = useSubscription()
13+
14+
const checkSubscriptionStatus = () => {
15+
if (!isLoggedIn.value) return
16+
17+
void requireActiveSubscription()
18+
}
19+
20+
watch(() => isLoggedIn.value, checkSubscriptionStatus, {
21+
immediate: true
22+
})
23+
}
24+
})

0 commit comments

Comments
 (0)